Compare commits
107 Commits
branch_1_1
...
master
Author | SHA1 | Date |
---|---|---|
hoenicke | e5c8e18a43 | 11 years ago |
hoenicke | 33504d1840 | 11 years ago |
hoenicke | 7a96e31c81 | 12 years ago |
hoenicke | 0277d99ebb | 12 years ago |
hoenicke | accfa1271e | 12 years ago |
hoenicke | 744346bbcb | 12 years ago |
hoenicke | 3c76f52d03 | 12 years ago |
hoenicke | 5815ab3a08 | 12 years ago |
hoenicke | 977e4a6e8d | 18 years ago |
asal | 0526241d2f | 18 years ago |
asal | 2610837e4e | 18 years ago |
asal | 08ca574741 | 18 years ago |
hoenicke | a69e8b35b6 | 18 years ago |
hoenicke | 39775ca4ee | 18 years ago |
hoenicke | f7d5e15584 | 19 years ago |
hoenicke | 000cbe01e8 | 19 years ago |
hoenicke | 4ff081adef | 19 years ago |
hoenicke | 183db2f66c | 20 years ago |
hoenicke | 4ec17554de | 20 years ago |
hoenicke | 7a700a7a5b | 20 years ago |
hoenicke | 9e663e0b65 | 20 years ago |
hoenicke | 7442ded059 | 20 years ago |
hoenicke | 487a4b49d9 | 20 years ago |
hoenicke | 033d9d57e5 | 20 years ago |
hoenicke | ec129979e1 | 20 years ago |
hoenicke | ae5ffbf3f8 | 20 years ago |
hoenicke | bf472df5c0 | 21 years ago |
hoenicke | 338feb1f61 | 21 years ago |
seeksthemoon | 2872b22195 | 21 years ago |
seeksthemoon | c53a8d1acf | 21 years ago |
hoenicke | 0c1d7a4b7c | 22 years ago |
hoenicke | 66dc0880ab | 22 years ago |
hoenicke | 48d511532d | 22 years ago |
hoenicke | d6462acefc | 22 years ago |
hoenicke | f43b317ae8 | 22 years ago |
hoenicke | 375a002248 | 23 years ago |
hoenicke | b33f6d1045 | 23 years ago |
hoenicke | c11b2426df | 23 years ago |
hoenicke | d7567a6b06 | 23 years ago |
hoenicke | 06f647eb1c | 23 years ago |
hoenicke | c0bd096c0d | 23 years ago |
hoenicke | d04992725b | 23 years ago |
hoenicke | d3f133999f | 23 years ago |
hoenicke | 25339761a8 | 23 years ago |
hoenicke | 0243eb4f23 | 23 years ago |
hoenicke | 9e5dca11ad | 23 years ago |
hoenicke | d5a0591d1f | 23 years ago |
hoenicke | 2d1bb14f08 | 23 years ago |
hoenicke | 14b4dd94f8 | 23 years ago |
hoenicke | 7714d5d503 | 23 years ago |
hoenicke | 6acf9d8d7a | 23 years ago |
hoenicke | dab92b2d4d | 23 years ago |
hoenicke | 4352b285ab | 23 years ago |
hoenicke | 1ce57d3614 | 23 years ago |
hoenicke | 804d4f7912 | 23 years ago |
hoenicke | 743e08ea39 | 23 years ago |
hoenicke | 31ebef4f9c | 23 years ago |
hoenicke | a2006f63d4 | 23 years ago |
hoenicke | f2d8663e9f | 23 years ago |
hoenicke | e78e8b0472 | 23 years ago |
hoenicke | 676e21257f | 23 years ago |
hoenicke | c30ac484c5 | 23 years ago |
hoenicke | 9f97289a90 | 23 years ago |
hoenicke | 472188e7ff | 23 years ago |
hoenicke | 14943a8451 | 24 years ago |
hoenicke | 9cbbe3b6ea | 24 years ago |
hoenicke | 51ad83c9c9 | 24 years ago |
hoenicke | 2ae9fec86a | 24 years ago |
hoenicke | 5a22174883 | 24 years ago |
hoenicke | e3e58de150 | 24 years ago |
hoenicke | 389f642dd5 | 24 years ago |
hoenicke | 342283c03a | 24 years ago |
hoenicke | 9470aef606 | 24 years ago |
hoenicke | 03a84b8f4f | 24 years ago |
hoenicke | 31b99cc4f0 | 24 years ago |
hoenicke | 8c85a88d39 | 24 years ago |
hoenicke | 854a466d67 | 24 years ago |
hoenicke | 0e32c28865 | 24 years ago |
hoenicke | 00448cfcbc | 24 years ago |
hoenicke | 8f00154e64 | 24 years ago |
hoenicke | 712f5d03dd | 24 years ago |
hoenicke | b14a4f5e86 | 24 years ago |
hoenicke | e4b704ca70 | 24 years ago |
hoenicke | 571bb071fe | 24 years ago |
hoenicke | 1a0fc97111 | 24 years ago |
hoenicke | 4a63627c87 | 24 years ago |
hoenicke | 5e6af53990 | 24 years ago |
hoenicke | ca386721b2 | 24 years ago |
hoenicke | af97d8da6d | 24 years ago |
hoenicke | 7ff611fe09 | 24 years ago |
hoenicke | bde4f7f48c | 24 years ago |
hoenicke | e154dfdc1b | 24 years ago |
hoenicke | 0b2f10fddf | 24 years ago |
hoenicke | bf597fea43 | 24 years ago |
hoenicke | aca625aa34 | 24 years ago |
hoenicke | 34081d2e06 | 24 years ago |
hoenicke | 96ef935ccc | 24 years ago |
hoenicke | 46f4102cec | 24 years ago |
hoenicke | ff73414ef3 | 24 years ago |
hoenicke | b99c87a98d | 24 years ago |
hoenicke | f85c46fd44 | 24 years ago |
hoenicke | 39d1fbb31b | 24 years ago |
hoenicke | 3378492cd3 | 24 years ago |
hoenicke | a34a837696 | 24 years ago |
hoenicke | b53430f5c5 | 24 years ago |
hoenicke | 723088e8be | 24 years ago |
hoenicke | 9c9de3b561 | 24 years ago |
@ -0,0 +1,7 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<classpath> |
||||||
|
<classpathentry excluding="net/sf/jode/obfuscator/modules/LocalOptimizer.java|net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java|net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java" kind="src" output="build" path="src"/> |
||||||
|
<classpathentry kind="lib" path="lib/java-getopt-1.0.8.jar"/> |
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> |
||||||
|
<classpathentry kind="output" path="build"/> |
||||||
|
</classpath> |
@ -0,0 +1,17 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<projectDescription> |
||||||
|
<name>jode</name> |
||||||
|
<comment></comment> |
||||||
|
<projects> |
||||||
|
</projects> |
||||||
|
<buildSpec> |
||||||
|
<buildCommand> |
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
</buildSpec> |
||||||
|
<natures> |
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature> |
||||||
|
</natures> |
||||||
|
</projectDescription> |
@ -0,0 +1,353 @@ |
|||||||
|
#Thu Mar 01 23:39:18 CET 2012 |
||||||
|
eclipse.preferences.version=1 |
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled |
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 |
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve |
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.4 |
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate |
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate |
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate |
||||||
|
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.deadCode=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecation=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error |
||||||
|
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.nullReference=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedImport=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning |
||||||
|
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning |
||||||
|
org.eclipse.jdt.core.compiler.source=1.3 |
||||||
|
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_assignment=0 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_package=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_field=0 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_method=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_package=0 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 |
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line |
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false |
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_block_comments=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_header=false |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_html=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_line_comments=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.format_source_code=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert |
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert |
||||||
|
org.eclipse.jdt.core.formatter.comment.line_length=80 |
||||||
|
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true |
||||||
|
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false |
||||||
|
org.eclipse.jdt.core.formatter.compact_else_if=true |
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation=2 |
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 |
||||||
|
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off |
||||||
|
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on |
||||||
|
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false |
||||||
|
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_empty_lines=false |
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true |
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false |
||||||
|
org.eclipse.jdt.core.formatter.indentation.size=4 |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert |
||||||
|
org.eclipse.jdt.core.formatter.join_lines_in_comments=true |
||||||
|
org.eclipse.jdt.core.formatter.join_wrapped_lines=true |
||||||
|
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false |
||||||
|
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false |
||||||
|
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false |
||||||
|
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false |
||||||
|
org.eclipse.jdt.core.formatter.lineSplit=80 |
||||||
|
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false |
||||||
|
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false |
||||||
|
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 |
||||||
|
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 |
||||||
|
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true |
||||||
|
org.eclipse.jdt.core.formatter.tabulation.char=mixed |
||||||
|
org.eclipse.jdt.core.formatter.tabulation.size=8 |
||||||
|
org.eclipse.jdt.core.formatter.use_on_off_tags=false |
||||||
|
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false |
||||||
|
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true |
||||||
|
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true |
@ -0,0 +1,4 @@ |
|||||||
|
#Thu Mar 01 22:21:28 CET 2012 |
||||||
|
eclipse.preferences.version=1 |
||||||
|
formatter_profile=org.eclipse.jdt.ui.default.sun_profile |
||||||
|
formatter_settings_version=12 |
@ -0,0 +1,3 @@ |
|||||||
|
#Thu Mar 01 22:15:48 CET 2012 |
||||||
|
eclipse.preferences.version=1 |
||||||
|
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false |
@ -1 +1 @@ |
|||||||
Jochen Hoenicke <Jochen.Hoenicke@Informatik.Uni-Oldenburg.DE> |
Jochen Hoenicke <Jochen.Hoenicke@Informatik.Uni-Oldenburg.DE> |
||||||
|
@ -0,0 +1,563 @@ |
|||||||
|
2005-10-14 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* src/net/sf/jode/flow/TransformConstructor.java: |
||||||
|
(lookForConstructorCall) Check for isStatic before setting |
||||||
|
outer $this reference |
||||||
|
(reported by Andreas Salathé, bug #1306688) |
||||||
|
|
||||||
|
2005-09-13 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
Check for NullPointer in SyntheticAnalyzer. Based on |
||||||
|
patch suggessted by Peter Klauser (klp at users.sf.net). |
||||||
|
|
||||||
|
* src/net/sf/jode/jvm/SyntheticAnalyzer.java: |
||||||
|
(checkStaticAccess): Check refField for null pointer. |
||||||
|
(checkAccess): Likewise. |
||||||
|
|
||||||
|
2004-08-06 Jochen Hoenicke <hoenicke@marge.Informatik.Uni-Oldenburg.DE> |
||||||
|
|
||||||
|
* src/net/sf/jode/bytecode/BinaryInfo.java (ACC_*): added |
||||||
|
constants describing modifier attributes. |
||||||
|
* src/net/sf/jode/bytecode/BasicBlockReader.java |
||||||
|
(convertHandlers): remove empty handlers. |
||||||
|
(readCode): merge adjacent try-blocks (splitted by javac-1.4 |
||||||
|
return rule). |
||||||
|
* src/net/sf/jode/bytecode/FieldInfo.java (syntheticFlag): |
||||||
|
removed, use modifier and ACC_SYNTHETIC (new in java 5) instead. |
||||||
|
Changed all usages. When writing it currently writes out both |
||||||
|
old and new synthetic format. |
||||||
|
(getSignature): New method to return full generic signature. |
||||||
|
* src/net/sf/jode/bytecode/MethodInfo.java |
||||||
|
(syntheticFlag, getSignature): likewise. |
||||||
|
* src/net/sf/jode/bytecode/ClassInfo.java (getSignature): |
||||||
|
New method to return full generic signature. |
||||||
|
* src/net/sf/jode/decompiler/MethodAnalyzer.java (skipWriting): |
||||||
|
Skip java 5 bridge methods. |
||||||
|
* src/net/sf/jode/expr/InvokeOperator.java (getClassAnalyzer): |
||||||
|
Check for null callee. |
||||||
|
* src/net/sf/jode/expr/FlowBlock.java (analyze): New order for |
||||||
|
T1,T2 analysis: Do not do T1 analysis when the block has more |
||||||
|
than one real successor and the next block can be easily merged. |
||||||
|
See comment for more information. |
||||||
|
|
||||||
|
2004-08-05 Jochen Hoenicke <hoenicke@marge.Informatik.Uni-Oldenburg.DE> |
||||||
|
|
||||||
|
* build.xml: replace execon with apply. |
||||||
|
* src/net/sf/jode/bytecode/ClassInfo.java (readAttributes): |
||||||
|
read in signature attribute (not yet published, though). |
||||||
|
* src/net/sf/jode/bytecode/MethodInfo.java (readAttributes): |
||||||
|
likewise. |
||||||
|
* src/net/sf/jode/bytecode/FieldInfo.java (readAttributes): |
||||||
|
likewise. |
||||||
|
* src/net/sf/jode/bytecode/ClassInfo.java (mergeModifiers): |
||||||
|
only check the traditional modifiers for equality. |
||||||
|
* src/net/sf/jode/bytecode/ConstantPool.java (getConstant): |
||||||
|
Support for CLASS constants (jdk1.5) added. |
||||||
|
* src/net/sf/jode/bytecode/BasicBlockReader.java (readCode): |
||||||
|
opc_ldc, opc_ldc_w: Support for CLASS constants added. |
||||||
|
* src/net/sf/jode/decompiler/Opcodes.java (addOpcode): |
||||||
|
likewise. |
||||||
|
* src/net/sf/jode/expr/InvokeOperator.java |
||||||
|
(simplifyStringBuffer, simplifyString): |
||||||
|
Also handle StringBuilder (jdk1.5). |
||||||
|
* src/net/sf/jode/type/Type.java (tStringBuilder): new field. |
||||||
|
* src/net/sf/jode/swingui/Main.java (main): handle debug |
||||||
|
options. |
||||||
|
|
||||||
|
|
||||||
|
2004-01-31 Jochen Hoenicke <hoenicke@informatik.uni-oldenburg.de> |
||||||
|
|
||||||
|
* src/net/sf/jode/jvm/SyntheticAnalyzer.java (checkGetClass): |
||||||
|
Handle jdk1.4 class$ methods. |
||||||
|
|
||||||
|
* src/net/sf/jode/jvm/RuntimeEnvironment.java: Fixed some javadocs. |
||||||
|
* src/net/sf/jode/flow/CompleteSynchronized.java: likewise. |
||||||
|
* src/net/sf/jode/flow/CreateExpression.java: likewise. |
||||||
|
* src/net/sf/jode/flow/CreateIfThenElseOperator.java: likewise. |
||||||
|
|
||||||
|
Added changes (except obfuscator changes) from jode-1.1 tree up to |
||||||
|
2001-07-08 |
||||||
|
|
||||||
|
* src/net/sf/jode/bytecode/ClassInfo.java (deprecatedFlag): Added |
||||||
|
flag for deprecated classes. Stuart Ballard noticed that this was |
||||||
|
missing. |
||||||
|
(readAttribute): Read deprecated attribute. |
||||||
|
(prepareWriting): Prepare deprecated attribute. |
||||||
|
(writeKnownAttributes): Write deprecated attribute. |
||||||
|
(isDeprected): New function. |
||||||
|
(setDeprecated): Likewise. |
||||||
|
|
||||||
|
* src/net/sf/jode/bytecode/BasicBlockReader.java (readCode): Fix |
||||||
|
the exception handlers that javac 1.4 produces: I simply shorten |
||||||
|
the start/end interval, so that the catcher is not in the end |
||||||
|
interval. |
||||||
|
|
||||||
|
* src/net/sf/jode/flow/CreateAssignExpression.java |
||||||
|
(createAssignOp): Bug fix: Check whether store is already a |
||||||
|
op-assign and break out. |
||||||
|
* src/net/sf/jode/expr/StoreInstruction.java (isOpAssign): New |
||||||
|
function to check whether this is an op-assign. |
||||||
|
|
||||||
|
* src/net/sf/jode/flow/CatchBlock.java (combineLocal): Added more |
||||||
|
checks if LocalStoreOperator is of the right form. |
||||||
|
|
||||||
|
* net/sf/jode/flow/TransformConstructors.java (Constructor): Ignore |
||||||
|
OuterValues for static constructor. |
||||||
|
|
||||||
|
* src/net/sf/jode/expr/CompareToIntOperator.java (dumpExpression): |
||||||
|
Added a missing breakOp. |
||||||
|
|
||||||
|
2004-01-22 Jochen Hoenicke <hoenicke@informatik.uni-oldenburg.de> |
||||||
|
|
||||||
|
* net/sf/jode/jvm/CodeVerifier.java (modelEffect): Allow assigning |
||||||
|
fields in an uninitialized class as some synthetic code does this. |
||||||
|
|
||||||
|
2003-06-11 Mark Morschhäuser <mark.morschhaeuser@firemail.de> |
||||||
|
* net/sf/jode/decompiler/Main.java: New MenuItem to save a decompiled file. |
||||||
|
|
||||||
|
* net/sf/jode/decompiler/Main.java: Main-window will be centered on startup |
||||||
|
|
||||||
|
* build.xml: |
||||||
|
(release): Added MANIFEST.MF to target and enabled compressed jar-file |
||||||
|
|
||||||
|
* MANIFEST.MF: Added this file to be able to create an executable jar-file |
||||||
|
|
||||||
|
2002-06-11 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* net/sf/jode/decompiler/Main.java: New option keep-alive. With |
||||||
|
this option jode won't stop after an error but will continue with |
||||||
|
the next class. |
||||||
|
Patch suggested by Francis Devereux, francis at hc.eclipse.co.uk |
||||||
|
|
||||||
|
2002-02-25 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* jode/bytecode/ClassInfo.java.in (read): Don't check for a |
||||||
|
maximum version anymore. Sun changes it with every release without |
||||||
|
changing the bytecode format. |
||||||
|
|
||||||
|
2002-02-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* net/sf/jode/bytecode/BasicBlockReader.java: handle empty loops. |
||||||
|
(IS_NULL): new constant to tag empty blocks. |
||||||
|
(markReachableBlocks): check for empty loops. |
||||||
|
(convertBlock): Handle empty blocks. |
||||||
|
(convert): Handle IS_NULL. |
||||||
|
|
||||||
|
* net/sf/jode/decompiler/MethodAnalyzer.java: |
||||||
|
(analyzeCode): handle empty blocks. |
||||||
|
|
||||||
|
2001-08-14 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* build.xml: test is default. |
||||||
|
(release-javadoc): New target. |
||||||
|
(release-src): Get from dir test only source files. |
||||||
|
(doc-javadoc): More parameters for nicer docu. |
||||||
|
|
||||||
|
2001-08-12 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* net/sf/jode/bytecode/TypeSignature.java: |
||||||
|
(getArgumentSize): Renamed to ... |
||||||
|
(getParameterSize): ... this. Changed all callers. |
||||||
|
(skipType): Made private. |
||||||
|
|
||||||
|
* net/sf/jode/jvm/CodeVerifier.java: |
||||||
|
(initInfo): Use TypeSignature.getParameterTypes instead of skipType. |
||||||
|
|
||||||
|
* net/sf/jode/jvm/SyntheticAnalyzer.java: |
||||||
|
(checkGetClass): Be more lenient with the types, they are already |
||||||
|
checked by the CodeVerifier. This is to support jdk-1.4. |
||||||
|
|
||||||
|
* net/sf/jode/expr/InvokeOperator.java |
||||||
|
(dumpExpression): Fixed the check for null outerExpr. |
||||||
|
|
||||||
|
* net/sf/jode/flow/FlowBlock.java: |
||||||
|
(checkConsistent): Allow lastModified in a finally block. |
||||||
|
* net/sf/jode/flow/TransformExceptionHandlers.java: Reworked exception |
||||||
|
handlers again. This time checked with javac 1.3, javac 1.1 and |
||||||
|
jikes. |
||||||
|
(checkTryCatchOrder): New method that was previously part of |
||||||
|
analyze. |
||||||
|
(analyze): Use checkTryCatchOrder. Don't merge try and catch flow |
||||||
|
blocks anymore, leave it to the analyzeXXX methods. |
||||||
|
(mergeTryCatch): New method. |
||||||
|
(analyzeCatchBlock): Get catchFlow as parameter. Call |
||||||
|
mergeTryCatch. |
||||||
|
(transformSubroutine): Handle POP-only subroutines. |
||||||
|
(removeJSR): Don't do special case for catchBlock any more. This |
||||||
|
is because catchFlow isn't yet merged when this method is called. |
||||||
|
(checkAndRemoveJSR): Likewise. |
||||||
|
(checkAndRemoveMonitorExit): Likewise. Merge subroutine only if |
||||||
|
we are the only predecessor. |
||||||
|
(analyzeSynchronized): Get catchFlow as parameter. Call |
||||||
|
mergeTryCatch. |
||||||
|
(mergeFinallyBlocks): New method, calls mergeTryCatch and does the |
||||||
|
common part of mergeFinally and mergeSpecialFinally. |
||||||
|
(analyzeFinally): Simplified, after checking and removing JSR, it |
||||||
|
does immediately analyze and transform subroutine to get the |
||||||
|
finallyBlock. Then it throws away the catchFlow and calls |
||||||
|
mergeFinallyBlocks. |
||||||
|
(analyzeSpecialFinally): Simplified, after checking it only handles |
||||||
|
the jumps in the try part and then call mergeFinallyBlocks. |
||||||
|
|
||||||
|
2001-08-08 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
More Documentation updates. |
||||||
|
* build.xml: Release rules. |
||||||
|
* scripts/jcpp.pl: Don't make backups of original. |
||||||
|
* net/sf/jode/bytecode/BasicBlocks.java (setBlocks): Check that |
||||||
|
successors are inside method. |
||||||
|
* net/sf/jode/bytecode/Block.java (getStackHeight): New Method. |
||||||
|
* net/sf/jode/bytecode/ClassPath.java (Location): public class to |
||||||
|
model a component of the class path. Previously it was Path. |
||||||
|
(ClassPath): New constructors added that take Location objects. |
||||||
|
* net/sf/jode/bytecode/ConstantPool.java (getClassName): Cache |
||||||
|
constants. |
||||||
|
* net/sf/jode/bytecode/GrowableConstantPool.java: Made public. |
||||||
|
(grow): Check that not too many constants are added. |
||||||
|
(reserveLongConstants): Removed (not used). |
||||||
|
(copyConstant): Removed (not used). |
||||||
|
* net/sf/jode/jvm/NewObject.java: Made package protected. |
||||||
|
* net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java: |
||||||
|
Big updates (almost rewrote from scratch). Still doesn't compile. |
||||||
|
|
||||||
|
2001-08-05 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
Documentation updates (INSTALL, javadoc). |
||||||
|
Added JUnit Test cases. |
||||||
|
* build.xml: Big update. |
||||||
|
* net/sf/jode/bytecode/BasicBlock.java: |
||||||
|
(updateMaxStackLocals): new method to calculate maxStack and |
||||||
|
maxLocals. |
||||||
|
(setBlocks): fixed calculation of handlers, call updateMaxLocals. |
||||||
|
* net/sf/jode/bytecode/BasicBlockReader.java: |
||||||
|
(maxLocals, maxStack): new fields. |
||||||
|
(readCode): read maxStack/Locals into private fields. |
||||||
|
(convert): check that maxStack/Locals match what we calculate. |
||||||
|
* net/sf/jode/bytecode/BinaryInfo.java: |
||||||
|
(getKnownAttributeCount): renamed to... |
||||||
|
(getAttributeCount): ... this, and also count internal attributes. |
||||||
|
Made it protected. |
||||||
|
(readAttribute): made protected. |
||||||
|
(drop): made protected. |
||||||
|
(prepareAttributes): made protected. |
||||||
|
(writeKnownAttributes): removed. |
||||||
|
(writeAttributes): made protected, use getAttributeCount. |
||||||
|
Changed policy: it doesn't call writeKnownAttribute, but instead |
||||||
|
it expects sub classes to override this method. |
||||||
|
(getAttributeSize): made protected, subclasses should override it. |
||||||
|
Changed all subclasses to new policy. |
||||||
|
* net/sf/jode/bytecode/Block.java: |
||||||
|
(lineNr): Removed, it wasn't used. |
||||||
|
(pop,push): Removed, replaced by ... |
||||||
|
(maxpop,maxpush,delta): ... these, with slightly changed semantics. |
||||||
|
(stackHeight): New variable. |
||||||
|
(Block): Default Constructor doesn't initialize fields now. |
||||||
|
(getCatchers): Renamed to ... |
||||||
|
(getHandlers): ... this, changed all callers. |
||||||
|
(initCode): Calculate maxpop, maxpush, delta correctly. |
||||||
|
(getStackPopPush): Changed accordingly to new fields. |
||||||
|
(setCode): Removed debugging output for illegal contents. |
||||||
|
* net/sf/jode/bytecode/Classes.java: Reworked handling of inner |
||||||
|
classes. |
||||||
|
(innerClasses): Field mustn't be null anymore when loaded. |
||||||
|
(setName): Update class in classpath. |
||||||
|
* net/sf/jode/bytecode/ClassPath.java: |
||||||
|
(renameClassInfo): new function, should only used by ClassInfo. |
||||||
|
* net/sf/jode/bytecode/ConstantPool.java: made public. |
||||||
|
(getUTF8,getRef,getClassType,getClassName): Don't allow the 0 index. |
||||||
|
(iterateClassNames): New method. |
||||||
|
* net/sf/jode/decompiler/Main.java: |
||||||
|
(decompileClass): Catch ClassFormatExceptions and decompile |
||||||
|
remaining classes. |
||||||
|
* net/sf/jode/obfuscator/ClassIdentifier.java: |
||||||
|
Updated handling of inner/extra classes to new ClassInfo behaviour. |
||||||
|
(initSuperClasses): Load DECLARATION of super classes. |
||||||
|
* net/sf/jode/obfuscator/PackageIdentifier.java: |
||||||
|
Replace deprecated methods of ClassInfo with corresponding classpath |
||||||
|
calls. |
||||||
|
(loadMatchingClasses): Initialize packages loaded on demand if we |
||||||
|
are initialize. |
||||||
|
* net/sf/jode/obfuscator/modules/ConstantAnalyzer.java: |
||||||
|
Now extends SimpleAnalyzer. |
||||||
|
(canonizeIfaceRef): Removed; it is now inherited. |
||||||
|
(canonizeRef): likewise. |
||||||
|
Big updates to handle jsr correctly. |
||||||
|
(handleOpcode): Moved method to BlockInfo. |
||||||
|
* net/sf/jode/obfuscator/modules/SimpleAnalyzer.java: |
||||||
|
(canonizeIfaceRef): New method, copied from ConstantAnalyzer. |
||||||
|
(canonizeRef): call canonizeIfaceRef for interfaces. |
||||||
|
* net/sf/jode/util/UnifyHash.java |
||||||
|
(iterateHashCode): iterator now supports remove(). |
||||||
|
(remove): New method. |
||||||
|
|
||||||
|
2001-07-30 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
Changed compilation procedure to ant. |
||||||
|
|
||||||
|
2001-07-30 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* jode/bytecode/BasicBlockReader.java: Fixed import of non |
||||||
|
collection java.util classes. |
||||||
|
* jode/bytecode/BasicBlockWriter.java: likewise. |
||||||
|
|
||||||
|
2001-07-28 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
* jode/AssertError.java: removed, all uses are now replaced |
||||||
|
by java.lang.InternalError. |
||||||
|
* jode/Makefile.am: removed AssertError.java |
||||||
|
* jode/bytecode/ClassInfo.java: reworked handling of inner |
||||||
|
classes. |
||||||
|
(extraClasses): removed, they are calculated automatically. |
||||||
|
(hasInnerClassesAttr): new variable. |
||||||
|
(readInnerClassesAttribute): Mark all classes in the constant |
||||||
|
pool as having OUTERCLASS info filled. Don't handle extraClasses |
||||||
|
specially. |
||||||
|
(prepareWriting): Change for automatically generating outer |
||||||
|
class info. |
||||||
|
(getKnownAttributes): dito. |
||||||
|
(writeKnownAttributes): dito. |
||||||
|
(getExtraClasses): removed. |
||||||
|
(setExtraClasses): removed. |
||||||
|
|
||||||
|
* jode/bytecode/ClassAnalyzer.java (conflicts): load or guess |
||||||
|
declarations of info before getting inner classes. |
||||||
|
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp): |
||||||
|
Set options correctly. |
||||||
|
* jode/expr/InvokeOperator.java (getMethodInfo): load or guess |
||||||
|
declarations before accessing methods. |
||||||
|
* jode/flow/FlowBlock.java (resolveSomeJumps): When creating a |
||||||
|
if-then-else move the jump from the then branch to the if, before |
||||||
|
restarting analysis. |
||||||
|
(doT1): handle the case when lastModified.jump is null. Throw |
||||||
|
statements have no jump now. |
||||||
|
* jode/jvm/SyntheticAnalyzer (checkAccess): Fix the detection for |
||||||
|
PUTDUPSTATIC/FIELD. |
||||||
|
* jode/type/ClassType.java (getCastHelper): More checks when |
||||||
|
cast is not needed: interfaces and null pointer. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
* jode/decompiler/Decompiler.java (decompile): removed |
||||||
|
setClassPath call. ClassInfo.forName() is no longer used. |
||||||
|
* jode/decompiler/Main.java (decompile): likewise. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patches from 2001-05-26 of Jode 1.1 tree: |
||||||
|
* configure.in: Set version to 1.1. |
||||||
|
|
||||||
|
* jode/swingui/Main.java (main): Also use bootclasspath if no |
||||||
|
classpath given. |
||||||
|
|
||||||
|
* jode/decompiler/MethodAnalyzer.java (skipWriting): Don't skip |
||||||
|
empty constructor that have a throws clause. |
||||||
|
|
||||||
|
* configure.in: Determine whether jdk1.1 resp. jdk1.2. Call jcpp |
||||||
|
in config.status. |
||||||
|
|
||||||
|
* jode/expr/Expression.java (makeInitializer): Now takes the |
||||||
|
type of the initialization. Changed all callers. |
||||||
|
* jode/expr/ConstantArrayOperator.java (makeInitializer): Check |
||||||
|
that type is our array type, otherwise we can't omit new Array[]. |
||||||
|
|
||||||
|
* jode/decompiler/LocalInfo.java (markFinal): Don't check that |
||||||
|
only one write is present. If two writes are in an then and an |
||||||
|
else branch of an if, the local can still be final. |
||||||
|
|
||||||
|
* jode/type/ArrayType.java (getSubType): Handle array of integer |
||||||
|
types correctly: byte[] is something completely different than |
||||||
|
int[]. |
||||||
|
(getSuperType): Likewise. |
||||||
|
|
||||||
|
* jode/expr/FieldOperator.java (getFieldInfo): New function. |
||||||
|
(needsCast): A cast is also needed if the field is private or |
||||||
|
package scope and the current type can't access the field. |
||||||
|
|
||||||
|
* jode/expr/InvokeOperator.java (getMethodInfo): New function. |
||||||
|
(needsCast): A cast is also needed if the method is private or |
||||||
|
package scope and the current type can't access the method. |
||||||
|
|
||||||
|
* jode/expr/ArrayStoreOperator.java (dumpExpression): Check if a |
||||||
|
cast of the array expression is needed. |
||||||
|
|
||||||
|
* jode/expr/TransformConstructors.java |
||||||
|
(transformFieldInitializers): Don't allow moving method invocations |
||||||
|
that throw a checked exception. |
||||||
|
|
||||||
|
* jode/bytecode/MethodInfo.java (readAttribute): Read Exceptions |
||||||
|
attribute even when not all attributes should be read. They are |
||||||
|
needed by TransformConstructors, see above. |
||||||
|
|
||||||
|
* jode/decompiler/TabbedPrintWriter.java (saveOps): Don't allow |
||||||
|
line breaks in not completed expressions since implicit parentheses |
||||||
|
would destroy the syntax. No need to put line break option on stack. |
||||||
|
(restoreOps): Adapted Stack format. |
||||||
|
|
||||||
|
* jode/decompiler/ClassAnalyzer.java (dumpDeclaration): Moved |
||||||
|
Code from dumpSource here. Don't put a line break after closing |
||||||
|
brace. |
||||||
|
(dumpSource): call dumpDeclaration and add a line break. |
||||||
|
(dumpBlock): Moved dropInfo(ATTRIBS) here. |
||||||
|
|
||||||
|
* jode/decompiler/ClassAnalyzer.java (STRICTFP): New Constant. |
||||||
|
(isStrictFP): New function. |
||||||
|
(initialize): Set strictfp modifier if a constructor has it set. |
||||||
|
(dumpSource): Handle strictfp modifier. |
||||||
|
|
||||||
|
* jode/decompiler/MethodAnalyzer.java (STRICTFP): New Constant. |
||||||
|
(isStrictFP): New function. |
||||||
|
(dumpSource): Handle strictfp modifier. |
||||||
|
|
||||||
|
* jode/jvm/SyntheticAnalyzer.java (checkAccess): Check for a |
||||||
|
special putfield access, where the set value is returned. Allow |
||||||
|
the modifier of field/method to be protected and the class to be |
||||||
|
a superclass. |
||||||
|
(checkStaticAccess): Likewise. |
||||||
|
(ACCESSDUPPUTFIELD): New Constant. |
||||||
|
(ACCESSDUPPUTSTATIC): New Constant. |
||||||
|
|
||||||
|
* jode/expr/InvokeOperator.java (simplifyAccess): Handle new |
||||||
|
synthetics. |
||||||
|
|
||||||
|
* jode/flow/SpecialBlock.java (removePop): Remove pop also for |
||||||
|
non void store instructions. |
||||||
|
|
||||||
|
* jode/decompiler/MethodAnalyzer.java (skipWriting): Also skip |
||||||
|
the new synthetics. |
||||||
|
|
||||||
|
* jode/decompiler/Main.java (main): Call System.exit() after |
||||||
|
everything was compiled. |
||||||
|
|
||||||
|
* jode/flow/TransformExceptionHandlers.java (removeJSR): |
||||||
|
Renamed back from removeBadJSR (see patch from 2001-02-04). The |
||||||
|
checkAndRemove* functions mustn't change the successors while they |
||||||
|
iterate over them. Instead of removing good jsr they mark them as |
||||||
|
good and removeJSR will finally remove them. |
||||||
|
(checkAndRemoveJSR): See above. |
||||||
|
(checkAndRemoveMonitorExit): See above. |
||||||
|
|
||||||
|
* jode/flow/JsrBlock.java (good): New variable, see above. |
||||||
|
(setGood): New method. |
||||||
|
(isGood): New method. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patch from 2001-05-08 of Jode 1.1 tree: |
||||||
|
* jode/jvm/CodeVerifier.java (doVerify): Don't check for |
||||||
|
uninitialized objects in local or stack slots on backwards jump or |
||||||
|
exception blocks. Sun's jdk also doesn't check it, and I never |
||||||
|
understood why it is necessary. But see JVM Spec 4.9.4. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patch from 2001-05-02 of Jode 1.1 tree: |
||||||
|
* jode/obfuscator/modules/ConstantAnalyzer.java (handleOpcode): |
||||||
|
Added divide by zero checks for opc_irem and opc_lrem. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patches from 2001-02-27 of Jode 1.1 tree: |
||||||
|
|
||||||
|
* acinclude.m4 (JODE_CHECK_CLASS): Changed "test -e" to "-f" since |
||||||
|
-e is not supported on all architectures (Solaris) and -f is more |
||||||
|
correct anyway. |
||||||
|
Reported by Erik Modén. |
||||||
|
|
||||||
|
* jode/swingui/Main.java (AreaWriter): Convert all kinds of |
||||||
|
line breaks (CR+LF, CR, LF) to a LF character, which a JTextArea |
||||||
|
understands. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patch from 2001-02-04 of Jode 1.1 tree: |
||||||
|
|
||||||
|
* jode/expr/IfThenElseOperator.java (simplify): Allow in the class$ |
||||||
|
simplification the then and else part to be swapped. |
||||||
|
* jode/type/ClassType.java (keywords): Added the package |
||||||
|
and import keywords. |
||||||
|
|
||||||
|
* jode/flow/TransformExceptionHandlers.java: |
||||||
|
(getPredecessor): New function. |
||||||
|
(getMonitorExitSlot): New function. |
||||||
|
(skipFinExitChain): New function. |
||||||
|
(removeJSR): Replaced by ... |
||||||
|
(removeBadJSR): ... this. |
||||||
|
(checkAndRemoveJSR): Use the new functions. Much simpler and |
||||||
|
handles nested synchronized blocks. It now traces the whole JSR |
||||||
|
and monitorexit chain before a jump to the first entry via |
||||||
|
skipFinExitChain, then checks and remove the first JSR |
||||||
|
resp. monitorexit. JSR jumps are simply ignored now. |
||||||
|
(checkAndRemoveMonitorExit): likewise. |
||||||
|
* jode/flow/StructuredBlock.java (prependBlock): New function. |
||||||
|
* jode/flow/CatchBlock.java (makeDeclaration): Generate name |
||||||
|
of dummyLocal, since nobody else will generate it. |
||||||
|
|
||||||
|
* jode/bytecode/BasicBlockReader.java (readCode): Remove bogus |
||||||
|
exceptionHandlers, whose catchers just throw the exception again. |
||||||
|
This kind of entries are inserted by an obfuscator and would break |
||||||
|
JODE. |
||||||
|
* jode/util/UnifyHash.java (iterateHashCode): Call cleanUp, |
||||||
|
to clean unneeded references. |
||||||
|
* jode/flow/TransformConstructors.java (transformOneField): |
||||||
|
Changed to private. Take field number as parameter. Check that |
||||||
|
expression doesn't contain a FieldOperator for a later field of |
||||||
|
the same class or a PutFieldOperator. Changed all callers. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
|
||||||
|
Applied patch from 2001-02-01 of Jode 1.1 tree: |
||||||
|
* jode/jvm/CodeVerifier.java (Type.mergeType): If array elem |
||||||
|
types can't be merged, return tObject as common super type. |
||||||
|
* jode/type/ArrayType.java (getGeneralizedType): If array elem |
||||||
|
type can't be intersected, return tObject as common super type. |
||||||
|
|
||||||
|
2001-07-15 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patch from Jode 1.1 tree: |
||||||
|
|
||||||
|
* jode/expr/Expression.java (updateParentTypes): Call setType, |
||||||
|
instead of merging the types. Other childs want to know about the |
||||||
|
type change as well. |
||||||
|
* jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit, |
||||||
|
but no changes. |
||||||
|
* jode/expr/InvokeOperator.java (dumpExpression): Always print |
||||||
|
the ThisOperator if a field is from a parent class of an outer |
||||||
|
class is used. And always qualify the this operator if not |
||||||
|
innermost. |
||||||
|
|
||||||
|
2001-07-14 Jochen Hoenicke <jochen@gnu.org> |
||||||
|
Applied patches from the Jode 1.1 tree: |
||||||
|
|
||||||
|
* jode/decompiler/TabbedPrintWriter.java: Better gnu style handling: |
||||||
|
(openBraceClass) (closeBraceClass) |
||||||
|
(openBraceNoIndent) (closeBraceNoIndent): new functions. |
||||||
|
(closeBraceNoSpace): Removed. |
||||||
|
* jode/decompiler/TabbedPrintWriter.java (GNU_SPACING): new constant. |
||||||
|
(printOptionalSpace): Print space for GNU_SPACING. |
||||||
|
* jode/decompiler/Options.java (setOptions): changed gnu style |
||||||
|
to include GNU_SPACING. |
||||||
|
* jode/decompiler/ClassAnalyzer.java (dumpSource): Use |
||||||
|
open/closeBraceClass. |
||||||
|
* jode/decompiler/MethodAnalyzer.java (dumpSource): Use |
||||||
|
open/closeBraceNoIndent. Call printOptionalSpace. |
||||||
|
* jode/decompiler/InvokeOperator.java (dumpExpression): |
||||||
|
Call printOptionalSpace, use open/closeBraceClass for inner |
||||||
|
classes. |
||||||
|
* jode/decompiler/UnaryOperator.java (dumpExpression): Call |
||||||
|
printOptionalSpace. |
||||||
|
|
||||||
|
Added pascal style from Rolf Howarth <rolf@squarebox.co.uk> |
||||||
|
* jode/decompiler/Decompiler.java (setOption): detect pascal option. |
||||||
|
* jode/decompiler/TabbedPrintWriter.java (BRACE_FLUSH_LEFT): |
||||||
|
new constant. |
||||||
|
(openBrace, openBraceContinue, closeBrace, closeBraceNoSpace, |
||||||
|
closeBraceContinue): handle flush left. |
||||||
|
|
||||||
|
* jode/type/NullType.java (intersection): Removed, since the |
||||||
|
version in ReferenceType is more correct. Before |
||||||
|
tNull.isOfType(tRange(X,tNull)) returned false, which lead to |
||||||
|
incorrect behaviour in InvokeOperator.needsCast. |
||||||
|
* jode/decompiler/FieldAnalyzer.java (dumpSource): Removed the |
||||||
|
"= null" hack for final fields; it was not correct, since the |
||||||
|
field could be initialized in a constructor. |
||||||
|
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp): |
||||||
|
Simplified the code, copy options always from child. |
||||||
|
* jode/expr/InvokeOperator.java (isGetClass): Allow the method to |
||||||
|
be declared inside an outer class: We simply check if we can get |
||||||
|
the method analyzer. |
||||||
|
(simplify): handle unifyParam. |
||||||
|
* jode/expr/PopOperator.java (getBreakPenalty): return penalty of |
||||||
|
inner expression. (dumpExpression): Call dumpExpression of |
||||||
|
subexpression immediately without priority. |
@ -1,46 +1,23 @@ |
|||||||
Before installing, make sure you have a java compiler (e.g javac or |
Before installing, make sure you have at least version 1.1 of the java |
||||||
jikes) and the java 1.1 runtime class library installed. If you want |
developement kit installed. If you want to run this program you only |
||||||
to run this program you need at least a 1.1 compatible java virtual |
need the java runtime environment. Version 1.1 is quite old, I |
||||||
machine. There are some bugs in javac included in the SUN JDK 1.1, it |
recommend using Java 2 (jdk1.2 or above). You need perl if you want |
||||||
won't work. |
to compile a 1.1 version. |
||||||
|
|
||||||
This package was designed to use the GNU standard for configuration |
This package was designed to use the ANT from the jakarta.apache.org |
||||||
and makefiles. To build and install do the following: |
tools. I assume you have installed it correctly. |
||||||
|
|
||||||
1). You need a java development kit (at least version 1.1), some unix |
Take some time to edit config.props. There are a few options you need |
||||||
tools and some java packages. Make sure that you have all java |
to take care of. (Unfortunately ant can't test for executables). |
||||||
packages that are needed in your classpath. This are gnu.getopt, and |
|
||||||
if you have JDK 1.1 you also need the collection classes and swing for |
Now you are ready to invoke ant. There are many possible targets, here |
||||||
1.1. These packages are accessible from the following urls: |
are the most useful ones: |
||||||
|
|
||||||
CYGWIN (unix tools for win95/NT): |
all builds class files and documentation. |
||||||
http://sourceware.cygnus.com/cygwin/ |
build builds class files only (autodetects java version). |
||||||
|
build-1.1 builds JDK1.1 class files. |
||||||
JDK 1.1: |
doc builds documentation. |
||||||
http://java.sun.com/products/jdk/1.1/index.htm |
dist creates all release files. |
||||||
|
test does some self tests. You need to have junit installed for this. |
||||||
Collection classes and Swing for JDK 1.1: |
clean cleans everything that doesn't belong to the source distribution. |
||||||
http://java.sun.com/beans/infobus/#DOWNLOAD_COLLECTIONS |
cvsclean cleans everything that doesn't belong into the cvs repository. |
||||||
http://java.sun.com/products/jfc/index.html#download-swing |
|
||||||
|
|
||||||
JDK 1.2: |
|
||||||
http://java.sun.com/products/jdk/1.2/index.html |
|
||||||
|
|
||||||
Getopt: |
|
||||||
http://www.urbanophile.com/arenn/hacking/download.html#getopt |
|
||||||
|
|
||||||
2). Run the "configure" script to configure the package. There are |
|
||||||
various options you might want to pass to configure to control how the |
|
||||||
package is built. "configure --help" will give a complete list. |
|
||||||
|
|
||||||
Use the --with-jdk option to specify the install directory of the jdk. |
|
||||||
|
|
||||||
If you have jikes, you should specify it with --with-jikes. You can |
|
||||||
give a path to the directory where it resides, otherwise it is |
|
||||||
searched in the path. |
|
||||||
|
|
||||||
3). Type "make" to build the package. |
|
||||||
|
|
||||||
4). Type "make install" to install the package. This doesn't work yet. |
|
||||||
|
|
||||||
Jochen |
|
||||||
|
@ -0,0 +1,3 @@ |
|||||||
|
Manifest-Version: 1.0 |
||||||
|
Main-Class: net.sf.jode.swingui.Main |
||||||
|
Created-By: SeeksTheMoon |
@ -1,5 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
SUBDIRS = jode bin doc test
|
|
||||||
|
|
||||||
EXTRA_DIST = TODO
|
|
@ -0,0 +1,5 @@ |
|||||||
|
Joe Bronkema <joseph.d.bronkema at lmco.com> |
||||||
|
Rolf Howarth <rolf at squarebox.co.uk> for pascal indentaton style. |
||||||
|
Erik Modén <Erik.Moden at emw.ericsson.se> |
||||||
|
Martin Schmitz <m.schmitz at e-sign.com> for finding many bugs in the obfuscator. |
||||||
|
zzzeek <classic at io.com> |
@ -1,44 +0,0 @@ |
|||||||
dnl |
|
||||||
dnl Add macros |
|
||||||
dnl JODE_CHECK_JAVA |
|
||||||
dnl |
|
||||||
|
|
||||||
dnl JODE_CHECK_JAVA(path) |
|
||||||
AC_DEFUN(JODE_CHECK_JAVA, |
|
||||||
[ |
|
||||||
AC_PATH_PROG(JAVA, java, "", $1/bin:$1/jre/bin:$PATH) |
|
||||||
AC_PATH_PROG(JAVAC, javac, "", $1/bin:$PATH) |
|
||||||
AC_PATH_PROG(JAR, jar, "", $1/bin:$PATH) |
|
||||||
for path in $1/lib $1/jre/lib $1/shared; do |
|
||||||
for classlib in classes.zip rt.jar; do |
|
||||||
AC_CHECK_FILES($path/$classlib, |
|
||||||
[ CLASSLIB=$path/$classlib |
|
||||||
break 3 |
|
||||||
], [ true ]) |
|
||||||
done |
|
||||||
done |
|
||||||
AC_SUBST(CLASSPATH) |
|
||||||
AC_SUBST(CLASSLIB) |
|
||||||
]) |
|
||||||
|
|
||||||
AC_DEFUN(JODE_CHECK_CLASS, |
|
||||||
[ |
|
||||||
if (IFS=":" |
|
||||||
clazz=`echo $1 | sed -e 's/\./\//g' -e 's/\(.*\)/\1.class/'` |
|
||||||
myclasspath=$2; |
|
||||||
for path in $myclasspath; do |
|
||||||
if test -d $path; then |
|
||||||
if test -e $path/$clazz; then |
|
||||||
exit 0 |
|
||||||
fi |
|
||||||
elif CLASS_CHECK $path $clazz ; then |
|
||||||
exit 0 |
|
||||||
fi |
|
||||||
done; |
|
||||||
exit 1) |
|
||||||
then |
|
||||||
$3 |
|
||||||
else |
|
||||||
$4 |
|
||||||
fi |
|
||||||
]) |
|
@ -0,0 +1,380 @@ |
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?> |
||||||
|
<!-- Jakarta-Ant build file for jode, Copyright (C) 1999-2004 Jochen Hoenicke. |
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation; either version 2, or (at your option) |
||||||
|
any later version. |
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with this program; see the file COPYING. If not, write to |
||||||
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
|
||||||
|
$Id$ |
||||||
|
--> |
||||||
|
|
||||||
|
<!DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "project.dtd"> |
||||||
|
<project name="jode" default="test" basedir="."> |
||||||
|
<!-- set global properties for this build --> |
||||||
|
<property name="version" value="1.90-CVS"/> |
||||||
|
|
||||||
|
<property name="build" value="${basedir}/build"/> |
||||||
|
<property name="props" value="${basedir}/props"/> |
||||||
|
<property name="doc" value="${basedir}/doc"/> |
||||||
|
<property name="lib" value="${basedir}/lib"/> |
||||||
|
<property name="src" value="${basedir}/src"/> |
||||||
|
<property name="release" value="${basedir}/release"/> |
||||||
|
<property name="distdir" value="${release}/jode-${version}"/> |
||||||
|
<property name="scripts" value="${basedir}/scripts"/> |
||||||
|
|
||||||
|
<property name="api.doc" value="${doc}/api"/> |
||||||
|
|
||||||
|
<property name="test" value="${basedir}/test"/> |
||||||
|
<property name="test.src" value="${test}/src"/> |
||||||
|
<property name="test.build" value="${test}/build"/> |
||||||
|
<property name="test.log" value="${test}/log"/> |
||||||
|
|
||||||
|
<property name="jcpp" value="${scripts}/jcpp.pl"/> |
||||||
|
|
||||||
|
<property name="versionfile" value="${src}/jode/GlobalOptions.java"/> |
||||||
|
|
||||||
|
<property file="config.props"/> |
||||||
|
|
||||||
|
<path id="project.classpath"> |
||||||
|
<pathelement path="${classpath}"/> |
||||||
|
<fileset dir="lib" includes="*.jar"/> |
||||||
|
</path> |
||||||
|
|
||||||
|
<!-- ********* General targets ******* --> |
||||||
|
|
||||||
|
<!-- compiles jode and creates its javadoc-files --> |
||||||
|
<target name="all" depends="build,doc"/> |
||||||
|
|
||||||
|
<!-- clean all --> |
||||||
|
<target name="clean" depends="clean-jcpp,clean-build,clean-doc,clean-test"/> |
||||||
|
<target name="cvsclean" depends="clean,clean-html,clean-release"/> |
||||||
|
|
||||||
|
<!-- ********* jcpp targets ******* --> |
||||||
|
|
||||||
|
<target name="check-jcpp" unless="perl.present"> |
||||||
|
<fail message="need perl to configure for JDK 1.1"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="run-jcpp" depends="check-packages,check-jcpp"> |
||||||
|
<apply dir="." executable="perl" parallel="true"> |
||||||
|
<arg file="${jcpp}"/> |
||||||
|
<arg value="-DJDK11"/> |
||||||
|
<arg value="-DCOLLECTIONS=${collections.package}"/> |
||||||
|
<arg value="-DCOLLECTIONEXTRA=${collections.package}"/> |
||||||
|
<arg value="-DJAVAX_SWING=${swing.package}"/> |
||||||
|
<fileset dir="${src}" includes="**/*.java"/> |
||||||
|
</apply> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="clean-jcpp" if="perl.present"> |
||||||
|
<apply dir="." executable="perl" parallel="true"> |
||||||
|
<arg file="${jcpp}"/> |
||||||
|
<arg value="-DJDK12"/> |
||||||
|
<arg value="-DCOLLECTIONS=java.util"/> |
||||||
|
<arg value="-DCOLLECTIONEXTRA=java.lang"/> |
||||||
|
<arg value="-DJAVAX_SWING=javax.swing"/> |
||||||
|
<fileset dir="${src}" includes="**/*.java"/> |
||||||
|
</apply> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* Check Environment ******* --> |
||||||
|
|
||||||
|
<target name="check-jdk" unless="jdk1.1.forced"> |
||||||
|
<available property="jdk1.2+" classname="java.lang.ThreadLocal" /> |
||||||
|
<available property="jdk1.3+" classname="java.lang.StrictMath" /> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="fail-getopt" unless="getopt.present"> |
||||||
|
<fail message="Package gnu.getopt not found!"/> |
||||||
|
</target> |
||||||
|
<target name="check-getopt"> |
||||||
|
<available property="getopt.present" |
||||||
|
classname="gnu.getopt.Getopt" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
<antcall target="fail-getopt"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="check-packages"> |
||||||
|
<available property="collections.package" |
||||||
|
value="gnu.java.util.collections" |
||||||
|
classname="gnu.java.util.collections.Set" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
<available property="collections.package" |
||||||
|
value="org.gnu.java.util.collections" |
||||||
|
classname="org.gnu.java.util.collections.Set" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
<available property="collections.package" |
||||||
|
value="com.sun.java.util.collections" |
||||||
|
classname="com.sun.java.util.collections.Set" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
<available property="swing.package" value="com.sun.java.swing" |
||||||
|
classname="com.sun.java.swing.JFrame" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
<available property="swing.package" value="javax.swing" |
||||||
|
classname="javax.swing.JFrame" |
||||||
|
classpathref="project.classpath" /> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* Build targets ******* --> |
||||||
|
|
||||||
|
<target name="preconfig" depends="check-jdk,check-getopt,preconfig.11"/> |
||||||
|
<target name="preconfig.11" unless="jdk1.2+"> |
||||||
|
<antcall target="run-jcpp"/> |
||||||
|
</target> |
||||||
|
<target name="preconfig.12" if="jdk1.2+"> |
||||||
|
<antcall target="clean-jcpp"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="build-1.1"> |
||||||
|
<antcall target="build"> |
||||||
|
<param name="jdk1.1.forced" value="on"/> |
||||||
|
</antcall> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="build" depends="check-jdk,preconfig"> |
||||||
|
<mkdir dir="${build}"/> |
||||||
|
<javac srcdir="${src}" |
||||||
|
destdir="${build}" |
||||||
|
debug="true" |
||||||
|
classpathref="project.classpath" |
||||||
|
deprecation="on"> |
||||||
|
<exclude name="net/sf/jode/obfuscator/modules/RemovePopAnalyzer.java"/> |
||||||
|
<exclude name="net/sf/jode/obfuscator/modules/LocalOptimizer.java"/> |
||||||
|
<exclude name="net/sf/jode/obfuscator/modules/LocalizeFieldTransformer.java"/> |
||||||
|
<!-- |
||||||
|
<exclude name="net/sf/jode/bytecode/*Subroutine*" /> |
||||||
|
--> |
||||||
|
</javac> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- clean the class files --> |
||||||
|
<target name="clean-build"> |
||||||
|
<delete dir="${build}"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* Create Release files ******* --> |
||||||
|
|
||||||
|
<target name="release" depends="release-bin,release-bin11,release-src,release-javadoc"/> |
||||||
|
|
||||||
|
<target name="release-bindist" depends="build"> |
||||||
|
<jar jarfile="${distdir}/jode.jar" compress="true" manifest="${basedir}/MANIFEST.MF"> |
||||||
|
<fileset dir="${build}" includes="**/*.class"/> |
||||||
|
<fileset dir="${props}" includes="**/*.properties"/> |
||||||
|
</jar> |
||||||
|
<copy todir="${distdir}"> |
||||||
|
<fileset dir="${lib}"> |
||||||
|
<include name="*getopt*.jar" /> |
||||||
|
<include name="*collection*.jar" unless="jdk1.2+" /> |
||||||
|
</fileset> |
||||||
|
<fileset dir="${basedir}" |
||||||
|
includes="AUTHORS,COPYING,NEWS,README,THANKS,TODO"> |
||||||
|
<include name="doc/*.html" /> |
||||||
|
<include name="doc/*.gif" /> |
||||||
|
<include name="doc/*.jos" /> |
||||||
|
<include name="doc/*.perl" /> |
||||||
|
</fileset> |
||||||
|
</copy> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="release-bin" depends="doc-html"> |
||||||
|
<antcall target="clean"/> |
||||||
|
<mkdir dir="${release}"/> |
||||||
|
<mkdir dir="${distdir}"/> |
||||||
|
<antcall target="release-bindist"/> |
||||||
|
<jar jarfile="${release}/jode-${version}.jar" |
||||||
|
basedir="${release}" includes="jode-${version}/**"/> |
||||||
|
<delete dir="${distdir}"/> |
||||||
|
<antcall target="clean"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="release-bin11" depends="doc-html"> |
||||||
|
<antcall target="clean"/> |
||||||
|
<mkdir dir="${release}"/> |
||||||
|
<mkdir dir="${distdir}"/> |
||||||
|
<antcall target="release-bindist"> |
||||||
|
<param name="jdk1.1.forced" value="on"/> |
||||||
|
</antcall> |
||||||
|
<jar jarfile="${release}/jode-${version}-JDK1.1.jar" |
||||||
|
basedir="${release}" includes="jode-${version}/**"/> |
||||||
|
<delete dir="${distdir}"/> |
||||||
|
<antcall target="clean"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="release-src" depends="doc-html"> |
||||||
|
<antcall target="clean"/> |
||||||
|
<mkdir dir="${release}"/> |
||||||
|
<mkdir dir="${distdir}"/> |
||||||
|
<copy todir="${distdir}"> |
||||||
|
<fileset dir="${basedir}" |
||||||
|
includes="AUTHORS,COPYING,INSTALL,NEWS,README,THANKS,TODO,ChangeLog"> |
||||||
|
<include name="build.xml,config.props,project*.dtd"/> |
||||||
|
<include name="doc/**"/> |
||||||
|
<include name="scripts/**"/> |
||||||
|
<include name="src/**"/> |
||||||
|
<include name="test/*.java"/> |
||||||
|
<include name="test/*.j"/> |
||||||
|
<include name="test/src/**"/> |
||||||
|
<include name="props/**"/> |
||||||
|
<include name="lib/**"/> |
||||||
|
</fileset> |
||||||
|
</copy> |
||||||
|
<jar jarfile="${release}/jode-${version}-src.jar" |
||||||
|
basedir="${release}" includes="jode-${version}/**"/> |
||||||
|
<delete dir="${distdir}"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="release-javadoc"> |
||||||
|
<antcall target="doc-javadoc"/> |
||||||
|
<mkdir dir="${release}"/> |
||||||
|
<jar jarfile="${release}/jode-${version}-API.jar" |
||||||
|
basedir="${doc}" includes="api/**"/> |
||||||
|
<antcall target="clean-doc"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="clean-release"> |
||||||
|
<delete dir="${release}"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* Javadoc targets ********** --> |
||||||
|
|
||||||
|
<target name="doc" depends="doc-javadoc,doc-html"/> |
||||||
|
|
||||||
|
<target name="doc-html" if="htp.present"> |
||||||
|
<apply executable="htp" dir="${doc}" dest="${doc}" parallel="false" relative="yes"> |
||||||
|
<arg value="-NODEPEND" /> |
||||||
|
<srcfile /> |
||||||
|
<targetfile /> |
||||||
|
<fileset dir="${doc}" includes="*.htp"/> |
||||||
|
<mapper type="glob" from="*.htp" to="*.html"/> |
||||||
|
</apply> |
||||||
|
</target> |
||||||
|
<target name="doc-javadoc"> |
||||||
|
<tstamp> |
||||||
|
<format property="date" pattern="MMM d, yyyy"/> |
||||||
|
</tstamp> |
||||||
|
<mkdir dir="${api.doc}"/> |
||||||
|
<javadoc packagenames="net.sf.jode.*" |
||||||
|
windowtitle="Jode ${version} API Specification" |
||||||
|
header='<b><a href="http://jode.sourceforge.net/">Jode</a> ${version}</b><br><font size="-2">Build ${date}</font>' |
||||||
|
overview="${src}/net/sf/jode/overview.html" |
||||||
|
bottom='Copyright &copy; 1998-2004 by Jochen Hoenicke.' |
||||||
|
sourcepath="${src}" |
||||||
|
destdir="${api.doc}" |
||||||
|
use="yes"> |
||||||
|
<link offline="${javadoc.offline}" |
||||||
|
href="${javadoc.href}" |
||||||
|
packagelistLoc="${javadoc.packagelistLoc}"/> |
||||||
|
</javadoc> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="clean-doc"> |
||||||
|
<delete dir="${api.doc}"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="clean-html"> |
||||||
|
<delete> |
||||||
|
<fileset dir="${doc}" includes="*.html"/> |
||||||
|
</delete> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* test targets ************* --> |
||||||
|
|
||||||
|
<target name="build-test" depends="build"> |
||||||
|
<mkdir dir="${test.build}"/> |
||||||
|
<javac srcdir="${test.src}" |
||||||
|
destdir="${test.build}" |
||||||
|
debug="true" |
||||||
|
classpathref="project.classpath" |
||||||
|
classpath="${build}" |
||||||
|
deprecation="on"> |
||||||
|
</javac> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="test" depends="build-test"> |
||||||
|
<mkdir dir="${test.log}"/> |
||||||
|
<junit printsummary="yes" fork="yes" haltonfailure="yes"> |
||||||
|
<classpath> |
||||||
|
<pathelement path="${test.build}"/> |
||||||
|
<pathelement path="${build}"/> |
||||||
|
<path refid="project.classpath"/> |
||||||
|
</classpath> |
||||||
|
<formatter type="plain" /> |
||||||
|
<batchtest fork="no" todir="${test.log}"> |
||||||
|
<fileset dir="${test.src}"> |
||||||
|
<include name="**/*.java"/> |
||||||
|
</fileset> |
||||||
|
</batchtest> |
||||||
|
</junit> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="test-cvs" depends="build-test"> |
||||||
|
<mkdir dir="${test.log}"/> |
||||||
|
<junit printsummary="yes" fork="yes" haltonfailure="yes"> |
||||||
|
<classpath> |
||||||
|
<pathelement path="${test.build}"/> |
||||||
|
<pathelement path="${build}"/> |
||||||
|
<fileset dir="lib" includes="*.jar"/> |
||||||
|
<fileset dir="/usr/local/ant/lib" includes="*.jar"/> |
||||||
|
</classpath> |
||||||
|
<formatter type="plain" /> |
||||||
|
<batchtest fork="no" todir="${test.log}"> |
||||||
|
<fileset dir="${test.src}"> |
||||||
|
<include name="**/*.java"/> |
||||||
|
</fileset> |
||||||
|
</batchtest> |
||||||
|
</junit> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="clean-test"> |
||||||
|
<delete dir="${test.build}"/> |
||||||
|
<delete dir="${test.log}"/> |
||||||
|
</target> |
||||||
|
|
||||||
|
<!-- ********* version targets ************* --> |
||||||
|
|
||||||
|
<target name="setversion" if="version"> |
||||||
|
<echo message="updating version in ${versionfile} ..."/> |
||||||
|
<exec executable="perl"> |
||||||
|
<arg value="-i"/> |
||||||
|
<arg value="-pe"/> |
||||||
|
<arg value='s/(String\s*version\s*=\s*")[^"]*/$1${version}/' /> |
||||||
|
<arg value="${versionfile}"/> |
||||||
|
</exec> |
||||||
|
</target> |
||||||
|
|
||||||
|
<target name="commit" depends="setversion,test-cvs" if="version"> |
||||||
|
<antcall target="cvsclean"/> |
||||||
|
<echo message="---------------------------------------------------"/> |
||||||
|
<echo message=' Commiting new Jode version: ${version} !!!'/> |
||||||
|
<echo message="==================================================="/> |
||||||
|
<!-- |
||||||
|
search the old version information and replace it with the new version |
||||||
|
we will search the $(mainclass) for 'String VERSION = "..."' and |
||||||
|
replace the contents of the String with the new version. |
||||||
|
--> |
||||||
|
|
||||||
|
<!-- commit the new $(VERSIONFILE) to the CVS |
||||||
|
<echo message="commiting updated file to CVS..."/> |
||||||
|
<cvs command='ci -m"new version ${version}" ${versionfile}'/> |
||||||
|
--> |
||||||
|
|
||||||
|
<!-- commit the new $(VERSIONFILE) to the CVS |
||||||
|
<echo message="tagging files in CVS..."/> |
||||||
|
<property |
||||||
|
<cvs command="tag ${cvstag}"/> |
||||||
|
--> |
||||||
|
|
||||||
|
<echo message="...done!"/> |
||||||
|
<echo message="---------------------------------------------------"/> |
||||||
|
</target> |
||||||
|
</project> |
@ -0,0 +1,28 @@ |
|||||||
|
# Do you have online access for generating javadoc? |
||||||
|
# If not, where are your local files. |
||||||
|
javadoc.offline=false |
||||||
|
javadoc.packagelistLoc= |
||||||
|
javadoc.href=http://java.sun.com/products/jdk/1.2/docs/api/ |
||||||
|
#javadoc.href=file:/usr/doc/inet/java/jdk1.2/docs/api |
||||||
|
|
||||||
|
#javadoc.offline=true |
||||||
|
#javadoc.packagelistLoc=/usr/doc/inet/java/jdk1.2/docs/api |
||||||
|
|
||||||
|
# Is Perl installed on your system? |
||||||
|
# |
||||||
|
# perl is needed to reconfigure Jode for JDK-1.1. If you haven't |
||||||
|
# installed it you can only configure for JDK-1.2 and you should |
||||||
|
# comment out the next line. |
||||||
|
# |
||||||
|
# perl is also used for things that are relevant for the maintainer. |
||||||
|
# |
||||||
|
# Remove the next line if perl is not installed. |
||||||
|
perl.present=true |
||||||
|
|
||||||
|
# Is HTP installed on your system? |
||||||
|
# |
||||||
|
# htp is needed to generate html files from htp files. |
||||||
|
# see http://htp.sourceforge.net/ |
||||||
|
# |
||||||
|
# Remove the next line if either htp is not installed. |
||||||
|
htp.present=true |
@ -1,245 +0,0 @@ |
|||||||
dnl Process this file with autoconf to produce a configure script. |
|
||||||
AC_INIT() |
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(jode, 1.0.93) |
|
||||||
|
|
||||||
dnl Checks for programs. |
|
||||||
dnl AC_PROG_CXX |
|
||||||
dnl AC_PROG_AWK |
|
||||||
dnl AC_PROG_CC |
|
||||||
dnl AC_PROG_CPP |
|
||||||
dnl AC_PROG_INSTALL |
|
||||||
dnl AC_PROG_LN_S |
|
||||||
AC_PROG_MAKE_SET |
|
||||||
dnl AC_PROG_RANLIB |
|
||||||
dnl AC_PATH_PROG(ZIP, zip) |
|
||||||
AC_PATH_PROG(PERL, perl) |
|
||||||
AC_PATH_PROG(CYGPATH, cygpath) |
|
||||||
|
|
||||||
dnl Checks for libraries. |
|
||||||
|
|
||||||
dnl Checks for header files. |
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics. |
|
||||||
|
|
||||||
dnl Checks for library functions. |
|
||||||
|
|
||||||
dnl hack to quote Makefile lines |
|
||||||
QUOTE="" |
|
||||||
AC_SUBST(QUOTE) |
|
||||||
|
|
||||||
AC_SUBST(SHELL) |
|
||||||
|
|
||||||
if test -n "$CYGPATH"; then |
|
||||||
# Extra check if java take windows path? |
|
||||||
CLASSPATH=`$CYGPATH --unix --path $CLASSPATH` |
|
||||||
SUBSTCP="$CYGPATH --windows --path" |
|
||||||
else |
|
||||||
SUBSTCP="echo" |
|
||||||
fi |
|
||||||
|
|
||||||
AC_SUBST(SUBSTCP) |
|
||||||
|
|
||||||
AC_ARG_WITH(java, |
|
||||||
[ --with-java specify path to a java-like program ], |
|
||||||
[ |
|
||||||
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then |
|
||||||
# set javac to user input value |
|
||||||
JODE_CHECK_JAVA(${withval}) |
|
||||||
else |
|
||||||
JODE_CHECK_JAVA(/usr/lib/java) |
|
||||||
fi |
|
||||||
], |
|
||||||
[ |
|
||||||
JODE_CHECK_JAVA(/usr/lib/java) |
|
||||||
]) |
|
||||||
|
|
||||||
dnl jikes can also handle dependancies. |
|
||||||
AC_ARG_WITH(jikes, |
|
||||||
[ --with-jikes specify location of jikes ], |
|
||||||
[ |
|
||||||
USER_SPECIFIED_JIKES=true |
|
||||||
if test "${withval}" = "yes" || test "${withval}" = ""; then |
|
||||||
AC_PATH_PROG(JIKES, jikes, "", $PATH) |
|
||||||
else |
|
||||||
echo "searching jikes in ${withval}:$PATH" |
|
||||||
AC_PATH_PROG(JIKES, jikes, "", ${withval}:$PATH) |
|
||||||
fi |
|
||||||
if test -n "$JIKES"; then |
|
||||||
JAVAC=$JIKES |
|
||||||
fi |
|
||||||
], |
|
||||||
[ |
|
||||||
USER_SPECIFIED_JIKES= |
|
||||||
AC_PATH_PROG(JIKES, jikes, "", $PATH) |
|
||||||
]) |
|
||||||
AM_CONDITIONAL(HAVE_JIKES, test x"$JIKES" != x) |
|
||||||
|
|
||||||
AC_ARG_WITH(javac, |
|
||||||
[ --with-javac specify location of javac ], |
|
||||||
[ |
|
||||||
if test x$USER_SPECIFIED_JIKES == xtrue; then |
|
||||||
AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes) |
|
||||||
fi |
|
||||||
if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then |
|
||||||
AC_CHECK_FILES(${withval}, |
|
||||||
[ JAVAC=${withval} ], |
|
||||||
[ AC_MSG_ERROR(${withval} does not exists) ]) |
|
||||||
fi |
|
||||||
], [ |
|
||||||
dnl use jikes as default, if javac option not given. |
|
||||||
if test -n "$JIKES"; then |
|
||||||
JAVAC=$JIKES |
|
||||||
fi |
|
||||||
]) |
|
||||||
|
|
||||||
AC_PATH_PROG(UNZIP, unzip) |
|
||||||
if test -n "$UNZIP"; then |
|
||||||
CLASS_CHECK () { |
|
||||||
$UNZIP -v -C `$SUBSTCP $1` $2 >/dev/null 2>&1 |
|
||||||
} |
|
||||||
else |
|
||||||
if test -n "$JAR"; then |
|
||||||
CLASS_CHECK () { |
|
||||||
$JAR -tf `$SUBSTCP $1` 2>&1 | grep $2 >/dev/null |
|
||||||
} |
|
||||||
else |
|
||||||
AC_MSG_ERROR(You need either unzip or jar.) |
|
||||||
fi |
|
||||||
fi |
|
||||||
|
|
||||||
AC_MSG_CHECKING(for java.lang.Object) |
|
||||||
JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB, |
|
||||||
[ AC_MSG_RESULT(yes) ], |
|
||||||
[ AC_MSG_RESULT(no) |
|
||||||
AC_MSG_ERROR(Please specify location of core java class library) ]) |
|
||||||
|
|
||||||
AC_MSG_CHECKING(for collection classes) |
|
||||||
JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB, |
|
||||||
[ COLLECTIONS="java.util" |
|
||||||
COLLECTIONEXTRA="java.lang" ], |
|
||||||
[ JODE_CHECK_CLASS(gnu.java.util.collections.Set, $CLASSPATH:$CLASSLIB, |
|
||||||
[ COLLECTIONS="gnu.java.util.collections" |
|
||||||
COLLECTIONEXTRA="gnu.java.util.collections" ], |
|
||||||
[ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB, |
|
||||||
[ COLLECTIONS="com.sun.java.util.collections" |
|
||||||
COLLECTIONEXTRA="com.sun.java.util.collections" ], |
|
||||||
[ AC_MSG_RESULT(no) |
|
||||||
AC_MSG_ERROR(You need the Java 1.2 collection classes in your classpath) |
|
||||||
]) |
|
||||||
]) |
|
||||||
]) |
|
||||||
AC_MSG_RESULT($COLLECTIONS) |
|
||||||
AC_SUBST(COLLECTIONS) |
|
||||||
AC_SUBST(COLLECTIONEXTRA) |
|
||||||
|
|
||||||
AC_MSG_CHECKING(for gnu.getopt) |
|
||||||
JODE_CHECK_CLASS(gnu.getopt.Getopt, $CLASSPATH:$CLASSLIB, |
|
||||||
[ AC_MSG_RESULT(yes) ], |
|
||||||
[ AC_MSG_RESULT(no) |
|
||||||
AC_MSG_ERROR(You need gnu getopt for java.) ]) |
|
||||||
|
|
||||||
AC_MSG_CHECKING(for swing) |
|
||||||
JODE_CHECK_CLASS(javax.swing.JFrame, $CLASSPATH:$CLASSLIB, |
|
||||||
[ JAVAX_SWING="javax.swing" ], |
|
||||||
[ JODE_CHECK_CLASS(com.sun.java.swing.JFrame, $CLASSPATH:$CLASSLIB, |
|
||||||
[ JAVAX_SWING="com.sun.java.swing" ], |
|
||||||
[ JAVAX_SWING="no" ]) ] ) |
|
||||||
AC_MSG_RESULT($JAVAX_SWING) |
|
||||||
AC_SUBST(JAVAX_SWING) |
|
||||||
if test "$JAVAX_SWING" != "no"; then |
|
||||||
SWINGUI="swingui" |
|
||||||
else |
|
||||||
AC_MSG_WARN(Swing is not in classpath ... skipping swingui) |
|
||||||
SWINGUI="" |
|
||||||
fi |
|
||||||
AC_SUBST(SWINGUI) |
|
||||||
|
|
||||||
AC_SUBST(CLASSPATH) |
|
||||||
AC_SUBST(JAVAC) |
|
||||||
|
|
||||||
AC_OUTPUT(Makefile |
|
||||||
javaDependencies.pl |
|
||||||
jode/Makefile |
|
||||||
jode/bytecode/Makefile |
|
||||||
jode/decompiler/Makefile |
|
||||||
jode/expr/Makefile |
|
||||||
jode/flow/Makefile |
|
||||||
jode/jvm/Makefile |
|
||||||
jode/obfuscator/Makefile |
|
||||||
jode/obfuscator/modules/Makefile |
|
||||||
jode/swingui/Makefile |
|
||||||
jode/type/Makefile |
|
||||||
jode/util/Makefile |
|
||||||
jode/bytecode/BinaryInfo.java |
|
||||||
jode/bytecode/BytecodeInfo.java |
|
||||||
jode/bytecode/ClassInfo.java |
|
||||||
jode/bytecode/Reference.java |
|
||||||
jode/decompiler/ImportHandler.java |
|
||||||
jode/decompiler/ClassAnalyzer.java |
|
||||||
jode/decompiler/FieldAnalyzer.java |
|
||||||
jode/decompiler/MethodAnalyzer.java |
|
||||||
jode/decompiler/DeadCodeAnalysis.java |
|
||||||
jode/expr/Expression.java |
|
||||||
jode/expr/FieldOperator.java |
|
||||||
jode/expr/InvokeOperator.java |
|
||||||
jode/expr/LocalVarOperator.java |
|
||||||
jode/expr/Operator.java |
|
||||||
jode/expr/CheckNullOperator.java |
|
||||||
jode/flow/RetBlock.java |
|
||||||
jode/flow/InstructionContainer.java |
|
||||||
jode/flow/LoopBlock.java |
|
||||||
jode/flow/SequentialBlock.java |
|
||||||
jode/flow/SlotSet.java |
|
||||||
jode/flow/StructuredBlock.java |
|
||||||
jode/flow/SynchronizedBlock.java |
|
||||||
jode/flow/VariableSet.java |
|
||||||
jode/flow/CatchBlock.java |
|
||||||
jode/flow/IfThenElseBlock.java |
|
||||||
jode/flow/InstructionBlock.java |
|
||||||
jode/flow/FlowBlock.java |
|
||||||
jode/flow/TransformExceptionHandlers.java |
|
||||||
jode/jvm/CodeVerifier.java |
|
||||||
jode/jvm/Interpreter.java |
|
||||||
jode/jvm/SyntheticAnalyzer.java |
|
||||||
jode/obfuscator/ClassBundle.java |
|
||||||
jode/obfuscator/ClassIdentifier.java |
|
||||||
jode/obfuscator/ConstantRuntimeEnvironment.java |
|
||||||
jode/obfuscator/FieldIdentifier.java |
|
||||||
jode/obfuscator/Identifier.java |
|
||||||
jode/obfuscator/LocalIdentifier.java |
|
||||||
jode/obfuscator/Main.java |
|
||||||
jode/obfuscator/MethodIdentifier.java |
|
||||||
jode/obfuscator/OptionHandler.java |
|
||||||
jode/obfuscator/PackageIdentifier.java |
|
||||||
jode/obfuscator/Renamer.java |
|
||||||
jode/obfuscator/ScriptParser.java |
|
||||||
jode/obfuscator/TranslationTable.java |
|
||||||
jode/obfuscator/modules/ConstantAnalyzer.java |
|
||||||
jode/obfuscator/modules/KeywordRenamer.java |
|
||||||
jode/obfuscator/modules/LocalOptimizer.java |
|
||||||
jode/obfuscator/modules/LocalizeFieldTransformer.java |
|
||||||
jode/obfuscator/modules/ModifierMatcher.java |
|
||||||
jode/obfuscator/modules/MultiIdentifierMatcher.java |
|
||||||
jode/obfuscator/modules/NameSwapper.java |
|
||||||
jode/obfuscator/modules/RemovePopAnalyzer.java |
|
||||||
jode/obfuscator/modules/SerializePreserver.java |
|
||||||
jode/obfuscator/modules/SimpleAnalyzer.java |
|
||||||
jode/obfuscator/modules/StrongRenamer.java |
|
||||||
jode/obfuscator/modules/UniqueRenamer.java |
|
||||||
jode/obfuscator/modules/WildCard.java |
|
||||||
jode/swingui/Main.java |
|
||||||
jode/swingui/PackagesTreeModel.java |
|
||||||
jode/swingui/HierarchyTreeModel.java |
|
||||||
jode/type/Type.java |
|
||||||
jode/util/SimpleSet.java |
|
||||||
jode/util/SimpleMap.java |
|
||||||
jode/util/UnifyHash.java |
|
||||||
jode/GlobalOptions.java |
|
||||||
bin/Makefile |
|
||||||
bin/jode |
|
||||||
bin/jode.bat |
|
||||||
doc/Makefile |
|
||||||
doc/download.html |
|
||||||
test/Makefile, |
|
||||||
[chmod 755 javaDependencies.pl bin/jode]) |
|
@ -1,2 +1,3 @@ |
|||||||
Makefile |
Makefile |
||||||
Makefile.in |
Makefile.in |
||||||
|
*.html |
||||||
|
@ -1,14 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
applet.html \ |
|
||||||
download.html.in \ |
|
||||||
history.html \ |
|
||||||
jode.html \ |
|
||||||
license.html \ |
|
||||||
links.html \ |
|
||||||
usage.html \ |
|
||||||
myproject.jos \ |
|
||||||
dasm_to_java.perl \ |
|
||||||
gimp/jode-logo.xcf \ |
|
||||||
jode-logo.gif |
|
@ -1,97 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<h1>The <i>JODE</i> Applet</h1> |
|
||||||
|
|
||||||
Please be patience, loading the applet may take some time.<br><br> |
|
||||||
|
|
||||||
<center> |
|
||||||
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400> |
|
||||||
<param name=pagecolor value="ffffff"> |
|
||||||
<param name=classpath value="http://jode.sourceforge.net/load.html/http%3a//www.informatik.uni-oldenburg.de/~mw/plasma.jar"> |
|
||||||
<param name=class value="PlasmaApplet"> |
|
||||||
<p>Sorry you need a java enabled browser to test a java applet ;-)</p> |
|
||||||
<p>Don't read the rest, it only contains information about the applet.</p> |
|
||||||
</applet> |
|
||||||
</center><br> |
|
||||||
|
|
||||||
Press the start button to decompile <a |
|
||||||
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's |
|
||||||
Plasma applet</a> (and give the decompiler some time to download the |
|
||||||
jar file). <br><br> |
|
||||||
|
|
||||||
You may change the classpath to point to a zip or jar file of your |
|
||||||
choice, using a similar syntax. Use <code>%3a</code> instead of a |
|
||||||
colon `:' in the url. You can also point it to a directory containing |
|
||||||
the class-files (include a slash `/' at the end in this case), but |
|
||||||
this is not recommended, since it is <i>very</i> slow. You may give |
|
||||||
multiple entries in the class path field separated by a comma.<br><br> |
|
||||||
|
|
||||||
You can't use this applet for local files; the class files must be on |
|
||||||
a server that is accessible from sourceforge. You can try to give |
|
||||||
local filenames directly without the load.html wrapper, but that is |
|
||||||
probably forbidden by your browser. Most browser only allow loading |
|
||||||
files from the same server as the applet, and this is the reason why |
|
||||||
you have to use such a cryptic URL.<br><br> |
|
||||||
|
|
||||||
Save probably doesn't work, because it is forbidden by your browser.<br><br> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
@ -0,0 +1,25 @@ |
|||||||
|
<section title="The <i>JODE</i> Applet"> |
||||||
|
|
||||||
|
<p>Please be patience, loading the applet may take some time.</p> |
||||||
|
|
||||||
|
<center> |
||||||
|
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400> |
||||||
|
<param name=pagecolor value="ffffff"> |
||||||
|
<param name=classpath value="http://jode.sourceforge.net/plasma.jar"> |
||||||
|
<param name=class value="PlasmaApplet"> |
||||||
|
<p>Sorry you need a java enabled browser to test a java applet ;-)</p> |
||||||
|
<p>Don't read the rest, it only contains information about the applet.</p> |
||||||
|
</applet> |
||||||
|
</center><br> |
||||||
|
|
||||||
|
<p> Press the start button to decompile <a |
||||||
|
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's |
||||||
|
Plasma applet</a> (and give the decompiler some time to download the |
||||||
|
jar file). </p> |
||||||
|
|
||||||
|
<p>You may change the classpath to point to a zip or jar file of your |
||||||
|
choice. Unfortunately, your browser will most likely forbid URL's that |
||||||
|
aren't located on jode.sourceforge.net. |
||||||
|
Save probably doesn't work, because it is forbidden by your browser.</p> |
||||||
|
|
||||||
|
</section> |
@ -1,36 +0,0 @@ |
|||||||
<?php require("header.inc"); ?> |
|
||||||
<h1>The <i>JODE</i> Applet</h1> |
|
||||||
|
|
||||||
Please be patience, loading the applet may take some time.<br><br> |
|
||||||
|
|
||||||
<center> |
|
||||||
<applet code="jode/Applet.class" archive="jode-applet.jar" width=540 height=400> |
|
||||||
<param name=pagecolor value="ffffff"> |
|
||||||
<param name=classpath value="http://jode.sourceforge.net/load.php/http%3a//www.informatik.uni-oldenburg.de/~mw/plasma.jar"> |
|
||||||
<param name=class value="PlasmaApplet"> |
|
||||||
<p>Sorry you need a java enabled browser to test a java applet ;-)</p> |
|
||||||
<p>Don't read the rest, it only contains information about the applet.</p> |
|
||||||
</applet> |
|
||||||
</center><br> |
|
||||||
|
|
||||||
Press the start button to decompile <a |
|
||||||
href="http://www.informatik.uni-oldenburg.de/~mw/plasma.html">Michael's |
|
||||||
Plasma applet</a> (and give the decompiler some time to download the |
|
||||||
jar file). <br><br> |
|
||||||
|
|
||||||
You may change the classpath to point to a zip or jar file of your |
|
||||||
choice, using a similar syntax. Use <code>%3a</code> instead of a |
|
||||||
colon `:' in the url. You can also point it to a directory containing |
|
||||||
the class-files (include a slash `/' at the end in this case), but |
|
||||||
this is not recommended, since it is <i>very</i> slow. You may give |
|
||||||
multiple entries in the class path field separated by a comma.<br><br> |
|
||||||
|
|
||||||
You can't use this applet for local files; the class files must be on |
|
||||||
a server that is accessible from sourceforge. You can try to give |
|
||||||
local filenames directly without the load.php wrapper, but that is |
|
||||||
probably forbidden by your browser. Most browser only allow loading |
|
||||||
files from the same server as the applet, and this is the reason why |
|
||||||
you have to use such a cryptic URL.<br><br> |
|
||||||
|
|
||||||
Save probably doesn't work, because it is forbidden by your browser.<br><br> |
|
||||||
<?php require("footer.inc"); ?> |
|
@ -1,133 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<h1>Blue Sky</h1> |
|
||||||
|
|
||||||
<p>This section contains features that I think would be great to have, |
|
||||||
but are also very hard to implement. The name of the section is |
|
||||||
inspired, by <a |
|
||||||
href="http://www.mozilla.org/blue-sky/">Mozilla</a>.</p> |
|
||||||
|
|
||||||
<p>Currently this are all my own ideas. But if you send me an idea |
|
||||||
for an interesting feature, I will add it to this list.</p> |
|
||||||
|
|
||||||
<h2><i>Out</i>line inlined methods</h2> |
|
||||||
|
|
||||||
<p>If java gets called with `<code>-O</code>' switch, it inlines methods, |
|
||||||
that are private, final, or static and contain no loops. When |
|
||||||
decompiling this it sometimes produces really ugly code. The right |
|
||||||
way to solve this would be to <i>out</i>line the code again. This is |
|
||||||
possible but requires to find the inlined method. </p> |
|
||||||
|
|
||||||
<p>The name `outline' was suggested by <a |
|
||||||
href="http://www.informatik.uni-oldenburg.de/~mw">Michael</a>. |
|
||||||
</p> |
|
||||||
|
|
||||||
<h2>Better names of local variables</h2> |
|
||||||
|
|
||||||
<p>The local variable naming is very stupid. Even with pretty it just |
|
||||||
names the variable after the type with a unifying number appended. A |
|
||||||
method containing very much objects of the same type looks very |
|
||||||
ugly. </p> |
|
||||||
|
|
||||||
<p>My plan is looking at the assignments. If we have locals in |
|
||||||
assignments |
|
||||||
<pre> |
|
||||||
int l_1 = array.length |
|
||||||
String l_2 = object.getName() |
|
||||||
</pre> |
|
||||||
we could name them "length" and "name". If we |
|
||||||
have assignments: |
|
||||||
<pre> |
|
||||||
MenuItem local_1 = new MenuItem("Open"); |
|
||||||
MenuItem local_2 = new MenuItem("Save"); |
|
||||||
</pre> |
|
||||||
good names would be <code>miOpen</code> and <code>miSave</code>. </p> |
|
||||||
|
|
||||||
<p>It is currently possible to assign a <i>(hint name,type)</i> pair |
|
||||||
to a local. If the type matches, the local will be named after |
|
||||||
<i>hint name</i>. This could be extended by giving them several |
|
||||||
weighted hints and constructing the name in an intelligent way. </p> |
|
||||||
|
|
||||||
<h2>Better deobfuscation features</h2> |
|
||||||
<p>First there should be a good Renamer: Methods that simply |
|
||||||
return a field value should be renamed to get<i>FieldName</i>. |
|
||||||
Fields should be named after their type, maybe also by assignments |
|
||||||
(see section about local variable names).</p> |
|
||||||
|
|
||||||
<p>The deobfuscator should detect inner and anonymous variables, |
|
||||||
synthetic methods and so on, and rename them accordingly.</p> |
|
||||||
|
|
||||||
<h2>Handling of Class.forName in obfuscator</h2> |
|
||||||
<p>The obfuscator should detect Class.forName constructs (and |
|
||||||
similarly for methods and fields) and if their parameters are constant |
|
||||||
it should change the parameter according to the rename function. </p> |
|
||||||
|
|
||||||
<h2>Merging javadoc comments</h2> |
|
||||||
<p>It would be nice if the decompiler could merge the javadoc comments |
|
||||||
into the class file. More and more people use javadoc to comment the |
|
||||||
public api of their java classes. It shouldn't be too difficult to |
|
||||||
copy them back into the java code. </p> |
|
||||||
|
|
||||||
<p>This doesn't need to be built into the decompiler. A script that takes |
|
||||||
the javadoc pages and the decompiled code can easily merge them.</p> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
@ -1,92 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<h2>Download</h2> |
|
||||||
|
|
||||||
The latest source code of <i>JODE</i> is available at the <a href="http://sourceforge.net/project/?group_id=3790">project page</a>. |
|
||||||
You need several other packages to build <i>JODE</i>, check the <a href="./links.html">links page</a>. <br><br> |
|
||||||
|
|
||||||
The simplest way to get it, especially for non unix users, is in |
|
||||||
precompiled form, though. I have two jar archives at the <a |
|
||||||
href="ftp://jode.sourceforge.net/pub/jode">ftp server</a>. You may |
|
||||||
need to press shift while clicking on the link, depending on your |
|
||||||
browser. |
|
||||||
|
|
||||||
|
|
||||||
<ul> <li><a href="ftp://jode.sourceforge.net/pub/jode/jode-1.0.93-1.1.jar">jode-1.0.93-1.1.jar</a> is for JDK 1.1. It already |
|
||||||
contains Getopt and the collection classes from the GNU Classpath |
|
||||||
project. If you want to use the swing interface, you have to download |
|
||||||
swing separately. </li> |
|
||||||
|
|
||||||
<li> <a href="ftp://jode.sourceforge.net/pub/jode/jode-1.0.93-1.2.jar">jode-1.0.93-1.2.jar</a> is for JDK 1.2. It already |
|
||||||
contains Getopt, so you don't need any other package.</li> </ul> |
|
||||||
|
|
||||||
<h2>CVS Repository</h2> |
|
||||||
|
|
||||||
You can get the latest sources from the <a href="http://sourceforge.net/cvs/?group_id=3790">CVS repository</a>. |
|
||||||
Follow the instruction on that page; use <code>jode</code> as |
|
||||||
<i>modulename</i>. Then change to the directory jode and run |
|
||||||
|
|
||||||
<pre>aclocal && automake -a && autoconf</pre> |
|
||||||
|
|
||||||
Afterwards follow the instruction in the INSTALL file. |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
@ -0,0 +1,39 @@ |
|||||||
|
<section title="Download"> |
||||||
|
|
||||||
|
<p>Jode is available in the <sflink |
||||||
|
href="project/showfiles.php">download area</a> in source or binary |
||||||
|
form. For compiling the source code, you need several other packages, |
||||||
|
check the <a href="links.html">links page</a>. You need a unix like |
||||||
|
environment for compilation.</p> |
||||||
|
|
||||||
|
<p>The simplest way to get it, especially for non unix users, is in |
||||||
|
precompiled form, though. There are two jar archives in the download |
||||||
|
area:</P> |
||||||
|
|
||||||
|
<ul> <li>jode-1.1-JDK1.1.jar is for JDK 1.1. If you want to use |
||||||
|
the swing interface, you have to download swing separately, all other |
||||||
|
packages are already included in the archive. </li> |
||||||
|
|
||||||
|
<li>jode-1.1.jar is for JDK 1.2 or better. It should run |
||||||
|
without any other package.</li> </ul> |
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="Subversion Repository"> |
||||||
|
|
||||||
|
<p>You can get the latest sources from the <a |
||||||
|
href="http://sourceforge.net/svn/?group_id=3790">SVN repository</a>. |
||||||
|
Follow the instruction on that page; use |
||||||
|
<code>/svnroot/jode/trunk/jode</code> as last part of the URL. If you |
||||||
|
want to checkout a specific version you can checkout the URL |
||||||
|
<code>.../svnroot/jode/tags/xxx/jode</code>:</p> |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li><code>../jode/tags/jode_1_0_93/jode</code>: checks out the version 1.0.93</li> |
||||||
|
<li><code>../jode/branches/branch_1_1/jode</code>: checks out the latest version in the |
||||||
|
1.1 series.</li> </ul> |
||||||
|
|
||||||
|
<p>To build the sources from latest SVN change to the main directory and invoke ant.</p> |
||||||
|
<p>To build the 1.1 versions of jode change to the main directory and run |
||||||
|
<pre>aclocal && automake -a && autoconf</pre> |
||||||
|
<p>Afterwards follow the instruction in the INSTALL file. </p> |
||||||
|
</section> |
@ -1,40 +0,0 @@ |
|||||||
<?php require("header.inc"); ?> |
|
||||||
<h2>Download</h2> |
|
||||||
|
|
||||||
The latest source code of <i>JODE</i> is available at the <?php |
|
||||||
sflink("project/") ?>project page</a>. |
|
||||||
You need several other packages to build <i>JODE</i>, check the <?php |
|
||||||
selflink("links") ?>links page</a>. <br><br> |
|
||||||
|
|
||||||
The simplest way to get it, especially for non unix users, is in |
|
||||||
precompiled form, though. I have two jar archives at the <a |
|
||||||
href="ftp://jode.sourceforge.net/pub/jode">ftp server</a>. You may |
|
||||||
need to press shift while clicking on the link, depending on your |
|
||||||
browser. |
|
||||||
|
|
||||||
<?php |
|
||||||
function jarlink($what) { |
|
||||||
global $version; |
|
||||||
echo "<a href=\"ftp://jode.sourceforge.net/pub/jode/jode-".$version.$what; |
|
||||||
echo ".jar\">jode-".$version.$what.".jar</a>"; |
|
||||||
} ?> |
|
||||||
|
|
||||||
<ul> <li><?php jarlink("-1.1") ?> is for JDK 1.1. It already
|
|
||||||
contains Getopt and the collection classes from the GNU Classpath |
|
||||||
project. If you want to use the swing interface, you have to download |
|
||||||
swing separately. </li> |
|
||||||
|
|
||||||
<li> <?php jarlink("-1.2") ?> is for JDK 1.2. It already
|
|
||||||
contains Getopt, so you don't need any other package.</li> </ul> |
|
||||||
|
|
||||||
<h2>CVS Repository</h2> |
|
||||||
|
|
||||||
You can get the latest sources from the <?php sflink("cvs/") ?> |
|
||||||
CVS repository</a>. |
|
||||||
Follow the instruction on that page; use <code>jode</code> as |
|
||||||
<i>modulename</i>. Then change to the directory jode and run |
|
||||||
|
|
||||||
<pre>aclocal && automake -a && autoconf</pre> |
|
||||||
|
|
||||||
Afterwards follow the instruction in the INSTALL file. |
|
||||||
<?php require("footer.inc"); ?> |
|
@ -0,0 +1,90 @@ |
|||||||
|
<section title="FAQ - Frequently Asked Questions"> |
||||||
|
This is a list of some questions that pop up from time to time. |
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="Decompiler issues"> |
||||||
|
|
||||||
|
<h3>Does Jode support Java 5?</h3> |
||||||
|
|
||||||
|
<p>It does not support generics/vararg method or the new for loop at |
||||||
|
the moment. It produces readable code and I think it may even compile |
||||||
|
again. But it is not compatible as the generics and varargs |
||||||
|
information is not included.</p> |
||||||
|
|
||||||
|
<h3>Jode crashes with ExceptionHandler order failed</h3> |
||||||
|
|
||||||
|
<p>Try jode-1.1.2pre1 or the latest CVS version. If it still does not |
||||||
|
work rewrite <code>jode.flow.TransformExceptionHandlers</code> and |
||||||
|
send me the fix :) </p> |
||||||
|
|
||||||
|
<p>Since Java 1.4 the format for finally and synchronized blocks |
||||||
|
changed again. It was always a very difficult task to reconstruct |
||||||
|
<code>finally</code> blocks correctly and the code is huge and very |
||||||
|
hard to maintain. With Java 5 it gets even worse.</p> |
||||||
|
|
||||||
|
<h3>The decompiler crashes with a VerifyException, what can I do?</h3> |
||||||
|
|
||||||
|
<p>The class isn't verifiable, probably because there is not enough |
||||||
|
information about used classes. See the question about the |
||||||
|
classpath.</p> |
||||||
|
|
||||||
|
<p>This could also be caused by malicious bytecode, or because there |
||||||
|
is a bug in Jode's verifier, or because Sun decided to change the |
||||||
|
definition of correct bytecode, again.</p> |
||||||
|
|
||||||
|
<h3>What should be included in the classpath?</h3> |
||||||
|
|
||||||
|
<p>Jode needs to know the full class hierarchie to guess the types. |
||||||
|
This includes not only the classes in the program, but also the |
||||||
|
libraries used by the java program, even the Java runtime library. |
||||||
|
You should set the classpath to include all these classes.</p> |
||||||
|
|
||||||
|
<p>If you don't specify the classpath on the command line, Jode uses |
||||||
|
the same as your Java Virtual Machine.</p> |
||||||
|
|
||||||
|
<p>As last resort, if Jode can't find a class in the classpath it uses |
||||||
|
reflection to ask the Virtual Machine. This works quite well, but |
||||||
|
loading classes can have side effects, e.g. when AWT classes are |
||||||
|
loaded, an AWT thread is created, even though Jode doesn't need |
||||||
|
it.</p> |
||||||
|
|
||||||
|
<h3>Why doesn't Jode decompile my inner class |
||||||
|
<code>MyClass$Inner.class</code>?</h3> |
||||||
|
|
||||||
|
<p>You should decompile the outermost class (<code>MyClass</code> in |
||||||
|
this case). The produced code contains the inner class. </p> |
||||||
|
|
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="Obfuscator issues"> |
||||||
|
|
||||||
|
<h3>What should be included in the classpath?</h3> |
||||||
|
|
||||||
|
<p>The program, all libraries, the Java runtime library. Don't omit a |
||||||
|
library even when you don't want to obfuscate it.</p> |
||||||
|
|
||||||
|
<h3>What should I preserve</h3> |
||||||
|
|
||||||
|
<p>The most common mistake is to preserve a class. In most cases this |
||||||
|
is not what you want. This only makes sure the class won't be |
||||||
|
renamed, it doesn't prevent it from being stripped. Instead you |
||||||
|
should preserve methods and constructors. The constructor is just a |
||||||
|
method with the special name <tt><init></tt>. </p> |
||||||
|
|
||||||
|
<p> Another common mistake is to omit the type |
||||||
|
signature, e.g. to preserve <tt>Class.main</tt> instead of |
||||||
|
<tt>Class.main.([Ljava/lang/String;)V</tt>. That doesn't work. If |
||||||
|
you don't want to care about the format of the type signature use a |
||||||
|
wildcard as in <tt>Class.main.*</tt>. </p> |
||||||
|
|
||||||
|
<h3>What is a type signature</h3> |
||||||
|
|
||||||
|
<p>The type signature is a machine readable representation of a java |
||||||
|
type that is used all over in java bytecode. The JDK ships a command |
||||||
|
named <tt>javap</tt>. With <tt>java -s</tt> you can lists the fields |
||||||
|
and methods of a class with their type signatures.</p> |
||||||
|
|
||||||
|
<p> If you are interested in the format of type signatures read the |
||||||
|
Java Virtual Machine Specification, Chapter 4.3 Descriptors</p> |
||||||
|
|
||||||
|
</section> |
@ -0,0 +1,106 @@ |
|||||||
|
/* XPM */ |
||||||
|
static char * favicon_xpm[] = { |
||||||
|
"16 16 87 1", |
||||||
|
" c None", |
||||||
|
". c #C2C2C2", |
||||||
|
"+ c #A1A1A1", |
||||||
|
"@ c #BBBBBB", |
||||||
|
"# c #D9D9D9", |
||||||
|
"$ c #BABABA", |
||||||
|
"% c #C1C1C1", |
||||||
|
"& c #ECECEC", |
||||||
|
"* c #A7A7A7", |
||||||
|
"= c #636363", |
||||||
|
"- c #989898", |
||||||
|
"; c #C3C3C3", |
||||||
|
"> c #C5C5C5", |
||||||
|
", c #A6A6A6", |
||||||
|
"' c #747474", |
||||||
|
") c #646464", |
||||||
|
"! c #6D6D6D", |
||||||
|
"~ c #8C8C8C", |
||||||
|
"{ c #ABABAB", |
||||||
|
"] c #A5A5A5", |
||||||
|
"^ c #787878", |
||||||
|
"/ c #A8A8A8", |
||||||
|
"( c #606060", |
||||||
|
"_ c #FFFFFF", |
||||||
|
": c #626262", |
||||||
|
"< c #7A7A7A", |
||||||
|
"[ c #FEFEFE", |
||||||
|
"} c #949494", |
||||||
|
"| c #535353", |
||||||
|
"1 c #919191", |
||||||
|
"2 c #F0F0F0", |
||||||
|
"3 c #5B5B5B", |
||||||
|
"4 c #B3B3B3", |
||||||
|
"5 c #5A5A5A", |
||||||
|
"6 c #3E3E3E", |
||||||
|
"7 c #4C4C4C", |
||||||
|
"8 c #666666", |
||||||
|
"9 c #616161", |
||||||
|
"0 c #939393", |
||||||
|
"a c #F8F8F8", |
||||||
|
"b c #1C1C1C", |
||||||
|
"c c #999999", |
||||||
|
"d c #DFDFDF", |
||||||
|
"e c #0D0D0D", |
||||||
|
"f c #B1B1B1", |
||||||
|
"g c #343434", |
||||||
|
"h c #5D5D5D", |
||||||
|
"i c #676767", |
||||||
|
"j c #6F6F6F", |
||||||
|
"k c #9E9E9E", |
||||||
|
"l c #4F4F4F", |
||||||
|
"m c #F7F7F7", |
||||||
|
"n c #1B1B1B", |
||||||
|
"o c #E7E7E7", |
||||||
|
"p c #1D1D1D", |
||||||
|
"q c #7C7C7C", |
||||||
|
"r c #9B9B9B", |
||||||
|
"s c #525252", |
||||||
|
"t c #EFEFEF", |
||||||
|
"u c #9C9C9C", |
||||||
|
"v c #434343", |
||||||
|
"w c #414141", |
||||||
|
"x c #3D3D3D", |
||||||
|
"y c #3F3F3F", |
||||||
|
"z c #BFBFBF", |
||||||
|
"A c #3A3A3A", |
||||||
|
"B c #686868", |
||||||
|
"C c #6B6B6B", |
||||||
|
"D c #C4C4C4", |
||||||
|
"E c #F4F4F4", |
||||||
|
"F c #FAFAFA", |
||||||
|
"G c #D7D7D7", |
||||||
|
"H c #AFAFAF", |
||||||
|
"I c #828282", |
||||||
|
"J c #737373", |
||||||
|
"K c #818181", |
||||||
|
"L c #DEDEDE", |
||||||
|
"M c #E9E9E9", |
||||||
|
"N c #696969", |
||||||
|
"O c #9F9F9F", |
||||||
|
"P c #A2A2A2", |
||||||
|
"Q c #717171", |
||||||
|
"R c #B4B4B4", |
||||||
|
"S c #E8E8E8", |
||||||
|
"T c #898989", |
||||||
|
"U c #767676", |
||||||
|
"V c #DBDBDB", |
||||||
|
" ", |
||||||
|
" ", |
||||||
|
" ", |
||||||
|
" ", |
||||||
|
" .++@ #$%& ", |
||||||
|
"*=-;>,')!~{]^)/ ", |
||||||
|
"(_:<[}|123:42567", |
||||||
|
"8_,90=abc|defg*h", |
||||||
|
"i_jklfmnj1opq(r=", |
||||||
|
"9sgtugvuwxyzwAB:", |
||||||
|
"}CDEFGHIJK{L[MNO", |
||||||
|
" #PQCKRd S@TiUV ", |
||||||
|
" ", |
||||||
|
" ", |
||||||
|
" ", |
||||||
|
" "}; |
@ -0,0 +1,11 @@ |
|||||||
|
<section title="Feedback"> |
||||||
|
|
||||||
|
<p>You can report bugs to the <?php sflink("bugs/")?>bug forum</a>. </p> |
||||||
|
|
||||||
|
<p>You can contact me by email via <a |
||||||
|
href="http://sourceforge.net/sendmessage.php?touser=18252">hoenicke at |
||||||
|
users.sourceforge.net</a>. Please mention <i>jode</i> in the |
||||||
|
subject.</p> |
||||||
|
|
||||||
|
<p>There is a mailing list. Check <a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">this page</a> for subscription informations.</p> |
||||||
|
</section> |
Binary file not shown.
@ -1,84 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<h2>History</h2> |
|
||||||
|
|
||||||
<p>Someday I found <code>guavad</code>, a disassembler for java byte |
|
||||||
code (it does similar things like <code>javap -c</code>). I used |
|
||||||
it on a class file, and found that it was possible to reconstruct the |
|
||||||
original java code. First I did it by hand on some small routines, |
|
||||||
but I soon realized that it was a rather stupid task. So I wrote a |
|
||||||
small <a href="dasm_to_java.perl"><code>perl</code> script</a> that |
|
||||||
did this process automatically. At the end of the next day I had my |
|
||||||
first working decompiler.</p> |
|
||||||
|
|
||||||
<p>Now while the <code>perl</code> script is working, it is not easy |
|
||||||
to use. You have to decompile the code first with a disassembler, cut |
|
||||||
out the code of a single method, and run the perl script on it. I |
|
||||||
decided to get the bytecode directly out of the class files and do |
|
||||||
this all automatically. I decided to write it in <code>java</code> |
|
||||||
now, because it suited best.</p> |
|
||||||
|
|
||||||
<p>Just for the records: the java code is now more than 50 times |
|
||||||
bigger than the original perl script and is still growing.</p> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
||||||
|
|
@ -0,0 +1,52 @@ |
|||||||
|
<opt quiet> |
||||||
|
<file template="jode.htt"> |
||||||
|
<set version="1.1"> |
||||||
|
<set sfgroup="3790"> |
||||||
|
<def name="sflink" option="href"> |
||||||
|
<a href="http://sourceforge.net/${href}?group_id=${sfgroup}"> |
||||||
|
</def> |
||||||
|
<def name="entry" option="name type href"> |
||||||
|
<if type="sflink"> |
||||||
|
<sflink href="$href"><use name></a> |
||||||
|
<else> |
||||||
|
<if _htpfile_out="${href}.html"> |
||||||
|
<use name> |
||||||
|
<elseif $href="index"> |
||||||
|
<a href="."><use name></a> |
||||||
|
<else> |
||||||
|
<a href="${href}.html"><use name></a> |
||||||
|
</if> |
||||||
|
</if> |
||||||
|
</def> |
||||||
|
|
||||||
|
<block name=menu> |
||||||
|
<entry name="<B>Home</B>" href="index"> |
||||||
|
<entry type=sflink name="Project page" href="project/"> |
||||||
|
<entry name="Applet" href="applet"> |
||||||
|
<entry name="Download" href="download"> |
||||||
|
<entry name="FAQ" href="faq"> |
||||||
|
<entry name="Feedback" href="feedback"> |
||||||
|
<entry name="Documentation" href="usage"> |
||||||
|
<entry name="License" href="license"> |
||||||
|
<entry name="History" href="history"> |
||||||
|
<entry name="Links" href="links"> |
||||||
|
<entry name="Blue Sky" href="bluesky"> |
||||||
|
</block> |
||||||
|
|
||||||
|
<blockdef name=section option="title"> |
||||||
|
<if not sect_ctr><set sect_ctr="0" global></if> |
||||||
|
<inc sect_ctr global> |
||||||
|
<set title${sect_ctr}="$title" global> |
||||||
|
<block name=section${sect_ctr} global expand> |
||||||
|
<use block noexpand> |
||||||
|
</block> |
||||||
|
</blockdef> |
||||||
|
|
||||||
|
<block name=everything> |
||||||
|
<set i=1> |
||||||
|
<while section$i> |
||||||
|
<h1><use title$i></h1> |
||||||
|
<use section$i> |
||||||
|
<inc i> |
||||||
|
</while> |
||||||
|
</block> |
@ -1,131 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
|
|
||||||
|
|
||||||
<P><i>JODE</i> is a java package containing a decompiler and an |
|
||||||
optimizer for java. This package is freely available under the GPL |
|
||||||
(see <a href="./license.html">license</a>).<p> |
|
||||||
|
|
||||||
<P>The decompiler takes <tt>class</tt> files as input and produces |
|
||||||
something similar to the original <tt>java</tt> file. Of course this |
|
||||||
can't be perfect: There is no way to produce the comments or the names |
|
||||||
of local variables (except when compiled with debuging) and there are |
|
||||||
often more ways to write the same thing. But <i>JODE</i> does its job |
|
||||||
quite well, so you should give it a try: <a href="./applet.html">start |
|
||||||
the applet</a>.</P> |
|
||||||
|
|
||||||
<P>The optimizer transforms <tt>class</tt> files in various ways with |
|
||||||
can be controlled by a script file. It supports the following |
|
||||||
operations:</p> |
|
||||||
<ul> |
|
||||||
<li>Renaming class, method, field and local names to shorter, |
|
||||||
obfuscated, or unique names or according to a given translation |
|
||||||
table</li> |
|
||||||
<li>Removing debugging information</li> |
|
||||||
<li>Removing dead code (classes, fields, methods) and constant |
|
||||||
fields</li> |
|
||||||
<li>Optimizing local variable allocation</li> |
|
||||||
</ul> |
|
||||||
|
|
||||||
<h2>News</h2> |
|
||||||
|
|
||||||
<ul> |
|
||||||
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li> |
|
||||||
<li>The latest <a href="http://sourceforge.net/cvs/?group_id=3790">CVS</a> version breaks long lines</li> |
|
||||||
<li>I can now decompile <b>inner and anonymous</b> classes.</li> |
|
||||||
<li>The optimizer (aka obfuscator) can be customized via a small |
|
||||||
config file</li> |
|
||||||
<li>Jode is <tt>autoconf</tt>igured.</li> |
|
||||||
</ul> |
|
||||||
|
|
||||||
<h2>Limitations</h2> |
|
||||||
|
|
||||||
<p>If not all dependent classes can be found, the verifier (which is |
|
||||||
run before decompilation starts) may exit with a type error. You |
|
||||||
can decompile it with <tt>--verify=off</tt>, but take the warning |
|
||||||
serious, that types may be incorrect. There's sometimes no way to |
|
||||||
guess the right type, if you don't have access the full class |
|
||||||
hierarchie.<br> |
|
||||||
|
|
||||||
This is not a bug in the verifier: java will complain the same way, |
|
||||||
if it is run with bytecode verification turned on. And if you don't |
|
||||||
have the dependent classes, you can't compile the code again.</p> |
|
||||||
|
|
||||||
<p>There may be situations, where the code doesn't understand complex |
|
||||||
expressions. In this case many ugly temporary variables are used, but |
|
||||||
the code should still be compileable. This does especially happen |
|
||||||
when you compile with <tt>`-O'</tt> flag and javac has inlined some |
|
||||||
methods. </p> |
|
||||||
|
|
||||||
<p>Sometimes this program may exit with an <code>Exception</code> or |
|
||||||
produce incorrect code. Most time the code can't be compiled, so that |
|
||||||
it can be easily spotted. If you have one of these problems (except |
|
||||||
those that occur on some of the <code>jode.test</code> files, I would |
|
||||||
be very interested in a bug report (including the <code>class</code> |
|
||||||
file, if possible). </p> |
|
||||||
|
|
||||||
<p>Sometimes <i>JODE</i> generates some GOTO expression and labels. |
|
||||||
This shouldn't happen any more with code produced by javac or jikes. |
|
||||||
But some flow obfuscator may provoke this. In that case you can run |
|
||||||
the Obfuscator first (to optimize away the flow obfuscation ;-).</p> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
@ -0,0 +1,74 @@ |
|||||||
|
<section title="Introduction"> |
||||||
|
|
||||||
|
<P><i>JODE</i> is a java package containing a decompiler and an |
||||||
|
optimizer for java. This package is <a href="license.html">freely |
||||||
|
available</a> under the GNU GPL. The bytecode package and the core |
||||||
|
decompiler is now under GNU Lesser General Public License, so you can |
||||||
|
integrate it in your project.</p> |
||||||
|
|
||||||
|
<P>The decompiler reads in <tt>class</tt> files and produces something |
||||||
|
similar to the original <tt>java</tt> file. Of course this can't be |
||||||
|
perfect: There is no way to produce the comments or the names of local |
||||||
|
variables (except when compiled with debuging) and there are often |
||||||
|
more ways to write the same thing. However, <i>JODE</i> does its job quite |
||||||
|
well, so you should give it a try and <a href="applet.html">start the |
||||||
|
applet</a>.</P> |
||||||
|
|
||||||
|
<P>The optimizer transforms <tt>class</tt> files in various ways with |
||||||
|
can be controlled by a script file. It supports the following |
||||||
|
operations:</p> |
||||||
|
<ul> |
||||||
|
<li>Renaming class, method, field and local names to shorter, |
||||||
|
obfuscated, or unique names or according to a given translation |
||||||
|
table</li> |
||||||
|
<li>Removing debugging information</li> |
||||||
|
<li>Removing dead code (classes, fields, methods) and constant |
||||||
|
fields</li> |
||||||
|
<li>Optimizing local variable allocation</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="News"> |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li><i>JODE</i> 1.1.1 is out. With support for javac v8 (jdk 1.3). </li> |
||||||
|
<li>The license changed to LGPL for the bytecode interface and decompiler.</li> |
||||||
|
</ul> |
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="Known Bugs"> |
||||||
|
|
||||||
|
<p>The current version has problems try/catch/finally code produced |
||||||
|
by java 1.4 compiler. You may try the latest CVS version or pre-release |
||||||
|
instead.</p> |
||||||
|
|
||||||
|
<p>Some jdk1.3 synthetic access functions aren't understood. The |
||||||
|
produced source contains access$xxx functions, but it still compiles.</p> |
||||||
|
|
||||||
|
<p>There may be other bugs, that cause Exceptions or invalid code. |
||||||
|
If you have such a problems don't hesitate to issue a bug report. |
||||||
|
Please include the <code>class</code> file if possible.</p> |
||||||
|
|
||||||
|
</section> |
||||||
|
|
||||||
|
<section title="Limits"> |
||||||
|
|
||||||
|
<p>If not all dependent classes can be found, the verifier (which is |
||||||
|
run before decompilation starts) may exit with a type error. You |
||||||
|
can decompile it with <tt>--verify=off</tt>, but take the warning |
||||||
|
serious, that types may be incorrect. There's sometimes no way to |
||||||
|
guess the right type, if you don't have access the full class |
||||||
|
hierarchie.<br> |
||||||
|
|
||||||
|
This is not a bug in the verifier: java will complain the same way, |
||||||
|
if it is run with bytecode verification turned on. And if you don't |
||||||
|
have the dependent classes, you can't compile the code again.</p> |
||||||
|
|
||||||
|
<p>There may be situations, where the code doesn't understand complex |
||||||
|
expressions. In this case many ugly temporary variables are used, but |
||||||
|
the code should still be compileable. This does especially happen |
||||||
|
when you compile with <tt>`-O'</tt> flag and javac has inlined some |
||||||
|
methods. </p> |
||||||
|
|
||||||
|
</section> |
@ -1,69 +0,0 @@ |
|||||||
<?php require("header.inc"); ?>
|
|
||||||
|
|
||||||
<P><i>JODE</i> is a java package containing a decompiler and an |
|
||||||
optimizer for java. This package is freely available under the GPL |
|
||||||
(see <?php selflink("license") ?>license</a>).<p>
|
|
||||||
|
|
||||||
<P>The decompiler takes <tt>class</tt> files as input and produces |
|
||||||
something similar to the original <tt>java</tt> file. Of course this |
|
||||||
can't be perfect: There is no way to produce the comments or the names |
|
||||||
of local variables (except when compiled with debuging) and there are |
|
||||||
often more ways to write the same thing. But <i>JODE</i> does its job |
|
||||||
quite well, so you should give it a try: <? selflink("applet") ?>start
|
|
||||||
the applet</a>.</P> |
|
||||||
|
|
||||||
<P>The optimizer transforms <tt>class</tt> files in various ways with |
|
||||||
can be controlled by a script file. It supports the following |
|
||||||
operations:</p> |
|
||||||
<ul> |
|
||||||
<li>Renaming class, method, field and local names to shorter, |
|
||||||
obfuscated, or unique names or according to a given translation |
|
||||||
table</li> |
|
||||||
<li>Removing debugging information</li> |
|
||||||
<li>Removing dead code (classes, fields, methods) and constant |
|
||||||
fields</li> |
|
||||||
<li>Optimizing local variable allocation</li> |
|
||||||
</ul> |
|
||||||
|
|
||||||
<h2>News</h2> |
|
||||||
|
|
||||||
<ul> |
|
||||||
<li><i>JODE</i> is now hosted by <a href="http://sourceforge.net/">SourceForge</a>.</li> |
|
||||||
<li>The latest <?php sflink("cvs/") ?>CVS</a> version breaks long lines</li>
|
|
||||||
<li>I can now decompile <b>inner and anonymous</b> classes.</li> |
|
||||||
<li>The optimizer (aka obfuscator) can be customized via a small |
|
||||||
config file</li> |
|
||||||
<li>Jode is <tt>autoconf</tt>igured.</li> |
|
||||||
</ul> |
|
||||||
|
|
||||||
<h2>Limitations</h2> |
|
||||||
|
|
||||||
<p>If not all dependent classes can be found, the verifier (which is |
|
||||||
run before decompilation starts) may exit with a type error. You |
|
||||||
can decompile it with <tt>--verify=off</tt>, but take the warning |
|
||||||
serious, that types may be incorrect. There's sometimes no way to |
|
||||||
guess the right type, if you don't have access the full class |
|
||||||
hierarchie.<br> |
|
||||||
|
|
||||||
This is not a bug in the verifier: java will complain the same way, |
|
||||||
if it is run with bytecode verification turned on. And if you don't |
|
||||||
have the dependent classes, you can't compile the code again.</p> |
|
||||||
|
|
||||||
<p>There may be situations, where the code doesn't understand complex |
|
||||||
expressions. In this case many ugly temporary variables are used, but |
|
||||||
the code should still be compileable. This does especially happen |
|
||||||
when you compile with <tt>`-O'</tt> flag and javac has inlined some |
|
||||||
methods. </p> |
|
||||||
|
|
||||||
<p>Sometimes this program may exit with an <code>Exception</code> or |
|
||||||
produce incorrect code. Most time the code can't be compiled, so that |
|
||||||
it can be easily spotted. If you have one of these problems (except |
|
||||||
those that occur on some of the <code>jode.test</code> files, I would |
|
||||||
be very interested in a bug report (including the <code>class</code> |
|
||||||
file, if possible). </p> |
|
||||||
|
|
||||||
<p>Sometimes <i>JODE</i> generates some GOTO expression and labels. |
|
||||||
This shouldn't happen any more with code produced by javac or jikes. |
|
||||||
But some flow obfuscator may provoke this. In that case you can run |
|
||||||
the Obfuscator first (to optimize away the flow obfuscation ;-).</p> |
|
||||||
<?php require("footer.inc"); ?> |
|
Before Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
@ -0,0 +1,67 @@ |
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Java Optimize and Decompile Environment (JODE)</title> |
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
||||||
|
<meta name="date" content="2001-05-29"> |
||||||
|
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
||||||
|
<meta name="author" content="Jochen Hoenicke"> |
||||||
|
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
||||||
|
<style type="text/css"> |
||||||
|
<!-- |
||||||
|
body { color:#000000; background-color: #FFFFFF; } |
||||||
|
.nav { font-family: Helvetica, Arial, sans-serif; font-weight: bold; |
||||||
|
color:#000000; background-color: #EEEEF8; } |
||||||
|
.footer { color:#FFFFFF; background-color: #737B9C; } |
||||||
|
.boldlink { font-weight:bold; text-decoration: none; color:#FFFFFF; } |
||||||
|
//--> |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body text="#000000" bgcolor="#FFFFFF"> |
||||||
|
|
||||||
|
<table cellpadding=4 cellspacing=1 width="100%" |
||||||
|
><tr |
||||||
|
><td align="left" |
||||||
|
><img src="jode-logo.png" alt="JODE" |
||||||
|
></td |
||||||
|
><td align="right" |
||||||
|
>Powered by <a href="http://sourceforge.net"><img |
||||||
|
src="http://sourceforge.net/sflogo.php?group_id=3790&type=1" |
||||||
|
border=0 width=88 height=31 alt="SourceForge"></a><br |
||||||
|
>HTML coding <a href="http://htp.sourceforge.net"><img |
||||||
|
src="poweredbyhtp.png" border=0 alt="Powered by htp"></a><br |
||||||
|
>Best viewed with <a |
||||||
|
href="http://www.anybrowser.org/campaign/"><img |
||||||
|
src="w3c_ab.png" border=0 alt="Any Browser"></a><br |
||||||
|
></td |
||||||
|
></tr |
||||||
|
></table> |
||||||
|
|
||||||
|
<table cellspacing=0 cellpadding=3 border=0 bgcolor="#EEEEF8" class="nav"> |
||||||
|
<tr><td class="nav"> |
||||||
|
<use menu> |
||||||
|
</td></tr> |
||||||
|
</table><br> |
||||||
|
|
||||||
|
<use everything> |
||||||
|
|
||||||
|
<if _htpfile_out="index.html"> |
||||||
|
<set pageref=""> |
||||||
|
<else> |
||||||
|
<set pageref="$_htpfile_out"> |
||||||
|
</if> |
||||||
|
|
||||||
|
<TABLE class=footer width="100%" border="0" cellspacing="0" cellpadding="2"> |
||||||
|
<TR> |
||||||
|
<TD align="center"><SPAN class=footer> |
||||||
|
All trademarks and copyrights on this page are properties of their respective owners. <br> |
||||||
|
Last updated on <file date>, |
||||||
|
Copyright © 1998-2004 by Jochen Hoenicke. |
||||||
|
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/$pageref">http://jode.sourceforge.net/<use pageref></a></SPAN> |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
</TABLE> |
||||||
|
|
||||||
|
</BODY> |
||||||
|
</HTML> |
@ -1,76 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<p><i>JODE</i> is Copyright © 1998-2000 by Jochen Hoenicke. <br><br> |
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify |
|
||||||
it under the terms of the <a |
|
||||||
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public |
|
||||||
License</a> as published by the Free Software Foundation; either |
|
||||||
version 2 of the License, or (at your option) any later version.<br><br> |
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, |
|
||||||
but <b>without any warranty</b>; without even the implied warranty of |
|
||||||
<b>merchantability</b> or <b>fitness for a particular purpose</b>. See the |
|
||||||
GNU General Public License for more details. |
|
||||||
|
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
@ -0,0 +1,21 @@ |
|||||||
|
<section title="License"> |
||||||
|
<p><i>JODE</i> is Copyright © 1998-2004 by Jochen Hoenicke. <br><br> |
||||||
|
|
||||||
|
<p>This program is free software; you can redistribute it and/or modify |
||||||
|
it under the terms of the <a |
||||||
|
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public |
||||||
|
License</a> as published by the Free Software Foundation; either |
||||||
|
version 2 of the License, or (at your option) any later version.</p> |
||||||
|
|
||||||
|
<p>You can redistribute some of the packages under the |
||||||
|
terms of the of the <a |
||||||
|
href="http://www.gnu.org/copyleft/lesser.html">GNU Lesser General |
||||||
|
Public License</a> as published by the Free Software Foundation. See |
||||||
|
the copyright headers in the source code.</p> |
||||||
|
|
||||||
|
<p>This program is distributed in the hope that it will be useful, |
||||||
|
but <b>without any warranty</b>; without even the implied warranty of |
||||||
|
<b>merchantability</b> or <b>fitness for a particular purpose</b>. See the |
||||||
|
GNU General Public License for more details.</p> |
||||||
|
|
||||||
|
</section> |
@ -1,15 +0,0 @@ |
|||||||
<?php require("header.inc"); ?> |
|
||||||
<p><i>JODE</i> is Copyright © 1998-2000 by Jochen Hoenicke. <br><br> |
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify |
|
||||||
it under the terms of the <a |
|
||||||
href="http://www.gnu.org/copyleft/gpl.html">GNU General Public |
|
||||||
License</a> as published by the Free Software Foundation; either |
|
||||||
version 2 of the License, or (at your option) any later version.<br><br> |
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, |
|
||||||
but <b>without any warranty</b>; without even the implied warranty of |
|
||||||
<b>merchantability</b> or <b>fitness for a particular purpose</b>. See the |
|
||||||
GNU General Public License for more details. |
|
||||||
|
|
||||||
<?php require("footer.inc"); ?> |
|
@ -1,123 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<h1><i>JODE</i> Links</h1> |
|
||||||
<h3>Other decompilers</h3> |
|
||||||
<ul> |
|
||||||
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Decompilers_and_Disassemblers/">The Open Directory list</a></li> |
|
||||||
<li>A list of decompilers can be found at <a href="http://www.meurrens.org/ip-Links/Java/CodeEngineering/#tocDecompilersToJava">Marc Meurren's list</a> |
|
||||||
</li> |
|
||||||
<li>A very fast decompiler is <a |
|
||||||
href="http://www.geocities.com/SiliconValley/Bridge/8617/jad.html">jad</a> |
|
||||||
written in C++. It doesn't come with source code though, and misses |
|
||||||
some features <i>JODE</i> has ;-)</li> <li><a |
|
||||||
href="http://www.javaworld.com/javaworld/jw-07-1997/jw-07-decompilers.html">A |
|
||||||
comparison of three decompilers</a> (but not <i>JODE</i>) was done by Dave |
|
||||||
Dyer. |
|
||||||
</ul> |
|
||||||
<h3>Other obfuscators</h3> |
|
||||||
<ul> |
|
||||||
<li><a href="http://dmoz.org/Computers/Programming/Languages/Java/Obfuscators/">The Open Directory list</a></li> |
|
||||||
<li><a href="http://www.sbktech.org/hashjava_old.html">Hashjava</a> is another free obfuscator. It is no longer maintained, though, since its successor was commercialized.</li> |
|
||||||
<li><a href="http://www.zelix.com/klassmaster/index.html">Zelix |
|
||||||
Klassmaster</a> does a very good flow optimization and also decrypts |
|
||||||
strings. But <i>JODE</i>'s deobfuscator can undo both.</li> |
|
||||||
<li><a href="http://www.cs.arizona.edu/~collberg/Research/">Christian S. Collberg</a> has some really interesting papers about non reversible obfuscations.</li> |
|
||||||
</ul> |
|
||||||
<h3>Graphical User Interface</h3> |
|
||||||
<ul> |
|
||||||
<li><i>JODE</i> is used by the <a |
|
||||||
href="http://jedit.standmed.com/plugins/JavaInsight">JavaInsight plugin</a> for |
|
||||||
<a href="http://jedit.sourceforge.net/">jEdit</a>.</li> |
|
||||||
</ul> |
|
||||||
<h3>Miscellanous packages needed to run JODE</h3> |
|
||||||
<dl> |
|
||||||
<dt>CYGWIN (unix tools for win95/NT)</dt> |
|
||||||
<dd> |
|
||||||
<a href="http://sourceware.cygnus.com/cygwin/">http://sourceware.cygnus.com/cygwin/</a> |
|
||||||
</dd> |
|
||||||
<dt>JDK 1.1:</dt> |
|
||||||
<dd> |
|
||||||
<a href="http://java.sun.com/products/jdk/1.1/">http://java.sun.com/products/jdk/1.1/</a> |
|
||||||
</dd> |
|
||||||
<dt><a name="swing">Swing for JDK 1.1:</a><dt> |
|
||||||
<dd> |
|
||||||
<a href="http://java.sun.com/products/jfc/index.html#download-swing">http://java.sun.com/products/jfc/index.html#download-swing</a> |
|
||||||
</dd> |
|
||||||
<dt>JDK 1.2:</dt> |
|
||||||
<dd> |
|
||||||
<a href="http://java.sun.com/products/jdk/1.2/">http://java.sun.com/products/jdk/1.2/</a> |
|
||||||
</dd> |
|
||||||
<dt><a name="getopt">Getopt</a>:</dt> |
|
||||||
<dd> |
|
||||||
<a href="http://www.urbanophile.com/arenn/hacking/download.html#getopt">http://www.urbanophile.com/arenn/hacking/download.html#getopt</a> |
|
||||||
</dd> |
|
||||||
<dt><a name="collections">Collection Classes</a>:</dt> |
|
||||||
<dd>I have written a small script that puts the collection classes |
|
||||||
from the <a href="http://www.classpath.org">GNU Classpath Project</a> into |
|
||||||
its own package (<code>org.gnu.java.util.collections</code>). You can |
|
||||||
download the <a href="http://www.informatik.uni-oldenburg.de/~delwi/jode/collections.tar.gz">source code</a> (including |
|
||||||
the script), or <a href="collections.jar">a precompiled jar file</a>. |
|
||||||
</dd> |
|
||||||
</dl> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
||||||
|
|
@ -1,115 +1,47 @@ |
|||||||
<?php |
<?php |
||||||
$menu = array( |
$menu = |
||||||
"Jode", |
array("<B>Home</B>" , "selflink", "index", |
||||||
array("<B>Home</B>" , "selflink", "jode", |
|
||||||
"Project page" , "sflink", "project/", |
"Project page" , "sflink", "project/", |
||||||
"-", "-", "-", |
|
||||||
"Applet" , "selflink", "applet", |
"Applet" , "selflink", "applet", |
||||||
"Download" , "selflink", "download", |
"Download" , "selflink", "download", |
||||||
|
"FAQ" , "selflink", "faq", |
||||||
|
"Feedback" , "selflink", "feedback", |
||||||
"Documentation", "selflink", "usage", |
"Documentation", "selflink", "usage", |
||||||
"License" , "selflink", "license", |
"License" , "selflink", "license", |
||||||
"History" , "selflink", "history", |
"History" , "selflink", "history", |
||||||
"Links" , "selflink", "links", |
"Links" , "selflink", "links", |
||||||
"Blue Sky" , "selflink", "bluesky"), |
"Blue Sky" , "selflink", "bluesky"); |
||||||
"Feedback", |
?> |
||||||
array("Bug Tracking" , "sflink", "bugs/", |
|
||||||
"Public Forums" , "sflink", "forum/", |
|
||||||
"Mailing List" , "link", |
|
||||||
"http://lists.sourceforge.net/mailman/listinfo/jode-users", |
|
||||||
"Private Mail" , "link", |
|
||||||
"http://sourceforge.net/sendmessage.php?touser=18252"), |
|
||||||
"Download", |
|
||||||
array("FTP server", "link", "ftp://jode.sourceforge.net/pub/jode/", |
|
||||||
"Source releases", "sflink", "project/filelist.php")); |
|
||||||
|
|
||||||
$images = array( |
|
||||||
"Powered by ", "http://sourceforge.net/sflogo.php?group_id=3790&type=1", |
|
||||||
"SourceForge", "http://sourceforge.net", |
|
||||||
"Best viewed with ", "a-logo.gif", |
|
||||||
"Any Browser", "http://www.anybrowser.org/campaign/"); |
|
||||||
|
|
||||||
if (eregi("^Lynx", $HTTP_USER_AGENT)) { |
|
||||||
|
|
||||||
reset($menu); |
|
||||||
while (list($dummy, $header) = each($menu)) { |
|
||||||
list($dummy, $subitems) = each($menu); |
|
||||||
|
|
||||||
echo "<b>$header:</b>\n"; |
|
||||||
reset($subitems); |
|
||||||
while (list($dummy, $name) = each($subitems)) { |
|
||||||
list($dummy, $type) = each($subitems); |
|
||||||
list($dummy, $link) = each($subitems); |
|
||||||
if ($type == "selflink") { |
|
||||||
selflink($link); |
|
||||||
} else if ($type == "sflink") { |
|
||||||
sflink($link); |
|
||||||
} else if ($type == "-") { |
|
||||||
echo "<br>\n"; |
|
||||||
continue; |
|
||||||
} else if ($type == "link") { |
|
||||||
echo "<a href=\"$link\">"; |
|
||||||
} |
|
||||||
$name = ereg_replace(" ", " ", $name); |
|
||||||
echo "$name</a>"; |
|
||||||
if (current($subitems)) { |
|
||||||
echo " |\n"; |
|
||||||
} |
|
||||||
} |
|
||||||
echo "<br>\n\n"; |
|
||||||
} |
|
||||||
echo "<right>\n"; |
|
||||||
reset($images); |
|
||||||
while (list($dummy, $label) = each($images)) { |
|
||||||
list($dummy, $src) = each($images); |
|
||||||
list($dummy, $alt) = each($images); |
|
||||||
list($dummy, $link) = each($images); |
|
||||||
echo "$label<a href=\"$link\"><img src=\"$src\" border=0"; |
|
||||||
echo " width=88 height=31 alt=\"$alt\"></a>\n"; |
|
||||||
} |
|
||||||
echo "</right>\n"; |
|
||||||
} else { |
|
||||||
echo "<table cellspacing=0 cellpadding=3 width=100%"; |
|
||||||
echo " border=0 bgcolor=eeeef8>\n"; |
|
||||||
|
|
||||||
reset($menu); |
<table cellspacing=0 cellpadding=3 border=0 bgcolor="#EEEEF8" class="nav"> |
||||||
while (list($dummy, $header) = each($menu)) { |
<tr><td class="nav"> |
||||||
list($dummy, $subitems) = each($menu); |
<?php |
||||||
echo "<tr bgcolor=\"7272cc\">\n<td align=\"center\">"; |
reset($menu); |
||||||
echo "<font color=\"ffffff\"><b>$header</b></font></td></tr>\n"; |
$self = ereg_replace("^.*/", "", $PHP_SELF); |
||||||
echo "<tr><td align=\"right\">\n"; |
while (list($dummy, $name) = each($menu)) { |
||||||
reset($subitems); |
list($dummy, $type) = each($menu); |
||||||
while (list($dummy, $name) = each($subitems)) { |
list($dummy, $link) = each($menu); |
||||||
list($dummy, $type) = each($subitems); |
$name = ereg_replace(" ", " ", $name); |
||||||
list($dummy, $link) = each($subitems); |
if ($type == "selflink") { |
||||||
if ($type == "selflink") { |
if ($self == "$link.$extension") { |
||||||
selflink($link); |
echo "$name"; |
||||||
} else if ($type == "sflink") { |
} else { |
||||||
sflink($link); |
selflink($link); |
||||||
} else if ($type == "-") { |
|
||||||
echo "<br>\n"; |
|
||||||
continue; |
|
||||||
} else if ($type == "link") { |
|
||||||
echo "<a href=\"$link\">"; |
|
||||||
} |
|
||||||
$name = ereg_replace(" ", " ", $name); |
|
||||||
echo "$name</a>"; |
echo "$name</a>"; |
||||||
if (current($subitems)) { |
|
||||||
echo "<br>\n"; |
|
||||||
} |
|
||||||
} |
} |
||||||
|
} else if ($type == "sflink") { |
||||||
|
sflink($link); |
||||||
|
echo "$name</a>"; |
||||||
|
} else if ($type == "-") { |
||||||
|
echo "<br>\n"; |
||||||
|
continue; |
||||||
|
} else if ($type == "link") { |
||||||
|
echo "<a href=\"$link\">$name</a>"; |
||||||
} |
} |
||||||
echo "</td></tr>\n"; |
if (current($menu)) { |
||||||
echo "<tr bgcolor=\"ffffff\"><td align=\"center\">"; |
echo " |\n"; |
||||||
|
|
||||||
reset($images); |
|
||||||
while (list($dummy, $label) = each($images)) { |
|
||||||
list($dummy, $src) = each($images); |
|
||||||
list($dummy, $alt) = each($images); |
|
||||||
list($dummy, $link) = each($images); |
|
||||||
echo "<br>$label<br>\n"; |
|
||||||
echo "<a href=\"$link\"><img src=\"$src\" border=0"; |
|
||||||
echo " width=88 height=31 alt=\"$alt\"></a><br>\n"; |
|
||||||
} |
} |
||||||
echo "</td></tr></table>\n"; |
|
||||||
} |
} |
||||||
?> |
?> |
||||||
|
</td></tr> |
||||||
|
</table><br> |
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -1,281 +0,0 @@ |
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<title>Java Optimize and Decompile Environment (JODE)</title> |
|
||||||
<meta name="date" content="2000-06-30"> |
|
||||||
<meta name="description" content="JODE - Java Optimize and Decompile Environment."> |
|
||||||
<meta name="author" content="Jochen Hoenicke"> |
|
||||||
<meta name="keywords" content="jode, java, decompiler, obfuscator, deobfuscator, reverse engineering, free, GPL"> |
|
||||||
</head> |
|
||||||
|
|
||||||
<BODY bgcolor=#FFFFFF topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" marginheight="0" marginwidth="0"> |
|
||||||
<table cellpadding=4 cellspacing=1 width=100%> |
|
||||||
<tr><td> |
|
||||||
</td> |
|
||||||
<td> <img src="jode-logo.gif" alt="JODE" width=286 height=110></td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<td valign="top"> |
|
||||||
<table cellspacing=0 cellpadding=3 width=100% border=0 bgcolor=eeeef8> |
|
||||||
<tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Jode</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="./"><B>Home</B></a><br> |
|
||||||
<a href="http://sourceforge.net/project/?group_id=3790">Project page</a><br> |
|
||||||
<br> |
|
||||||
<a href="./applet.html">Applet</a><br> |
|
||||||
<a href="./download.html">Download</a><br> |
|
||||||
<a href="./usage.html">Documentation</a><br> |
|
||||||
<a href="./license.html">License</a><br> |
|
||||||
<a href="./history.html">History</a><br> |
|
||||||
<a href="./links.html">Links</a><br> |
|
||||||
<a href="./bluesky.html">Blue Sky</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Feedback</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="http://sourceforge.net/bugs/?group_id=3790">Bug Tracking</a><br> |
|
||||||
<a href="http://sourceforge.net/forum/?group_id=3790">Public Forums</a><br> |
|
||||||
<a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">Mailing List</a><br> |
|
||||||
<a href="http://sourceforge.net/sendmessage.html?touser=18252">Private Mail</a><tr bgcolor="7272cc"> |
|
||||||
<td align="center"><font color="ffffff"><b>Download</b></font></td></tr> |
|
||||||
<tr><td align="right"> |
|
||||||
<a href="ftp://jode.sourceforge.net/pub/jode/">FTP server</a><br> |
|
||||||
<a href="http://sourceforge.net/project/filelist.html?group_id=3790">Source releases</a></td></tr> |
|
||||||
<tr bgcolor="ffffff"><td align="center"><br>Powered by <br> |
|
||||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.html?group_id=3790&type=1" border=0 width=88 height=31 alt="SourceForge"></a><br> |
|
||||||
<br>Best viewed with <br> |
|
||||||
<a href="http://www.anybrowser.org/campaign/"><img src="a-logo.gif" border=0 width=88 height=31 alt="Any Browser"></a><br> |
|
||||||
</td></tr></table> |
|
||||||
</td> |
|
||||||
<td valign="top"> |
|
||||||
<a name="decompiler"> |
|
||||||
<h1>Using the Decompiler</h1></a> |
|
||||||
After you have <a href="./download.html">downloaded</a> the necessary |
|
||||||
packages, put them into your <tt>CLASSPATH</tt>: |
|
||||||
|
|
||||||
<ul><li>Under Windows you have to start a MSDOS session and type |
|
||||||
something like: |
|
||||||
<pre> |
|
||||||
set CLASSPATH=C:\download\jode-xxx.jar;C:\swing\swingall.jar |
|
||||||
</pre> |
|
||||||
</li><li>Under Unix you start a shell and type (for bourne shell): |
|
||||||
<pre>export CLASSPATH=/tmp/jode-xxx.jar:/usr/local/swing/swingall.jar</pre> |
|
||||||
or for csh: |
|
||||||
<pre>setenv CLASSPATH /tmp/jode-xxx.jar:/usr/local/swing/swingall.jar</pre> |
|
||||||
</ul> |
|
||||||
<br> |
|
||||||
There is also a batch file for windows and a script file for unix, |
|
||||||
that you can use. Adapt the CLASSPATH in the file and put it to a |
|
||||||
convenient location. |
|
||||||
<pre> |
|
||||||
jar -xvf jode-xxx.jar bin/jode.bat <i>resp.</i> bin/jode |
|
||||||
</pre> |
|
||||||
|
|
||||||
<a name="cmdline"><h3>Command Line Interface</h3></a> |
|
||||||
|
|
||||||
The most powerful way to start <I>JODE</I>'s decompiler is the command |
|
||||||
line interface. Some people don't like long command lines; they |
|
||||||
should go to the next section. <br> |
|
||||||
|
|
||||||
Start the class <tt>jode.decompiler.Main</tt> with the options. The |
|
||||||
following command will give a complete list of the available commands: |
|
||||||
|
|
||||||
<pre>java jode.decompiler.Main --help</pre> |
|
||||||
|
|
||||||
<a name="awt"><h3>AWT Interface</h3></a> |
|
||||||
|
|
||||||
The AWT Interface looks exactly like the <a href="./applet.html">applet</a>. In fact the applet uses the AWT Interface. You start it |
|
||||||
after setting the <tt>CLASSPATH</tt> (see <a href="./usage.html#decompiler">above</a>), with |
|
||||||
|
|
||||||
<pre>java jode.decompiler.Window</pre> |
|
||||||
|
|
||||||
In the classpath line you can enter a number of jar files, zip files |
|
||||||
and directories separated by comma(<tt>,</tt>). Then enter the |
|
||||||
dot(<tt>.</tt>) separated name of the class you want to decompile. |
|
||||||
Press the <code>start</code> button and the decompiled class should |
|
||||||
appear. You can save it via the <code>save</code> button. |
|
||||||
|
|
||||||
<a name="swing"><h3>Swing Interface</h3></a> |
|
||||||
|
|
||||||
For the swing interface you need java version 1.2 or the separately |
|
||||||
available swing package (see <a href="./links.html#swing">link |
|
||||||
page</a>. You can invoke it like this: |
|
||||||
<pre> |
|
||||||
java jode.swingui.Main --classpath classes.jar |
|
||||||
</pre> |
|
||||||
|
|
||||||
The swing interface will show the package hierarchie of all classes |
|
||||||
in the classpath on the left side. You can now select a class and the |
|
||||||
decompiled code will appear on the right side. Via the menu, you may |
|
||||||
change the classpath or switch between package hierarchie tree and |
|
||||||
class inheritence tree.<br> |
|
||||||
|
|
||||||
The swing interface is very useful to browse through class files if |
|
||||||
you don't have the source code. You can also use it to trace bugs in |
|
||||||
library code. It is not meant to generate <tt>java</tt> files and so |
|
||||||
you won't find a save option there.<br> |
|
||||||
|
|
||||||
<a name="java"><h3>Java Interface</h3></a> |
|
||||||
|
|
||||||
If you want to integrate <i>JODE</i> into your own java program, you |
|
||||||
can use the <a |
|
||||||
href="Decompiler.java"><code>jode.decompiler.Decompiler</code></a> |
|
||||||
class. Note that the GPL only allows you to integrate <i>JODE</i> |
|
||||||
into GPL programs. Please contact me if you use <i>JODE</i> in this |
|
||||||
way.<br> |
|
||||||
|
|
||||||
You may use this <a |
|
||||||
href="ftp://jode.sourceforge.net/pub/jode/jode-embedded.jar">stripped |
|
||||||
down jar archive</a> containing all necessary classes. |
|
||||||
|
|
||||||
<a name="optimizer"><h1>Using the Obfuscator</h1> |
|
||||||
|
|
||||||
To use the obfuscator you should first create a script file, say <a |
|
||||||
href="myproject.jos"><tt>myproject.jos</tt></a>. Then you can invoke the |
|
||||||
obfuscator with: |
|
||||||
<pre> |
|
||||||
java jode.obfuscator.Main myproject.jos |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>The script file should contain the following options: </p> |
|
||||||
|
|
||||||
<p>First select the classpath. You should include everything in the |
|
||||||
classpath that you need to run your application. This also includes |
|
||||||
the system class files (Sun puts them into <code>classes.zip</code> or |
|
||||||
<code>rt.jar</code>))</p> |
|
||||||
<pre> |
|
||||||
classpath = "c:\\jdk1.2\\jre\\lib\\rt.jar","d:\\project\\java", |
|
||||||
"ftp://www.myorg.org/pub/classlib.jar" |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Specify where you want the obfuscated classes to go. I recommend |
|
||||||
to write them directly into a zip file, but you can also give a |
|
||||||
directory.</p> |
|
||||||
<pre> |
|
||||||
dest = "obfuscated.zip" |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>You can make <i>JODE</i> write its translation table. This table |
|
||||||
can be used later to undo the name obfuscation, or you can look there |
|
||||||
to decrypt exceptions you may get.</p> |
|
||||||
<pre> |
|
||||||
revtable = "translat.tbl" |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Select what you want to strip. There are several |
|
||||||
possibilities, which can be separated by comma(<tt>,</tt>):</p> |
|
||||||
<dl> |
|
||||||
<dt>unreach</dt> |
|
||||||
<dd>strip unreachable methods and classes.</dd> |
|
||||||
<dt>source</dt> |
|
||||||
<dd>remove the name of the java file (exceptions will get unreadable).</dd> |
|
||||||
<dt>lnt</dt> |
|
||||||
<dd>remove the line number table (exceptions will get unreadable).</dd> |
|
||||||
<dt>lvt</dt> |
|
||||||
<dd>remove the local variable table (debugging doesn't work).</dd> |
|
||||||
<dt>inner</dt> |
|
||||||
<dd>strip inner class info (reflection doesn't work correctly).</dd> |
|
||||||
</dl> |
|
||||||
<pre> |
|
||||||
strip = "unreach","lvt","inner" |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Select the packages and classes you want to obfuscate. You should |
|
||||||
only include libraries, that you don't ship separately. If you give a |
|
||||||
package, all classes and subpackages are loaded. You can also use |
|
||||||
<code>*</code> as wild card, that matches everything (including dots). |
|
||||||
</p> |
|
||||||
<pre> |
|
||||||
load = new WildCard { value = "org.myorg.myproject" }, |
|
||||||
new WildCard { value = "org.myorg.mylib*" }, |
|
||||||
new WildCard { value = "org.otherorg.shortlib" } |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Select the methods and classes you want to preserve. This is |
|
||||||
the <tt>main</tt> method for applications and the default constructor |
|
||||||
<tt><init>.()V</tt> for applets, resource bundles and other classes |
|
||||||
that you load manually at runtime.<br> You have to give the method |
|
||||||
name and the type signature to identify your method. <tt>javap |
|
||||||
-s</tt> will show you the type signatures for your classes, but you |
|
||||||
may also use <tt>*</tt>, to select all methods with that name.</p> |
|
||||||
<pre> |
|
||||||
preserve = new WildCard { value = "org.myorg.ApplicationClass.main.*" }, |
|
||||||
new WildCard { value = "org.myorg.AppletClass.<init>.()V" }, |
|
||||||
new WildCard { value = "org.resources.Bundle*.<init>.()V" }, |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>If you want to obfuscate (or just shorten) the identifier you can |
|
||||||
specify a renamer. There are currently following renamer |
|
||||||
available</p> |
|
||||||
<dl><dt>StrongRenamer</dt> |
|
||||||
<dd>Renames to the shortest possible name. You can give a charset |
|
||||||
that should be used. It uses the same name as much as possible.</dd> |
|
||||||
<dt>UniqueRenamer</dt> |
|
||||||
<dd>Renames to unique identifier of the form <tt>xxx123</tt>. Useful |
|
||||||
to reduce name conflicts, before you decompile an obfuscated package.</dd> |
|
||||||
<dt>NameSwapper</dt> |
|
||||||
<dd>This renamer just swaps the names. This is a funny obfuscation |
|
||||||
option that is not very strong, but very confusing.</dd> |
|
||||||
<dt>KeywordRenamer</dt> |
|
||||||
<dd>Renames identifiers to keyword. You can give your own list of |
|
||||||
keywords as parameters. Resulting code is not decompilable directly, |
|
||||||
<b>but it is <i>not</i> legal bytecode either</b>. Some paranoid |
|
||||||
web browsers refuse to run applets containing keywords as identifiers |
|
||||||
(and they are completely within the Java VM spec).</dd> |
|
||||||
</dl> |
|
||||||
<pre> |
|
||||||
renamer = new StrongRenamer |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>You can also create a renaming table with the same format as the |
|
||||||
table written by revtable. The entries in the table get precedence |
|
||||||
over renamer. Entries not in the table will get renamed by the |
|
||||||
renamer.<p> |
|
||||||
<pre> |
|
||||||
table = "translat.tbl" |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Now you can select the analyzer. The purpose of the |
|
||||||
analyzer is to mark all reachable methods, find out which methods |
|
||||||
needs to get the same name (overloading), and which method names |
|
||||||
mustn't change (overload of library methods, e.g. <tt>nextElement</tt> |
|
||||||
for <tt>Enumeration</tt>s). There are currently two analyzers. |
|
||||||
<dl><dt>SimpleAnalyzer</dt> |
|
||||||
<dd>Straight forward analyzer. It is fast and will remove dead code |
|
||||||
on method basis.</dd> |
|
||||||
|
|
||||||
<dd><dt>ConstantAnalyzer</dt> |
|
||||||
<dd>Strong analyzer that will determine, which fields and instructions |
|
||||||
have constant values. It will remove dead code on instruction basis |
|
||||||
and replace constant instruction with a load of the constant, or |
|
||||||
remove them completely.<br> This analyzer is especially useful to |
|
||||||
revert the flow obfuscation of some other obfuscators.</dd> |
|
||||||
</dl> |
|
||||||
</p> |
|
||||||
<pre> |
|
||||||
analyzer = new ConstantAnalyzer |
|
||||||
</pre> |
|
||||||
|
|
||||||
<p>Pre- and Post transformers transform the bytecode before |
|
||||||
resp. after the Analyzer runs. Using this default should be okay. |
|
||||||
You may remove the LocalOptimizer, though, if you have problems.</p> |
|
||||||
<p>In the future I may add some new post transformers, that do string |
|
||||||
encryption, flow obfuscation and similar things. If you want to write |
|
||||||
your own Transformers please contact me, since the next version will |
|
||||||
change the bytecode interface.</p> |
|
||||||
<pre> |
|
||||||
post = new LocalOptimizer, new RemovePopAnalyzer |
|
||||||
</pre> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
<TABLE width="100%" border="0" cellspacing="0" cellpadding="2" bgcolor="737b9c"> |
|
||||||
<TR> |
|
||||||
<TD align="center"><FONT color="#ffffff"><SPAN class="titlebar"> |
|
||||||
All trademarks and copyrights on this page are properties of their respective owners. <br> |
|
||||||
Last updated on 8-May-2000, |
|
||||||
Copyright © 1998-2000 by Jochen Hoenicke.</SPAN></FONT> |
|
||||||
</TD> |
|
||||||
</TR> |
|
||||||
</TABLE> |
|
||||||
|
|
||||||
</BODY> |
|
||||||
</HTML> |
|
After Width: | Height: | Size: 1.0 KiB |
@ -1,4 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
||||||
.java.deps |
|
||||||
jode.jar |
|
@ -1,29 +0,0 @@ |
|||||||
/* AssertError Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode; |
|
||||||
|
|
||||||
public class AssertError extends Error { |
|
||||||
public AssertError() { |
|
||||||
} |
|
||||||
|
|
||||||
public AssertError(String detail) { |
|
||||||
super(detail); |
|
||||||
} |
|
||||||
} |
|
@ -1,41 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
SUBDIRS = util bytecode type jvm expr flow decompiler obfuscator @SWINGUI@
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
AssertError.java \
|
|
||||||
GlobalOptions.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
|
|
||||||
JARFILE = jode-@VERSION@.jar
|
|
||||||
#data_DATA = $(JARFILE)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
||||||
|
|
||||||
$(JARFILE): $(noinst_DATA) |
|
||||||
CLASSPATH=$(top_builddir):$(CLASSPATH) $(JAVA) -mx80m \
|
|
||||||
jode.obfuscator.Main --classpath=$(top_builddir) \
|
|
||||||
--dest=$(JARFILE) -v -v $(srcdir)/jode.jodescript
|
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
@ -1,229 +0,0 @@ |
|||||||
/* BinaryInfo Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
import java.io.DataInputStream; |
|
||||||
import java.io.DataOutputStream; |
|
||||||
import java.io.EOFException; |
|
||||||
import java.io.FilterInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import jode.util.SimpleMap; |
|
||||||
|
|
||||||
import @COLLECTIONS@.Map; |
|
||||||
import @COLLECTIONS@.Collections; |
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
* @author Jochen Hoenicke |
|
||||||
*/ |
|
||||||
public class BinaryInfo { |
|
||||||
public static final int HIERARCHY = 0x01; |
|
||||||
public static final int FIELDS = 0x02; |
|
||||||
public static final int METHODS = 0x04; |
|
||||||
public static final int CONSTANTS = 0x08; |
|
||||||
public static final int KNOWNATTRIBS = 0x10; |
|
||||||
public static final int INNERCLASSES = 0x20; |
|
||||||
public static final int OUTERCLASSES = 0x40; |
|
||||||
public static final int UNKNOWNATTRIBS = 0x80; |
|
||||||
public static final int FULLINFO = 0xff; |
|
||||||
public static final int MOSTINFO = 0x7f; |
|
||||||
public static final int REFLECTINFO = 0x6f; |
|
||||||
|
|
||||||
private Map unknownAttributes = null; |
|
||||||
|
|
||||||
protected void skipAttributes(DataInputStream input) throws IOException { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
input.readUnsignedShort(); // the name index
|
|
||||||
long length = input.readInt(); |
|
||||||
while (length > 0) { |
|
||||||
long skipped = input.skip(length); |
|
||||||
if (skipped == 0) |
|
||||||
throw new EOFException("Can't skip. EOF?"); |
|
||||||
length -= skipped; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected int getKnownAttributeCount() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
protected void readAttribute(String name, int length, |
|
||||||
ConstantPool constantPool, |
|
||||||
DataInputStream input, |
|
||||||
int howMuch) throws IOException { |
|
||||||
byte[] data = new byte[length]; |
|
||||||
input.readFully(data); |
|
||||||
if ((howMuch & UNKNOWNATTRIBS) != 0) { |
|
||||||
if (unknownAttributes == null) |
|
||||||
unknownAttributes = new SimpleMap(); |
|
||||||
unknownAttributes.put(name, data); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static class ConstrainedInputStream extends FilterInputStream { |
|
||||||
int length; |
|
||||||
|
|
||||||
public ConstrainedInputStream(int attrLength, InputStream input) { |
|
||||||
super(input); |
|
||||||
length = attrLength; |
|
||||||
} |
|
||||||
|
|
||||||
public int read() throws IOException { |
|
||||||
if (length > 0) { |
|
||||||
int data = super.read(); |
|
||||||
length--; |
|
||||||
return data; |
|
||||||
} |
|
||||||
throw new EOFException(); |
|
||||||
} |
|
||||||
|
|
||||||
public int read(byte[] b, int off, int len) throws IOException { |
|
||||||
if (length < len) { |
|
||||||
len = length; |
|
||||||
} |
|
||||||
if (len == 0) |
|
||||||
return -1; |
|
||||||
int count = super.read(b, off, len); |
|
||||||
length -= count; |
|
||||||
return count; |
|
||||||
} |
|
||||||
|
|
||||||
public int read(byte[] b) throws IOException { |
|
||||||
return read(b, 0, b.length); |
|
||||||
} |
|
||||||
|
|
||||||
public long skip(long count) throws IOException { |
|
||||||
if (length < count) { |
|
||||||
count = length; |
|
||||||
} |
|
||||||
count = super.skip(count); |
|
||||||
length -= (int) count; |
|
||||||
return count; |
|
||||||
} |
|
||||||
|
|
||||||
public void skipRemaining() throws IOException { |
|
||||||
while (length > 0) { |
|
||||||
int skipped = (int) skip(length); |
|
||||||
if (skipped == 0) |
|
||||||
throw new EOFException(); |
|
||||||
length -= skipped; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected void readAttributes(ConstantPool constantPool, |
|
||||||
DataInputStream input, |
|
||||||
int howMuch) throws IOException { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
unknownAttributes = null; |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
String attrName = |
|
||||||
constantPool.getUTF8(input.readUnsignedShort()); |
|
||||||
final int attrLength = input.readInt(); |
|
||||||
ConstrainedInputStream constrInput = |
|
||||||
new ConstrainedInputStream(attrLength, input); |
|
||||||
readAttribute(attrName, attrLength, |
|
||||||
constantPool, new DataInputStream(constrInput), |
|
||||||
howMuch); |
|
||||||
constrInput.skipRemaining(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void dropInfo(int howMuch) { |
|
||||||
if ((howMuch & UNKNOWNATTRIBS) != 0) |
|
||||||
unknownAttributes = null; |
|
||||||
} |
|
||||||
|
|
||||||
protected void prepareAttributes(GrowableConstantPool gcp) { |
|
||||||
if (unknownAttributes == null) |
|
||||||
return; |
|
||||||
Iterator i = unknownAttributes.keySet().iterator(); |
|
||||||
while (i.hasNext()) |
|
||||||
gcp.putUTF8((String) i.next()); |
|
||||||
} |
|
||||||
|
|
||||||
protected void writeKnownAttributes |
|
||||||
(GrowableConstantPool constantPool, |
|
||||||
DataOutputStream output) throws IOException { |
|
||||||
} |
|
||||||
|
|
||||||
protected void writeAttributes |
|
||||||
(GrowableConstantPool constantPool, |
|
||||||
DataOutputStream output) throws IOException { |
|
||||||
int count = getKnownAttributeCount(); |
|
||||||
if (unknownAttributes != null) |
|
||||||
count += unknownAttributes.size(); |
|
||||||
output.writeShort(count); |
|
||||||
writeKnownAttributes(constantPool, output); |
|
||||||
if (unknownAttributes != null) { |
|
||||||
Iterator i = unknownAttributes.entrySet().iterator(); |
|
||||||
while (i.hasNext()) { |
|
||||||
Map.Entry e = (Map.Entry) i.next(); |
|
||||||
String name = (String) e.getKey(); |
|
||||||
byte[] data = (byte[]) e.getValue(); |
|
||||||
output.writeShort(constantPool.putUTF8(name)); |
|
||||||
output.writeInt(data.length); |
|
||||||
output.write(data); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public int getAttributeSize() { |
|
||||||
int size = 2; /* attribute count */ |
|
||||||
if (unknownAttributes != null) { |
|
||||||
Iterator i = unknownAttributes.values().iterator(); |
|
||||||
while (i.hasNext()) |
|
||||||
size += 2 + 4 + ((byte[]) i.next()).length; |
|
||||||
} |
|
||||||
return size; |
|
||||||
} |
|
||||||
|
|
||||||
public byte[] findAttribute(String name) { |
|
||||||
if (unknownAttributes != null) |
|
||||||
return (byte[]) unknownAttributes.get(name); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public Iterator getAttributes() { |
|
||||||
if (unknownAttributes != null) |
|
||||||
return unknownAttributes.values().iterator(); |
|
||||||
return Collections.EMPTY_SET.iterator(); |
|
||||||
} |
|
||||||
|
|
||||||
public void setAttribute(String name, byte[] content) { |
|
||||||
if (unknownAttributes == null) |
|
||||||
unknownAttributes = new SimpleMap(); |
|
||||||
unknownAttributes.put(name, content); |
|
||||||
} |
|
||||||
|
|
||||||
public byte[] removeAttribute(String name) { |
|
||||||
if (unknownAttributes != null) |
|
||||||
return (byte[]) unknownAttributes.remove(name); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void removeAllAttributes() { |
|
||||||
unknownAttributes = null; |
|
||||||
} |
|
||||||
} |
|
File diff suppressed because it is too large
Load Diff
@ -1,868 +0,0 @@ |
|||||||
/* ClassInfo Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
import jode.GlobalOptions; |
|
||||||
import jode.util.UnifyHash; |
|
||||||
|
|
||||||
import java.io.DataInputStream; |
|
||||||
import java.io.BufferedInputStream; |
|
||||||
import java.io.DataOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Enumeration; |
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
|
|
||||||
import java.lang.reflect.Constructor; |
|
||||||
import java.lang.reflect.Field; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class does represent a class similar to java.lang.Class. You |
|
||||||
* can get the super class and the interfaces. <br> |
|
||||||
* |
|
||||||
* The main difference to java.lang.Class is, that the objects are builded |
|
||||||
* from a stream containing the .class file, and that it uses the |
|
||||||
* <code>Type</code> to represent types instead of Class itself. <br> |
|
||||||
* |
|
||||||
* <h2>The InnerClasses attribute</h2> |
|
||||||
* |
|
||||||
* The InnerClasses attribute is transformed in a special way by this |
|
||||||
* class so we want to taker a closer look. According to the <a |
|
||||||
* href="http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html#18814">inner |
|
||||||
* class specification</a> there must be an InnerClass attribute for |
|
||||||
* every non top-level class that is referenced somewhere in the |
|
||||||
* bytecode. This implies that if this is an inner class, it must |
|
||||||
* contain a inner class attribute for itself. Before a class is |
|
||||||
* referenced as outer class in an InnerClass attribute, it must be |
|
||||||
* described by another InnerClass attribute. <br> |
|
||||||
* |
|
||||||
* Since every class references itself, there must be informations |
|
||||||
* about the outer class for each class scoped class. If that outer |
|
||||||
* class is an outer class again, there must be information about it, |
|
||||||
* too. This particular chain of InnerClassInfos is returned by the |
|
||||||
* getOuterClasses() method; for convenience in reverse order, i.e. |
|
||||||
* current class first, then the outer classes from innermost to |
|
||||||
* outermost. <br> |
|
||||||
* |
|
||||||
* A valid bytecode must also contain InnerClass infos for each inner |
|
||||||
* classes it declares. These information are returned by the |
|
||||||
* getInnerClasses() method. The order of these classes is the same |
|
||||||
* as in the bytecode attribute. |
|
||||||
* |
|
||||||
* All remaining attributes are returned by getExtraClasses() in the |
|
||||||
* same order as in the bytecode attribute. |
|
||||||
* |
|
||||||
* @author Jochen Hoenicke |
|
||||||
*/ |
|
||||||
public class ClassInfo extends BinaryInfo { |
|
||||||
|
|
||||||
private static SearchPath classpath; |
|
||||||
|
|
||||||
private static final UnifyHash classes = new UnifyHash(); |
|
||||||
|
|
||||||
private int status = 0; |
|
||||||
|
|
||||||
private boolean modified = false; |
|
||||||
|
|
||||||
private int modifiers = -1; |
|
||||||
private String name; |
|
||||||
private ClassInfo superclass; |
|
||||||
private ClassInfo[] interfaces; |
|
||||||
private FieldInfo[] fields; |
|
||||||
private MethodInfo[] methods; |
|
||||||
private InnerClassInfo[] outerClasses; |
|
||||||
private InnerClassInfo[] innerClasses; |
|
||||||
private InnerClassInfo[] extraClasses; |
|
||||||
private String sourceFile; |
|
||||||
|
|
||||||
public final static ClassInfo javaLangObject = forName("java.lang.Object"); |
|
||||||
|
|
||||||
public static void setClassPath(String path) { |
|
||||||
setClassPath(new SearchPath(path)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void setClassPath(SearchPath path) { |
|
||||||
if (classpath != path) { |
|
||||||
classpath = path; |
|
||||||
Iterator i = classes.iterator(); |
|
||||||
while (i.hasNext()) { |
|
||||||
ClassInfo ci = (ClassInfo) i.next(); |
|
||||||
ci.status = 0; |
|
||||||
ci.superclass = null; |
|
||||||
ci.fields = null; |
|
||||||
ci.interfaces = null; |
|
||||||
ci.methods = null; |
|
||||||
ci.removeAllAttributes(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean exists(String name) { |
|
||||||
return classpath.exists(name.replace('.', '/') + ".class"); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isPackage(String name) { |
|
||||||
return classpath.isDirectory(name.replace('.', '/')); |
|
||||||
} |
|
||||||
|
|
||||||
public static Enumeration getClassesAndPackages(final String packageName) { |
|
||||||
final Enumeration enum = |
|
||||||
classpath.listFiles(packageName.replace('.','/')); |
|
||||||
return new Enumeration() { |
|
||||||
public boolean hasMoreElements() { |
|
||||||
return enum.hasMoreElements(); |
|
||||||
} |
|
||||||
public Object nextElement() { |
|
||||||
String name = (String) enum.nextElement(); |
|
||||||
if (!name.endsWith(".class")) |
|
||||||
// This is a package
|
|
||||||
return name; |
|
||||||
return name.substring(0, name.length()-6); |
|
||||||
|
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
public static ClassInfo forName(String name) { |
|
||||||
if (name == null |
|
||||||
|| name.indexOf(';') != -1 |
|
||||||
|| name.indexOf('[') != -1 |
|
||||||
|| name.indexOf('/') != -1) |
|
||||||
throw new IllegalArgumentException("Illegal class name: "+name); |
|
||||||
|
|
||||||
int hash = name.hashCode(); |
|
||||||
Iterator iter = classes.iterateHashCode(hash); |
|
||||||
while (iter.hasNext()) { |
|
||||||
ClassInfo clazz = (ClassInfo) iter.next(); |
|
||||||
if (clazz.name.equals(name)) |
|
||||||
return clazz; |
|
||||||
} |
|
||||||
ClassInfo clazz = new ClassInfo(name); |
|
||||||
classes.put(hash, clazz); |
|
||||||
return clazz; |
|
||||||
} |
|
||||||
|
|
||||||
private ClassInfo(String name) { |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
|
|
||||||
protected void readAttribute(String name, int length, |
|
||||||
ConstantPool cp, |
|
||||||
DataInputStream input, |
|
||||||
int howMuch) throws IOException { |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("SourceFile")) { |
|
||||||
if (length != 2) |
|
||||||
throw new ClassFormatException("SourceFile attribute" |
|
||||||
+ " has wrong length"); |
|
||||||
sourceFile = cp.getUTF8(input.readUnsignedShort()); |
|
||||||
} else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0 |
|
||||||
&& name.equals("InnerClasses")) { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
if (length != 2 + 8 * count) |
|
||||||
throw new ClassFormatException |
|
||||||
("InnerClasses attribute has wrong length"); |
|
||||||
int innerCount = 0, outerCount = 0, extraCount = 0; |
|
||||||
InnerClassInfo[] innerClassInfo = new InnerClassInfo[count]; |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
int innerIndex = input.readUnsignedShort(); |
|
||||||
int outerIndex = input.readUnsignedShort(); |
|
||||||
int nameIndex = input.readUnsignedShort(); |
|
||||||
String inner = cp.getClassName(innerIndex); |
|
||||||
String outer = |
|
||||||
outerIndex != 0 ? cp.getClassName(outerIndex) : null; |
|
||||||
String innername = |
|
||||||
nameIndex != 0 ? cp.getUTF8(nameIndex) : null; |
|
||||||
int access = input.readUnsignedShort(); |
|
||||||
if (innername != null && innername.length() == 0) |
|
||||||
innername = null; |
|
||||||
InnerClassInfo ici = new InnerClassInfo |
|
||||||
(inner, outer, innername, access); |
|
||||||
|
|
||||||
if (outer != null && outer.equals(getName()) |
|
||||||
&& innername != null) |
|
||||||
innerClassInfo[innerCount++] = ici; |
|
||||||
else |
|
||||||
innerClassInfo[count - (++extraCount)] = ici; |
|
||||||
} |
|
||||||
/* Now innerClasses are at the front of innerClassInfo array |
|
||||||
* in correct order. The other InnerClassInfos are in reverse |
|
||||||
* order in the rest of the innerClassInfo array. |
|
||||||
*/ |
|
||||||
|
|
||||||
/* We now count the outerClasses. The reverse order is the |
|
||||||
* right thing for us. |
|
||||||
*/ |
|
||||||
{ |
|
||||||
String lastOuterName = getName(); |
|
||||||
for (int i = count - extraCount; |
|
||||||
i < count && lastOuterName != null; i++) { |
|
||||||
InnerClassInfo ici = innerClassInfo[i]; |
|
||||||
if (ici.inner.equals(lastOuterName)) { |
|
||||||
outerCount++; |
|
||||||
extraCount--; |
|
||||||
lastOuterName = ici.outer; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if (innerCount > 0) { |
|
||||||
innerClasses = new InnerClassInfo[innerCount]; |
|
||||||
System.arraycopy(innerClassInfo, 0, |
|
||||||
innerClasses, 0, innerCount); |
|
||||||
} else |
|
||||||
innerClasses = null; |
|
||||||
|
|
||||||
if (outerCount > 0) { |
|
||||||
outerClasses = new InnerClassInfo[outerCount]; |
|
||||||
} else |
|
||||||
outerClasses = null; |
|
||||||
|
|
||||||
if (extraCount > 0) { |
|
||||||
extraClasses = new InnerClassInfo[extraCount]; |
|
||||||
} else |
|
||||||
extraClasses = null; |
|
||||||
|
|
||||||
/* The last part: We split between outer and extra classes. |
|
||||||
* In this step we will also revert the order of the extra |
|
||||||
* classes. |
|
||||||
*/ |
|
||||||
{ |
|
||||||
int outerPtr = 0; |
|
||||||
String lastOuterName = getName(); |
|
||||||
for (int i = count - extraCount - outerCount; |
|
||||||
i < count; i++) { |
|
||||||
InnerClassInfo ici = innerClassInfo[i]; |
|
||||||
|
|
||||||
/* If we counted correctly there is no NullPointer |
|
||||||
* or ArrayIndexOutOfBoundsException here |
|
||||||
*/ |
|
||||||
if (ici.inner.equals(lastOuterName)) { |
|
||||||
outerClasses[outerPtr++] = ici; |
|
||||||
lastOuterName = ici.outer; |
|
||||||
} else |
|
||||||
extraClasses[--extraCount] = ici; |
|
||||||
} |
|
||||||
} |
|
||||||
} else |
|
||||||
super.readAttribute(name, length, cp, input, howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public void read(DataInputStream input, int howMuch) throws IOException { |
|
||||||
/* Since we have to read the whole class anyway, we load all |
|
||||||
* info, that we may need later and that does not take much memory. |
|
||||||
*/ |
|
||||||
howMuch |= HIERARCHY | INNERCLASSES | OUTERCLASSES; |
|
||||||
howMuch &= ~status; |
|
||||||
/* header */ |
|
||||||
if (input.readInt() != 0xcafebabe) |
|
||||||
throw new ClassFormatException("Wrong magic"); |
|
||||||
if (input.readUnsignedShort() > 3) |
|
||||||
throw new ClassFormatException("Wrong minor"); |
|
||||||
if (input.readUnsignedShort() != 45) |
|
||||||
throw new ClassFormatException("Wrong major"); |
|
||||||
|
|
||||||
/* constant pool */ |
|
||||||
ConstantPool cpool = new ConstantPool(); |
|
||||||
cpool.read(input); |
|
||||||
|
|
||||||
/* always read modifiers, name, super, ifaces */ |
|
||||||
{ |
|
||||||
modifiers = input.readUnsignedShort(); |
|
||||||
String className = cpool.getClassName(input.readUnsignedShort()); |
|
||||||
if (!name.equals(className)) |
|
||||||
throw new ClassFormatException("wrong name " + className); |
|
||||||
String superName = cpool.getClassName(input.readUnsignedShort()); |
|
||||||
superclass = superName != null ? ClassInfo.forName(superName) : null; |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
interfaces = new ClassInfo[count]; |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
interfaces[i] = ClassInfo.forName |
|
||||||
(cpool.getClassName(input.readUnsignedShort())); |
|
||||||
} |
|
||||||
status |= HIERARCHY; |
|
||||||
} |
|
||||||
|
|
||||||
/* fields */ |
|
||||||
if ((howMuch & (FIELDS | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
if ((status & FIELDS) == 0) |
|
||||||
fields = new FieldInfo[count]; |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
if ((status & FIELDS) == 0) |
|
||||||
fields[i] = new FieldInfo(this); |
|
||||||
fields[i].read(cpool, input, howMuch); |
|
||||||
} |
|
||||||
} else { |
|
||||||
byte[] skipBuf = new byte[6]; |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
input.readFully(skipBuf); // modifier, name, type
|
|
||||||
skipAttributes(input); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* methods */ |
|
||||||
if ((howMuch & (METHODS | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
if ((status & METHODS) == 0) |
|
||||||
methods = new MethodInfo[count]; |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
if ((status & METHODS) == 0) |
|
||||||
methods[i] = new MethodInfo(this); |
|
||||||
methods[i].read(cpool, input, howMuch); |
|
||||||
} |
|
||||||
} else { |
|
||||||
byte[] skipBuf = new byte[6]; |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
for (int i=0; i< count; i++) { |
|
||||||
input.readFully(skipBuf); // modifier, name, type
|
|
||||||
skipAttributes(input); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* attributes */ |
|
||||||
readAttributes(cpool, input, howMuch); |
|
||||||
status |= howMuch; |
|
||||||
} |
|
||||||
|
|
||||||
public void reserveSmallConstants(GrowableConstantPool gcp) { |
|
||||||
for (int i=0; i < fields.length; i++) |
|
||||||
fields[i].reserveSmallConstants(gcp); |
|
||||||
|
|
||||||
for (int i=0; i < methods.length; i++) |
|
||||||
methods[i].reserveSmallConstants(gcp); |
|
||||||
} |
|
||||||
|
|
||||||
public void prepareWriting(GrowableConstantPool gcp) { |
|
||||||
gcp.putClassName(name); |
|
||||||
gcp.putClassName(superclass.getName()); |
|
||||||
for (int i=0; i < interfaces.length; i++) |
|
||||||
gcp.putClassName(interfaces[i].getName()); |
|
||||||
|
|
||||||
for (int i=0; i < fields.length; i++) |
|
||||||
fields[i].prepareWriting(gcp); |
|
||||||
|
|
||||||
for (int i=0; i < methods.length; i++) |
|
||||||
methods[i].prepareWriting(gcp); |
|
||||||
|
|
||||||
if (sourceFile != null) { |
|
||||||
gcp.putUTF8("SourceFile"); |
|
||||||
gcp.putUTF8(sourceFile); |
|
||||||
} |
|
||||||
if (outerClasses != null || innerClasses != null |
|
||||||
|| extraClasses != null) { |
|
||||||
gcp.putUTF8("InnerClasses"); |
|
||||||
int outerCount = outerClasses != null ? outerClasses.length : 0; |
|
||||||
for (int i=outerCount; i-- > 0;) { |
|
||||||
gcp.putClassName(outerClasses[i].inner); |
|
||||||
if (outerClasses[i].outer != null) |
|
||||||
gcp.putClassName(outerClasses[i].outer); |
|
||||||
if (outerClasses[i].name != null) |
|
||||||
gcp.putUTF8(outerClasses[i].name); |
|
||||||
} |
|
||||||
int innerCount = innerClasses != null ? innerClasses.length : 0; |
|
||||||
for (int i=0; i< innerCount; i++) { |
|
||||||
gcp.putClassName(innerClasses[i].inner); |
|
||||||
if (innerClasses[i].outer != null) |
|
||||||
gcp.putClassName(innerClasses[i].outer); |
|
||||||
if (innerClasses[i].name != null) |
|
||||||
gcp.putUTF8(innerClasses[i].name); |
|
||||||
} |
|
||||||
int extraCount = extraClasses != null ? extraClasses.length : 0; |
|
||||||
for (int i=0; i< extraCount; i++) { |
|
||||||
gcp.putClassName(extraClasses[i].inner); |
|
||||||
if (extraClasses[i].outer != null) |
|
||||||
gcp.putClassName(extraClasses[i].outer); |
|
||||||
if (extraClasses[i].name != null) |
|
||||||
gcp.putUTF8(extraClasses[i].name); |
|
||||||
} |
|
||||||
} |
|
||||||
prepareAttributes(gcp); |
|
||||||
} |
|
||||||
|
|
||||||
protected int getKnownAttributeCount() { |
|
||||||
int count = 0; |
|
||||||
if (sourceFile != null) |
|
||||||
count++; |
|
||||||
if (innerClasses != null || outerClasses != null |
|
||||||
|| extraClasses != null) |
|
||||||
count++; |
|
||||||
return count; |
|
||||||
} |
|
||||||
|
|
||||||
public void writeKnownAttributes(GrowableConstantPool gcp, |
|
||||||
DataOutputStream output) |
|
||||||
throws IOException { |
|
||||||
if (sourceFile != null) { |
|
||||||
output.writeShort(gcp.putUTF8("SourceFile")); |
|
||||||
output.writeInt(2); |
|
||||||
output.writeShort(gcp.putUTF8(sourceFile)); |
|
||||||
} |
|
||||||
if (outerClasses != null || innerClasses != null |
|
||||||
|| extraClasses != null) { |
|
||||||
output.writeShort(gcp.putUTF8("InnerClasses")); |
|
||||||
int outerCount = (outerClasses != null) ? outerClasses.length : 0; |
|
||||||
int innerCount = (innerClasses != null) ? innerClasses.length : 0; |
|
||||||
int extraCount = (extraClasses != null) ? extraClasses.length : 0; |
|
||||||
int count = outerCount + innerCount + extraCount; |
|
||||||
output.writeInt(2 + count * 8); |
|
||||||
output.writeShort(count); |
|
||||||
for (int i=outerCount; i-- > 0; ) { |
|
||||||
output.writeShort(gcp.putClassName(outerClasses[i].inner)); |
|
||||||
output.writeShort(outerClasses[i].outer != null ? |
|
||||||
gcp.putClassName(outerClasses[i].outer) : 0); |
|
||||||
output.writeShort(outerClasses[i].name != null ? |
|
||||||
gcp.putUTF8(outerClasses[i].name) : 0); |
|
||||||
output.writeShort(outerClasses[i].modifiers); |
|
||||||
} |
|
||||||
for (int i=0; i< innerCount; i++) { |
|
||||||
output.writeShort(gcp.putClassName(innerClasses[i].inner)); |
|
||||||
output.writeShort(innerClasses[i].outer != null ? |
|
||||||
gcp.putClassName(innerClasses[i].outer) : 0); |
|
||||||
output.writeShort(innerClasses[i].name != null ? |
|
||||||
gcp.putUTF8(innerClasses[i].name) : 0); |
|
||||||
output.writeShort(innerClasses[i].modifiers); |
|
||||||
} |
|
||||||
for (int i=0; i< extraCount; i++) { |
|
||||||
output.writeShort(gcp.putClassName(extraClasses[i].inner)); |
|
||||||
output.writeShort(extraClasses[i].outer != null ? |
|
||||||
gcp.putClassName(extraClasses[i].outer) : 0); |
|
||||||
output.writeShort(extraClasses[i].name != null ? |
|
||||||
gcp.putUTF8(extraClasses[i].name) : 0); |
|
||||||
output.writeShort(extraClasses[i].modifiers); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void write(DataOutputStream out) throws IOException { |
|
||||||
GrowableConstantPool gcp = new GrowableConstantPool(); |
|
||||||
reserveSmallConstants(gcp); |
|
||||||
prepareWriting(gcp); |
|
||||||
|
|
||||||
out.writeInt(0xcafebabe); |
|
||||||
out.writeShort(3); |
|
||||||
out.writeShort(45); |
|
||||||
gcp.write(out); |
|
||||||
|
|
||||||
out.writeShort(modifiers); |
|
||||||
out.writeShort(gcp.putClassName(name)); |
|
||||||
out.writeShort(gcp.putClassName(superclass.getName())); |
|
||||||
out.writeShort(interfaces.length); |
|
||||||
for (int i=0; i < interfaces.length; i++) |
|
||||||
out.writeShort(gcp.putClassName(interfaces[i].getName())); |
|
||||||
|
|
||||||
out.writeShort(fields.length); |
|
||||||
for (int i=0; i < fields.length; i++) |
|
||||||
fields[i].write(gcp, out); |
|
||||||
|
|
||||||
out.writeShort(methods.length); |
|
||||||
for (int i=0; i < methods.length; i++) |
|
||||||
methods[i].write(gcp, out); |
|
||||||
|
|
||||||
writeAttributes(gcp, out); |
|
||||||
} |
|
||||||
|
|
||||||
public void loadInfoReflection(Class clazz, int howMuch) |
|
||||||
throws SecurityException { |
|
||||||
if ((howMuch & HIERARCHY) != 0) { |
|
||||||
modifiers = clazz.getModifiers(); |
|
||||||
if (clazz.getSuperclass() == null) |
|
||||||
superclass = clazz == Object.class ? null : javaLangObject; |
|
||||||
else |
|
||||||
superclass = ClassInfo.forName |
|
||||||
(clazz.getSuperclass().getName()); |
|
||||||
Class[] ifaces = clazz.getInterfaces(); |
|
||||||
interfaces = new ClassInfo[ifaces.length]; |
|
||||||
for (int i=0; i<ifaces.length; i++) |
|
||||||
interfaces[i] = ClassInfo.forName(ifaces[i].getName()); |
|
||||||
status |= HIERARCHY; |
|
||||||
} |
|
||||||
if ((howMuch & FIELDS) != 0 && fields == null) { |
|
||||||
Field[] fs; |
|
||||||
try { |
|
||||||
fs = clazz.getDeclaredFields(); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
fs = clazz.getFields(); |
|
||||||
GlobalOptions.err.println |
|
||||||
("Could only get public fields of class " |
|
||||||
+ name + "."); |
|
||||||
} |
|
||||||
fields = new FieldInfo[fs.length]; |
|
||||||
for (int i = fs.length; --i >= 0; ) { |
|
||||||
String type = TypeSignature.getSignature(fs[i].getType()); |
|
||||||
fields[i] = new FieldInfo |
|
||||||
(this, fs[i].getName(), type, fs[i].getModifiers()); |
|
||||||
} |
|
||||||
} |
|
||||||
if ((howMuch & METHODS) != 0 && methods == null) { |
|
||||||
Constructor[] cs; |
|
||||||
Method[] ms; |
|
||||||
try { |
|
||||||
cs = clazz.getDeclaredConstructors(); |
|
||||||
ms = clazz.getDeclaredMethods(); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
cs = clazz.getConstructors(); |
|
||||||
ms = clazz.getMethods(); |
|
||||||
GlobalOptions.err.println |
|
||||||
("Could only get public methods of class " |
|
||||||
+ name + "."); |
|
||||||
} |
|
||||||
methods = new MethodInfo[cs.length + ms.length]; |
|
||||||
for (int i = cs.length; --i >= 0; ) { |
|
||||||
String type = TypeSignature.getSignature |
|
||||||
(cs[i].getParameterTypes(), void.class); |
|
||||||
methods[i] = new MethodInfo |
|
||||||
(this, "<init>", type, cs[i].getModifiers()); |
|
||||||
} |
|
||||||
for (int i = ms.length; --i >= 0; ) { |
|
||||||
String type = TypeSignature.getSignature |
|
||||||
(ms[i].getParameterTypes(), ms[i].getReturnType()); |
|
||||||
methods[cs.length+i] = new MethodInfo |
|
||||||
(this, ms[i].getName(), type, ms[i].getModifiers()); |
|
||||||
} |
|
||||||
} |
|
||||||
if ((howMuch & INNERCLASSES) != 0 && innerClasses == null) { |
|
||||||
Class[] is; |
|
||||||
try { |
|
||||||
is = clazz.getDeclaredClasses(); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
is = clazz.getClasses(); |
|
||||||
GlobalOptions.err.println |
|
||||||
("Could only get public inner classes of class " |
|
||||||
+ name + "."); |
|
||||||
} |
|
||||||
if (is.length > 0) { |
|
||||||
innerClasses = new InnerClassInfo[is.length]; |
|
||||||
for (int i = is.length; --i >= 0; ) { |
|
||||||
String inner = is[i].getName(); |
|
||||||
int dollar = inner.lastIndexOf('$'); |
|
||||||
String name = inner.substring(dollar+1); |
|
||||||
innerClasses[i] = new InnerClassInfo |
|
||||||
(inner, getName(), name, is[i].getModifiers()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if ((howMuch & OUTERCLASSES) != 0 && outerClasses == null) { |
|
||||||
int count = 0; |
|
||||||
Class declarer = clazz.getDeclaringClass(); |
|
||||||
while (declarer != null) { |
|
||||||
count++; |
|
||||||
declarer = declarer.getDeclaringClass(); |
|
||||||
} |
|
||||||
if (count > 0) { |
|
||||||
outerClasses = new InnerClassInfo[count]; |
|
||||||
Class current = clazz; |
|
||||||
for (int i = 0; i < count; i++) { |
|
||||||
declarer = current.getDeclaringClass(); |
|
||||||
String name = current.getName(); |
|
||||||
int dollar = name.lastIndexOf('$'); |
|
||||||
outerClasses[i] = new InnerClassInfo |
|
||||||
(name, declarer.getName(), |
|
||||||
name.substring(dollar+1), current.getModifiers()); |
|
||||||
current = declarer; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
status |= howMuch; |
|
||||||
} |
|
||||||
|
|
||||||
public void loadInfo(int howMuch) { |
|
||||||
if ((status & howMuch) == howMuch) |
|
||||||
return; |
|
||||||
if (modified) { |
|
||||||
System.err.println("Allocating info 0x" |
|
||||||
+ Integer.toHexString(howMuch) |
|
||||||
+ " (status 0x" + Integer.toHexString(status) |
|
||||||
+ ") in class " + this); |
|
||||||
Thread.dumpStack(); |
|
||||||
return; |
|
||||||
} |
|
||||||
try { |
|
||||||
DataInputStream input = new DataInputStream |
|
||||||
(new BufferedInputStream |
|
||||||
(classpath.getFile(name.replace('.', '/') + ".class"))); |
|
||||||
read(input, howMuch); |
|
||||||
|
|
||||||
} catch (IOException ex) { |
|
||||||
String message = ex.getMessage(); |
|
||||||
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY |
|
||||||
|INNERCLASSES|OUTERCLASSES)) != 0) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("Can't read class " + name + "."); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
throw new NoClassDefFoundError(name); |
|
||||||
} |
|
||||||
// Try getting the info through the reflection interface
|
|
||||||
// instead.
|
|
||||||
Class clazz = null; |
|
||||||
try { |
|
||||||
clazz = Class.forName(name); |
|
||||||
} catch (ClassNotFoundException ex2) { |
|
||||||
} catch (NoClassDefFoundError ex2) { |
|
||||||
} |
|
||||||
try { |
|
||||||
if (clazz != null) { |
|
||||||
loadInfoReflection(clazz, howMuch); |
|
||||||
return; |
|
||||||
} |
|
||||||
} catch (SecurityException ex2) { |
|
||||||
GlobalOptions.err.println |
|
||||||
(ex2+" while collecting info about class " + name + "."); |
|
||||||
} |
|
||||||
|
|
||||||
// Give a warning and ``guess'' the hierarchie, methods etc.
|
|
||||||
GlobalOptions.err.println |
|
||||||
("Can't read class " + name + ", types may be incorrect. (" |
|
||||||
+ ex.getClass().getName() |
|
||||||
+ (message != null ? ": " + message : "") + ")"); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
|
|
||||||
if ((howMuch & HIERARCHY) != 0) { |
|
||||||
modifiers = Modifier.PUBLIC; |
|
||||||
if (name.equals("java.lang.Object")) |
|
||||||
superclass = null; |
|
||||||
else |
|
||||||
superclass = javaLangObject; |
|
||||||
interfaces = new ClassInfo[0]; |
|
||||||
} |
|
||||||
if ((howMuch & METHODS) != 0) |
|
||||||
methods = new MethodInfo[0]; |
|
||||||
if ((howMuch & FIELDS) != 0) |
|
||||||
fields = new FieldInfo[0]; |
|
||||||
status |= howMuch; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This is the counter part to loadInfo. It will drop all info specified |
|
||||||
* in howMuch and clean up the memory. |
|
||||||
* @param howMuch tells how much info we should drop |
|
||||||
*/ |
|
||||||
public void dropInfo(int howMuch) { |
|
||||||
if ((status & howMuch) == 0) |
|
||||||
return; |
|
||||||
if (modified) { |
|
||||||
System.err.println("Dropping info 0x" |
|
||||||
+ Integer.toHexString(howMuch) |
|
||||||
+ " (status 0x" + Integer.toHexString(status) |
|
||||||
+ ") in class " + this); |
|
||||||
Thread.dumpStack(); |
|
||||||
return; |
|
||||||
} |
|
||||||
howMuch &= status; |
|
||||||
|
|
||||||
if ((howMuch & FIELDS) != 0) { |
|
||||||
fields = null; |
|
||||||
} else if ((status & FIELDS) != 0 |
|
||||||
&& (howMuch & (KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) { |
|
||||||
for (int i=0; i < fields.length; i++) |
|
||||||
fields[i].dropInfo(howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
if ((howMuch & METHODS) != 0) { |
|
||||||
methods = null; |
|
||||||
} else if ((status & METHODS) != 0 |
|
||||||
&& (howMuch & (KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) { |
|
||||||
for (int i=0; i < methods.length; i++) |
|
||||||
methods[i].dropInfo(howMuch); |
|
||||||
} |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0) |
|
||||||
sourceFile = null; |
|
||||||
if ((howMuch & OUTERCLASSES) != 0) |
|
||||||
outerClasses = null; |
|
||||||
if ((howMuch & INNERCLASSES) != 0) { |
|
||||||
innerClasses = null; |
|
||||||
extraClasses = null; |
|
||||||
} |
|
||||||
super.dropInfo(howMuch); |
|
||||||
status &= ~howMuch; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getJavaName() { |
|
||||||
/* Don't load attributes for class names not containing a |
|
||||||
* dollar sign. |
|
||||||
*/ |
|
||||||
if (name.indexOf('$') == -1) |
|
||||||
return getName(); |
|
||||||
if (getOuterClasses() != null) { |
|
||||||
int last = outerClasses.length-1; |
|
||||||
StringBuffer sb = |
|
||||||
new StringBuffer(outerClasses[last].outer != null |
|
||||||
? outerClasses[last].outer : "METHOD"); |
|
||||||
for (int i=last; i >= 0; i--) |
|
||||||
sb.append(".").append(outerClasses[i].name != null |
|
||||||
? outerClasses[i].name : "ANONYMOUS"); |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
return getName(); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInfo getSuperclass() { |
|
||||||
if ((status & HIERARCHY) == 0) |
|
||||||
loadInfo(HIERARCHY); |
|
||||||
return superclass; |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInfo[] getInterfaces() { |
|
||||||
if ((status & HIERARCHY) == 0) |
|
||||||
loadInfo(HIERARCHY); |
|
||||||
return interfaces; |
|
||||||
} |
|
||||||
|
|
||||||
public int getModifiers() { |
|
||||||
if ((status & HIERARCHY) == 0) |
|
||||||
loadInfo(HIERARCHY); |
|
||||||
return modifiers; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isInterface() { |
|
||||||
return Modifier.isInterface(getModifiers()); |
|
||||||
} |
|
||||||
|
|
||||||
public FieldInfo findField(String name, String typeSig) { |
|
||||||
if ((status & FIELDS) == 0) |
|
||||||
loadInfo(FIELDS); |
|
||||||
for (int i=0; i< fields.length; i++) |
|
||||||
if (fields[i].getName().equals(name) |
|
||||||
&& fields[i].getType().equals(typeSig)) |
|
||||||
return fields[i]; |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public MethodInfo findMethod(String name, String typeSig) { |
|
||||||
if ((status & METHODS) == 0) |
|
||||||
loadInfo(METHODS); |
|
||||||
for (int i=0; i< methods.length; i++) |
|
||||||
if (methods[i].getName().equals(name) |
|
||||||
&& methods[i].getType().equals(typeSig)) |
|
||||||
return methods[i]; |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public MethodInfo[] getMethods() { |
|
||||||
if ((status & METHODS) == 0) |
|
||||||
loadInfo(METHODS); |
|
||||||
return methods; |
|
||||||
} |
|
||||||
|
|
||||||
public FieldInfo[] getFields() { |
|
||||||
if ((status & FIELDS) == 0) |
|
||||||
loadInfo(FIELDS); |
|
||||||
return fields; |
|
||||||
} |
|
||||||
|
|
||||||
public InnerClassInfo[] getOuterClasses() { |
|
||||||
if ((status & OUTERCLASSES) == 0) |
|
||||||
loadInfo(OUTERCLASSES); |
|
||||||
return outerClasses; |
|
||||||
} |
|
||||||
|
|
||||||
public InnerClassInfo[] getInnerClasses() { |
|
||||||
if ((status & INNERCLASSES) == 0) |
|
||||||
loadInfo(INNERCLASSES); |
|
||||||
return innerClasses; |
|
||||||
} |
|
||||||
|
|
||||||
public InnerClassInfo[] getExtraClasses() { |
|
||||||
if ((status & INNERCLASSES) == 0) |
|
||||||
loadInfo(INNERCLASSES); |
|
||||||
return extraClasses; |
|
||||||
} |
|
||||||
|
|
||||||
public String getSourceFile() { |
|
||||||
return sourceFile; |
|
||||||
} |
|
||||||
|
|
||||||
public void setName(String newName) { |
|
||||||
name = newName; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSuperclass(ClassInfo newSuper) { |
|
||||||
superclass = newSuper; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setInterfaces(ClassInfo[] newIfaces) { |
|
||||||
interfaces = newIfaces; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setModifiers(int newModifiers) { |
|
||||||
modifiers = newModifiers; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setMethods(MethodInfo[] mi) { |
|
||||||
methods = mi; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFields(FieldInfo[] fi) { |
|
||||||
fields = fi; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setOuterClasses(InnerClassInfo[] oc) { |
|
||||||
outerClasses = oc; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setInnerClasses(InnerClassInfo[] ic) { |
|
||||||
innerClasses = ic; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setExtraClasses(InnerClassInfo[] ec) { |
|
||||||
extraClasses = ec; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSourceFile(String newSource) { |
|
||||||
sourceFile = newSource; |
|
||||||
modified = true; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean superClassOf(ClassInfo son) { |
|
||||||
while (son != this && son != null) { |
|
||||||
son = son.getSuperclass(); |
|
||||||
} |
|
||||||
return son == this; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean implementedBy(ClassInfo clazz) { |
|
||||||
while (clazz != this && clazz != null) { |
|
||||||
ClassInfo[] ifaces = clazz.getInterfaces(); |
|
||||||
for (int i=0; i< ifaces.length; i++) { |
|
||||||
if (implementedBy(ifaces[i])) |
|
||||||
return true; |
|
||||||
} |
|
||||||
clazz = clazz.getSuperclass(); |
|
||||||
} |
|
||||||
return clazz == this; |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
} |
|
@ -1,203 +0,0 @@ |
|||||||
/* FieldInfo Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
import java.io.DataInputStream; |
|
||||||
import java.io.DataOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
|
|
||||||
public class FieldInfo extends BinaryInfo { |
|
||||||
ClassInfo clazzInfo; |
|
||||||
|
|
||||||
int modifier; |
|
||||||
String name; |
|
||||||
String typeSig; |
|
||||||
|
|
||||||
Object constant; |
|
||||||
boolean syntheticFlag; |
|
||||||
boolean deprecatedFlag; |
|
||||||
|
|
||||||
public FieldInfo(ClassInfo ci) { |
|
||||||
this.clazzInfo = ci; |
|
||||||
} |
|
||||||
|
|
||||||
public FieldInfo(ClassInfo ci, String name, String typeSig, int modifier) { |
|
||||||
this.clazzInfo = ci; |
|
||||||
this.name = name; |
|
||||||
this.typeSig = typeSig; |
|
||||||
this.modifier = modifier; |
|
||||||
} |
|
||||||
|
|
||||||
protected void readAttribute(String name, int length, |
|
||||||
ConstantPool cp, |
|
||||||
DataInputStream input, |
|
||||||
int howMuch) throws IOException { |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("ConstantValue")) { |
|
||||||
if (length != 2) |
|
||||||
throw new ClassFormatException("ConstantValue attribute" |
|
||||||
+ " has wrong length"); |
|
||||||
int index = input.readUnsignedShort(); |
|
||||||
constant = cp.getConstant(index); |
|
||||||
} else if (name.equals("Synthetic")) { |
|
||||||
syntheticFlag = true; |
|
||||||
if (length != 0) |
|
||||||
throw new ClassFormatException |
|
||||||
("Synthetic attribute has wrong length"); |
|
||||||
} else if (name.equals("Deprecated")) { |
|
||||||
deprecatedFlag = true; |
|
||||||
if (length != 0) |
|
||||||
throw new ClassFormatException |
|
||||||
("Deprecated attribute has wrong length"); |
|
||||||
} else |
|
||||||
super.readAttribute(name, length, cp, input, howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public void read(ConstantPool constantPool, |
|
||||||
DataInputStream input, int howMuch) throws IOException { |
|
||||||
modifier = input.readUnsignedShort(); |
|
||||||
name = constantPool.getUTF8(input.readUnsignedShort()); |
|
||||||
typeSig = constantPool.getUTF8(input.readUnsignedShort()); |
|
||||||
readAttributes(constantPool, input, howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public void reserveSmallConstants(GrowableConstantPool gcp) { |
|
||||||
} |
|
||||||
|
|
||||||
public void prepareWriting(GrowableConstantPool gcp) { |
|
||||||
gcp.putUTF8(name); |
|
||||||
gcp.putUTF8(typeSig); |
|
||||||
if (constant != null) { |
|
||||||
gcp.putUTF8("ConstantValue"); |
|
||||||
if (typeSig.charAt(0) == 'J' || typeSig.charAt(0) == 'D') |
|
||||||
gcp.putLongConstant(constant); |
|
||||||
else |
|
||||||
gcp.putConstant(constant); |
|
||||||
} |
|
||||||
if (syntheticFlag) |
|
||||||
gcp.putUTF8("Synthetic"); |
|
||||||
if (deprecatedFlag) |
|
||||||
gcp.putUTF8("Deprecated"); |
|
||||||
prepareAttributes(gcp); |
|
||||||
} |
|
||||||
|
|
||||||
protected int getKnownAttributeCount() { |
|
||||||
int count = 0; |
|
||||||
if (constant != null) |
|
||||||
count++; |
|
||||||
if (syntheticFlag) |
|
||||||
count++; |
|
||||||
if (deprecatedFlag) |
|
||||||
count++; |
|
||||||
return count; |
|
||||||
} |
|
||||||
|
|
||||||
public void writeKnownAttributes(GrowableConstantPool gcp, |
|
||||||
DataOutputStream output) |
|
||||||
throws IOException { |
|
||||||
if (constant != null) { |
|
||||||
output.writeShort(gcp.putUTF8("ConstantValue")); |
|
||||||
output.writeInt(2); |
|
||||||
int index; |
|
||||||
if (typeSig.charAt(0) == 'J' |
|
||||||
|| typeSig.charAt(0) == 'D') |
|
||||||
index = gcp.putLongConstant(constant); |
|
||||||
else |
|
||||||
index = gcp.putConstant(constant); |
|
||||||
output.writeShort(index); |
|
||||||
} |
|
||||||
if (syntheticFlag) { |
|
||||||
output.writeShort(gcp.putUTF8("Synthetic")); |
|
||||||
output.writeInt(0); |
|
||||||
} |
|
||||||
if (deprecatedFlag) { |
|
||||||
output.writeShort(gcp.putUTF8("Deprecated")); |
|
||||||
output.writeInt(0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void write(GrowableConstantPool constantPool, |
|
||||||
DataOutputStream output) throws IOException { |
|
||||||
output.writeShort(modifier); |
|
||||||
output.writeShort(constantPool.putUTF8(name)); |
|
||||||
output.writeShort(constantPool.putUTF8(typeSig)); |
|
||||||
writeAttributes(constantPool, output); |
|
||||||
} |
|
||||||
|
|
||||||
public void dropInfo(int howMuch) { |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0) |
|
||||||
constant = null; |
|
||||||
super.dropInfo(howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getType() { |
|
||||||
return typeSig; |
|
||||||
} |
|
||||||
|
|
||||||
public int getModifiers() { |
|
||||||
return modifier; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSynthetic() { |
|
||||||
return syntheticFlag; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isDeprecated() { |
|
||||||
return deprecatedFlag; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getConstant() { |
|
||||||
clazzInfo.loadInfo(KNOWNATTRIBS); |
|
||||||
return constant; |
|
||||||
} |
|
||||||
|
|
||||||
public void setName(String newName) { |
|
||||||
name = newName; |
|
||||||
} |
|
||||||
|
|
||||||
public void setType(String newType) { |
|
||||||
typeSig = newType; |
|
||||||
} |
|
||||||
|
|
||||||
public void setModifiers(int newModifier) { |
|
||||||
modifier = newModifier; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSynthetic(boolean flag) { |
|
||||||
syntheticFlag = flag; |
|
||||||
} |
|
||||||
|
|
||||||
public void setDeprecated(boolean flag) { |
|
||||||
deprecatedFlag = flag; |
|
||||||
} |
|
||||||
|
|
||||||
public void setConstant(Object newConstant) { |
|
||||||
constant = newConstant; |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() { |
|
||||||
return "Field "+Modifier.toString(modifier)+" "+ |
|
||||||
typeSig+" "+name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,29 +0,0 @@ |
|||||||
/* Handler Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple class containing the info about an exception handler |
|
||||||
*/ |
|
||||||
public class Handler { |
|
||||||
public Instruction start, end, catcher; |
|
||||||
public String type; |
|
||||||
} |
|
||||||
|
|
@ -1,42 +0,0 @@ |
|||||||
/* InnerClassInfo Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple class containing the info about an inner class. |
|
||||||
*/ |
|
||||||
public class InnerClassInfo { |
|
||||||
public String inner, outer; |
|
||||||
public String name; |
|
||||||
public int modifiers; |
|
||||||
|
|
||||||
public InnerClassInfo(String inner, String outer, String name, int modif) { |
|
||||||
this.inner = inner; |
|
||||||
this.outer = outer; |
|
||||||
this.name = name; |
|
||||||
this.modifiers = modif; |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() { |
|
||||||
return "InnerClassInfo["+inner+","+outer+","+name+"," |
|
||||||
+java.lang.reflect.Modifier.toString(modifiers)+"]"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,830 +0,0 @@ |
|||||||
/* Instruction Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class represents an instruction in the byte code. |
|
||||||
* |
|
||||||
*/ |
|
||||||
public final class Instruction implements Opcodes{ |
|
||||||
/** |
|
||||||
* The opcode of the instruction. We map some opcodes, e.g. |
|
||||||
* <pre> |
|
||||||
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc. |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
// a byte would be enough, but then we would need an unsigned convert.
|
|
||||||
private int opcode; |
|
||||||
/** |
|
||||||
* If this opcode uses a local this gives the slot. For multianewarray |
|
||||||
* this gives the dimension. |
|
||||||
*/ |
|
||||||
private int shortData; |
|
||||||
/** |
|
||||||
* The address of this opcode. |
|
||||||
*/ |
|
||||||
private int addr; |
|
||||||
/** |
|
||||||
* Optional object data for this opcode. There are four different |
|
||||||
* usages of this field: |
|
||||||
* <dl> |
|
||||||
* <dt>opc_ldc / opc_ldc2_w</dt> |
|
||||||
* <dd>The constant of type Integer/Long/Float/Double/String. </dd> |
|
||||||
* <dt>opc_invokexxx / opc_xxxfield / opc_xxxstatic</dt> |
|
||||||
* <dd>The field/method Reference</dd> |
|
||||||
* <dt>opc_new / opc_checkcast / opc_instanceof / opc_multianewarray</dt> |
|
||||||
* <dd>The typesignature of the class/array</dd> |
|
||||||
* <dt>opc_lookupswitch</dt> |
|
||||||
* <dd>The array of values of type int[]</dd> |
|
||||||
* </dl> |
|
||||||
*/ |
|
||||||
private Object objData; |
|
||||||
/** |
|
||||||
* The successors of this opcodes, where flow may lead to |
|
||||||
* (except that nextByAddr is implicit if !alwaysJump). The |
|
||||||
* value null means no successor, if there is one succesor, this |
|
||||||
* is of type Instruction, otherwise, this is an array of Instruction. |
|
||||||
*/ |
|
||||||
private Object succs; |
|
||||||
/** |
|
||||||
* The predecessors of this opcode, orthogonal to the succs array. |
|
||||||
* This must be null or a non empty array. |
|
||||||
*/ |
|
||||||
private Instruction[] preds; |
|
||||||
/** |
|
||||||
* The next instruction in code order. |
|
||||||
*/ |
|
||||||
Instruction nextByAddr; |
|
||||||
/** |
|
||||||
* The previous instruction in code order, useful when changing |
|
||||||
* the order. |
|
||||||
*/ |
|
||||||
Instruction prevByAddr; |
|
||||||
|
|
||||||
/** |
|
||||||
* You can use this field to add some info to each instruction. |
|
||||||
* After using, you must set it to null again. |
|
||||||
* @XXX Do we really need this. Every field here can quickly take |
|
||||||
* half a megabyte! |
|
||||||
*/ |
|
||||||
private Object tmpInfo; |
|
||||||
|
|
||||||
public Instruction(int opcode) { |
|
||||||
this.opcode = opcode; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the opcode of the instruction. We map some opcodes: |
|
||||||
* <pre> |
|
||||||
* [iflda]load_x -> [iflda]load |
|
||||||
* [iflda]store_x -> [iflda]store |
|
||||||
* [ifa]const_xx, ldc_w -> ldc |
|
||||||
* [dl]const_xx -> ldc2_w |
|
||||||
* wide opcode -> opcode |
|
||||||
* tableswitch -> lookupswitch |
|
||||||
* [a]newarray -> multianewarray |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
public final int getOpcode() { |
|
||||||
return opcode; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the address of this opcode. As long as you don't remove |
|
||||||
* or insert instructions, you can be sure, that the addresses of the |
|
||||||
* opcodes are unique, and that |
|
||||||
* <pre> |
|
||||||
* instr.getAddr() + instr.getLength() == instr.getNextByAddr().getAddr() |
|
||||||
* <pre> |
|
||||||
* |
|
||||||
* If you insert/remove Instructions, you should be aware that the |
|
||||||
* above property is not guaranteed anymore. |
|
||||||
*/ |
|
||||||
public final int getAddr() { |
|
||||||
return addr; |
|
||||||
} |
|
||||||
|
|
||||||
public final int getNextAddr() { |
|
||||||
return nextByAddr.addr; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the length of this opcode. See getAddr() for some |
|
||||||
* notes. Note that the length doesn't necessarily reflect the |
|
||||||
* real length, when this bytecode is written again, since the |
|
||||||
* length of an ldc instruction depends on the number of entries |
|
||||||
* in constant pool, and the order they are allocated. |
|
||||||
*/ |
|
||||||
public final int getLength() { |
|
||||||
return getNextAddr() - addr; |
|
||||||
} |
|
||||||
|
|
||||||
final void setAddr(int addr) { |
|
||||||
this.addr = addr; |
|
||||||
} |
|
||||||
|
|
||||||
public final boolean hasLocalSlot() { |
|
||||||
return opcode == opc_iinc || opcode == opc_ret |
|
||||||
|| opcode >= opc_iload && opcode <= opc_aload |
|
||||||
|| opcode >= opc_istore && opcode <= opc_astore; |
|
||||||
} |
|
||||||
|
|
||||||
public final int getLocalSlot() |
|
||||||
/*{ require { hasLocalSlot() |
|
||||||
:: "Instruction has no slot" } }*/ |
|
||||||
{ |
|
||||||
return shortData; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setLocalSlot(int slot) |
|
||||||
/*{ require { hasLocalSlot() |
|
||||||
:: "Instruction has no slot" } }*/ |
|
||||||
{ |
|
||||||
shortData = slot; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Optional integer data for this opcode. There are various uses |
|
||||||
* for this: |
|
||||||
* <dl> |
|
||||||
* <dt>opc_iinc</dt> |
|
||||||
* <dd>The value by which the constant is increased/decreased. (short)</dd> |
|
||||||
* <dt>opc_multianewarray</dt> |
|
||||||
* <dd>The number of dimensions (1..255)</dd> |
|
||||||
* </dl> |
|
||||||
*/ |
|
||||||
public final int getIncrement() |
|
||||||
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray |
|
||||||
|| opcode == opc_tableswitch |
|
||||||
:: "Instruction has no int data" } }*/ |
|
||||||
{ |
|
||||||
/* shortData already used for local slot */ |
|
||||||
return ((Short) objData).shortValue(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Optional integer data for this opcode. There are various uses |
|
||||||
* for this: |
|
||||||
* <dl> |
|
||||||
* <dt>opc_iinc</dt> |
|
||||||
* <dd>The value by which the constant is increased/decreased. (short)</dd> |
|
||||||
* <dt>opc_multianewarray</dt> |
|
||||||
* <dd>The number of dimensions (1..255)</dd> |
|
||||||
* </dl> |
|
||||||
*/ |
|
||||||
public final void setIncrement(int incr) |
|
||||||
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray |
|
||||||
:: "Instruction has no int data" } }*/ |
|
||||||
{ |
|
||||||
/* shortData already used for local slot */ |
|
||||||
objData = new Short((short) incr); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
*/ |
|
||||||
public final int getDimensions() |
|
||||||
/*{ require { opcode == opc_multianewarray |
|
||||||
:: "Instruction has no dimensions" } }*/ |
|
||||||
{ |
|
||||||
return shortData; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
*/ |
|
||||||
public final void setDimensions(int dims) |
|
||||||
/*{ require { opcode == opc_multianewarray |
|
||||||
:: "Instruction has no dimensions" } }*/ |
|
||||||
{ |
|
||||||
shortData = dims; |
|
||||||
} |
|
||||||
|
|
||||||
public final Object getConstant() |
|
||||||
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w |
|
||||||
:: "Instruction has no constant" } }*/ |
|
||||||
{ |
|
||||||
return objData; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setConstant(Object constant) |
|
||||||
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w |
|
||||||
:: "Instruction has no constant" } }*/ |
|
||||||
{ |
|
||||||
objData = constant; |
|
||||||
} |
|
||||||
|
|
||||||
public final Reference getReference() |
|
||||||
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface |
|
||||||
:: "Instruction has no reference" } }*/ |
|
||||||
{ |
|
||||||
return (Reference) objData; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setReference(Reference ref) |
|
||||||
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface |
|
||||||
:: "Instruction has no reference" } }*/ |
|
||||||
{ |
|
||||||
objData = ref; |
|
||||||
} |
|
||||||
|
|
||||||
public final String getClazzType() |
|
||||||
/*{ require { opcode == opc_new |
|
||||||
|| opcode == opc_checkcast |
|
||||||
|| opcode == opc_instanceof |
|
||||||
|| opcode == opc_multianewarray |
|
||||||
:: "Instruction has no typesig" } }*/ |
|
||||||
{ |
|
||||||
return (String) objData; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setClazzType(String type) |
|
||||||
/*{ require { opcode == opc_new |
|
||||||
|| opcode == opc_checkcast |
|
||||||
|| opcode == opc_instanceof |
|
||||||
|| opcode == opc_multianewarray |
|
||||||
:: "Instruction has no typesig" } }*/ |
|
||||||
{ |
|
||||||
objData = type; |
|
||||||
} |
|
||||||
|
|
||||||
public final int[] getValues() |
|
||||||
/*{ require { opcode == opc_lookupswitch |
|
||||||
:: "Instruction has no values" } }*/ |
|
||||||
{ |
|
||||||
return (int[]) objData; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setValues(int[] values) |
|
||||||
/*{ require { opcode == opc_lookupswitch |
|
||||||
:: "Instruction has no values" } }*/ |
|
||||||
{ |
|
||||||
objData = values; |
|
||||||
} |
|
||||||
|
|
||||||
public final boolean doesAlwaysJump() { |
|
||||||
switch (opcode) { |
|
||||||
case opc_ret: |
|
||||||
case opc_goto: |
|
||||||
case opc_jsr: |
|
||||||
case opc_tableswitch: |
|
||||||
case opc_lookupswitch: |
|
||||||
case opc_ireturn: |
|
||||||
case opc_lreturn: |
|
||||||
case opc_freturn: |
|
||||||
case opc_dreturn: |
|
||||||
case opc_areturn: |
|
||||||
case opc_return: |
|
||||||
case opc_athrow: |
|
||||||
return true; |
|
||||||
default: |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public final Instruction[] getPreds() { |
|
||||||
return preds; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns true if this opcode has successors, other than the implicit |
|
||||||
* getNextByAddr(). |
|
||||||
*/ |
|
||||||
public boolean hasSuccs() { |
|
||||||
return succs != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the successors of this opcodes, where flow may lead to |
|
||||||
* (except that nextByAddr is implicit if !alwaysJump). The |
|
||||||
* value null means that there is no successor. |
|
||||||
*/ |
|
||||||
public final Instruction[] getSuccs() { |
|
||||||
if (succs instanceof Instruction) |
|
||||||
return new Instruction[] { (Instruction) succs }; |
|
||||||
return (Instruction[]) succs; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the single successor of this opcodes. This gives the |
|
||||||
* target of a goto, jsr, or if opcode. |
|
||||||
* @return null if there is no successor, otherwise the successor. |
|
||||||
* @exception ClassCastException if this has more than one succ. |
|
||||||
*/ |
|
||||||
public final Instruction getSingleSucc() { |
|
||||||
return (Instruction) succs; |
|
||||||
} |
|
||||||
|
|
||||||
public final Instruction getPrevByAddr() { |
|
||||||
if (prevByAddr.opcode == opc_impdep1) |
|
||||||
return null; |
|
||||||
return prevByAddr; |
|
||||||
} |
|
||||||
|
|
||||||
public final Instruction getNextByAddr() { |
|
||||||
if (nextByAddr.opcode == opc_impdep1) |
|
||||||
return null; |
|
||||||
return nextByAddr; |
|
||||||
} |
|
||||||
|
|
||||||
public final Object getTmpInfo() { |
|
||||||
return tmpInfo; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setTmpInfo(Object info) { |
|
||||||
tmpInfo = info; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// INTERNAL FUNCTIONS TO KEEP PREDS AND SUCCS CONSISTENT
|
|
||||||
|
|
||||||
final void removeSuccs() { |
|
||||||
if (succs == null) |
|
||||||
return; |
|
||||||
if (succs instanceof Instruction[]) { |
|
||||||
Instruction[] ss = (Instruction[]) succs; |
|
||||||
for (int i = 0; i < ss.length; i++) |
|
||||||
if (ss[i] != null) |
|
||||||
ss[i].removePredecessor(this); |
|
||||||
} else |
|
||||||
((Instruction) succs).removePredecessor(this); |
|
||||||
succs = null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param to may be null |
|
||||||
*/ |
|
||||||
private final void promoteSuccs(Instruction from, Instruction to) { |
|
||||||
if (succs == from) |
|
||||||
succs = to; |
|
||||||
else if (succs instanceof Instruction[]) { |
|
||||||
Instruction[] ss = (Instruction[]) succs; |
|
||||||
for (int i = 0; i < ss.length; i++) |
|
||||||
if (ss[i] == from) |
|
||||||
ss[i] = to; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @exception ClassCastException if newSuccs is neither an Instruction |
|
||||||
* nor an array of instructions. |
|
||||||
*/ |
|
||||||
public final void setSuccs(Object newSuccs) { |
|
||||||
if (succs == newSuccs) |
|
||||||
return; |
|
||||||
removeSuccs(); |
|
||||||
if (newSuccs == null) |
|
||||||
return; |
|
||||||
if (newSuccs instanceof Instruction[]) { |
|
||||||
Instruction[] ns = (Instruction[]) newSuccs; |
|
||||||
switch (ns.length) { |
|
||||||
case 0: |
|
||||||
break; |
|
||||||
case 1: |
|
||||||
succs = ns[0]; |
|
||||||
ns[0].addPredecessor(this); |
|
||||||
break; |
|
||||||
default: |
|
||||||
succs = ns; |
|
||||||
for (int i = 0; i < ns.length; i++) |
|
||||||
ns[i].addPredecessor(this); |
|
||||||
break; |
|
||||||
} |
|
||||||
} else { |
|
||||||
succs = newSuccs; |
|
||||||
((Instruction) newSuccs).addPredecessor(this); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void addPredecessor(Instruction pred) { |
|
||||||
if (preds == null) { |
|
||||||
preds = new Instruction[] { pred }; |
|
||||||
return; |
|
||||||
} |
|
||||||
int predsLength = preds.length; |
|
||||||
Instruction[] newPreds = new Instruction[predsLength+1]; |
|
||||||
System.arraycopy(preds, 0, newPreds, 0, predsLength); |
|
||||||
newPreds[predsLength] = pred; |
|
||||||
preds = newPreds; |
|
||||||
} |
|
||||||
|
|
||||||
void removePredecessor(Instruction pred) { |
|
||||||
/* Hopefully it doesn't matter if this is slow */ |
|
||||||
int predLength = preds.length; |
|
||||||
if (predLength == 1) { |
|
||||||
if (preds[0] != pred) |
|
||||||
throw new jode.AssertError |
|
||||||
("removing not existing predecessor"); |
|
||||||
preds = null; |
|
||||||
} else { |
|
||||||
Instruction[] newPreds = new Instruction[predLength-1]; |
|
||||||
int j; |
|
||||||
for (j = 0; preds[j] != pred; j++) |
|
||||||
newPreds[j] = preds[j]; |
|
||||||
System.arraycopy(preds, j+1, newPreds, j, predLength - j - 1); |
|
||||||
preds = newPreds; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// ADDING, REMOVING AND REPLACING INSTRUCTIONS
|
|
||||||
|
|
||||||
/** |
|
||||||
* Replaces the opcode of this instruction. You should only use the |
|
||||||
* mapped opcodes: |
|
||||||
* <pre> |
|
||||||
* [iflda]load_x -> [iflda]load |
|
||||||
* [iflda]store_x -> [iflda]store |
|
||||||
* [ifa]const_xx, ldc_w -> ldc |
|
||||||
* [dl]const_xx -> ldc2_w |
|
||||||
* wide opcode -> opcode |
|
||||||
* tableswitch -> lookupswitch |
|
||||||
* [a]newarray -> multianewarray |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
public final void replaceInstruction(Instruction newInstr, |
|
||||||
BytecodeInfo codeinfo) { |
|
||||||
/* remove predecessors of successors */ |
|
||||||
removeSuccs(); |
|
||||||
|
|
||||||
newInstr.addr = addr; |
|
||||||
nextByAddr.prevByAddr = newInstr; |
|
||||||
newInstr.nextByAddr = nextByAddr; |
|
||||||
prevByAddr.nextByAddr = newInstr; |
|
||||||
newInstr.prevByAddr = prevByAddr; |
|
||||||
prevByAddr = null; |
|
||||||
nextByAddr = null; |
|
||||||
|
|
||||||
/* promote the successors of the predecessors to newInstr */ |
|
||||||
if (preds != null) { |
|
||||||
for (int j=0; j < preds.length; j++) |
|
||||||
preds[j].promoteSuccs(this, newInstr); |
|
||||||
newInstr.preds = preds; |
|
||||||
preds = null; |
|
||||||
} |
|
||||||
|
|
||||||
/* adjust exception handlers */ |
|
||||||
Handler[] handlers = codeinfo.getExceptionHandlers(); |
|
||||||
for (int i=0; i< handlers.length; i++) { |
|
||||||
if (handlers[i].start == this) |
|
||||||
handlers[i].start = newInstr; |
|
||||||
if (handlers[i].end == this) |
|
||||||
handlers[i].end = newInstr; |
|
||||||
if (handlers[i].catcher == this) |
|
||||||
handlers[i].catcher = newInstr; |
|
||||||
} |
|
||||||
|
|
||||||
/* adjust local variable table and line number table */ |
|
||||||
LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable(); |
|
||||||
if (lvt != null) { |
|
||||||
for (int i=0; i< lvt.length; i++) { |
|
||||||
if (lvt[i].start == this) |
|
||||||
lvt[i].start = newInstr; |
|
||||||
if (lvt[i].end == this) |
|
||||||
lvt[i].end = newInstr; |
|
||||||
} |
|
||||||
} |
|
||||||
LineNumber[] lnt = codeinfo.getLineNumberTable(); |
|
||||||
if (lnt != null) { |
|
||||||
for (int i=0; i< lnt.length; i++) { |
|
||||||
if (lnt[i].start == this) |
|
||||||
lnt[i].start = newInstr; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void appendInstruction(Instruction newInstr, BytecodeInfo codeinfo) { |
|
||||||
newInstr.addr = nextByAddr.addr; |
|
||||||
|
|
||||||
newInstr.nextByAddr = nextByAddr; |
|
||||||
nextByAddr.prevByAddr = newInstr; |
|
||||||
newInstr.prevByAddr = this; |
|
||||||
nextByAddr = newInstr; |
|
||||||
|
|
||||||
/* adjust exception handlers end */ |
|
||||||
Handler[] handlers = codeinfo.getExceptionHandlers(); |
|
||||||
if (handlers != null) { |
|
||||||
for (int i=0; i< handlers.length; i++) { |
|
||||||
if (handlers[i].end == this) |
|
||||||
handlers[i].end = newInstr; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Removes this instruction (as if it would be replaced by a nop). |
|
||||||
*/ |
|
||||||
void removeInstruction(BytecodeInfo codeinfo) { |
|
||||||
|
|
||||||
/* remove from chained list and adjust addr / length */ |
|
||||||
prevByAddr.nextByAddr = nextByAddr; |
|
||||||
nextByAddr.prevByAddr = prevByAddr; |
|
||||||
|
|
||||||
/* remove predecessors of successors */ |
|
||||||
removeSuccs(); |
|
||||||
|
|
||||||
/* promote the predecessors to next instruction */ |
|
||||||
if (preds != null) { |
|
||||||
for (int j=0; j < preds.length; j++) |
|
||||||
preds[j].promoteSuccs(this, nextByAddr); |
|
||||||
if (nextByAddr.preds == null) |
|
||||||
nextByAddr.preds = preds; |
|
||||||
else { |
|
||||||
Instruction[] newPreds = new Instruction |
|
||||||
[nextByAddr.preds.length + preds.length]; |
|
||||||
System.arraycopy(nextByAddr.preds, 0, newPreds, 0, |
|
||||||
nextByAddr.preds.length); |
|
||||||
System.arraycopy(preds, 0, newPreds, nextByAddr.preds.length, |
|
||||||
preds.length); |
|
||||||
nextByAddr.preds = newPreds; |
|
||||||
} |
|
||||||
preds = null; |
|
||||||
} |
|
||||||
|
|
||||||
/* adjust exception handlers */ |
|
||||||
Handler[] handlers = codeinfo.getExceptionHandlers(); |
|
||||||
for (int i=0; i< handlers.length; i++) { |
|
||||||
if (handlers[i].start == this && handlers[i].end == this) { |
|
||||||
/* Remove the handler. |
|
||||||
* This is very seldom, so we can make it slow */ |
|
||||||
Handler[] newHandlers = new Handler[handlers.length - 1]; |
|
||||||
System.arraycopy(handlers, 0, newHandlers, 0, i); |
|
||||||
System.arraycopy(handlers, i+1, newHandlers, i, |
|
||||||
handlers.length - (i+1)); |
|
||||||
handlers = newHandlers; |
|
||||||
codeinfo.setExceptionHandlers(newHandlers); |
|
||||||
i--; |
|
||||||
} else { |
|
||||||
if (handlers[i].start == this) |
|
||||||
handlers[i].start = nextByAddr; |
|
||||||
if (handlers[i].end == this) |
|
||||||
handlers[i].end = prevByAddr; |
|
||||||
if (handlers[i].catcher == this) |
|
||||||
handlers[i].catcher = nextByAddr; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* adjust local variable table and line number table */ |
|
||||||
LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable(); |
|
||||||
if (lvt != null) { |
|
||||||
for (int i=0; i< lvt.length; i++) { |
|
||||||
if (lvt[i].start == this && lvt[i].end == this) { |
|
||||||
/* Remove the local variable info. |
|
||||||
* This is very seldom, so we can make it slow |
|
||||||
*/ |
|
||||||
LocalVariableInfo[] newLVT = |
|
||||||
new LocalVariableInfo[lvt.length - 1]; |
|
||||||
System.arraycopy(lvt, 0, newLVT, 0, i); |
|
||||||
System.arraycopy(lvt, i+1, newLVT, i, |
|
||||||
newLVT.length - i); |
|
||||||
lvt = newLVT; |
|
||||||
codeinfo.setLocalVariableTable(newLVT); |
|
||||||
i--; |
|
||||||
} else { |
|
||||||
if (lvt[i].start == this) |
|
||||||
lvt[i].start = nextByAddr; |
|
||||||
if (lvt[i].end == this) |
|
||||||
lvt[i].end = prevByAddr; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
LineNumber[] lnt = codeinfo.getLineNumberTable(); |
|
||||||
if (lnt != null) { |
|
||||||
for (int i=0; i< lnt.length; i++) { |
|
||||||
if (lnt[i].start == this) { |
|
||||||
if (nextByAddr.opcode == opc_impdep1 |
|
||||||
|| (i+1 < lnt.length |
|
||||||
&& lnt[i+1].start == nextByAddr)) { |
|
||||||
/* Remove the line number. |
|
||||||
* This is very seldom, so we can make it slow */ |
|
||||||
LineNumber[] newLNT = |
|
||||||
new LineNumber[lnt.length - 1]; |
|
||||||
System.arraycopy(lnt, 0, newLNT, 0, i); |
|
||||||
System.arraycopy(lnt, i+1, newLNT, i, |
|
||||||
newLNT.length - i); |
|
||||||
lnt = newLNT; |
|
||||||
codeinfo.setLineNumberTable(newLNT); |
|
||||||
i--; |
|
||||||
} else |
|
||||||
lnt[i].start = nextByAddr; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
prevByAddr = null; |
|
||||||
nextByAddr = null; |
|
||||||
} |
|
||||||
|
|
||||||
public int compareTo(Instruction instr) { |
|
||||||
if (addr != instr.addr) |
|
||||||
return addr - instr.addr; |
|
||||||
if (this == instr) |
|
||||||
return 0; |
|
||||||
do { |
|
||||||
instr = instr.nextByAddr; |
|
||||||
if (instr.addr > addr) |
|
||||||
return -1; |
|
||||||
} while (instr != this); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This returns the number of stack entries this instruction |
|
||||||
* pushes and pops from the stack. The result fills the given |
|
||||||
* array. |
|
||||||
* |
|
||||||
* @param poppush an array of two ints. The first element will |
|
||||||
* get the number of pops, the second the number of pushes. |
|
||||||
*/ |
|
||||||
public void getStackPopPush(int[] poppush) |
|
||||||
/*{ require { poppush != null && poppush.length == 2 |
|
||||||
:: "poppush must be an array of two ints" } } */ |
|
||||||
{ |
|
||||||
byte delta = (byte) stackDelta.charAt(opcode); |
|
||||||
if (delta < 0x40) { |
|
||||||
poppush[0] = delta & 7; |
|
||||||
poppush[1] = delta >> 3; |
|
||||||
} else { |
|
||||||
switch (opcode) { |
|
||||||
case opc_invokevirtual: |
|
||||||
case opc_invokespecial: |
|
||||||
case opc_invokestatic: |
|
||||||
case opc_invokeinterface: { |
|
||||||
Reference ref = getReference(); |
|
||||||
String typeSig = ref.getType(); |
|
||||||
poppush[0] = opcode != opc_invokestatic ? 1 : 0; |
|
||||||
poppush[0] += TypeSignature.getArgumentSize(typeSig); |
|
||||||
poppush[1] = TypeSignature.getReturnSize(typeSig); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case opc_putfield: |
|
||||||
case opc_putstatic: { |
|
||||||
Reference ref = getReference(); |
|
||||||
poppush[1] = 0; |
|
||||||
poppush[0] = TypeSignature.getTypeSize(ref.getType()); |
|
||||||
if (opcode == opc_putfield) |
|
||||||
poppush[0]++; |
|
||||||
break; |
|
||||||
} |
|
||||||
case opc_getstatic: |
|
||||||
case opc_getfield: { |
|
||||||
Reference ref = getReference(); |
|
||||||
poppush[1] = TypeSignature.getTypeSize(ref.getType()); |
|
||||||
poppush[0] = opcode == opc_getfield ? 1 : 0; |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case opc_multianewarray: { |
|
||||||
poppush[1] = 1; |
|
||||||
poppush[0] = getDimensions(); |
|
||||||
break; |
|
||||||
} |
|
||||||
default: |
|
||||||
throw new jode.AssertError("Unknown Opcode: "+opcode); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Instruction findMatchingPop() { |
|
||||||
int poppush[] = new int[2]; |
|
||||||
getStackPopPush(poppush); |
|
||||||
|
|
||||||
int count = poppush[1]; |
|
||||||
Instruction instr = this; |
|
||||||
while (true) { |
|
||||||
if (instr.succs != null || instr.doesAlwaysJump()) |
|
||||||
return null; |
|
||||||
instr = instr.nextByAddr; |
|
||||||
if (instr.preds != null) |
|
||||||
return null; |
|
||||||
|
|
||||||
instr.getStackPopPush(poppush); |
|
||||||
if (count == poppush[0]) |
|
||||||
return instr; |
|
||||||
count += poppush[1] - poppush[0]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Instruction findMatchingPush() { |
|
||||||
int count = 0; |
|
||||||
Instruction instr = this; |
|
||||||
int poppush[] = new int[2]; |
|
||||||
while (true) { |
|
||||||
if (instr.preds != null) |
|
||||||
return null; |
|
||||||
instr = instr.prevByAddr; |
|
||||||
if (instr == null || instr.succs != null || instr.doesAlwaysJump()) |
|
||||||
return null; |
|
||||||
|
|
||||||
instr.getStackPopPush(poppush); |
|
||||||
if (count < poppush[1]) { |
|
||||||
return count == 0 ? instr : null; |
|
||||||
} |
|
||||||
count += poppush[0] - poppush[1]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public String getDescription() { |
|
||||||
StringBuffer result = new StringBuffer(String.valueOf(addr)) |
|
||||||
.append('_').append(Integer.toHexString(hashCode())) |
|
||||||
.append(": ").append(opcodeString[opcode]); |
|
||||||
if (opcode != opc_lookupswitch) { |
|
||||||
if (hasLocalSlot()) |
|
||||||
result.append(' ').append(getLocalSlot()); |
|
||||||
if (succs != null) |
|
||||||
result.append(' ').append(((Instruction) succs).addr); |
|
||||||
if (objData != null) |
|
||||||
result.append(' ').append(objData); |
|
||||||
if (opcode == opc_multianewarray) |
|
||||||
result.append(' ').append(getDimensions()); |
|
||||||
} else { |
|
||||||
int[] values = getValues(); |
|
||||||
Instruction[] succs = getSuccs(); |
|
||||||
for (int i=0; i < values.length; i++) { |
|
||||||
result.append(' ').append(values[i]).append("->") |
|
||||||
.append(((Instruction) succs[i]).addr); |
|
||||||
} |
|
||||||
result.append(' ').append("default: ") |
|
||||||
.append(((Instruction) succs[values.length]).addr); |
|
||||||
} |
|
||||||
return result.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() { |
|
||||||
return "" + addr + "_" + Integer.toHexString(hashCode()); |
|
||||||
} |
|
||||||
|
|
||||||
private final static String stackDelta = |
|
||||||
"\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010"; |
|
||||||
|
|
||||||
/* stackDelta contains \100 if stack count of opcode is variable |
|
||||||
* \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise |
|
||||||
* The above values are extracted from following list with: |
|
||||||
* perl -ne'/"(.*)"/ and print $1' |
|
||||||
* |
|
||||||
* "\000" // nop
|
|
||||||
* "\010\010\010\010\010\010\010\010" // aconst_null, iconst_m?[0-5]
|
|
||||||
* "\020\020\010\010\010\020\020" // [lfd]const_[0-2]
|
|
||||||
* "\010\010\010\010\020" // sipush bipush ldcx
|
|
||||||
* "\010\020\010\020\010" // [ilfda]load
|
|
||||||
* "\010\010\010\010" |
|
||||||
* "\020\020\020\020" |
|
||||||
* "\010\010\010\010" |
|
||||||
* "\020\020\020\020" |
|
||||||
* "\010\010\010\010" |
|
||||||
* "\012\022\012\022\012\012\012\012" // [ilfdabcs]aload
|
|
||||||
* "\001\002\001\002\001" // [ilfda]store
|
|
||||||
* "\001\001\001\001" |
|
||||||
* "\002\002\002\002" |
|
||||||
* "\001\001\001\001" |
|
||||||
* "\002\002\002\002" |
|
||||||
* "\001\001\001\001" |
|
||||||
* "\003\004\003\004\003\003\003\003" // [ilfdabcs]astore
|
|
||||||
* "\001\002" // pop
|
|
||||||
* "\021\032\043\042\053\064" // dup2?(_x[12])?
|
|
||||||
* "\022" // swap
|
|
||||||
* "\012\024\012\024" // [ilfd]add
|
|
||||||
* "\012\024\012\024" // [ilfd]sub
|
|
||||||
* "\012\024\012\024" // [ilfd]mul
|
|
||||||
* "\012\024\012\024" // [ilfd]div
|
|
||||||
* "\012\024\012\024" // [ilfd]rem
|
|
||||||
* "\011\022\011\022" // [ilfd]neg
|
|
||||||
* "\012\023\012\023\012\023" // [il]u?sh[lr]
|
|
||||||
* "\012\024\012\024\012\024" // [il](and|or|xor)
|
|
||||||
* "\000" // opc_iinc
|
|
||||||
* "\021\011\021" // i2[lfd]
|
|
||||||
* "\012\012\022" // l2[ifd]
|
|
||||||
* "\011\021\021" // f2[ild]
|
|
||||||
* "\012\022\012" // d2[ilf]
|
|
||||||
* "\011\011\011" // i2[bcs]
|
|
||||||
* "\014\012\012\014\014" // [lfd]cmp.?
|
|
||||||
* "\001\001\001\001\001\001" // if..
|
|
||||||
* "\002\002\002\002\002\002" // if_icmp..
|
|
||||||
* "\002\002" // if_acmp..
|
|
||||||
* "\000\010\000\001\001" // goto,jsr,ret, .*switch
|
|
||||||
* "\001\002\001\002\001\000" // [ilfda]?return
|
|
||||||
* "\100\100\100\100" // (get/put)(static|field)
|
|
||||||
* "\100\100\100\100" // invoke.*
|
|
||||||
* "\177\010\011\011\011" // 186 - 190
|
|
||||||
* "\001\011\011\001\001" // 191 - 195
|
|
||||||
* "\177\100\001\001" // 196 - 199
|
|
||||||
* "\000\010" // goto_w, jsr_w
|
|
||||||
*/ |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
/* LineNumber Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple class containing the info of the LineNumberTable |
|
||||||
*/ |
|
||||||
public class LineNumber { |
|
||||||
public Instruction start; |
|
||||||
public int linenr; |
|
||||||
} |
|
||||||
|
|
@ -1,30 +0,0 @@ |
|||||||
/* LocalVariableInfo Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple class containing the info of the LocalVariableTable |
|
||||||
*/ |
|
||||||
public class LocalVariableInfo { |
|
||||||
public Instruction start, end; |
|
||||||
public String name, type; |
|
||||||
public int slot; |
|
||||||
} |
|
||||||
|
|
@ -1,45 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
BinaryInfo.java \
|
|
||||||
BytecodeInfo.java \
|
|
||||||
ClassFormatException.java \
|
|
||||||
ClassInfo.java \
|
|
||||||
ConstantPool.java \
|
|
||||||
FieldInfo.java \
|
|
||||||
GrowableConstantPool.java \
|
|
||||||
Handler.java \
|
|
||||||
InnerClassInfo.java \
|
|
||||||
Instruction.java \
|
|
||||||
LineNumber.java \
|
|
||||||
LocalVariableInfo.java \
|
|
||||||
MethodInfo.java \
|
|
||||||
Opcodes.java \
|
|
||||||
Reference.java \
|
|
||||||
SearchPath.java \
|
|
||||||
TypeSignature.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,239 +0,0 @@ |
|||||||
/* MethodInfo Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
import java.io.DataInputStream; |
|
||||||
import java.io.DataOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
|
|
||||||
public class MethodInfo extends BinaryInfo { |
|
||||||
|
|
||||||
ClassInfo clazzInfo; |
|
||||||
|
|
||||||
int modifier; |
|
||||||
String name; |
|
||||||
String typeSig; |
|
||||||
|
|
||||||
BytecodeInfo bytecode; |
|
||||||
String[] exceptions; |
|
||||||
boolean syntheticFlag; |
|
||||||
boolean deprecatedFlag; |
|
||||||
|
|
||||||
public MethodInfo(ClassInfo ci) { |
|
||||||
clazzInfo = ci; |
|
||||||
} |
|
||||||
|
|
||||||
public MethodInfo(ClassInfo ci, |
|
||||||
String name, String typeSig, int modifier) { |
|
||||||
this.clazzInfo = ci; |
|
||||||
this.name = name; |
|
||||||
this.typeSig = typeSig; |
|
||||||
this.modifier = modifier; |
|
||||||
} |
|
||||||
|
|
||||||
protected void readAttribute(String name, int length, ConstantPool cp, |
|
||||||
DataInputStream input, |
|
||||||
int howMuch) throws IOException { |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("Code")) { |
|
||||||
bytecode = new BytecodeInfo(this); |
|
||||||
bytecode.read(cp, input); |
|
||||||
} else if ((howMuch & KNOWNATTRIBS) != 0 |
|
||||||
&& name.equals("Exceptions")) { |
|
||||||
int count = input.readUnsignedShort(); |
|
||||||
exceptions = new String[count]; |
|
||||||
for (int i=0; i< count; i++) |
|
||||||
exceptions[i] = cp.getClassName(input.readUnsignedShort()); |
|
||||||
if (length != 2 * (count + 1)) |
|
||||||
throw new ClassFormatException |
|
||||||
("Exceptions attribute has wrong length"); |
|
||||||
} else if (name.equals("Synthetic")) { |
|
||||||
syntheticFlag = true; |
|
||||||
if (length != 0) |
|
||||||
throw new ClassFormatException |
|
||||||
("Synthetic attribute has wrong length"); |
|
||||||
} else if (name.equals("Deprecated")) { |
|
||||||
deprecatedFlag = true; |
|
||||||
if (length != 0) |
|
||||||
throw new ClassFormatException |
|
||||||
("Deprecated attribute has wrong length"); |
|
||||||
} else |
|
||||||
super.readAttribute(name, length, cp, input, howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public void read(ConstantPool constantPool, |
|
||||||
DataInputStream input, int howMuch) throws IOException { |
|
||||||
modifier = input.readUnsignedShort(); |
|
||||||
name = constantPool.getUTF8(input.readUnsignedShort()); |
|
||||||
typeSig = constantPool.getUTF8(input.readUnsignedShort()); |
|
||||||
readAttributes(constantPool, input, howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public void reserveSmallConstants(GrowableConstantPool gcp) { |
|
||||||
if (bytecode != null) |
|
||||||
bytecode.reserveSmallConstants(gcp); |
|
||||||
} |
|
||||||
|
|
||||||
public void prepareWriting(GrowableConstantPool gcp) { |
|
||||||
gcp.putUTF8(name); |
|
||||||
gcp.putUTF8(typeSig); |
|
||||||
if (bytecode != null) { |
|
||||||
gcp.putUTF8("Code"); |
|
||||||
bytecode.prepareWriting(gcp); |
|
||||||
} |
|
||||||
if (exceptions != null) { |
|
||||||
gcp.putUTF8("Exceptions"); |
|
||||||
for (int i=0; i< exceptions.length; i++) |
|
||||||
gcp.putClassName(exceptions[i]); |
|
||||||
} |
|
||||||
if (syntheticFlag) |
|
||||||
gcp.putUTF8("Synthetic"); |
|
||||||
if (deprecatedFlag) |
|
||||||
gcp.putUTF8("Deprecated"); |
|
||||||
prepareAttributes(gcp); |
|
||||||
} |
|
||||||
|
|
||||||
protected int getKnownAttributeCount() { |
|
||||||
int count = 0; |
|
||||||
if (bytecode != null) |
|
||||||
count++; |
|
||||||
if (exceptions != null) |
|
||||||
count++; |
|
||||||
if (syntheticFlag) |
|
||||||
count++; |
|
||||||
if (deprecatedFlag) |
|
||||||
count++; |
|
||||||
return count; |
|
||||||
} |
|
||||||
|
|
||||||
public void writeKnownAttributes(GrowableConstantPool gcp, |
|
||||||
DataOutputStream output) |
|
||||||
throws IOException { |
|
||||||
if (bytecode != null) { |
|
||||||
output.writeShort(gcp.putUTF8("Code")); |
|
||||||
output.writeInt(bytecode.getSize()); |
|
||||||
bytecode.write(gcp, output); |
|
||||||
} |
|
||||||
if (exceptions != null) { |
|
||||||
int count = exceptions.length; |
|
||||||
output.writeShort(gcp.putUTF8("Exceptions")); |
|
||||||
output.writeInt(2 + count * 2); |
|
||||||
output.writeShort(count); |
|
||||||
for (int i=0; i< count; i++) |
|
||||||
output.writeShort(gcp.putClassName(exceptions[i])); |
|
||||||
} |
|
||||||
if (syntheticFlag) { |
|
||||||
output.writeShort(gcp.putUTF8("Synthetic")); |
|
||||||
output.writeInt(0); |
|
||||||
} |
|
||||||
if (deprecatedFlag) { |
|
||||||
output.writeShort(gcp.putUTF8("Deprecated")); |
|
||||||
output.writeInt(0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void write(GrowableConstantPool constantPool, |
|
||||||
DataOutputStream output) throws IOException { |
|
||||||
output.writeShort(modifier); |
|
||||||
output.writeShort(constantPool.putUTF8(name)); |
|
||||||
output.writeShort(constantPool.putUTF8(typeSig)); |
|
||||||
writeAttributes(constantPool, output); |
|
||||||
} |
|
||||||
|
|
||||||
public void dropInfo(int howMuch) { |
|
||||||
if ((howMuch & KNOWNATTRIBS) != 0) { |
|
||||||
bytecode = null; |
|
||||||
exceptions = null; |
|
||||||
} |
|
||||||
if (bytecode != null) |
|
||||||
bytecode.dropInfo(howMuch); |
|
||||||
super.dropInfo(howMuch); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInfo getClazzInfo() { |
|
||||||
return clazzInfo; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getType() { |
|
||||||
return typeSig; |
|
||||||
} |
|
||||||
|
|
||||||
public int getModifiers() { |
|
||||||
return modifier; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isStatic() { |
|
||||||
return Modifier.isStatic(modifier); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSynthetic() { |
|
||||||
return syntheticFlag; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isDeprecated() { |
|
||||||
return deprecatedFlag; |
|
||||||
} |
|
||||||
|
|
||||||
public BytecodeInfo getBytecode() { |
|
||||||
return bytecode; |
|
||||||
} |
|
||||||
|
|
||||||
public String[] getExceptions() { |
|
||||||
return exceptions; |
|
||||||
} |
|
||||||
|
|
||||||
public void setName(String newName) { |
|
||||||
name = newName; |
|
||||||
} |
|
||||||
|
|
||||||
public void setType(String newType) { |
|
||||||
typeSig = newType; |
|
||||||
} |
|
||||||
|
|
||||||
public void setModifiers(int newModifier) { |
|
||||||
modifier = newModifier; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSynthetic(boolean flag) { |
|
||||||
syntheticFlag = flag; |
|
||||||
} |
|
||||||
|
|
||||||
public void setDeprecated(boolean flag) { |
|
||||||
deprecatedFlag = flag; |
|
||||||
} |
|
||||||
|
|
||||||
public void setBytecode(BytecodeInfo newBytecode) { |
|
||||||
clazzInfo.loadInfo(KNOWNATTRIBS); |
|
||||||
bytecode = newBytecode; |
|
||||||
} |
|
||||||
|
|
||||||
public void setExceptions(String[] newExceptions) { |
|
||||||
clazzInfo.loadInfo(KNOWNATTRIBS); |
|
||||||
exceptions = newExceptions; |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() { |
|
||||||
return "Method "+Modifier.toString(modifier)+" "+ |
|
||||||
typeSig + " " + clazzInfo.getName() + "."+ name; |
|
||||||
} |
|
||||||
} |
|
@ -1,576 +0,0 @@ |
|||||||
/* SearchPath Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.bytecode; |
|
||||||
import java.io.ByteArrayInputStream; |
|
||||||
import java.io.File; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.FileNotFoundException; |
|
||||||
import java.io.FilterInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import java.net.MalformedURLException; |
|
||||||
import java.net.URL; |
|
||||||
import java.net.URLConnection; |
|
||||||
import java.util.Enumeration; |
|
||||||
import java.util.Hashtable; |
|
||||||
import java.util.StringTokenizer; |
|
||||||
import java.util.Vector; |
|
||||||
import java.util.zip.ZipEntry; |
|
||||||
import java.util.zip.ZipFile; |
|
||||||
import java.util.zip.ZipInputStream; |
|
||||||
import jode.GlobalOptions; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class represents a path of multiple directories and/or zip files, |
|
||||||
* where we can search for file names. |
|
||||||
* |
|
||||||
* @author Jochen Hoenicke |
|
||||||
*/ |
|
||||||
public class SearchPath { |
|
||||||
|
|
||||||
/** |
|
||||||
* We need a different pathSeparatorChar, since ':' (used for most |
|
||||||
* UNIX System) is used a protocol separator in URLs. |
|
||||||
* |
|
||||||
* We currently allow both pathSeparatorChar and |
|
||||||
* altPathSeparatorChar and decide if it is a protocol separator |
|
||||||
* by context. |
|
||||||
*/ |
|
||||||
public static final char altPathSeparatorChar = ','; |
|
||||||
URL[] bases; |
|
||||||
byte[][] urlzips; |
|
||||||
File[] dirs; |
|
||||||
ZipFile[] zips; |
|
||||||
String[] zipDirs; |
|
||||||
Hashtable[] zipEntries; |
|
||||||
|
|
||||||
private static void addEntry(Hashtable entries, String name) { |
|
||||||
String dir = ""; |
|
||||||
int pathsep = name.lastIndexOf("/"); |
|
||||||
if (pathsep != -1) { |
|
||||||
dir = name.substring(0, pathsep); |
|
||||||
name = name.substring(pathsep+1); |
|
||||||
} |
|
||||||
|
|
||||||
Vector dirContent = (Vector) entries.get(dir); |
|
||||||
if (dirContent == null) { |
|
||||||
dirContent = new Vector(); |
|
||||||
entries.put(dir, dirContent); |
|
||||||
if (dir != "") |
|
||||||
addEntry(entries, dir); |
|
||||||
} |
|
||||||
dirContent.addElement(name); |
|
||||||
} |
|
||||||
|
|
||||||
private void fillZipEntries(int nr) { |
|
||||||
Enumeration zipEnum = zips[nr].entries(); |
|
||||||
zipEntries[nr] = new Hashtable(); |
|
||||||
while (zipEnum.hasMoreElements()) { |
|
||||||
ZipEntry ze = (ZipEntry) zipEnum.nextElement(); |
|
||||||
String name = ze.getName(); |
|
||||||
// if (name.charAt(0) == '/')
|
|
||||||
// name = name.substring(1);
|
|
||||||
if (zipDirs[nr] != null) { |
|
||||||
if (!name.startsWith(zipDirs[nr])) |
|
||||||
continue; |
|
||||||
name = name.substring(zipDirs[nr].length()); |
|
||||||
} |
|
||||||
if (!ze.isDirectory() && name.endsWith(".class")) |
|
||||||
addEntry(zipEntries[nr], name); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void readURLZip(int nr, URLConnection conn) { |
|
||||||
int length = conn.getContentLength(); |
|
||||||
if (length <= 0) |
|
||||||
// Give a approximation if length is unknown
|
|
||||||
length = 10240; |
|
||||||
else |
|
||||||
// Increase the length by one, so we hopefully don't need
|
|
||||||
// to grow the array later (we need a little overshot to
|
|
||||||
// know when the end is reached).
|
|
||||||
length++; |
|
||||||
|
|
||||||
urlzips[nr] = new byte[length]; |
|
||||||
try { |
|
||||||
InputStream is = conn.getInputStream(); |
|
||||||
int pos = 0; |
|
||||||
for (;;) { |
|
||||||
// This is ugly, is.available() may return zero even
|
|
||||||
// if there are more bytes.
|
|
||||||
int avail = Math.max(is.available(), 1); |
|
||||||
if (pos + is.available() > urlzips[nr].length) { |
|
||||||
// grow the byte array.
|
|
||||||
byte[] newarr = new byte |
|
||||||
[Math.max(2*urlzips[nr].length, pos + is.available())]; |
|
||||||
System.arraycopy(urlzips[nr], 0, newarr, 0, pos); |
|
||||||
urlzips[nr] = newarr; |
|
||||||
} |
|
||||||
int count = is.read(urlzips[nr], pos, urlzips[nr].length-pos); |
|
||||||
if (count == -1) |
|
||||||
break; |
|
||||||
pos += count; |
|
||||||
} |
|
||||||
if (pos < urlzips[nr].length) { |
|
||||||
// shrink the byte array again.
|
|
||||||
byte[] newarr = new byte[pos]; |
|
||||||
System.arraycopy(urlzips[nr], 0, newarr, 0, pos); |
|
||||||
urlzips[nr] = newarr; |
|
||||||
} |
|
||||||
} catch (IOException ex) { |
|
||||||
GlobalOptions.err.println("IOException while reading " |
|
||||||
+"remote zip file "+bases[nr]); |
|
||||||
// disable entry
|
|
||||||
bases[nr] = null; |
|
||||||
urlzips[nr] = null; |
|
||||||
return; |
|
||||||
} |
|
||||||
try { |
|
||||||
// fill entries into hash table
|
|
||||||
ZipInputStream zis = new ZipInputStream |
|
||||||
(new ByteArrayInputStream(urlzips[nr])); |
|
||||||
zipEntries[nr] = new Hashtable(); |
|
||||||
ZipEntry ze; |
|
||||||
while ((ze = zis.getNextEntry()) != null) { |
|
||||||
String name = ze.getName(); |
|
||||||
// if (name.charAt(0) == '/')
|
|
||||||
// name = name.substring(1);
|
|
||||||
if (zipDirs[nr] != null) { |
|
||||||
if (!name.startsWith(zipDirs[nr])) |
|
||||||
continue; |
|
||||||
name = name.substring(zipDirs[nr].length()); |
|
||||||
} |
|
||||||
if (!ze.isDirectory() && name.endsWith(".class")) |
|
||||||
addEntry(zipEntries[nr], name); |
|
||||||
zis.closeEntry(); |
|
||||||
} |
|
||||||
zis.close(); |
|
||||||
} catch (IOException ex) { |
|
||||||
GlobalOptions.err.println("Remote zip file "+bases[nr] |
|
||||||
+" is corrupted."); |
|
||||||
// disable entry
|
|
||||||
bases[nr] = null; |
|
||||||
urlzips[nr] = null; |
|
||||||
zipEntries[nr] = null; |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a new search path for the given path. |
|
||||||
* @param path The path where we should search for files. They |
|
||||||
* should be separated by the system dependent pathSeparator. The |
|
||||||
* entries may also be zip or jar files. |
|
||||||
*/ |
|
||||||
public SearchPath(String path) { |
|
||||||
// Calculate a good approximation (rounded upwards) of the tokens
|
|
||||||
// in this path.
|
|
||||||
int length = 1; |
|
||||||
for (int index=path.indexOf(File.pathSeparatorChar); |
|
||||||
index != -1; length++) |
|
||||||
index = path.indexOf(File.pathSeparatorChar, index+1); |
|
||||||
if (File.pathSeparatorChar != altPathSeparatorChar) { |
|
||||||
for (int index=path.indexOf(altPathSeparatorChar); |
|
||||||
index != -1; length++) |
|
||||||
index = path.indexOf(altPathSeparatorChar, index+1); |
|
||||||
} |
|
||||||
bases = new URL[length]; |
|
||||||
urlzips = new byte[length][]; |
|
||||||
dirs = new File[length]; |
|
||||||
zips = new ZipFile[length]; |
|
||||||
zipEntries = new Hashtable[length]; |
|
||||||
zipDirs = new String[length]; |
|
||||||
int i = 0; |
|
||||||
for (int ptr=0; ptr < path.length(); ptr++, i++) { |
|
||||||
int next = ptr; |
|
||||||
while (next < path.length() |
|
||||||
&& path.charAt(next) != File.pathSeparatorChar |
|
||||||
&& path.charAt(next) != altPathSeparatorChar) |
|
||||||
next++; |
|
||||||
|
|
||||||
int index = ptr; |
|
||||||
colon_separator: |
|
||||||
while (next > ptr |
|
||||||
&& next < path.length() |
|
||||||
&& path.charAt(next) == ':') { |
|
||||||
// Check if this is a URL instead of a pathSeparator
|
|
||||||
// Since this is a while loop it allows nested urls like
|
|
||||||
// jar:ftp://ftp.foo.org/pub/foo.jar!/
|
|
||||||
|
|
||||||
while (index < next) { |
|
||||||
char c = path.charAt(index); |
|
||||||
// According to RFC 1738 letters, digits, '+', '-'
|
|
||||||
// and '.' are allowed SCHEMA characters. We
|
|
||||||
// disallow '.' because it is a good marker that
|
|
||||||
// the user has specified a filename instead of a
|
|
||||||
// URL.
|
|
||||||
if ((c < 'A' || c > 'Z') |
|
||||||
&& (c < 'a' || c > 'z') |
|
||||||
&& (c < '0' || c > '9') |
|
||||||
&& "+-".indexOf(c) == -1) { |
|
||||||
break colon_separator; |
|
||||||
} |
|
||||||
index++; |
|
||||||
} |
|
||||||
next++; |
|
||||||
index++; |
|
||||||
while (next < path.length() |
|
||||||
&& path.charAt(next) != File.pathSeparatorChar |
|
||||||
&& path.charAt(next) != altPathSeparatorChar) |
|
||||||
next++; |
|
||||||
} |
|
||||||
String token = path.substring(ptr, next); |
|
||||||
ptr = next; |
|
||||||
|
|
||||||
boolean mustBeJar = false; |
|
||||||
// We handle jar URL's ourself.
|
|
||||||
if (token.startsWith("jar:")) { |
|
||||||
index = 0; |
|
||||||
do { |
|
||||||
index = token.indexOf('!', index); |
|
||||||
} while (index != -1 && index != token.length()-1 |
|
||||||
&& token.charAt(index+1) != '/'); |
|
||||||
|
|
||||||
if (index == -1 || index == token.length()-1) { |
|
||||||
GlobalOptions.err.println("Warning: Illegal jar url " |
|
||||||
+ token + "."); |
|
||||||
continue; |
|
||||||
} |
|
||||||
zipDirs[i] = token.substring(index+2); |
|
||||||
if (!zipDirs[i].endsWith("/")) |
|
||||||
zipDirs[i] = zipDirs[i] + "/"; |
|
||||||
token = token.substring(4, index); |
|
||||||
mustBeJar = true; |
|
||||||
} |
|
||||||
index = token.indexOf(':'); |
|
||||||
if (index != -1 && index < token.length()-2 |
|
||||||
&& token.charAt(index+1) == '/' |
|
||||||
&& token.charAt(index+2) == '/') { |
|
||||||
// This looks like an URL.
|
|
||||||
try { |
|
||||||
bases[i] = new URL(token); |
|
||||||
try { |
|
||||||
URLConnection connection = bases[i].openConnection(); |
|
||||||
if (mustBeJar |
|
||||||
|| token.endsWith(".zip") || token.endsWith(".jar") |
|
||||||
|| connection.getContentType().endsWith("/zip")) { |
|
||||||
// This is a zip file. Read it into memory.
|
|
||||||
readURLZip(i, connection); |
|
||||||
} |
|
||||||
} catch (IOException ex) { |
|
||||||
// ignore
|
|
||||||
} catch (SecurityException ex) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("Warning: Security exception while accessing " |
|
||||||
+bases[i]+"."); |
|
||||||
} |
|
||||||
} catch (MalformedURLException ex) { |
|
||||||
/* disable entry */ |
|
||||||
bases[i] = null; |
|
||||||
dirs[i] = null; |
|
||||||
} |
|
||||||
} else { |
|
||||||
try { |
|
||||||
dirs[i] = new File(token); |
|
||||||
if (mustBeJar || !dirs[i].isDirectory()) { |
|
||||||
try { |
|
||||||
zips[i] = new ZipFile(dirs[i]); |
|
||||||
} catch (java.io.IOException ex) { |
|
||||||
/* disable this entry */ |
|
||||||
dirs[i] = null; |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (SecurityException ex) { |
|
||||||
/* disable this entry */ |
|
||||||
GlobalOptions.err.println |
|
||||||
("Warning: SecurityException while accessing " |
|
||||||
+ token + "."); |
|
||||||
dirs[i] = null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public boolean exists(String filename) { |
|
||||||
for (int i=0; i<dirs.length; i++) { |
|
||||||
if (zipEntries[i] != null) { |
|
||||||
if (zipEntries[i].get(filename) != null) |
|
||||||
return true; |
|
||||||
|
|
||||||
String dir = ""; |
|
||||||
String name = filename; |
|
||||||
int index = filename.lastIndexOf('/'); |
|
||||||
if (index >= 0) { |
|
||||||
dir = filename.substring(0, index); |
|
||||||
name = filename.substring(index+1); |
|
||||||
} |
|
||||||
Vector directory = (Vector)zipEntries[i].get(dir); |
|
||||||
if (directory != null && directory.contains(name)) |
|
||||||
return true; |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (bases[i] != null) { |
|
||||||
try { |
|
||||||
URL url = new URL(bases[i], filename); |
|
||||||
URLConnection conn = url.openConnection(); |
|
||||||
conn.connect(); |
|
||||||
conn.getInputStream().close(); |
|
||||||
return true; |
|
||||||
} catch (IOException ex) { |
|
||||||
/* ignore */ |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (dirs[i] == null) |
|
||||||
continue; |
|
||||||
if (zips[i] != null) { |
|
||||||
String fullname = zipDirs[i] != null |
|
||||||
? zipDirs[i] + filename : filename; |
|
||||||
ZipEntry ze = zips[i].getEntry(fullname); |
|
||||||
if (ze != null) |
|
||||||
return true; |
|
||||||
} else { |
|
||||||
if (java.io.File.separatorChar != '/') |
|
||||||
filename = filename |
|
||||||
.replace('/', java.io.File.separatorChar); |
|
||||||
try { |
|
||||||
File f = new File(dirs[i], filename); |
|
||||||
if (f.exists()) |
|
||||||
return true; |
|
||||||
} catch (SecurityException ex) { |
|
||||||
/* ignore and take next element */ |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Searches for a file in the search path. |
|
||||||
* @param filename the filename. The path components should be separated |
|
||||||
* by <code>/</code>. |
|
||||||
* @return An InputStream for the file. |
|
||||||
*/ |
|
||||||
public InputStream getFile(String filename) throws IOException { |
|
||||||
for (int i=0; i<dirs.length; i++) { |
|
||||||
if (urlzips[i] != null) { |
|
||||||
ZipInputStream zis = new ZipInputStream |
|
||||||
(new ByteArrayInputStream(urlzips[i])); |
|
||||||
ZipEntry ze; |
|
||||||
String fullname = zipDirs[i] != null |
|
||||||
? zipDirs[i] + filename : filename; |
|
||||||
while ((ze = zis.getNextEntry()) != null) { |
|
||||||
if (ze.getName().equals(fullname)) { |
|
||||||
///#ifdef JDK11
|
|
||||||
// The skip method in jdk1.1.7 ZipInputStream
|
|
||||||
// is buggy. We return a wrapper that fixes
|
|
||||||
// this.
|
|
||||||
return new FilterInputStream(zis) { |
|
||||||
private byte[] tmpbuf = new byte[512]; |
|
||||||
public long skip(long n) throws IOException { |
|
||||||
long skipped = 0; |
|
||||||
while (n > 0) { |
|
||||||
int count = read(tmpbuf, 0, |
|
||||||
(int)Math.min(n, 512L)); |
|
||||||
if (count == -1) |
|
||||||
return skipped; |
|
||||||
skipped += count; |
|
||||||
n -= count; |
|
||||||
} |
|
||||||
return skipped; |
|
||||||
} |
|
||||||
}; |
|
||||||
///#else
|
|
||||||
/// return zis;
|
|
||||||
///#endif
|
|
||||||
} |
|
||||||
zis.closeEntry(); |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (bases[i] != null) { |
|
||||||
try { |
|
||||||
URL url = new URL(bases[i], filename); |
|
||||||
URLConnection conn = url.openConnection(); |
|
||||||
conn.setAllowUserInteraction(true); |
|
||||||
return conn.getInputStream(); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
GlobalOptions.err.println("Warning: SecurityException" |
|
||||||
+" while accessing " |
|
||||||
+bases[i]+filename); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
/* ignore and take next element */ |
|
||||||
} catch (FileNotFoundException ex) { |
|
||||||
/* ignore and take next element */ |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (dirs[i] == null) |
|
||||||
continue; |
|
||||||
if (zips[i] != null) { |
|
||||||
String fullname = zipDirs[i] != null |
|
||||||
? zipDirs[i] + filename : filename; |
|
||||||
ZipEntry ze = zips[i].getEntry(fullname); |
|
||||||
if (ze != null) |
|
||||||
return zips[i].getInputStream(ze); |
|
||||||
} else { |
|
||||||
if (java.io.File.separatorChar != '/') |
|
||||||
filename = filename |
|
||||||
.replace('/', java.io.File.separatorChar); |
|
||||||
try { |
|
||||||
File f = new File(dirs[i], filename); |
|
||||||
if (f.exists()) |
|
||||||
return new FileInputStream(f); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
GlobalOptions.err.println("Warning: SecurityException" |
|
||||||
+" while accessing " |
|
||||||
+dirs[i]+filename); |
|
||||||
/* ignore and take next element */ |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
throw new FileNotFoundException(filename); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Searches for a filename in the search path and tells if it is a |
|
||||||
* directory. |
|
||||||
* @param filename the filename. The path components should be separated |
|
||||||
* by <code>/</code>. |
|
||||||
* @return true, if filename exists and is a directory, false otherwise. |
|
||||||
*/ |
|
||||||
public boolean isDirectory(String filename) { |
|
||||||
for (int i=0; i<dirs.length; i++) { |
|
||||||
if (dirs[i] == null) |
|
||||||
continue; |
|
||||||
if (zips[i] != null && zipEntries[i] == null) |
|
||||||
fillZipEntries(i); |
|
||||||
|
|
||||||
if (zipEntries[i] != null) { |
|
||||||
if (zipEntries[i].containsKey(filename)) |
|
||||||
return true; |
|
||||||
} else { |
|
||||||
if (java.io.File.separatorChar != '/') |
|
||||||
filename = filename |
|
||||||
.replace('/', java.io.File.separatorChar); |
|
||||||
try { |
|
||||||
File f = new File(dirs[i], filename); |
|
||||||
if (f.exists()) |
|
||||||
return f.isDirectory(); |
|
||||||
} catch (SecurityException ex) { |
|
||||||
GlobalOptions.err.println("Warning: SecurityException" |
|
||||||
+" while accessing " |
|
||||||
+dirs[i]+filename); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Searches for all files in the given directory. |
|
||||||
* @param dirName the directory name. The path components should |
|
||||||
* be separated by <code>/</code>. |
|
||||||
* @return An enumeration with all files/directories in the given |
|
||||||
* directory. */ |
|
||||||
public Enumeration listFiles(final String dirName) { |
|
||||||
return new Enumeration() { |
|
||||||
int pathNr; |
|
||||||
Enumeration zipEnum; |
|
||||||
int fileNr; |
|
||||||
String localDirName = |
|
||||||
(java.io.File.separatorChar != '/') |
|
||||||
? dirName.replace('/', java.io.File.separatorChar) |
|
||||||
: dirName; |
|
||||||
File currentDir; |
|
||||||
String[] files; |
|
||||||
|
|
||||||
public String findNextFile() { |
|
||||||
while (true) { |
|
||||||
if (zipEnum != null) { |
|
||||||
while (zipEnum.hasMoreElements()) { |
|
||||||
return (String) zipEnum.nextElement(); |
|
||||||
} |
|
||||||
zipEnum = null; |
|
||||||
} |
|
||||||
if (files != null) { |
|
||||||
while (fileNr < files.length) { |
|
||||||
String name = files[fileNr++]; |
|
||||||
if (name.endsWith(".class")) { |
|
||||||
return name; |
|
||||||
} else if (name.indexOf(".") == -1) { |
|
||||||
/* ignore directories containing a dot. |
|
||||||
* they can't be a package directory. |
|
||||||
*/ |
|
||||||
File f = new File(currentDir, name); |
|
||||||
if (f.exists() && f.isDirectory()) |
|
||||||
return name; |
|
||||||
} |
|
||||||
} |
|
||||||
files = null; |
|
||||||
} |
|
||||||
if (pathNr == dirs.length) |
|
||||||
return null; |
|
||||||
|
|
||||||
if (zips[pathNr] != null && zipEntries[pathNr] == null) |
|
||||||
fillZipEntries(pathNr); |
|
||||||
|
|
||||||
if (zipEntries[pathNr] != null) { |
|
||||||
Vector entries = |
|
||||||
(Vector) zipEntries[pathNr].get(dirName); |
|
||||||
if (entries != null) |
|
||||||
zipEnum = entries.elements(); |
|
||||||
} else if (dirs[pathNr] != null) { |
|
||||||
try { |
|
||||||
File f = new File(dirs[pathNr], localDirName); |
|
||||||
if (f.exists() && f.isDirectory()) { |
|
||||||
currentDir = f; |
|
||||||
files = f.list(); |
|
||||||
} |
|
||||||
} catch (SecurityException ex) { |
|
||||||
GlobalOptions.err.println("Warning: SecurityException" |
|
||||||
+" while accessing " |
|
||||||
+dirs[pathNr]+localDirName); |
|
||||||
/* ignore and take next element */ |
|
||||||
} |
|
||||||
} |
|
||||||
pathNr++; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
String nextName; |
|
||||||
|
|
||||||
public boolean hasMoreElements() { |
|
||||||
return (nextName != null |
|
||||||
|| (nextName = findNextFile()) != null); |
|
||||||
} |
|
||||||
|
|
||||||
public Object nextElement() { |
|
||||||
if (nextName == null) |
|
||||||
return findNextFile(); |
|
||||||
else { |
|
||||||
String result = nextName; |
|
||||||
nextName = null; |
|
||||||
return result; |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
@ -1,116 +0,0 @@ |
|||||||
/* DeadCodeAnalysis Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.decompiler; |
|
||||||
import jode.bytecode.BytecodeInfo; |
|
||||||
import jode.bytecode.Instruction; |
|
||||||
import jode.bytecode.Handler; |
|
||||||
|
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
|
|
||||||
public class DeadCodeAnalysis { |
|
||||||
|
|
||||||
private final static String REACHABLE = "R"; |
|
||||||
private final static String REACHCHANGED = "C"; |
|
||||||
|
|
||||||
private static void propagateReachability(BytecodeInfo code) { |
|
||||||
boolean changed; |
|
||||||
do { |
|
||||||
changed = false; |
|
||||||
for (Iterator iter = code.getInstructions().iterator(); |
|
||||||
iter.hasNext(); ) { |
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (instr.getTmpInfo() == REACHCHANGED) { |
|
||||||
changed = true; |
|
||||||
instr.setTmpInfo(REACHABLE); |
|
||||||
Instruction[] succs = instr.getSuccs(); |
|
||||||
if (succs != null) |
|
||||||
for (int i=0; i< succs.length; i++) |
|
||||||
if (succs[i].getTmpInfo() == null) |
|
||||||
succs[i].setTmpInfo(REACHCHANGED); |
|
||||||
if (!instr.doesAlwaysJump() |
|
||||||
&& instr.getNextByAddr() != null) |
|
||||||
if (instr.getNextByAddr().getTmpInfo() == null) |
|
||||||
instr.getNextByAddr().setTmpInfo(REACHCHANGED); |
|
||||||
/*XXX code after jsr reachable iff ret is reachable...*/ |
|
||||||
if (instr.getOpcode() == Opcodes.opc_jsr) |
|
||||||
if (instr.getNextByAddr().getTmpInfo() == null) |
|
||||||
instr.getNextByAddr().setTmpInfo(REACHCHANGED); |
|
||||||
} |
|
||||||
} |
|
||||||
} while (changed); |
|
||||||
} |
|
||||||
|
|
||||||
public static void removeDeadCode(BytecodeInfo code) { |
|
||||||
((Instruction) code.getInstructions().get(0)).setTmpInfo(REACHCHANGED); |
|
||||||
propagateReachability(code); |
|
||||||
Handler[] handlers = code.getExceptionHandlers(); |
|
||||||
boolean changed; |
|
||||||
do { |
|
||||||
changed = false; |
|
||||||
for (int i=0; i < handlers.length; i++) { |
|
||||||
if (handlers[i].catcher.getTmpInfo() == null) { |
|
||||||
/* check if the try block is somewhere reachable |
|
||||||
* and mark the catcher as reachable then. |
|
||||||
*/ |
|
||||||
for (Instruction instr = handlers[i].start; |
|
||||||
instr != null; instr = instr.getNextByAddr()) { |
|
||||||
if (instr.getTmpInfo() != null) { |
|
||||||
handlers[i].catcher.setTmpInfo(REACHCHANGED); |
|
||||||
propagateReachability(code); |
|
||||||
changed = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
if (instr == handlers[i].end) |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} while (changed); |
|
||||||
|
|
||||||
for (int i=0; i< handlers.length; i++) { |
|
||||||
/* A handler is not reachable iff the catcher is not reachable */ |
|
||||||
if (handlers[i].catcher.getTmpInfo() == null) { |
|
||||||
/* This is very seldom, so we can make it slow */ |
|
||||||
Handler[] newHandlers = new Handler[handlers.length - 1]; |
|
||||||
System.arraycopy(handlers, 0, newHandlers, 0, i); |
|
||||||
System.arraycopy(handlers, i+1, newHandlers, i, |
|
||||||
handlers.length - (i+1)); |
|
||||||
handlers = newHandlers; |
|
||||||
code.setExceptionHandlers(newHandlers); |
|
||||||
i--; |
|
||||||
} else { |
|
||||||
/* This works! */ |
|
||||||
while (handlers[i].start.getTmpInfo() == null) |
|
||||||
handlers[i].start = handlers[i].start.getNextByAddr(); |
|
||||||
while (handlers[i].end.getTmpInfo() == null) |
|
||||||
handlers[i].end = handlers[i].end.getPrevByAddr(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Now remove the dead code and clean up tmpInfo */ |
|
||||||
for (Iterator i = code.getInstructions().iterator(); i.hasNext(); ) { |
|
||||||
Instruction instr = (Instruction) i.next(); |
|
||||||
if (instr.getTmpInfo() != null) |
|
||||||
instr.setTmpInfo(null); |
|
||||||
else |
|
||||||
i.remove(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
/* LocalVarEntry Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.decompiler; |
|
||||||
import jode.type.Type; |
|
||||||
|
|
||||||
public class LocalVarEntry { |
|
||||||
String name; |
|
||||||
Type type; |
|
||||||
int startAddr; |
|
||||||
int endAddr; |
|
||||||
LocalVarEntry next; |
|
||||||
|
|
||||||
public LocalVarEntry(int s, int e, String n, Type t) { |
|
||||||
startAddr = s; |
|
||||||
endAddr = e; |
|
||||||
name = n; |
|
||||||
type = t; |
|
||||||
next = null; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public Type getType() { |
|
||||||
return type; |
|
||||||
} |
|
||||||
} |
|
@ -1,79 +0,0 @@ |
|||||||
/* LocalVariableRangeList Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.decompiler; |
|
||||||
import jode.GlobalOptions; |
|
||||||
import jode.type.Type; |
|
||||||
|
|
||||||
public class LocalVariableRangeList { |
|
||||||
|
|
||||||
LocalVarEntry list = null; |
|
||||||
|
|
||||||
LocalVariableRangeList() { |
|
||||||
} |
|
||||||
|
|
||||||
private void add(LocalVarEntry li) { |
|
||||||
LocalVarEntry prev = null; |
|
||||||
LocalVarEntry next = list; |
|
||||||
while (next != null && next.endAddr < li.startAddr) { |
|
||||||
prev = next; |
|
||||||
next = next.next; |
|
||||||
} |
|
||||||
/* prev.endAddr < li.startAddr <= next.endAddr |
|
||||||
*/ |
|
||||||
if (next != null && li.endAddr >= next.startAddr) { |
|
||||||
if (next.type.equals(li.type) |
|
||||||
&& next.name.equals(li.name)) { |
|
||||||
/* Same type, same name and overlapping range. |
|
||||||
* This is the same local: extend next to the common |
|
||||||
* range and don't add li. |
|
||||||
*/ |
|
||||||
next.startAddr = Math.min(next.startAddr, li.startAddr); |
|
||||||
next.endAddr = Math.max(next.endAddr, li.endAddr); |
|
||||||
return; |
|
||||||
} |
|
||||||
GlobalOptions.err.println("warning: non disjoint locals"); |
|
||||||
} |
|
||||||
li.next = next; |
|
||||||
if (prev == null) |
|
||||||
list = li; |
|
||||||
else |
|
||||||
prev.next = li; |
|
||||||
} |
|
||||||
|
|
||||||
private LocalVarEntry find(int addr) { |
|
||||||
LocalVarEntry li = list; |
|
||||||
while (li != null && li.endAddr < addr) |
|
||||||
li = li.next; |
|
||||||
if (li == null || li.startAddr > addr) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return li; |
|
||||||
} |
|
||||||
|
|
||||||
public void addLocal(int startAddr, int endAddr, |
|
||||||
String name, Type type) { |
|
||||||
LocalVarEntry li = new LocalVarEntry(startAddr,endAddr,name,type); |
|
||||||
add (li); |
|
||||||
} |
|
||||||
|
|
||||||
public LocalVarEntry getInfo(int addr) { |
|
||||||
return find(addr); |
|
||||||
} |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
/* LocalVariableTable Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.decompiler; |
|
||||||
import jode.type.Type; |
|
||||||
import jode.bytecode.LocalVariableInfo; |
|
||||||
|
|
||||||
public class LocalVariableTable { |
|
||||||
LocalVariableRangeList[] locals; |
|
||||||
|
|
||||||
public LocalVariableTable(int maxLocals, LocalVariableInfo[] lvt) { |
|
||||||
locals = new LocalVariableRangeList[maxLocals]; |
|
||||||
for (int i=0; i < maxLocals; i++) |
|
||||||
locals[i] = new LocalVariableRangeList(); |
|
||||||
|
|
||||||
for (int i=0; i<lvt.length; i++) |
|
||||||
locals[lvt[i].slot].addLocal(lvt[i].start.getAddr(), |
|
||||||
lvt[i].end.getAddr(), |
|
||||||
lvt[i].name, Type.tType(lvt[i].type)); |
|
||||||
} |
|
||||||
|
|
||||||
public LocalVarEntry getLocal(int slot, int addr) |
|
||||||
throws ArrayIndexOutOfBoundsException |
|
||||||
{ |
|
||||||
return locals[slot].getInfo(addr); |
|
||||||
} |
|
||||||
} |
|
@ -1,328 +0,0 @@ |
|||||||
/* Main Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.decompiler; |
|
||||||
import jode.bytecode.ClassInfo; |
|
||||||
import jode.bytecode.SearchPath; |
|
||||||
import jode.GlobalOptions; |
|
||||||
|
|
||||||
import java.io.BufferedOutputStream; |
|
||||||
import java.io.File; |
|
||||||
import java.io.FileOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.PrintWriter; |
|
||||||
import java.util.zip.ZipOutputStream; |
|
||||||
import java.util.zip.ZipEntry; |
|
||||||
|
|
||||||
import gnu.getopt.LongOpt; |
|
||||||
import gnu.getopt.Getopt; |
|
||||||
|
|
||||||
|
|
||||||
public class Main extends Options { |
|
||||||
private static final int OPTION_START=0x10000; |
|
||||||
private static final int OPTION_END =0x20000; |
|
||||||
|
|
||||||
private static final LongOpt[] longOptions = new LongOpt[] { |
|
||||||
new LongOpt("cp", LongOpt.REQUIRED_ARGUMENT, null, 'c'), |
|
||||||
new LongOpt("classpath", LongOpt.REQUIRED_ARGUMENT, null, 'c'), |
|
||||||
new LongOpt("dest", LongOpt.REQUIRED_ARGUMENT, null, 'd'), |
|
||||||
new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'), |
|
||||||
new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V'), |
|
||||||
new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v'), |
|
||||||
new LongOpt("debug", LongOpt.OPTIONAL_ARGUMENT, null, 'D'), |
|
||||||
new LongOpt("import", LongOpt.REQUIRED_ARGUMENT, null, 'i'), |
|
||||||
new LongOpt("style", LongOpt.REQUIRED_ARGUMENT, null, 's'), |
|
||||||
new LongOpt("lvt", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+0), |
|
||||||
new LongOpt("inner", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+1), |
|
||||||
new LongOpt("anonymous", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+2), |
|
||||||
new LongOpt("push", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+3), |
|
||||||
new LongOpt("pretty", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+4), |
|
||||||
new LongOpt("decrypt", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+5), |
|
||||||
new LongOpt("onetime", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+6), |
|
||||||
new LongOpt("immediate", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+7), |
|
||||||
new LongOpt("verify", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+8), |
|
||||||
new LongOpt("contrafo", LongOpt.OPTIONAL_ARGUMENT, null, |
|
||||||
OPTION_START+9) |
|
||||||
}; |
|
||||||
|
|
||||||
public static void usage() { |
|
||||||
PrintWriter err = GlobalOptions.err; |
|
||||||
err.println("Version: " + GlobalOptions.version); |
|
||||||
err.println("Usage: java jode.decompiler.Main [OPTIONS]... [CLASSES]..."); |
|
||||||
err.println(" -h, --help "+ |
|
||||||
"show this information."); |
|
||||||
err.println(" -V, --version "+ |
|
||||||
"output version information and exit."); |
|
||||||
err.println(" -v, --verbose "+ |
|
||||||
"be verbose (multiple times means more verbose)."); |
|
||||||
err.println(" -c, --classpath <path> "+ |
|
||||||
"search for classes in specified classpath."); |
|
||||||
err.println(" "+ |
|
||||||
"The directories should be separated by ','."); |
|
||||||
err.println(" -d, --dest <dir> "+ |
|
||||||
"write decompiled files to disk into directory destdir."); |
|
||||||
err.println(" -s, --style {sun|gnu} "+ |
|
||||||
"specify indentation style"); |
|
||||||
err.println(" -i, --import <pkglimit>,<clslimit>"); |
|
||||||
err.println(" "+ |
|
||||||
"import classes used more than clslimit times"); |
|
||||||
err.println(" "+ |
|
||||||
"and packages with more then pkglimit used classes."); |
|
||||||
err.println(" "+ |
|
||||||
"Limit 0 means, never import, default is 0,1."); |
|
||||||
|
|
||||||
err.println("The following options can be turned on or off with `yes' or `no' argument."); |
|
||||||
err.println(" --inner "+ |
|
||||||
"decompile inner classes (default)."); |
|
||||||
err.println(" --anonymous "+ |
|
||||||
"decompile anonymous classes (default)."); |
|
||||||
err.println(" --contrafo "+ |
|
||||||
"transform constructors of inner classes (default)."); |
|
||||||
err.println(" --lvt "+ |
|
||||||
"use the local variable table (default)."); |
|
||||||
err.println(" --pretty "+ |
|
||||||
"use `pretty' names for local variables."); |
|
||||||
err.println(" --push "+ |
|
||||||
"allow PUSH instructions in output."); |
|
||||||
err.println(" --decrypt "+ |
|
||||||
"decrypt encrypted strings (default)."); |
|
||||||
err.println(" --onetime "+ |
|
||||||
"remove locals, that are used only one time."); |
|
||||||
err.println(" --immediate "+ |
|
||||||
"output source immediately (may produce buggy code)."); |
|
||||||
err.println(" --verify "+ |
|
||||||
"verify code before decompiling it."); |
|
||||||
err.println("Debugging options, mainly used to debug this decompiler:"); |
|
||||||
err.println(" -D, --debug=... "+ |
|
||||||
"use --debug=help for more information."); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean handleOption(int option, int longind, String arg) { |
|
||||||
if (arg == null) |
|
||||||
options ^= 1 << option; |
|
||||||
else if ("yes".startsWith(arg) || arg.equals("on")) |
|
||||||
options |= 1 << option; |
|
||||||
else if ("no".startsWith(arg) || arg.equals("off")) |
|
||||||
options &= ~(1 << option); |
|
||||||
else { |
|
||||||
GlobalOptions.err.println |
|
||||||
("jode.decompiler.Main: option --"+longOptions[longind].getName() |
|
||||||
+" takes one of `yes', `no', `on', `off' as parameter"); |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public static void main(String[] params) { |
|
||||||
if (params.length == 0) { |
|
||||||
usage(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
String classPath = System.getProperty("java.class.path") |
|
||||||
.replace(File.pathSeparatorChar, SearchPath.altPathSeparatorChar); |
|
||||||
String destDir = null; |
|
||||||
|
|
||||||
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT; |
|
||||||
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;; |
|
||||||
|
|
||||||
GlobalOptions.err.println(GlobalOptions.copyright); |
|
||||||
|
|
||||||
boolean errorInParams = false; |
|
||||||
Getopt g = new Getopt("jode.decompiler.Main", params, "hVvc:d:D:i:s:", |
|
||||||
longOptions, true); |
|
||||||
for (int opt = g.getopt(); opt != -1; opt = g.getopt()) { |
|
||||||
switch(opt) { |
|
||||||
case 0: |
|
||||||
break; |
|
||||||
case 'h': |
|
||||||
usage(); |
|
||||||
errorInParams = true; |
|
||||||
break; |
|
||||||
case 'V': |
|
||||||
GlobalOptions.err.println(GlobalOptions.version); |
|
||||||
break; |
|
||||||
case 'c': |
|
||||||
classPath = g.getOptarg(); |
|
||||||
break; |
|
||||||
case 'd': |
|
||||||
destDir = g.getOptarg(); |
|
||||||
break; |
|
||||||
case 'v': { |
|
||||||
String arg = g.getOptarg(); |
|
||||||
if (arg == null) |
|
||||||
GlobalOptions.verboseLevel++; |
|
||||||
else { |
|
||||||
try { |
|
||||||
GlobalOptions.verboseLevel = Integer.parseInt(arg); |
|
||||||
} catch (NumberFormatException ex) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("jode.decompiler.Main: Argument `" |
|
||||||
+arg+"' to --verbose must be numeric:"); |
|
||||||
errorInParams = true; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
case 'D': { |
|
||||||
String arg = g.getOptarg(); |
|
||||||
if (arg == null) |
|
||||||
arg = "help"; |
|
||||||
errorInParams |= !GlobalOptions.setDebugging(arg); |
|
||||||
break; |
|
||||||
} |
|
||||||
case 's': { |
|
||||||
String arg = g.getOptarg(); |
|
||||||
if ("sun".startsWith(arg)) |
|
||||||
outputStyle = SUN_STYLE; |
|
||||||
else if ("gnu".startsWith(arg)) |
|
||||||
outputStyle = GNU_STYLE; |
|
||||||
else { |
|
||||||
GlobalOptions.err.println |
|
||||||
("jode.decompiler.Main: Unknown style `"+arg+"'."); |
|
||||||
errorInParams = true; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
case 'i': { |
|
||||||
String arg = g.getOptarg(); |
|
||||||
int comma = arg.indexOf(','); |
|
||||||
try { |
|
||||||
int packLimit = Integer.parseInt(arg.substring(0, comma)); |
|
||||||
if (packLimit == 0) |
|
||||||
packLimit = Integer.MAX_VALUE; |
|
||||||
if (packLimit < 0) |
|
||||||
throw new IllegalArgumentException(); |
|
||||||
int clazzLimit = Integer.parseInt(arg.substring(comma+1)); |
|
||||||
if (clazzLimit == 0) |
|
||||||
clazzLimit = Integer.MAX_VALUE; |
|
||||||
if (clazzLimit < 0) |
|
||||||
throw new IllegalArgumentException(); |
|
||||||
|
|
||||||
importPackageLimit = packLimit; |
|
||||||
importClassLimit = clazzLimit; |
|
||||||
|
|
||||||
} catch (RuntimeException ex) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("jode.decompiler.Main: Invalid argument for -i option."); |
|
||||||
errorInParams = true; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
default: |
|
||||||
if (opt >= OPTION_START && opt <= OPTION_END) { |
|
||||||
errorInParams |= !handleOption(opt-OPTION_START, |
|
||||||
g.getLongind(), |
|
||||||
g.getOptarg()); |
|
||||||
} else |
|
||||||
errorInParams = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (errorInParams) |
|
||||||
return; |
|
||||||
ClassInfo.setClassPath(classPath.toString()); |
|
||||||
ImportHandler imports = new ImportHandler(importPackageLimit, |
|
||||||
importClassLimit); |
|
||||||
|
|
||||||
ZipOutputStream destZip = null; |
|
||||||
TabbedPrintWriter writer = null; |
|
||||||
if (destDir == null) |
|
||||||
writer = new TabbedPrintWriter(System.out, imports); |
|
||||||
else if (destDir.toLowerCase().endsWith(".zip") |
|
||||||
|| destDir.toLowerCase().endsWith(".jar")) { |
|
||||||
try { |
|
||||||
destZip = new ZipOutputStream(new FileOutputStream(destDir)); |
|
||||||
} catch (IOException ex) { |
|
||||||
GlobalOptions.err.println("Can't open zip file "+destDir); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
return; |
|
||||||
} |
|
||||||
writer = new TabbedPrintWriter(new BufferedOutputStream(destZip), |
|
||||||
imports, false); |
|
||||||
} |
|
||||||
for (int i= g.getOptind(); i< params.length; i++) { |
|
||||||
try { |
|
||||||
ClassInfo clazz; |
|
||||||
try { |
|
||||||
clazz = ClassInfo.forName(params[i]); |
|
||||||
} catch (IllegalArgumentException ex) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("`"+params[i]+"' is not a class name"); |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (skipClass(clazz)) |
|
||||||
continue; |
|
||||||
|
|
||||||
String filename = |
|
||||||
params[i].replace('.', File.separatorChar)+".java"; |
|
||||||
if (destZip != null) { |
|
||||||
writer.flush(); |
|
||||||
destZip.putNextEntry(new ZipEntry(filename)); |
|
||||||
} else if (destDir != null) { |
|
||||||
File file = new File (destDir, filename); |
|
||||||
File directory = new File(file.getParent()); |
|
||||||
if (!directory.exists() && !directory.mkdirs()) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("Could not create directory " |
|
||||||
+ directory.getPath() + ", check permissions."); |
|
||||||
} |
|
||||||
writer = new TabbedPrintWriter |
|
||||||
(new BufferedOutputStream(new FileOutputStream(file)), |
|
||||||
imports, false); |
|
||||||
} |
|
||||||
|
|
||||||
GlobalOptions.err.println(params[i]); |
|
||||||
|
|
||||||
ClassAnalyzer clazzAna = new ClassAnalyzer(clazz, imports); |
|
||||||
clazzAna.dumpJavaFile(writer); |
|
||||||
|
|
||||||
if (destZip != null) { |
|
||||||
writer.flush(); |
|
||||||
destZip.closeEntry(); |
|
||||||
} else if (destDir != null) |
|
||||||
writer.close(); |
|
||||||
/* Now is a good time to clean up */ |
|
||||||
System.gc(); |
|
||||||
} catch (IOException ex) { |
|
||||||
GlobalOptions.err.println |
|
||||||
("Can't write source of "+params[i]+"."); |
|
||||||
GlobalOptions.err.println("Check the permissions."); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
} |
|
||||||
} |
|
||||||
if (destZip != null) { |
|
||||||
try { |
|
||||||
destZip.close(); |
|
||||||
} catch (IOException ex) { |
|
||||||
GlobalOptions.err.println("Can't close Zipfile"); |
|
||||||
ex.printStackTrace(GlobalOptions.err); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,51 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
Analyzer.java \
|
|
||||||
Applet.java \
|
|
||||||
ClassAnalyzer.java \
|
|
||||||
ClassDeclarer.java \
|
|
||||||
DeadCodeAnalysis.java \
|
|
||||||
Declarable.java \
|
|
||||||
Decompiler.java \
|
|
||||||
FieldAnalyzer.java \
|
|
||||||
ImportHandler.java \
|
|
||||||
LocalInfo.java \
|
|
||||||
LocalVarEntry.java \
|
|
||||||
LocalVariableRangeList.java \
|
|
||||||
LocalVariableTable.java \
|
|
||||||
Main.java \
|
|
||||||
MethodAnalyzer.java \
|
|
||||||
Opcodes.java \
|
|
||||||
Options.java \
|
|
||||||
OuterValueListener.java \
|
|
||||||
OuterValues.java \
|
|
||||||
ProgressListener.java \
|
|
||||||
Scope.java \
|
|
||||||
TabbedPrintWriter.java \
|
|
||||||
Window.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
@ -1,35 +0,0 @@ |
|||||||
/* ArrayStoreOperator Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.expr; |
|
||||||
import jode.type.Type; |
|
||||||
import jode.type.ArrayType; |
|
||||||
import jode.decompiler.TabbedPrintWriter; |
|
||||||
|
|
||||||
public class ArrayStoreOperator extends ArrayLoadOperator |
|
||||||
implements LValueExpression { |
|
||||||
|
|
||||||
public ArrayStoreOperator(Type type) { |
|
||||||
super(type); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean matches(Operator loadop) { |
|
||||||
return loadop instanceof ArrayLoadOperator; |
|
||||||
} |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
ArrayLengthOperator.java \
|
|
||||||
ArrayLoadOperator.java \
|
|
||||||
ArrayStoreOperator.java \
|
|
||||||
BinaryOperator.java \
|
|
||||||
CheckCastOperator.java \
|
|
||||||
CheckNullOperator.java \
|
|
||||||
ClassFieldOperator.java \
|
|
||||||
CombineableOperator.java \
|
|
||||||
CompareBinaryOperator.java \
|
|
||||||
CompareToIntOperator.java \
|
|
||||||
CompareUnaryOperator.java \
|
|
||||||
ConstOperator.java \
|
|
||||||
ConstantArrayOperator.java \
|
|
||||||
ConvertOperator.java \
|
|
||||||
Expression.java \
|
|
||||||
FieldOperator.java \
|
|
||||||
GetFieldOperator.java \
|
|
||||||
IIncOperator.java \
|
|
||||||
IfThenElseOperator.java \
|
|
||||||
InstanceOfOperator.java \
|
|
||||||
InvokeOperator.java \
|
|
||||||
LValueExpression.java \
|
|
||||||
LocalLoadOperator.java \
|
|
||||||
LocalStoreOperator.java \
|
|
||||||
LocalVarOperator.java \
|
|
||||||
MatchableOperator.java \
|
|
||||||
MonitorEnterOperator.java \
|
|
||||||
MonitorExitOperator.java \
|
|
||||||
NewArrayOperator.java \
|
|
||||||
NewOperator.java \
|
|
||||||
NoArgOperator.java \
|
|
||||||
NopOperator.java \
|
|
||||||
Operator.java \
|
|
||||||
OuterLocalOperator.java \
|
|
||||||
PopOperator.java \
|
|
||||||
PrePostFixOperator.java \
|
|
||||||
PutFieldOperator.java \
|
|
||||||
ShiftOperator.java \
|
|
||||||
SimpleOperator.java \
|
|
||||||
StoreInstruction.java \
|
|
||||||
StringAddOperator.java \
|
|
||||||
ThisOperator.java \
|
|
||||||
UnaryOperator.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
@ -1,68 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
BreakBlock.java \
|
|
||||||
BreakableBlock.java \
|
|
||||||
CaseBlock.java \
|
|
||||||
CatchBlock.java \
|
|
||||||
CombineIfGotoExpressions.java \
|
|
||||||
CompleteSynchronized.java \
|
|
||||||
ConditionalBlock.java \
|
|
||||||
ContinueBlock.java \
|
|
||||||
CreateAssignExpression.java \
|
|
||||||
CreateCheckNull.java \
|
|
||||||
CreateClassField.java \
|
|
||||||
CreateConstantArray.java \
|
|
||||||
CreateExpression.java \
|
|
||||||
CreateForInitializer.java \
|
|
||||||
CreateIfThenElseOperator.java \
|
|
||||||
CreateNewConstructor.java \
|
|
||||||
CreatePrePostIncExpression.java \
|
|
||||||
DescriptionBlock.java \
|
|
||||||
EmptyBlock.java \
|
|
||||||
FinallyBlock.java \
|
|
||||||
FlowBlock.java \
|
|
||||||
IfThenElseBlock.java \
|
|
||||||
InstructionBlock.java \
|
|
||||||
InstructionContainer.java \
|
|
||||||
JsrBlock.java \
|
|
||||||
Jump.java \
|
|
||||||
LoopBlock.java \
|
|
||||||
RetBlock.java \
|
|
||||||
ReturnBlock.java \
|
|
||||||
SequentialBlock.java \
|
|
||||||
SpecialBlock.java \
|
|
||||||
StructuredBlock.java \
|
|
||||||
SwitchBlock.java \
|
|
||||||
SynchronizedBlock.java \
|
|
||||||
ThrowBlock.java \
|
|
||||||
TransformConstructors.java \
|
|
||||||
TransformExceptionHandlers.java \
|
|
||||||
TryBlock.java \
|
|
||||||
VariableSet.java \
|
|
||||||
VariableStack.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,982 +0,0 @@ |
|||||||
/* TransformExceptionHandlers Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.flow; |
|
||||||
import jode.AssertError; |
|
||||||
import jode.GlobalOptions; |
|
||||||
import jode.type.Type; |
|
||||||
import jode.decompiler.LocalInfo; |
|
||||||
import jode.expr.*; |
|
||||||
|
|
||||||
import @COLLECTIONS@.TreeSet; |
|
||||||
import @COLLECTIONS@.SortedSet; |
|
||||||
import @COLLECTIONS@.Set; |
|
||||||
import @COLLECTIONS@.Map; |
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
import @COLLECTIONEXTRA@.Comparable; |
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
* @author Jochen Hoenicke |
|
||||||
*/ |
|
||||||
public class TransformExceptionHandlers { |
|
||||||
SortedSet handlers; |
|
||||||
|
|
||||||
static class Handler implements Comparable { |
|
||||||
FlowBlock start; |
|
||||||
int endAddr; |
|
||||||
FlowBlock handler; |
|
||||||
Type type; |
|
||||||
|
|
||||||
public Handler(FlowBlock tryBlock, int end, |
|
||||||
FlowBlock catchBlock, Type type) { |
|
||||||
this.start = tryBlock; |
|
||||||
this.endAddr = end; |
|
||||||
this.handler = catchBlock; |
|
||||||
this.type = type; |
|
||||||
} |
|
||||||
|
|
||||||
public int compareTo (Object o) { |
|
||||||
Handler second = (Handler) o; |
|
||||||
|
|
||||||
/* First sort by start offsets, highest address first...*/ |
|
||||||
if (start.getAddr() != second.start.getAddr()) |
|
||||||
/* this subtraction is save since addresses are only 16 bit */ |
|
||||||
return second.start.getAddr() - start.getAddr(); |
|
||||||
|
|
||||||
/* ...Second sort by end offsets, lowest address first... |
|
||||||
* this will move the innermost blocks to the beginning. */ |
|
||||||
if (endAddr != second.endAddr) |
|
||||||
return endAddr - second.endAddr; |
|
||||||
|
|
||||||
/* ...Last sort by handler offsets, lowest first */ |
|
||||||
if (handler.getAddr() != second.handler.getAddr()) |
|
||||||
return handler.getAddr() - second.handler.getAddr(); |
|
||||||
|
|
||||||
/* ...Last sort by typecode signature. Shouldn't happen to often. |
|
||||||
*/ |
|
||||||
if (type == second.type) |
|
||||||
return 0; |
|
||||||
if (type == null) |
|
||||||
return -1; |
|
||||||
if (second.type == null) |
|
||||||
return 1; |
|
||||||
return type.getTypeSignature() |
|
||||||
.compareTo(second.type.getTypeSignature()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public TransformExceptionHandlers() { |
|
||||||
handlers = new TreeSet(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Add an exception Handler. |
|
||||||
* @param start The start address of the exception range. |
|
||||||
* @param end The end address of the exception range + 1. |
|
||||||
* @param handler The address of the handler. |
|
||||||
* @param type The type of the exception, null for ALL. |
|
||||||
*/ |
|
||||||
public void addHandler(FlowBlock tryBlock, int end, |
|
||||||
FlowBlock catchBlock, Type type) { |
|
||||||
handlers.add(new Handler(tryBlock, end, catchBlock, type)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* simple try catch block: |
|
||||||
* |
|
||||||
* try-header |
|
||||||
* |- first instruction |
|
||||||
* | ... |
|
||||||
* | last instruction |
|
||||||
* |- optional jump (last+1) |
|
||||||
* | ... |
|
||||||
* `- catch block |
|
||||||
*/ |
|
||||||
static void analyzeCatchBlock(Type type, |
|
||||||
FlowBlock tryFlow, FlowBlock catchFlow) { |
|
||||||
|
|
||||||
StructuredBlock catchBlock = catchFlow.block; |
|
||||||
|
|
||||||
CatchBlock newBlock = new CatchBlock(type); |
|
||||||
((TryBlock)tryFlow.block).addCatchBlock(newBlock); |
|
||||||
newBlock.setCatchBlock(catchFlow.block); |
|
||||||
tryFlow.mergeSuccessors(catchFlow); |
|
||||||
tryFlow.mergeAddr(catchFlow); |
|
||||||
} |
|
||||||
|
|
||||||
/* And now the complicated parts. */ |
|
||||||
|
|
||||||
/** |
|
||||||
* This transforms a sub routine, that is checks if the beginning |
|
||||||
* local assignment matches the final ret and then returns. |
|
||||||
*/ |
|
||||||
boolean transformSubRoutine(StructuredBlock subRoutine) { |
|
||||||
if (!(subRoutine instanceof SequentialBlock) |
|
||||||
|| !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock)) |
|
||||||
return false; |
|
||||||
SequentialBlock sequBlock = (SequentialBlock) subRoutine; |
|
||||||
InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0]; |
|
||||||
|
|
||||||
if (!(instr.getInstruction() instanceof StoreInstruction) |
|
||||||
|| !(((StoreInstruction) instr.getInstruction()).getLValue() |
|
||||||
instanceof LocalStoreOperator)) |
|
||||||
return false; |
|
||||||
LocalStoreOperator store = (LocalStoreOperator) |
|
||||||
((StoreInstruction)instr.getInstruction()).getLValue(); |
|
||||||
|
|
||||||
while (sequBlock.subBlocks[1] instanceof SequentialBlock) |
|
||||||
sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; |
|
||||||
|
|
||||||
/* XXX - Check that the local isn't used for any other purposes |
|
||||||
* than RET and replace any RET with a flow control to end of |
|
||||||
* flow block. |
|
||||||
* |
|
||||||
* This is a complicated task which isn't needed for javac nor jikes. |
|
||||||
*/ |
|
||||||
if (sequBlock.subBlocks[1].jump != null |
|
||||||
&& sequBlock.subBlocks[1].jump.destination |
|
||||||
== FlowBlock.END_OF_METHOD) { |
|
||||||
instr.removeBlock(); |
|
||||||
return true; |
|
||||||
} |
|
||||||
if (! (sequBlock.subBlocks[1] instanceof RetBlock) |
|
||||||
|| !(((RetBlock)sequBlock.subBlocks[1]) |
|
||||||
.local.equals(store.getLocalInfo()))) |
|
||||||
return false; |
|
||||||
|
|
||||||
instr.removeBlock(); |
|
||||||
sequBlock.subBlocks[1].removeBlock(); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Remove the JSR's jumping to the specified subRoutine. It |
|
||||||
* is checked if the next block is a leaving instruction, and |
|
||||||
* otherwise the JsrBlock is not removed (to give the user a |
|
||||||
* hint that something went wrong). This will also remove the |
|
||||||
* local javac generates for returns. |
|
||||||
* @param tryFlow the FlowBLock of the try block. |
|
||||||
* @param subRoutine the FlowBlock of the sub routine. |
|
||||||
*/ |
|
||||||
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) { |
|
||||||
for (Jump jumps = tryFlow.removeJumps(subRoutine); |
|
||||||
jumps != null; jumps = jumps.next) { |
|
||||||
|
|
||||||
StructuredBlock prev = jumps.prev; |
|
||||||
prev.removeJump(); |
|
||||||
if (prev instanceof EmptyBlock |
|
||||||
&& prev.outer instanceof JsrBlock) { |
|
||||||
if (prev.outer.getNextFlowBlock() != null) { |
|
||||||
/* The jsr is directly before a jump, okay. */ |
|
||||||
prev.outer.removeBlock(); |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (prev.outer.outer instanceof SequentialBlock |
|
||||||
&& prev.outer.outer.getSubBlocks()[0] == prev.outer) { |
|
||||||
SequentialBlock seq = (SequentialBlock) prev.outer.outer; |
|
||||||
if (seq.subBlocks[1] instanceof JsrBlock |
|
||||||
|| (seq.subBlocks[1] instanceof SequentialBlock |
|
||||||
&& seq.subBlocks[1].getSubBlocks()[0] |
|
||||||
instanceof JsrBlock)) { |
|
||||||
/* The jsr is followed by a jsr, okay. */ |
|
||||||
prev.outer.removeBlock(); |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (seq.subBlocks[1] instanceof ReturnBlock |
|
||||||
&& !(seq.subBlocks[1] instanceof ThrowBlock)) { |
|
||||||
|
|
||||||
/* The jsr is followed by a return, okay. */ |
|
||||||
ReturnBlock ret = (ReturnBlock) seq.subBlocks[1]; |
|
||||||
prev.outer.removeBlock(); |
|
||||||
|
|
||||||
if (ret.outer != null |
|
||||||
&& ret.outer instanceof SequentialBlock) { |
|
||||||
/* Try to eliminate the local that javac uses |
|
||||||
* in this case. |
|
||||||
*/ |
|
||||||
try { |
|
||||||
StoreInstruction store = (StoreInstruction) |
|
||||||
((InstructionBlock) |
|
||||||
ret.outer.getSubBlocks()[0]).instr; |
|
||||||
LocalInfo local = |
|
||||||
((LocalStoreOperator) store.getLValue()) |
|
||||||
.getLocalInfo(); |
|
||||||
if (store.lvalueMatches |
|
||||||
((LocalLoadOperator) |
|
||||||
ret.getInstruction())) { |
|
||||||
Expression expr = |
|
||||||
store.getSubExpressions()[1]; |
|
||||||
ret.setInstruction(expr); |
|
||||||
ret.replace(ret.outer); |
|
||||||
} |
|
||||||
} catch(ClassCastException ex) { |
|
||||||
/* didn't succeed */ |
|
||||||
} |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
/* Now we have a jump to the subroutine, that is wrong. |
|
||||||
* We complain here. |
|
||||||
*/ |
|
||||||
DescriptionBlock msg |
|
||||||
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); |
|
||||||
prev.appendBlock(msg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine, |
|
||||||
int startOutExit, int endOutExit) { |
|
||||||
boolean foundSub = false; |
|
||||||
Iterator iter = tryFlow.getSuccessors().iterator(); |
|
||||||
dest_loop: |
|
||||||
while (iter.hasNext()) { |
|
||||||
FlowBlock dest = (FlowBlock) iter.next(); |
|
||||||
if (dest == subRoutine) { |
|
||||||
foundSub = true; |
|
||||||
continue dest_loop; |
|
||||||
} |
|
||||||
|
|
||||||
boolean isFirstJump = true; |
|
||||||
for (Jump jumps = tryFlow.getJumps(dest); |
|
||||||
jumps != null; jumps = jumps.next, isFirstJump = false) { |
|
||||||
|
|
||||||
StructuredBlock prev = jumps.prev; |
|
||||||
if (prev instanceof ThrowBlock) { |
|
||||||
/* The jump is a throw. We have a catch-all block |
|
||||||
* that will do the finally. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (prev instanceof JsrBlock) { |
|
||||||
/* The jump is directly preceeded by a jsr. |
|
||||||
* Everything okay. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (prev instanceof EmptyBlock |
|
||||||
&& prev.outer instanceof JsrBlock) { |
|
||||||
/* If jump is a jsr check the outer |
|
||||||
* block instead. |
|
||||||
*/ |
|
||||||
prev = prev.outer; |
|
||||||
} |
|
||||||
if ((prev instanceof ReturnBlock |
|
||||||
|| prev instanceof JsrBlock) |
|
||||||
&& prev.outer instanceof SequentialBlock) { |
|
||||||
SequentialBlock seq = (SequentialBlock) prev.outer; |
|
||||||
if (seq.subBlocks[1] == prev |
|
||||||
&& (seq.subBlocks[0] instanceof JsrBlock)) { |
|
||||||
/* The jump is preceeded by another jsr, okay. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (seq.subBlocks[0] == prev |
|
||||||
&& seq.outer instanceof SequentialBlock |
|
||||||
&& (seq.outer.getSubBlocks()[0] instanceof JsrBlock)) { |
|
||||||
/* Again the jump is preceeded by another jsr, okay. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (isFirstJump) { |
|
||||||
/* Now we have a jump that is not preceded by the |
|
||||||
* jsr. There's a last chance: the jump jumps |
|
||||||
* directly to a correct jsr instruction, which |
|
||||||
* lies outside the try/catch block. |
|
||||||
*/ |
|
||||||
if (jumps.destination.predecessors.size() == 1 |
|
||||||
&& jumps.destination.getAddr() >= startOutExit |
|
||||||
&& jumps.destination.getNextAddr() <= endOutExit) { |
|
||||||
jumps.destination.analyze(startOutExit, endOutExit); |
|
||||||
|
|
||||||
StructuredBlock sb = jumps.destination.block; |
|
||||||
if (sb instanceof SequentialBlock) |
|
||||||
sb = sb.getSubBlocks()[0]; |
|
||||||
if (sb instanceof JsrBlock |
|
||||||
&& sb.getSubBlocks()[0] instanceof EmptyBlock |
|
||||||
&& (sb.getSubBlocks()[0].jump.destination |
|
||||||
== subRoutine)) { |
|
||||||
StructuredBlock jsrInner = sb.getSubBlocks()[0]; |
|
||||||
jumps.destination.removeSuccessor(jsrInner.jump); |
|
||||||
jsrInner.removeJump(); |
|
||||||
sb.removeBlock(); |
|
||||||
continue dest_loop; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Now we have a jump with a wrong destination. |
|
||||||
* Complain! |
|
||||||
*/ |
|
||||||
DescriptionBlock msg |
|
||||||
= new DescriptionBlock("ERROR: NO JSR TO FINALLY"); |
|
||||||
prev.appendBlock(msg); |
|
||||||
msg.moveJump(jumps); |
|
||||||
} |
|
||||||
} |
|
||||||
if (foundSub) |
|
||||||
removeJSR(tryFlow, subRoutine); |
|
||||||
} |
|
||||||
|
|
||||||
static boolean isMonitorExit(Expression instr, LocalInfo local) { |
|
||||||
if (instr instanceof MonitorExitOperator) { |
|
||||||
MonitorExitOperator monExit = (MonitorExitOperator)instr; |
|
||||||
if (monExit.getFreeOperandCount() == 0 |
|
||||||
&& monExit.getSubExpressions()[0] instanceof LocalLoadOperator |
|
||||||
&& (((LocalLoadOperator) monExit.getSubExpressions()[0]) |
|
||||||
.getLocalInfo().getSlot() == local.getSlot())) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
boolean isMonitorExitSubRoutine(FlowBlock subRoutine, LocalInfo local) { |
|
||||||
if (transformSubRoutine(subRoutine.block)) { |
|
||||||
if (subRoutine.block instanceof InstructionBlock) { |
|
||||||
Expression instr = |
|
||||||
((InstructionBlock)subRoutine.block) |
|
||||||
.getInstruction(); |
|
||||||
if (isMonitorExit(instr, local)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, |
|
||||||
int startOutExit, int endOutExit, |
|
||||||
int startMonExit, int endMonExit) { |
|
||||||
FlowBlock subRoutine = null; |
|
||||||
Iterator succs = tryFlow.getSuccessors().iterator(); |
|
||||||
dest_loop: |
|
||||||
while (succs.hasNext()) { |
|
||||||
boolean isFirstJump = true; |
|
||||||
FlowBlock successor = (FlowBlock) succs.next(); |
|
||||||
for (Jump jumps = tryFlow.getJumps(successor); |
|
||||||
jumps != null; jumps = jumps.next, isFirstJump = false) { |
|
||||||
|
|
||||||
StructuredBlock prev = jumps.prev; |
|
||||||
|
|
||||||
if (prev instanceof ThrowBlock) { |
|
||||||
/* The jump is a throw. We have a catch all block |
|
||||||
* that will do the monitorexit. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (prev instanceof JsrBlock) { |
|
||||||
/* The jump is directly preceeded by a jsr. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (prev instanceof EmptyBlock |
|
||||||
&& prev.outer instanceof JsrBlock) { |
|
||||||
/* If jump is a jsr check the outer |
|
||||||
* block instead. |
|
||||||
*/ |
|
||||||
prev = prev.outer; |
|
||||||
} |
|
||||||
|
|
||||||
/* If the block is a jsr or a return block, check if |
|
||||||
* it is preceeded by another jsr. |
|
||||||
*/ |
|
||||||
if ((prev instanceof JsrBlock |
|
||||||
|| prev instanceof ReturnBlock) |
|
||||||
&& prev.outer instanceof SequentialBlock) { |
|
||||||
SequentialBlock seq = (SequentialBlock) prev.outer; |
|
||||||
StructuredBlock pred = null; |
|
||||||
if (seq.subBlocks[1] == prev) |
|
||||||
pred = seq.subBlocks[0]; |
|
||||||
else if (seq.outer instanceof SequentialBlock) |
|
||||||
pred = seq.outer.getSubBlocks()[0]; |
|
||||||
|
|
||||||
if (pred != null) { |
|
||||||
if (pred instanceof JsrBlock) |
|
||||||
/* The jump is preceeded by another jsr, okay. |
|
||||||
*/ |
|
||||||
continue; |
|
||||||
|
|
||||||
if (pred instanceof InstructionBlock) { |
|
||||||
Expression instr = |
|
||||||
((InstructionBlock)pred).getInstruction(); |
|
||||||
if (isMonitorExit(instr, local)) |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (prev instanceof InstructionBlock |
|
||||||
&& isMonitorExit(((InstructionBlock)prev).instr, local)) { |
|
||||||
/* This is probably the last expression in the |
|
||||||
* synchronized block, and has the right monitor exit |
|
||||||
* attached. Remove this block. |
|
||||||
*/ |
|
||||||
prev.removeBlock(); |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (isFirstJump) { |
|
||||||
/* This is the first jump to that destination. |
|
||||||
* Check if the destination does the monitorExit |
|
||||||
*/ |
|
||||||
|
|
||||||
/* The block is a jsr that is not preceeded by |
|
||||||
* another jsr. This must be the monitorexit |
|
||||||
* subroutine. |
|
||||||
*/ |
|
||||||
if (prev instanceof JsrBlock) { |
|
||||||
if (subRoutine == null |
|
||||||
&& successor.getAddr() >= startMonExit |
|
||||||
&& successor.getNextAddr() <= endMonExit) { |
|
||||||
successor.analyze(startMonExit, endMonExit); |
|
||||||
|
|
||||||
if (isMonitorExitSubRoutine(successor, local)) |
|
||||||
subRoutine = successor; |
|
||||||
} |
|
||||||
|
|
||||||
if (subRoutine == successor) |
|
||||||
continue dest_loop; |
|
||||||
} |
|
||||||
|
|
||||||
/* Now we have a jump that is not preceded by a |
|
||||||
* monitorexit. There's a last chance: the jump |
|
||||||
* jumps directly to the correct monitorexit |
|
||||||
* instruction, which lies outside the try/catch |
|
||||||
* block. |
|
||||||
*/ |
|
||||||
if (successor.predecessors.size() == 1 |
|
||||||
&& successor.getAddr() >= startOutExit |
|
||||||
&& successor.getNextAddr() <= endOutExit) { |
|
||||||
successor.analyze(startOutExit, endOutExit); |
|
||||||
|
|
||||||
StructuredBlock sb = successor.block; |
|
||||||
if (sb instanceof SequentialBlock) |
|
||||||
sb = sb.getSubBlocks()[0]; |
|
||||||
if (sb instanceof JsrBlock |
|
||||||
&& sb.getSubBlocks()[0] instanceof EmptyBlock) { |
|
||||||
StructuredBlock jsrInner = sb.getSubBlocks()[0]; |
|
||||||
FlowBlock dest = jsrInner.jump.destination; |
|
||||||
if (subRoutine == null |
|
||||||
&& dest.getAddr() >= startMonExit |
|
||||||
&& dest.getNextAddr() <= endMonExit) { |
|
||||||
dest.analyze(startMonExit, endMonExit); |
|
||||||
if (isMonitorExitSubRoutine(dest, local)) |
|
||||||
subRoutine = dest; |
|
||||||
} |
|
||||||
|
|
||||||
if (subRoutine == dest) { |
|
||||||
sb.removeBlock(); |
|
||||||
continue dest_loop; |
|
||||||
} |
|
||||||
} |
|
||||||
if (sb instanceof InstructionBlock) { |
|
||||||
Expression instr = ((InstructionBlock)sb) |
|
||||||
.getInstruction(); |
|
||||||
if (isMonitorExit(instr, local)) { |
|
||||||
sb.removeBlock(); |
|
||||||
continue dest_loop; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Complain! |
|
||||||
*/ |
|
||||||
DescriptionBlock msg |
|
||||||
= new DescriptionBlock("ERROR: NO MONITOREXIT"); |
|
||||||
prev.appendBlock(msg); |
|
||||||
msg.moveJump(jumps); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (subRoutine != null) { |
|
||||||
removeJSR(tryFlow, subRoutine); |
|
||||||
tryFlow.mergeAddr(subRoutine); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private boolean analyzeSynchronized(FlowBlock tryFlow, |
|
||||||
FlowBlock catchFlow, |
|
||||||
int endHandler) { |
|
||||||
if (!(catchFlow.block instanceof SequentialBlock |
|
||||||
&& catchFlow.block.getSubBlocks()[0] |
|
||||||
instanceof InstructionBlock)) |
|
||||||
return false; |
|
||||||
|
|
||||||
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block; |
|
||||||
Expression instr = |
|
||||||
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction(); |
|
||||||
|
|
||||||
if (instr instanceof MonitorExitOperator |
|
||||||
&& instr.getFreeOperandCount() == 0 |
|
||||||
&& (((MonitorExitOperator)instr).getSubExpressions()[0] |
|
||||||
instanceof LocalLoadOperator) |
|
||||||
&& catchBlock.subBlocks[1] instanceof ThrowBlock |
|
||||||
&& (((ThrowBlock)catchBlock.subBlocks[1]).instr |
|
||||||
instanceof NopOperator)) { |
|
||||||
|
|
||||||
/* This is a synchronized block: |
|
||||||
* |
|
||||||
* local_x = monitor object; // later
|
|
||||||
* monitorenter local_x // later
|
|
||||||
* tryFlow: |
|
||||||
* |- synchronized block |
|
||||||
* | ... |
|
||||||
* | every jump to outside is preceded by jsr subroutine-, |
|
||||||
* | ... | |
|
||||||
* |- monitorexit local_x | |
|
||||||
* ` jump after this block (without jsr monexit) | |
|
||||||
* | |
|
||||||
* catchFlow: | |
|
||||||
* local_n = stack | |
|
||||||
* monitorexit local_x | |
|
||||||
* throw local_n | |
|
||||||
* optional subroutine: <-----------------------------------' |
|
||||||
* astore_n |
|
||||||
* monitorexit local_x |
|
||||||
* return_n |
|
||||||
*/ |
|
||||||
|
|
||||||
/* Now remove the jump (after the throw) from the |
|
||||||
* catch block so that we can forget about it. |
|
||||||
*/ |
|
||||||
|
|
||||||
catchFlow.removeSuccessor(catchBlock.subBlocks[1].jump); |
|
||||||
MonitorExitOperator monexit = (MonitorExitOperator) |
|
||||||
((InstructionBlock) catchBlock.subBlocks[0]).instr; |
|
||||||
LocalInfo local = |
|
||||||
((LocalLoadOperator)monexit.getSubExpressions()[0]) |
|
||||||
.getLocalInfo(); |
|
||||||
|
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
||||||
GlobalOptions.err.println |
|
||||||
("analyzeSynchronized(" + tryFlow.getAddr() |
|
||||||
+ "," + tryFlow.getNextAddr() + "," + catchFlow.getAddr() |
|
||||||
+ "," + catchFlow.getNextAddr() + "," + endHandler + ")"); |
|
||||||
|
|
||||||
checkAndRemoveMonitorExit |
|
||||||
(tryFlow, local, |
|
||||||
tryFlow.getNextAddr(), catchFlow.getAddr(), |
|
||||||
catchFlow.getNextAddr(), endHandler); |
|
||||||
|
|
||||||
tryFlow.mergeAddr(catchFlow); |
|
||||||
SynchronizedBlock syncBlock = new SynchronizedBlock(local); |
|
||||||
TryBlock tryBlock = (TryBlock) tryFlow.block; |
|
||||||
syncBlock.replace(tryBlock); |
|
||||||
syncBlock.moveJump(tryBlock.jump); |
|
||||||
syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1 |
|
||||||
? tryBlock.subBlocks[0] : tryBlock); |
|
||||||
tryFlow.lastModified = syncBlock; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean analyzeFinally(FlowBlock tryFlow, FlowBlock catchFlow, |
|
||||||
int end) { |
|
||||||
|
|
||||||
/* Layout of a try-finally block: |
|
||||||
* |
|
||||||
* tryFlow: |
|
||||||
* |- first instruction |
|
||||||
* | ... |
|
||||||
* | every jump to outside is preceded by jsr finally |
|
||||||
* | ... |
|
||||||
* | jsr finally -----------------, |
|
||||||
* `- jump after finally | |
|
||||||
* | |
|
||||||
* catchFlow: (already checked) | |
|
||||||
* local_n = stack v |
|
||||||
* jsr finally ---------------->| |
|
||||||
* throw local_n; | |
|
||||||
* finally: <-----------------------' |
|
||||||
* astore_n |
|
||||||
* ... |
|
||||||
* return_n |
|
||||||
*/ |
|
||||||
|
|
||||||
if (!(catchFlow.block instanceof SequentialBlock) |
|
||||||
|| !(catchFlow.block.getSubBlocks()[0] |
|
||||||
instanceof InstructionBlock) |
|
||||||
|| !(catchFlow.block.getSubBlocks()[1] |
|
||||||
instanceof SequentialBlock)) |
|
||||||
return false; |
|
||||||
|
|
||||||
StructuredBlock finallyBlock = null; |
|
||||||
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block; |
|
||||||
Expression instr = |
|
||||||
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction(); |
|
||||||
catchBlock = (SequentialBlock)catchBlock.subBlocks[1]; |
|
||||||
|
|
||||||
if (catchBlock.subBlocks[0] instanceof LoopBlock) { |
|
||||||
/* In case the try block has no exit (that means, it throws |
|
||||||
* an exception), the finallyBlock was already merged with |
|
||||||
* the catchBlock. We have to check for this case separately: |
|
||||||
* |
|
||||||
* do { |
|
||||||
* JSR |
|
||||||
* break; |
|
||||||
* throw local_x |
|
||||||
* } while(false); |
|
||||||
* finallyBlock; |
|
||||||
*/ |
|
||||||
LoopBlock doWhileFalse = (LoopBlock)catchBlock.subBlocks[0]; |
|
||||||
if (doWhileFalse.type == LoopBlock.DOWHILE |
|
||||||
&& doWhileFalse.cond == LoopBlock.FALSE |
|
||||||
&& doWhileFalse.bodyBlock instanceof SequentialBlock) { |
|
||||||
finallyBlock = catchBlock.subBlocks[1]; |
|
||||||
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!(catchBlock instanceof SequentialBlock |
|
||||||
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock |
|
||||||
&& instr instanceof StoreInstruction |
|
||||||
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock)) |
|
||||||
|
|
||||||
return false; |
|
||||||
|
|
||||||
JsrBlock jsrBlock = (JsrBlock)catchBlock.getSubBlocks()[0]; |
|
||||||
ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1]; |
|
||||||
|
|
||||||
|
|
||||||
if (!(throwBlock.instr instanceof LocalLoadOperator) |
|
||||||
|| !(((StoreInstruction) instr).lvalueMatches |
|
||||||
((LocalLoadOperator) throwBlock.instr))) |
|
||||||
return false; |
|
||||||
|
|
||||||
/* Wow that was complicated :-) |
|
||||||
* But now we know that the catch block looks |
|
||||||
* exactly like it should: |
|
||||||
* |
|
||||||
* catchBlock: |
|
||||||
* JSR |
|
||||||
* finally |
|
||||||
* throw local_n <- matches the local in instr. |
|
||||||
*/ |
|
||||||
|
|
||||||
if (finallyBlock != null) { |
|
||||||
/* Check if the jsr breaks (see two comments above). We don't |
|
||||||
* need to check if it breaks to the right block, because |
|
||||||
* we know that there is only one Block around the jsr. |
|
||||||
*/ |
|
||||||
if (!(jsrBlock.innerBlock instanceof BreakBlock)) |
|
||||||
return false; |
|
||||||
|
|
||||||
/* Check if the try block has no exit (except throws) |
|
||||||
*/ |
|
||||||
Set succs = tryFlow.getSuccessors(); |
|
||||||
if (succs.size() > 0) { |
|
||||||
if (!succs.contains(FlowBlock.END_OF_METHOD)) |
|
||||||
return false; |
|
||||||
Jump throwJumps |
|
||||||
= tryFlow.getJumps(FlowBlock.END_OF_METHOD); |
|
||||||
for (/**/; throwJumps != null; |
|
||||||
throwJumps = throwJumps.next) { |
|
||||||
if (!(throwJumps.prev instanceof ThrowBlock)) |
|
||||||
/* There is a return exit in the try block */ |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
/* Remove the jump of the throw instruction. |
|
||||||
*/ |
|
||||||
catchFlow.removeSuccessor(throwBlock.jump); |
|
||||||
throwBlock.removeJump(); |
|
||||||
|
|
||||||
/* Replace the catchBlock with the finallyBlock. |
|
||||||
*/ |
|
||||||
finallyBlock.replace(catchFlow.block); |
|
||||||
transformSubRoutine(finallyBlock); |
|
||||||
|
|
||||||
tryFlow.updateInOutCatch(catchFlow); |
|
||||||
tryFlow.mergeAddr(catchFlow); |
|
||||||
finallyBlock = catchFlow.block; |
|
||||||
tryFlow.mergeSuccessors(catchFlow); |
|
||||||
|
|
||||||
} else { |
|
||||||
FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination; |
|
||||||
checkAndRemoveJSR(tryFlow, subRoutine, |
|
||||||
tryFlow.getNextAddr(), catchFlow.getAddr()); |
|
||||||
|
|
||||||
while (subRoutine.analyze(catchFlow.getNextAddr(), end)); |
|
||||||
|
|
||||||
/* Now check if the subroutine is correct and has only the |
|
||||||
* catchFlow as predecessor. |
|
||||||
*/ |
|
||||||
if (subRoutine.predecessors.size() == 1 |
|
||||||
&& transformSubRoutine(subRoutine.block)) { |
|
||||||
subRoutine.mergeAddr(catchFlow); |
|
||||||
|
|
||||||
/* Now remove the jump to the JSR from the catch block |
|
||||||
* and the jump of the throw instruction. |
|
||||||
*/ |
|
||||||
catchFlow.removeSuccessor(jsrBlock.innerBlock.jump); |
|
||||||
jsrBlock.innerBlock.removeJump(); |
|
||||||
catchFlow.removeSuccessor(throwBlock.jump); |
|
||||||
throwBlock.removeJump(); |
|
||||||
|
|
||||||
tryFlow.updateInOutCatch(subRoutine); |
|
||||||
tryFlow.mergeAddr(subRoutine); |
|
||||||
tryFlow.mergeSuccessors(subRoutine); |
|
||||||
finallyBlock = subRoutine.block; |
|
||||||
} else { |
|
||||||
catchFlow.removeSuccessor(throwBlock.jump); |
|
||||||
throwBlock.removeJump(); |
|
||||||
finallyBlock = jsrBlock; |
|
||||||
|
|
||||||
finallyBlock.replace(catchFlow.block); |
|
||||||
transformSubRoutine(finallyBlock); |
|
||||||
|
|
||||||
tryFlow.updateInOutCatch(catchFlow); |
|
||||||
tryFlow.mergeAddr(catchFlow); |
|
||||||
finallyBlock = catchFlow.block; |
|
||||||
tryFlow.mergeSuccessors(catchFlow); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
TryBlock tryBlock = (TryBlock)tryFlow.block; |
|
||||||
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { |
|
||||||
/* remove the surrounding tryBlock */ |
|
||||||
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; |
|
||||||
innerTry.gen = tryBlock.gen; |
|
||||||
innerTry.replace(tryBlock); |
|
||||||
tryBlock = innerTry; |
|
||||||
tryFlow.lastModified = tryBlock; |
|
||||||
tryFlow.block = tryBlock; |
|
||||||
} |
|
||||||
FinallyBlock newBlock = new FinallyBlock(); |
|
||||||
newBlock.setCatchBlock(finallyBlock); |
|
||||||
tryBlock.addCatchBlock(newBlock); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean analyzeSpecialFinally(FlowBlock tryFlow, |
|
||||||
FlowBlock catchFlow, int end) { |
|
||||||
|
|
||||||
StructuredBlock firstInstr = |
|
||||||
catchFlow.block instanceof SequentialBlock |
|
||||||
? catchFlow.block.getSubBlocks()[0]: catchFlow.block; |
|
||||||
|
|
||||||
if (firstInstr instanceof SpecialBlock |
|
||||||
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP |
|
||||||
&& ((SpecialBlock)firstInstr).count == 1) { |
|
||||||
|
|
||||||
/* This is a special try/finally-block, where |
|
||||||
* the finally block ends with a break, return or |
|
||||||
* similar. |
|
||||||
*/ |
|
||||||
|
|
||||||
FlowBlock succ = (firstInstr.jump != null) ? |
|
||||||
firstInstr.jump.destination : null; |
|
||||||
boolean hasExit = false; |
|
||||||
Iterator iter = tryFlow.getSuccessors().iterator(); |
|
||||||
while (iter.hasNext()) { |
|
||||||
FlowBlock dest = (FlowBlock) iter.next(); |
|
||||||
if (dest == succ) |
|
||||||
continue; |
|
||||||
if (dest != FlowBlock.END_OF_METHOD) { |
|
||||||
/* There is another exit in the try block, bad */ |
|
||||||
return false; |
|
||||||
} |
|
||||||
for (Jump throwJumps = (Jump) tryFlow.getJumps(dest); |
|
||||||
throwJumps != null; throwJumps = throwJumps.next) { |
|
||||||
if (!(throwJumps.prev instanceof ThrowBlock)) { |
|
||||||
/* There is a return exit in the try block */ |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* remove the pop now */ |
|
||||||
firstInstr.removeBlock(); |
|
||||||
tryFlow.mergeAddr(catchFlow); |
|
||||||
|
|
||||||
if (succ != null) { |
|
||||||
Jump jumps = tryFlow.removeJumps(succ); |
|
||||||
/* Handle the jumps in the tryFlow. |
|
||||||
*/ |
|
||||||
jumps = tryFlow.resolveSomeJumps(jumps, succ); |
|
||||||
tryFlow.resolveRemaining(jumps); |
|
||||||
} |
|
||||||
|
|
||||||
TryBlock tryBlock = (TryBlock)tryFlow.block; |
|
||||||
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { |
|
||||||
/* remove the unnecessary tryBlock */ |
|
||||||
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; |
|
||||||
innerTry.gen = tryBlock.gen; |
|
||||||
innerTry.replace(tryBlock); |
|
||||||
tryBlock = innerTry; |
|
||||||
tryFlow.lastModified = innerTry; |
|
||||||
} |
|
||||||
FinallyBlock newBlock = new FinallyBlock(); |
|
||||||
tryBlock.addCatchBlock(newBlock); |
|
||||||
/* try block has no successors */ |
|
||||||
|
|
||||||
if (succ != null && succ.predecessors.size() == 1) { |
|
||||||
while (succ.analyze(catchFlow.getNextAddr(), end)); |
|
||||||
tryFlow.mergeAddr(succ); |
|
||||||
tryFlow.removeJumps(succ); |
|
||||||
newBlock.setCatchBlock(succ.block); |
|
||||||
tryFlow.mergeSuccessors(succ); |
|
||||||
} else { |
|
||||||
/* Put the catchBlock in instead. |
|
||||||
*/ |
|
||||||
newBlock.setCatchBlock(catchFlow.block); |
|
||||||
tryFlow.mergeSuccessors(catchFlow); |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Analyzes all exception handlers to try/catch/finally or |
|
||||||
* synchronized blocks. |
|
||||||
*/ |
|
||||||
public void analyze() { |
|
||||||
/* Check if try/catch ranges are okay. The following succeeds |
|
||||||
* for all classes generated by the sun java compiler, but hand |
|
||||||
* optimized classes (or generated by other compilers) will fail. |
|
||||||
*/ |
|
||||||
{ |
|
||||||
Handler last = null; |
|
||||||
for (Iterator i = handlers.iterator(); i.hasNext(); ) { |
|
||||||
Handler exc = (Handler) i.next(); |
|
||||||
int start = exc.start.getAddr(); |
|
||||||
int end = exc.endAddr; |
|
||||||
int handler = exc.handler.getAddr(); |
|
||||||
if (start >= end || handler < end) |
|
||||||
throw new AssertError |
|
||||||
("ExceptionHandler order failed: not " |
|
||||||
+ start + " < " + end + " <= " + handler); |
|
||||||
if (last != null |
|
||||||
&& (last.start.getAddr() != start || last.endAddr != end)) { |
|
||||||
/* The last handler does catch another range. |
|
||||||
* Due to the order: |
|
||||||
* start < last.start.getAddr() || end > last.end.getAddr() |
|
||||||
*/ |
|
||||||
if (end > last.start.getAddr() && end < last.endAddr) |
|
||||||
throw new AssertError |
|
||||||
("Exception handlers ranges are intersecting: [" |
|
||||||
+ last.start.getAddr()+", "+last.endAddr+"] and [" |
|
||||||
+ start+", "+end+"]."); |
|
||||||
} |
|
||||||
last = exc; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
{ |
|
||||||
Iterator i = handlers.iterator(); |
|
||||||
Handler exc = null; |
|
||||||
Handler next = i.hasNext() ? (Handler) i.next() : null; |
|
||||||
while(next != null) { |
|
||||||
Handler last = exc; |
|
||||||
exc = next; |
|
||||||
next = i.hasNext() ? (Handler) i.next() : null; |
|
||||||
int endHandler = Integer.MAX_VALUE; |
|
||||||
/* If the next exception handler catches a bigger range |
|
||||||
* it must surround the handler completely. |
|
||||||
*/ |
|
||||||
if (next != null && next.endAddr > exc.endAddr) |
|
||||||
endHandler = next.endAddr; |
|
||||||
|
|
||||||
FlowBlock tryFlow = exc.start; |
|
||||||
tryFlow.checkConsistent(); |
|
||||||
|
|
||||||
if (last == null || exc.type == null |
|
||||||
|| last.start.getAddr() != exc.start.getAddr() |
|
||||||
|| last.endAddr != exc.endAddr) { |
|
||||||
/* The last handler does catch another range. |
|
||||||
* Create a new try block. |
|
||||||
*/ |
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
||||||
GlobalOptions.err.println |
|
||||||
("analyzeTry(" |
|
||||||
+ exc.start.getAddr() + ", " + exc.endAddr+")"); |
|
||||||
while (tryFlow.analyze(tryFlow.getAddr(), exc.endAddr)); |
|
||||||
|
|
||||||
TryBlock tryBlock = new TryBlock(tryFlow); |
|
||||||
} else if (!(tryFlow.block instanceof TryBlock)) |
|
||||||
throw new AssertError("no TryBlock"); |
|
||||||
|
|
||||||
FlowBlock catchFlow = exc.handler; |
|
||||||
boolean isMultiUsed = catchFlow.predecessors.size() != 0; |
|
||||||
if (!isMultiUsed && next != null) { |
|
||||||
for (Iterator j = handlers.tailSet(next).iterator(); |
|
||||||
j.hasNext();) { |
|
||||||
Handler h = (Handler) j.next(); |
|
||||||
if (h.handler == catchFlow) { |
|
||||||
isMultiUsed = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (isMultiUsed) { |
|
||||||
/* If this exception is used in other exception handlers, |
|
||||||
* create a new flow block, that jumps to the handler. |
|
||||||
* This will be our new exception handler. |
|
||||||
*/ |
|
||||||
EmptyBlock jump = new EmptyBlock(new Jump(catchFlow)); |
|
||||||
FlowBlock newFlow = new FlowBlock(catchFlow.method, |
|
||||||
catchFlow.getAddr()); |
|
||||||
newFlow.appendBlock(jump, 0); |
|
||||||
catchFlow.prevByAddr.nextByAddr = newFlow; |
|
||||||
newFlow.prevByAddr = catchFlow.prevByAddr; |
|
||||||
newFlow.nextByAddr = catchFlow; |
|
||||||
catchFlow.prevByAddr = newFlow; |
|
||||||
catchFlow = newFlow; |
|
||||||
} else { |
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
||||||
GlobalOptions.err.println |
|
||||||
("analyzeCatch(" |
|
||||||
+ catchFlow.getAddr() + ", " + endHandler + ")"); |
|
||||||
while (catchFlow.analyze(catchFlow.getAddr(), endHandler)); |
|
||||||
} |
|
||||||
|
|
||||||
tryFlow.updateInOutCatch(catchFlow); |
|
||||||
if (exc.type != null) |
|
||||||
analyzeCatchBlock(exc.type, tryFlow, catchFlow); |
|
||||||
|
|
||||||
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) |
|
||||||
&& ! analyzeFinally(tryFlow, catchFlow, endHandler) |
|
||||||
&& ! analyzeSpecialFinally(tryFlow, catchFlow, |
|
||||||
endHandler)) |
|
||||||
|
|
||||||
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); |
|
||||||
|
|
||||||
tryFlow.checkConsistent(); |
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
||||||
GlobalOptions.err.println |
|
||||||
("analyzeTryCatch(" + tryFlow.getAddr() + ", " |
|
||||||
+ tryFlow.getNextAddr() + ") done."); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
CodeVerifier.java \
|
|
||||||
Interpreter.java \
|
|
||||||
InterpreterException.java \
|
|
||||||
NewObject.java \
|
|
||||||
RuntimeEnvironment.java \
|
|
||||||
SimpleRuntimeEnvironment.java \
|
|
||||||
SyntheticAnalyzer.java \
|
|
||||||
Value.java \
|
|
||||||
VerifyException.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,369 +0,0 @@ |
|||||||
/* SyntheticAnalyzer Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.jvm; |
|
||||||
import jode.GlobalOptions; |
|
||||||
import jode.bytecode.BytecodeInfo; |
|
||||||
import jode.bytecode.ClassInfo; |
|
||||||
import jode.bytecode.FieldInfo; |
|
||||||
import jode.bytecode.Handler; |
|
||||||
import jode.bytecode.Instruction; |
|
||||||
import jode.bytecode.MethodInfo; |
|
||||||
import jode.bytecode.Opcodes; |
|
||||||
import jode.bytecode.Reference; |
|
||||||
import jode.type.Type; |
|
||||||
import jode.type.MethodType; |
|
||||||
|
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
|
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
|
|
||||||
public class SyntheticAnalyzer implements Opcodes { |
|
||||||
public final static int UNKNOWN = 0; |
|
||||||
public final static int GETCLASS = 1; |
|
||||||
public final static int ACCESSGETFIELD = 2; |
|
||||||
public final static int ACCESSPUTFIELD = 3; |
|
||||||
public final static int ACCESSMETHOD = 4; |
|
||||||
public final static int ACCESSGETSTATIC = 5; |
|
||||||
public final static int ACCESSPUTSTATIC = 6; |
|
||||||
public final static int ACCESSSTATICMETHOD = 7; |
|
||||||
public final static int ACCESSCONSTRUCTOR = 8; |
|
||||||
|
|
||||||
int kind = UNKNOWN; |
|
||||||
Reference reference; |
|
||||||
MethodInfo method; |
|
||||||
|
|
||||||
public SyntheticAnalyzer(MethodInfo method, boolean checkName) { |
|
||||||
this.method = method; |
|
||||||
if (method.getBytecode() == null) |
|
||||||
return; |
|
||||||
if (!checkName || method.getName().equals("class$")) |
|
||||||
if (checkGetClass()) |
|
||||||
return; |
|
||||||
if (!checkName || method.getName().startsWith("access$")) |
|
||||||
if (checkAccess()) |
|
||||||
return; |
|
||||||
if (method.getName().equals("<init>")) |
|
||||||
if (checkConstructorAccess()) |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
public int getKind() { |
|
||||||
return kind; |
|
||||||
} |
|
||||||
|
|
||||||
public Reference getReference() { |
|
||||||
return reference; |
|
||||||
} |
|
||||||
|
|
||||||
private static final int[] getClassOpcodes = { |
|
||||||
opc_aload, opc_invokestatic, opc_areturn, |
|
||||||
opc_astore, opc_new, opc_dup, opc_aload, |
|
||||||
opc_invokevirtual, opc_invokespecial, opc_athrow |
|
||||||
}; |
|
||||||
private static final Reference[] getClassRefs = { |
|
||||||
null, Reference.getReference("Ljava/lang/Class;", "forName", |
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;"), |
|
||||||
null, null, null, null, null, |
|
||||||
Reference.getReference("Ljava/lang/Throwable;", "getMessage", |
|
||||||
"()Ljava/lang/String;"), |
|
||||||
Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>", |
|
||||||
"(Ljava/lang/String;)V"), null |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
boolean checkGetClass() { |
|
||||||
if (!method.isStatic() |
|
||||||
|| !(method.getType() |
|
||||||
.equals("(Ljava/lang/String;)Ljava/lang/Class;"))) |
|
||||||
return false; |
|
||||||
|
|
||||||
BytecodeInfo bytecode = method.getBytecode(); |
|
||||||
|
|
||||||
Handler[] excHandlers = bytecode.getExceptionHandlers(); |
|
||||||
if (excHandlers.length != 1 |
|
||||||
|| !"java.lang.ClassNotFoundException".equals(excHandlers[0].type)) |
|
||||||
return false; |
|
||||||
|
|
||||||
int excSlot = -1; |
|
||||||
int i = 0; |
|
||||||
for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) { |
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (i == getClassOpcodes.length |
|
||||||
|| instr.getOpcode() != getClassOpcodes[i]) |
|
||||||
return false; |
|
||||||
if (i == 0 && (instr.getLocalSlot() != 0 |
|
||||||
|| excHandlers[0].start != instr)) |
|
||||||
return false; |
|
||||||
if (i == 2 && excHandlers[0].end != instr) |
|
||||||
return false; |
|
||||||
if (i == 3) { |
|
||||||
if (excHandlers[0].catcher != instr) |
|
||||||
return false; |
|
||||||
excSlot = instr.getLocalSlot(); |
|
||||||
} |
|
||||||
if (i == 4 && !instr.getClazzType().equals |
|
||||||
("Ljava/lang/NoClassDefFoundError;")) |
|
||||||
return false; |
|
||||||
if (i == 6 && instr.getLocalSlot() != excSlot) |
|
||||||
return false; |
|
||||||
if (getClassRefs[i] != null |
|
||||||
&& !getClassRefs[i].equals(instr.getReference())) |
|
||||||
return false; |
|
||||||
} |
|
||||||
this.kind = GETCLASS; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
private final int modifierMask = (Modifier.PRIVATE | Modifier.PROTECTED | |
|
||||||
Modifier.PUBLIC | Modifier.STATIC); |
|
||||||
|
|
||||||
public boolean checkStaticAccess() { |
|
||||||
ClassInfo clazzInfo = method.getClazzInfo(); |
|
||||||
BytecodeInfo bytecode = method.getBytecode(); |
|
||||||
Iterator iter = bytecode.getInstructions().iterator(); |
|
||||||
|
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() == opc_getstatic) { |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
FieldInfo refField |
|
||||||
= clazzInfo.findField(ref.getName(), ref.getType()); |
|
||||||
if ((refField.getModifiers() & modifierMask) != |
|
||||||
(Modifier.PRIVATE | Modifier.STATIC)) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() < opc_ireturn |
|
||||||
|| instr.getOpcode() > opc_areturn) |
|
||||||
return false; |
|
||||||
/* For valid bytecode the type matches automatically */ |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSGETSTATIC; |
|
||||||
return true; |
|
||||||
} |
|
||||||
int params = 0, slot = 0; |
|
||||||
while (instr.getOpcode() >= opc_iload |
|
||||||
&& instr.getOpcode() <= opc_aload |
|
||||||
&& instr.getLocalSlot() == slot) { |
|
||||||
params++; |
|
||||||
slot += (instr.getOpcode() == opc_lload |
|
||||||
|| instr.getOpcode() == opc_dload) ? 2 : 1; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
} |
|
||||||
if (instr.getOpcode() == opc_putstatic) { |
|
||||||
if (params != 1) |
|
||||||
return false; |
|
||||||
/* For valid bytecode the type of param matches automatically */ |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
FieldInfo refField |
|
||||||
= clazzInfo.findField(ref.getName(), ref.getType()); |
|
||||||
if ((refField.getModifiers() & modifierMask) != |
|
||||||
(Modifier.PRIVATE | Modifier.STATIC)) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() != opc_return) |
|
||||||
return false; |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSPUTSTATIC; |
|
||||||
return true; |
|
||||||
} |
|
||||||
if (instr.getOpcode() == opc_invokestatic) { |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
MethodInfo refMethod |
|
||||||
= clazzInfo.findMethod(ref.getName(), ref.getType()); |
|
||||||
MethodType refType = Type.tMethod(ref.getType()); |
|
||||||
if ((refMethod.getModifiers() & modifierMask) != |
|
||||||
(Modifier.PRIVATE | Modifier.STATIC) |
|
||||||
|| refType.getParameterTypes().length != params) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (refType.getReturnType() == Type.tVoid) { |
|
||||||
if (instr.getOpcode() != opc_return) |
|
||||||
return false; |
|
||||||
} else { |
|
||||||
if (instr.getOpcode() < opc_ireturn |
|
||||||
|| instr.getOpcode() > opc_areturn) |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/* For valid bytecode the types matches automatically */ |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSSTATICMETHOD; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean checkAccess() { |
|
||||||
ClassInfo clazzInfo = method.getClazzInfo(); |
|
||||||
BytecodeInfo bytecode = method.getBytecode(); |
|
||||||
Handler[] excHandlers = bytecode.getExceptionHandlers(); |
|
||||||
if (excHandlers != null && excHandlers.length != 0) |
|
||||||
return false; |
|
||||||
|
|
||||||
if (method.isStatic()) { |
|
||||||
if (checkStaticAccess()) |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
Iterator iter = bytecode.getInstructions().iterator(); |
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
|
|
||||||
if (instr.getOpcode() == opc_getfield) { |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
FieldInfo refField |
|
||||||
= clazzInfo.findField(ref.getName(), ref.getType()); |
|
||||||
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() < opc_ireturn |
|
||||||
|| instr.getOpcode() > opc_areturn) |
|
||||||
return false; |
|
||||||
/* For valid bytecode the type matches automatically */ |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSGETFIELD; |
|
||||||
return true; |
|
||||||
} |
|
||||||
int params = 0, slot = 1; |
|
||||||
while (instr.getOpcode() >= opc_iload |
|
||||||
&& instr.getOpcode() <= opc_aload |
|
||||||
&& instr.getLocalSlot() == slot) { |
|
||||||
params++; |
|
||||||
slot += (instr.getOpcode() == opc_lload |
|
||||||
|| instr.getOpcode() == opc_dload) ? 2 : 1; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
} |
|
||||||
if (instr.getOpcode() == opc_putfield) { |
|
||||||
if (params != 1) |
|
||||||
return false; |
|
||||||
/* For valid bytecode the type of param matches automatically */ |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
FieldInfo refField |
|
||||||
= clazzInfo.findField(ref.getName(), ref.getType()); |
|
||||||
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() != opc_return) |
|
||||||
return false; |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSPUTFIELD; |
|
||||||
return true; |
|
||||||
} |
|
||||||
if (instr.getOpcode() == opc_invokespecial) { |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
MethodInfo refMethod |
|
||||||
= clazzInfo.findMethod(ref.getName(), ref.getType()); |
|
||||||
MethodType refType = Type.tMethod(ref.getType()); |
|
||||||
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE |
|
||||||
|| refType.getParameterTypes().length != params) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (refType.getReturnType() == Type.tVoid) { |
|
||||||
if (instr.getOpcode() != opc_return) |
|
||||||
return false; |
|
||||||
} else { |
|
||||||
if (instr.getOpcode() < opc_ireturn |
|
||||||
|| instr.getOpcode() > opc_areturn) |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/* For valid bytecode the types matches automatically */ |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSMETHOD; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean checkConstructorAccess() { |
|
||||||
ClassInfo clazzInfo = method.getClazzInfo(); |
|
||||||
BytecodeInfo bytecode = method.getBytecode(); |
|
||||||
Handler[] excHandlers = bytecode.getExceptionHandlers(); |
|
||||||
if (excHandlers != null && excHandlers.length != 0) |
|
||||||
return false; |
|
||||||
|
|
||||||
Iterator iter = bytecode.getInstructions().iterator(); |
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
|
|
||||||
// slot begins with 2. Slot 1 contains a dummy value, that
|
|
||||||
// is used so that the constructor has a different type signature.
|
|
||||||
int params = 0, slot = 2; |
|
||||||
while (instr.getOpcode() >= opc_iload |
|
||||||
&& instr.getOpcode() <= opc_aload |
|
||||||
&& instr.getLocalSlot() == slot) { |
|
||||||
params++; |
|
||||||
slot += (instr.getOpcode() == opc_lload |
|
||||||
|| instr.getOpcode() == opc_dload) ? 2 : 1; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
} |
|
||||||
if (instr.getOpcode() == opc_invokespecial) { |
|
||||||
Reference ref = instr.getReference(); |
|
||||||
String refClazz = ref.getClazz().substring(1); |
|
||||||
if (!(refClazz.substring(0, refClazz.length()-1) |
|
||||||
.equals(clazzInfo.getName().replace('.','/')))) |
|
||||||
return false; |
|
||||||
MethodInfo refMethod |
|
||||||
= clazzInfo.findMethod(ref.getName(), ref.getType()); |
|
||||||
MethodType refType = Type.tMethod(ref.getType()); |
|
||||||
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE |
|
||||||
|| !refMethod.getName().equals("<init>") |
|
||||||
|| refType.getParameterTypes().length != params) |
|
||||||
return false; |
|
||||||
instr = (Instruction) iter.next(); |
|
||||||
if (instr.getOpcode() != opc_return) |
|
||||||
return false; |
|
||||||
|
|
||||||
/* For valid bytecode the types matches automatically */ |
|
||||||
reference = ref; |
|
||||||
kind = ACCESSCONSTRUCTOR; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
@ -1,47 +0,0 @@ |
|||||||
## Input file for automake to generate the Makefile.in used by configure
|
|
||||||
|
|
||||||
SUBDIRS = modules
|
|
||||||
|
|
||||||
JAR = @JAR@
|
|
||||||
JAVAC = @JAVAC@
|
|
||||||
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
|
|
||||||
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
|
|
||||||
-depfile=Makefile.dep
|
|
||||||
CLASSPATH = @CLASSPATH@
|
|
||||||
CLASSLIB = @CLASSLIB@
|
|
||||||
SUBSTCP = @SUBSTCP@
|
|
||||||
FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB))
|
|
||||||
|
|
||||||
MY_JAVA_FILES = \
|
|
||||||
ClassBundle.java \
|
|
||||||
ClassIdentifier.java \
|
|
||||||
CodeAnalyzer.java \
|
|
||||||
CodeTransformer.java \
|
|
||||||
ConstantRuntimeEnvironment.java \
|
|
||||||
FieldIdentifier.java \
|
|
||||||
Identifier.java \
|
|
||||||
IdentifierMatcher.java \
|
|
||||||
LocalIdentifier.java \
|
|
||||||
Main.java \
|
|
||||||
MethodIdentifier.java \
|
|
||||||
OptionHandler.java \
|
|
||||||
PackageIdentifier.java \
|
|
||||||
ParseException.java \
|
|
||||||
Renamer.java \
|
|
||||||
ScriptParser.java \
|
|
||||||
TranslationTable.java
|
|
||||||
|
|
||||||
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
|
|
||||||
EXTRA_DIST = $(MY_JAVA_FILES)
|
|
||||||
|
|
||||||
@QUOTE@-include Makefile.dep |
|
||||||
|
|
||||||
%.class: %.java |
|
||||||
$(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $<
|
|
||||||
|
|
||||||
Makefile.dep: $(MY_JAVA_FILES:.java=.class) |
|
||||||
$(JAVADEP) $^
|
|
||||||
|
|
||||||
clean-local: |
|
||||||
@rm -f *.class
|
|
||||||
@rm -f *.dep
|
|
@ -1,2 +0,0 @@ |
|||||||
Makefile |
|
||||||
Makefile.in |
|
File diff suppressed because it is too large
Load Diff
@ -1,941 +0,0 @@ |
|||||||
/* LocalOptimizer Copyright (C) 1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2, or (at your option) |
|
||||||
* any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.obfuscator.modules; |
|
||||||
import java.util.*; |
|
||||||
import jode.bytecode.*; |
|
||||||
import jode.obfuscator.*; |
|
||||||
import jode.AssertError; |
|
||||||
import jode.GlobalOptions; |
|
||||||
|
|
||||||
import @COLLECTIONS@.Iterator; |
|
||||||
import @COLLECTIONS@.ListIterator; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class takes some bytecode and tries to minimize the number |
|
||||||
* of locals used. It will also remove unnecessary stores. |
|
||||||
* |
|
||||||
* This class can only work on verified code. There should also be no |
|
||||||
* deadcode, since the verifier doesn't check that deadcode behaves |
|
||||||
* okay. |
|
||||||
* |
|
||||||
* This is done in two phases. First we determine which locals are |
|
||||||
* the same, and which locals have a overlapping life time. In the |
|
||||||
* second phase we will then redistribute the locals with a coloring |
|
||||||
* graph algorithm. |
|
||||||
* |
|
||||||
* The idea for the first phase is: For each read we follow the |
|
||||||
* instruction flow backward to find the corresponding writes. We can |
|
||||||
* also merge with another control flow that has a different read, in |
|
||||||
* this case we merge with that read, too. |
|
||||||
* |
|
||||||
* The tricky part is the subroutine handling. We follow the local |
|
||||||
* that is used in a ret and find the corresponding jsr target (there |
|
||||||
* must be only one, if the verifier should accept this class). While |
|
||||||
* we do this we remember in the info of the ret, which locals are |
|
||||||
* used in that subroutine. |
|
||||||
* |
|
||||||
* When we know the jsr target<->ret correlation, we promote from the |
|
||||||
* nextByAddr of every jsr the locals that are accessed by the |
|
||||||
* subroutine to the corresponding ret and the others to the jsr. Also |
|
||||||
* we will promote all reads from the jsr targets to the jsr. |
|
||||||
* |
|
||||||
* If you think this might be to complicated, keep in mind that jsr's |
|
||||||
* are not only left by the ret instructions, but also "spontanously" |
|
||||||
* (by not reading the return address again). |
|
||||||
*/ |
|
||||||
public class LocalOptimizer implements Opcodes, CodeTransformer { |
|
||||||
|
|
||||||
/** |
|
||||||
* This class keeps track of which locals must be the same, which |
|
||||||
* name and type each local (if there is a local variable table) and |
|
||||||
* which other locals have an intersecting life time. |
|
||||||
*/ |
|
||||||
class LocalInfo { |
|
||||||
LocalInfo shadow = null; |
|
||||||
|
|
||||||
public LocalInfo getReal() { |
|
||||||
LocalInfo real = this; |
|
||||||
while (real.shadow != null) |
|
||||||
real = real.shadow; |
|
||||||
return real; |
|
||||||
} |
|
||||||
|
|
||||||
String name; |
|
||||||
String type; |
|
||||||
Vector usingInstrs = new Vector(); |
|
||||||
Vector conflictingLocals = new Vector(); |
|
||||||
int size; |
|
||||||
int newSlot = -1; |
|
||||||
|
|
||||||
LocalInfo() { |
|
||||||
} |
|
||||||
|
|
||||||
LocalInfo(InstrInfo instr) { |
|
||||||
usingInstrs.addElement(instr); |
|
||||||
} |
|
||||||
|
|
||||||
void conflictsWith(LocalInfo l) { |
|
||||||
if (shadow != null) { |
|
||||||
getReal().conflictsWith(l); |
|
||||||
} else { |
|
||||||
l = l.getReal(); |
|
||||||
if (!conflictingLocals.contains(l)) { |
|
||||||
conflictingLocals.addElement(l); |
|
||||||
l.conflictingLocals.addElement(this); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void combineInto(LocalInfo l) { |
|
||||||
if (shadow != null) { |
|
||||||
getReal().combineInto(l); |
|
||||||
return; |
|
||||||
} |
|
||||||
l = l.getReal(); |
|
||||||
if (this == l) |
|
||||||
return; |
|
||||||
shadow = l; |
|
||||||
if (shadow.name == null) { |
|
||||||
shadow.name = name; |
|
||||||
shadow.type = type; |
|
||||||
} |
|
||||||
Enumeration enum = usingInstrs.elements(); |
|
||||||
while (enum.hasMoreElements()) { |
|
||||||
InstrInfo instr = (InstrInfo) enum.nextElement(); |
|
||||||
instr.local = l; |
|
||||||
l.usingInstrs.addElement(instr); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public int getFirstAddr() { |
|
||||||
int minAddr = Integer.MAX_VALUE; |
|
||||||
Enumeration enum = usingInstrs.elements(); |
|
||||||
while (enum.hasMoreElements()) { |
|
||||||
InstrInfo info = (InstrInfo) enum.nextElement(); |
|
||||||
if (info.instr.getAddr() < minAddr) |
|
||||||
minAddr = info.instr.getAddr(); |
|
||||||
} |
|
||||||
return minAddr; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static class TodoQueue { |
|
||||||
public final InstrInfo LAST = new InstrInfo(); |
|
||||||
InstrInfo first = LAST; |
|
||||||
|
|
||||||
public void add(InstrInfo info) { |
|
||||||
if (info.nextTodo == null) { |
|
||||||
/* only enqueue if not already on queue */ |
|
||||||
info.nextTodo = first; |
|
||||||
first = info; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isEmpty() { |
|
||||||
return first == LAST; |
|
||||||
} |
|
||||||
|
|
||||||
public InstrInfo remove() { |
|
||||||
if (first == LAST) |
|
||||||
throw new NoSuchElementException(); |
|
||||||
InstrInfo result = first; |
|
||||||
first = result.nextTodo; |
|
||||||
result.nextTodo = null; |
|
||||||
return result; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* This class contains information for each instruction. |
|
||||||
*/ |
|
||||||
static class InstrInfo { |
|
||||||
/** |
|
||||||
* The next changed InstrInfo, or null, if this instr info did |
|
||||||
* not changed. |
|
||||||
*/ |
|
||||||
InstrInfo nextTodo; |
|
||||||
|
|
||||||
/** |
|
||||||
* The LocalInfo that this instruction manipulates, or null |
|
||||||
* if this is not an ret, iinc, load or store instruction. |
|
||||||
*/ |
|
||||||
LocalInfo local; |
|
||||||
/** |
|
||||||
* For each slot, this contains the InstrInfo of one of the |
|
||||||
* next Instruction, that may read from that slot, without |
|
||||||
* prior writing. */ |
|
||||||
InstrInfo[] nextReads; |
|
||||||
|
|
||||||
/** |
|
||||||
* This only has a value for ret instructions. In that case |
|
||||||
* this bitset contains all locals, that may be used between |
|
||||||
* jsr and ret. |
|
||||||
*/ |
|
||||||
BitSet usedBySub; |
|
||||||
/** |
|
||||||
* For each slot if get() is true, no instruction may read |
|
||||||
* this slot, since it may contain different locals, depending |
|
||||||
* on flow. |
|
||||||
*/ |
|
||||||
LocalInfo[] lifeLocals; |
|
||||||
/** |
|
||||||
* If instruction is the destination of a jsr, this contains |
|
||||||
* the single allowed ret instruction info, or null if there |
|
||||||
* is no ret at all (or not yet detected). |
|
||||||
*/ |
|
||||||
InstrInfo retInfo; |
|
||||||
/** |
|
||||||
* If this instruction is a ret, this contains the single |
|
||||||
* allowed jsr target to which this ret belongs. |
|
||||||
*/ |
|
||||||
InstrInfo jsrTargetInfo; |
|
||||||
/** |
|
||||||
* The Instruction of this info |
|
||||||
*/ |
|
||||||
Instruction instr; |
|
||||||
/** |
|
||||||
* The next info in the chain. |
|
||||||
*/ |
|
||||||
InstrInfo nextInfo; |
|
||||||
} |
|
||||||
|
|
||||||
BytecodeInfo bc; |
|
||||||
|
|
||||||
TodoQueue changedInfos; |
|
||||||
InstrInfo firstInfo; |
|
||||||
Hashtable instrInfos; |
|
||||||
boolean produceLVT; |
|
||||||
int maxlocals; |
|
||||||
|
|
||||||
LocalInfo[] paramLocals; |
|
||||||
|
|
||||||
public LocalOptimizer() { |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Merges the given vector to a new vector. Both vectors may |
|
||||||
* be null in which case they are interpreted as empty vectors. |
|
||||||
* The vectors will never changed, but the result may be one |
|
||||||
* of the given vectors. |
|
||||||
*/ |
|
||||||
Vector merge(Vector v1, Vector v2) { |
|
||||||
if (v1 == null || v1.isEmpty()) |
|
||||||
return v2; |
|
||||||
if (v2 == null || v2.isEmpty()) |
|
||||||
return v1; |
|
||||||
Vector result = (Vector) v1.clone(); |
|
||||||
Enumeration enum = v2.elements(); |
|
||||||
while (enum.hasMoreElements()) { |
|
||||||
Object elem = enum.nextElement(); |
|
||||||
if (!result.contains(elem)) |
|
||||||
result.addElement(elem); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
void promoteReads(InstrInfo info, Instruction preInstr, |
|
||||||
BitSet mergeSet, boolean inverted) { |
|
||||||
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); |
|
||||||
int omitLocal = -1; |
|
||||||
if (preInstr.getOpcode() >= opc_istore |
|
||||||
&& preInstr.getOpcode() <= opc_astore) { |
|
||||||
/* This is a store */ |
|
||||||
omitLocal = preInstr.getLocalSlot(); |
|
||||||
if (info.nextReads[omitLocal] != null) |
|
||||||
preInfo.local.combineInto(info.nextReads[omitLocal].local); |
|
||||||
} |
|
||||||
for (int i=0; i < maxlocals; i++) { |
|
||||||
if (info.nextReads[i] != null && i != omitLocal |
|
||||||
&& (mergeSet == null || mergeSet.get(i) != inverted)) { |
|
||||||
|
|
||||||
if (preInfo.nextReads[i] == null) { |
|
||||||
preInfo.nextReads[i] = info.nextReads[i]; |
|
||||||
changedInfos.add(preInfo); |
|
||||||
} else { |
|
||||||
preInfo.nextReads[i].local |
|
||||||
.combineInto(info.nextReads[i].local); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void promoteReads(InstrInfo info, Instruction preInstr) { |
|
||||||
promoteReads(info, preInstr, null, false); |
|
||||||
} |
|
||||||
|
|
||||||
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, |
|
||||||
int slot, int addr) { |
|
||||||
LocalVariableInfo match = null; |
|
||||||
for (int i=0; i < lvt.length; i++) { |
|
||||||
if (lvt[i].slot == slot |
|
||||||
&& lvt[i].start.getAddr() <= addr |
|
||||||
&& lvt[i].end.getAddr() >= addr) { |
|
||||||
if (match != null |
|
||||||
&& (!match.name.equals(lvt[i].name) |
|
||||||
|| !match.type.equals(lvt[i].type))) { |
|
||||||
/* Multiple matches..., give no info */ |
|
||||||
return null; |
|
||||||
} |
|
||||||
match = lvt[i]; |
|
||||||
} |
|
||||||
} |
|
||||||
return match; |
|
||||||
} |
|
||||||
|
|
||||||
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, |
|
||||||
Instruction instr) { |
|
||||||
int addr; |
|
||||||
if (instr.getOpcode() >= opc_istore |
|
||||||
&& instr.getOpcode() <= opc_astore) |
|
||||||
addr = instr.getNextAddr(); |
|
||||||
else |
|
||||||
addr = instr.getAddr(); |
|
||||||
return findLVTEntry(lvt, instr.getLocalSlot(), addr); |
|
||||||
} |
|
||||||
|
|
||||||
public void calcLocalInfo() { |
|
||||||
maxlocals = bc.getMaxLocals(); |
|
||||||
Handler[] handlers = bc.getExceptionHandlers(); |
|
||||||
LocalVariableInfo[] lvt = bc.getLocalVariableTable(); |
|
||||||
if (lvt != null) |
|
||||||
produceLVT = true; |
|
||||||
|
|
||||||
/* Initialize paramLocals */ |
|
||||||
{ |
|
||||||
String methodType = bc.getMethodInfo().getType(); |
|
||||||
int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1) |
|
||||||
+ TypeSignature.getArgumentSize(methodType); |
|
||||||
paramLocals = new LocalInfo[paramCount]; |
|
||||||
int slot = 0; |
|
||||||
if (!bc.getMethodInfo().isStatic()) { |
|
||||||
LocalInfo local = new LocalInfo(); |
|
||||||
if (lvt != null) { |
|
||||||
LocalVariableInfo lvi = findLVTEntry(lvt, 0, 0); |
|
||||||
if (lvi != null) { |
|
||||||
local.name = lvi.name; |
|
||||||
local.type = lvi.type; |
|
||||||
} |
|
||||||
} |
|
||||||
local.size = 1; |
|
||||||
paramLocals[slot++] = local; |
|
||||||
} |
|
||||||
int pos = 1; |
|
||||||
while (pos < methodType.length() |
|
||||||
&& methodType.charAt(pos) != ')') { |
|
||||||
|
|
||||||
LocalInfo local = new LocalInfo(); |
|
||||||
if (lvt != null) { |
|
||||||
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0); |
|
||||||
if (lvi != null) { |
|
||||||
local.name = lvi.name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
int start = pos; |
|
||||||
pos = TypeSignature.skipType(methodType, pos); |
|
||||||
local.type = methodType.substring(start, pos); |
|
||||||
local.size = TypeSignature.getTypeSize(local.type); |
|
||||||
paramLocals[slot] = local; |
|
||||||
slot += local.size; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Initialize the InstrInfos and LocalInfos |
|
||||||
*/ |
|
||||||
changedInfos = new TodoQueue(); |
|
||||||
instrInfos = new Hashtable(); |
|
||||||
{ |
|
||||||
InstrInfo info = firstInfo = new InstrInfo(); |
|
||||||
Iterator i = bc.getInstructions().iterator(); |
|
||||||
while (true) { |
|
||||||
Instruction instr = (Instruction) i.next(); |
|
||||||
instrInfos.put(instr, info); |
|
||||||
info.instr = instr; |
|
||||||
info.nextReads = new InstrInfo[maxlocals]; |
|
||||||
if (instr.hasLocalSlot()) { |
|
||||||
info.local = new LocalInfo(info); |
|
||||||
if (lvt != null) { |
|
||||||
LocalVariableInfo lvi = findLVTEntry(lvt, instr); |
|
||||||
if (lvi != null) { |
|
||||||
info.local.name = lvi.name; |
|
||||||
info.local.type = lvi.type; |
|
||||||
} |
|
||||||
} |
|
||||||
info.local.size = 1; |
|
||||||
switch (instr.getOpcode()) { |
|
||||||
case opc_lload: case opc_dload: |
|
||||||
info.local.size = 2; |
|
||||||
/* fall through */ |
|
||||||
case opc_iload: case opc_fload: case opc_aload: |
|
||||||
case opc_iinc: |
|
||||||
/* this is a load instruction */ |
|
||||||
info.nextReads[instr.getLocalSlot()] = info; |
|
||||||
changedInfos.add(info); |
|
||||||
break; |
|
||||||
|
|
||||||
case opc_ret: |
|
||||||
/* this is a ret instruction */ |
|
||||||
info.usedBySub = new BitSet(); |
|
||||||
info.nextReads[instr.getLocalSlot()] = info; |
|
||||||
changedInfos.add(info); |
|
||||||
break; |
|
||||||
|
|
||||||
case opc_lstore: case opc_dstore: |
|
||||||
info.local.size = 2; |
|
||||||
//case opc_istore: case opc_fstore: case opc_astore:
|
|
||||||
} |
|
||||||
} |
|
||||||
if (!i.hasNext()) |
|
||||||
break; |
|
||||||
info = info.nextInfo = new InstrInfo(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* find out which locals are the same. |
|
||||||
*/ |
|
||||||
while (!changedInfos.isEmpty()) { |
|
||||||
InstrInfo info = changedInfos.remove(); |
|
||||||
Instruction instr = info.instr; |
|
||||||
|
|
||||||
/* Mark the local as used in all ret instructions */ |
|
||||||
if (instr.hasLocalSlot()) { |
|
||||||
int slot = instr.getLocalSlot(); |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
InstrInfo retInfo = info.nextReads[i]; |
|
||||||
if (retInfo != null |
|
||||||
&& retInfo.instr.getOpcode() == opc_ret |
|
||||||
&& !retInfo.usedBySub.get(slot)) { |
|
||||||
retInfo.usedBySub.set(slot); |
|
||||||
if (retInfo.jsrTargetInfo != null) |
|
||||||
changedInfos.add(retInfo.jsrTargetInfo); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Instruction prevInstr = instr.getPrevByAddr(); |
|
||||||
if (prevInstr != null) { |
|
||||||
if (!prevInstr.doesAlwaysJump()) |
|
||||||
promoteReads(info, prevInstr); |
|
||||||
else if (prevInstr.getOpcode() == opc_jsr) { |
|
||||||
/* Prev instr is a jsr, promote reads to the |
|
||||||
* corresponding ret. |
|
||||||
*/ |
|
||||||
InstrInfo jsrInfo = |
|
||||||
(InstrInfo) instrInfos.get(prevInstr.getSingleSucc()); |
|
||||||
if (jsrInfo.retInfo != null) { |
|
||||||
/* Now promote reads that are modified by the |
|
||||||
* subroutine to the ret, and those that are not |
|
||||||
* to the jsr instruction. |
|
||||||
*/ |
|
||||||
promoteReads(info, jsrInfo.retInfo.instr, |
|
||||||
jsrInfo.retInfo.usedBySub, false); |
|
||||||
promoteReads(info, prevInstr, |
|
||||||
jsrInfo.retInfo.usedBySub, true); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (instr.getPreds() != null) { |
|
||||||
for (int i = 0; i < instr.getPreds().length; i++) { |
|
||||||
Instruction predInstr = instr.getPreds()[i]; |
|
||||||
if (instr.getPreds()[i].getOpcode() == opc_jsr) { |
|
||||||
/* This is the target of a jsr instr. |
|
||||||
*/ |
|
||||||
if (info.instr.getOpcode() != opc_astore) { |
|
||||||
/* XXX Grrr, the bytecode verifier doesn't |
|
||||||
* test if a jsr starts with astore. So |
|
||||||
* it is possible to do something else |
|
||||||
* before putting the ret address into a |
|
||||||
* local. */ |
|
||||||
throw new AssertError("Non standard jsr"); |
|
||||||
} |
|
||||||
InstrInfo retInfo = info.nextInfo.nextReads |
|
||||||
[info.instr.getLocalSlot()]; |
|
||||||
|
|
||||||
if (retInfo != null) { |
|
||||||
if (retInfo.instr.getOpcode() != opc_ret) |
|
||||||
throw new AssertError |
|
||||||
("reading return address"); |
|
||||||
|
|
||||||
info.retInfo = retInfo; |
|
||||||
retInfo.jsrTargetInfo = info; |
|
||||||
|
|
||||||
/* Now promote reads from the instruction |
|
||||||
* after the jsr to the ret instruction if |
|
||||||
* they are modified by the subroutine, |
|
||||||
* and to the jsr instruction otherwise. |
|
||||||
*/ |
|
||||||
Instruction nextInstr = predInstr.getNextByAddr(); |
|
||||||
InstrInfo nextInfo |
|
||||||
= (InstrInfo) instrInfos.get(nextInstr); |
|
||||||
|
|
||||||
promoteReads(nextInfo, retInfo.instr, |
|
||||||
retInfo.usedBySub, false); |
|
||||||
|
|
||||||
promoteReads(nextInfo, predInstr, |
|
||||||
retInfo.usedBySub, true); |
|
||||||
} |
|
||||||
} |
|
||||||
promoteReads(info, instr.getPreds()[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (int i=0; i < handlers.length; i++) { |
|
||||||
if (handlers[i].catcher == instr) { |
|
||||||
for (Instruction preInstr = handlers[i].start; |
|
||||||
preInstr != handlers[i].end.getNextByAddr(); |
|
||||||
preInstr = preInstr.getNextByAddr()) { |
|
||||||
promoteReads(info, preInstr); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
changedInfos = null; |
|
||||||
|
|
||||||
/* Now merge with the parameters |
|
||||||
* The params should be the locals in firstInfo.nextReads |
|
||||||
*/ |
|
||||||
for (int i=0; i< paramLocals.length; i++) { |
|
||||||
if (firstInfo.nextReads[i] != null) { |
|
||||||
firstInfo.nextReads[i].local.combineInto(paramLocals[i]); |
|
||||||
paramLocals[i] = paramLocals[i].getReal(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void stripLocals() { |
|
||||||
ListIterator iter = bc.getInstructions().listIterator(); |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
Instruction instr = (Instruction) iter.next(); |
|
||||||
if (info.local != null && info.local.usingInstrs.size() == 1) { |
|
||||||
/* If this is a store, whose value is never read; it can |
|
||||||
* be removed, i.e replaced by a pop. */ |
|
||||||
switch (instr.getOpcode()) { |
|
||||||
case opc_istore: |
|
||||||
case opc_fstore: |
|
||||||
case opc_astore: |
|
||||||
iter.set(new Instruction(opc_pop)); |
|
||||||
break; |
|
||||||
case opc_lstore: |
|
||||||
case opc_dstore: |
|
||||||
iter.set(new Instruction(opc_pop2)); |
|
||||||
break; |
|
||||||
default: |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void distributeLocals(Vector locals) { |
|
||||||
if (locals.size() == 0) |
|
||||||
return; |
|
||||||
|
|
||||||
/* Find the local with the least conflicts. */ |
|
||||||
int min = Integer.MAX_VALUE; |
|
||||||
LocalInfo bestLocal = null; |
|
||||||
Enumeration enum = locals.elements(); |
|
||||||
while (enum.hasMoreElements()) { |
|
||||||
LocalInfo li = (LocalInfo) enum.nextElement(); |
|
||||||
int conflicts = 0; |
|
||||||
Enumeration conflenum = li.conflictingLocals.elements(); |
|
||||||
while (conflenum.hasMoreElements()) { |
|
||||||
if (((LocalInfo)conflenum.nextElement()).newSlot != -2) |
|
||||||
conflicts++; |
|
||||||
} |
|
||||||
if (conflicts < min) { |
|
||||||
min = conflicts; |
|
||||||
bestLocal = li; |
|
||||||
} |
|
||||||
} |
|
||||||
/* Mark the local as taken */ |
|
||||||
locals.removeElement(bestLocal); |
|
||||||
bestLocal.newSlot = -2; |
|
||||||
/* Now distribute the remaining locals recursively. */ |
|
||||||
distributeLocals(locals); |
|
||||||
|
|
||||||
/* Finally find a new slot */ |
|
||||||
next_slot: |
|
||||||
for (int slot = 0; ; slot++) { |
|
||||||
Enumeration conflenum = bestLocal.conflictingLocals.elements(); |
|
||||||
while (conflenum.hasMoreElements()) { |
|
||||||
LocalInfo conflLocal = (LocalInfo)conflenum.nextElement(); |
|
||||||
if (bestLocal.size == 2 && conflLocal.newSlot == slot+1) { |
|
||||||
slot++; |
|
||||||
continue next_slot; |
|
||||||
} |
|
||||||
if (conflLocal.size == 2 && conflLocal.newSlot+1 == slot) |
|
||||||
continue next_slot; |
|
||||||
if (conflLocal.newSlot == slot) { |
|
||||||
if (conflLocal.size == 2) |
|
||||||
slot++; |
|
||||||
continue next_slot; |
|
||||||
} |
|
||||||
} |
|
||||||
bestLocal.newSlot = slot; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void distributeLocals() { |
|
||||||
/* give locals new slots. This is a graph coloring |
|
||||||
* algorithm (the optimal solution is NP complete, but this |
|
||||||
* should be a good approximation). |
|
||||||
*/ |
|
||||||
|
|
||||||
/* first give the params the same slot as they had before. |
|
||||||
*/ |
|
||||||
for (int i=0; i<paramLocals.length; i++) |
|
||||||
if (paramLocals[i] != null) |
|
||||||
paramLocals[i].newSlot = i; |
|
||||||
|
|
||||||
/* Now calculate the conflict settings. |
|
||||||
*/ |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
if (info.instr.getOpcode() >= BytecodeInfo.opc_istore |
|
||||||
&& info.instr.getOpcode() <= BytecodeInfo.opc_astore) { |
|
||||||
/* This is a store. It conflicts with every local, whose |
|
||||||
* value will be read without write. |
|
||||||
* |
|
||||||
* If this is inside a ret, it also conflicts with |
|
||||||
* locals, that are not used inside, and where any jsr |
|
||||||
* would conflict with. |
|
||||||
*/ |
|
||||||
for (int i=0; i < maxlocals; i++) { |
|
||||||
if (i != info.instr.getLocalSlot() |
|
||||||
&& info.nextReads[i] != null) |
|
||||||
info.local.conflictsWith(info.nextReads[i].local); |
|
||||||
if (info.nextInfo.nextReads[i] != null |
|
||||||
&& info.nextInfo.nextReads[i].jsrTargetInfo != null) { |
|
||||||
Instruction[] jsrs = info.nextInfo.nextReads[i] |
|
||||||
.jsrTargetInfo.instr.getPreds(); |
|
||||||
for (int j=0; j< jsrs.length; j++) { |
|
||||||
InstrInfo jsrInfo |
|
||||||
= (InstrInfo) instrInfos.get(jsrs[j]); |
|
||||||
for (int k=0; k < maxlocals; k++) { |
|
||||||
if (!info.nextInfo.nextReads[i].usedBySub |
|
||||||
.get(k) |
|
||||||
&& jsrInfo.nextReads[k] != null) |
|
||||||
info.local.conflictsWith |
|
||||||
(jsrInfo.nextReads[k].local); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Now put the locals that need a color into a vector. |
|
||||||
*/ |
|
||||||
Vector locals = new Vector(); |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
if (info.local != null |
|
||||||
&& info.local.newSlot == -1 |
|
||||||
&& !locals.contains(info.local)) |
|
||||||
locals.addElement(info.local); |
|
||||||
} |
|
||||||
|
|
||||||
/* Now distribute slots recursive. |
|
||||||
*/ |
|
||||||
distributeLocals(locals); |
|
||||||
|
|
||||||
/* Update the instructions and calculate new maxlocals. |
|
||||||
*/ |
|
||||||
maxlocals = paramLocals.length; |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
if (info.local != null) { |
|
||||||
if (info.local.newSlot+info.local.size > maxlocals) |
|
||||||
maxlocals = info.local.newSlot + info.local.size; |
|
||||||
info.instr.setLocalSlot(info.local.newSlot); |
|
||||||
} |
|
||||||
} |
|
||||||
bc.setMaxLocals(maxlocals); |
|
||||||
|
|
||||||
/* Update LocalVariableTable |
|
||||||
*/ |
|
||||||
if (produceLVT) |
|
||||||
buildNewLVT(); |
|
||||||
} |
|
||||||
|
|
||||||
private InstrInfo CONFLICT = new InstrInfo(); |
|
||||||
|
|
||||||
boolean promoteLifeLocals(LocalInfo[] newLife, InstrInfo nextInfo) { |
|
||||||
if (nextInfo.lifeLocals == null) { |
|
||||||
nextInfo.lifeLocals = (LocalInfo[]) newLife.clone(); |
|
||||||
return true; |
|
||||||
} |
|
||||||
boolean changed = false; |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
LocalInfo local = nextInfo.lifeLocals[i]; |
|
||||||
if (local == null) |
|
||||||
/* A conflict has already happened, or this slot |
|
||||||
* may not have been initialized. */ |
|
||||||
continue; |
|
||||||
|
|
||||||
local = local.getReal(); |
|
||||||
LocalInfo newLocal = newLife[i]; |
|
||||||
if (newLocal != null) |
|
||||||
newLocal = newLocal.getReal(); |
|
||||||
if (local != newLocal) { |
|
||||||
nextInfo.lifeLocals[i] = null; |
|
||||||
changed = true; |
|
||||||
} |
|
||||||
} |
|
||||||
return changed; |
|
||||||
} |
|
||||||
|
|
||||||
public void buildNewLVT() { |
|
||||||
/* First we recalculate the usedBySub, to use the new local numbers. |
|
||||||
*/ |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) |
|
||||||
if (info.usedBySub != null) |
|
||||||
info.usedBySub = new BitSet(); |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
if (info.local != null) { |
|
||||||
for (int i=0; i < info.nextReads.length; i++) { |
|
||||||
if (info.nextReads[i] != null |
|
||||||
&& info.nextReads[i].instr.getOpcode() == opc_ret) |
|
||||||
info.nextReads[i].usedBySub.set(info.local.newSlot); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* Now we begin with the first Instruction and follow program flow. |
|
||||||
* We remember which locals are life in lifeLocals. |
|
||||||
*/ |
|
||||||
|
|
||||||
firstInfo.lifeLocals = new LocalInfo[maxlocals]; |
|
||||||
for (int i=0; i < paramLocals.length; i++) |
|
||||||
firstInfo.lifeLocals[i] = paramLocals[i]; |
|
||||||
|
|
||||||
Stack changedInfo = new Stack(); |
|
||||||
changedInfo.push(firstInfo); |
|
||||||
Handler[] handlers = bc.getExceptionHandlers(); |
|
||||||
while (!changedInfo.isEmpty()) { |
|
||||||
InstrInfo info = (InstrInfo) changedInfo.pop(); |
|
||||||
Instruction instr = info.instr; |
|
||||||
LocalInfo[] newLife = info.lifeLocals; |
|
||||||
if (instr.hasLocalSlot()) { |
|
||||||
int slot = instr.getLocalSlot(); |
|
||||||
LocalInfo instrLocal = info.local.getReal(); |
|
||||||
newLife = (LocalInfo[]) newLife.clone(); |
|
||||||
newLife[slot] = instrLocal; |
|
||||||
if (instrLocal.name != null) { |
|
||||||
for (int j=0; j< newLife.length; j++) { |
|
||||||
if (j != slot |
|
||||||
&& newLife[j] != null |
|
||||||
&& instrLocal.name.equals(newLife[j].name)) { |
|
||||||
/* This local changed the slot. */ |
|
||||||
newLife[j] = null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!instr.doesAlwaysJump()) { |
|
||||||
InstrInfo nextInfo = info.nextInfo; |
|
||||||
if (promoteLifeLocals(newLife, nextInfo)) |
|
||||||
changedInfo.push(nextInfo); |
|
||||||
} |
|
||||||
if (instr.hasSuccs()) { |
|
||||||
Instruction[] succs = instr.getSuccs(); |
|
||||||
for (int i = 0; i < succs.length; i++) { |
|
||||||
InstrInfo nextInfo |
|
||||||
= (InstrInfo) instrInfos.get(succs[i]); |
|
||||||
if (promoteLifeLocals(newLife, nextInfo)) |
|
||||||
changedInfo.push(nextInfo); |
|
||||||
} |
|
||||||
} |
|
||||||
for (int i=0; i < handlers.length; i++) { |
|
||||||
if (handlers[i].start.compareTo(instr) <= 0 |
|
||||||
&& handlers[i].end.compareTo(instr) >= 0) { |
|
||||||
InstrInfo nextInfo |
|
||||||
= (InstrInfo) instrInfos.get(handlers[i].catcher); |
|
||||||
if (promoteLifeLocals(newLife, nextInfo)) |
|
||||||
changedInfo.push(nextInfo); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (info.instr.getOpcode() == opc_jsr) { |
|
||||||
/* On a jsr we do a special merge */ |
|
||||||
|
|
||||||
Instruction jsrTargetInstr = info.instr.getSingleSucc(); |
|
||||||
InstrInfo jsrTargetInfo |
|
||||||
= (InstrInfo) instrInfos.get(jsrTargetInstr); |
|
||||||
InstrInfo retInfo = jsrTargetInfo.retInfo; |
|
||||||
if (retInfo != null && retInfo.lifeLocals != null) { |
|
||||||
LocalInfo[] retLife = (LocalInfo[]) newLife.clone(); |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
if (retInfo.usedBySub.get(i)) |
|
||||||
retLife[i] = retInfo.lifeLocals[i]; |
|
||||||
} |
|
||||||
if (promoteLifeLocals(retLife, info.nextInfo)) |
|
||||||
changedInfo.push(info.nextInfo); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (info.jsrTargetInfo != null) { |
|
||||||
/* On a ret we do a special merge */ |
|
||||||
|
|
||||||
Instruction jsrTargetInstr = info.jsrTargetInfo.instr; |
|
||||||
for (int j=0; j< jsrTargetInstr.getPreds().length; j++) { |
|
||||||
InstrInfo jsrInfo |
|
||||||
= (InstrInfo) instrInfos.get(jsrTargetInstr.getPreds()[j]); |
|
||||||
|
|
||||||
if (jsrInfo.lifeLocals == null) |
|
||||||
/* life locals are not calculated, yet */ |
|
||||||
continue; |
|
||||||
LocalInfo[] retLife = (LocalInfo[]) newLife.clone(); |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
if (!info.usedBySub.get(i)) |
|
||||||
retLife[i] = jsrInfo.lifeLocals[i]; |
|
||||||
} |
|
||||||
if (promoteLifeLocals(retLife, jsrInfo.nextInfo)) |
|
||||||
changedInfo.push(jsrInfo.nextInfo); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Vector lvtEntries = new Vector(); |
|
||||||
LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals]; |
|
||||||
LocalInfo[] currentLocal = new LocalInfo[maxlocals]; |
|
||||||
for (int i=0; i< paramLocals.length; i++) { |
|
||||||
if (paramLocals[i] != null) { |
|
||||||
currentLocal[i] = paramLocals[i]; |
|
||||||
if (currentLocal[i].name != null) { |
|
||||||
lvi[i] = new LocalVariableInfo(); |
|
||||||
lvtEntries.addElement(lvi[i]); |
|
||||||
lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */ |
|
||||||
lvi[i].type = Main.getClassBundle() |
|
||||||
.getTypeAlias(currentLocal[i].type); |
|
||||||
lvi[i].start = (Instruction) bc.getInstructions().get(0); |
|
||||||
lvi[i].slot = i; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Instruction lastInstr = null; |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
LocalInfo lcl = info.lifeLocals != null ? info.lifeLocals[i] |
|
||||||
: null; |
|
||||||
if (lcl != currentLocal[i] |
|
||||||
&& (lcl == null || currentLocal[i] == null |
|
||||||
|| lcl.name == null || lcl.type == null |
|
||||||
|| !lcl.name.equals(currentLocal[i].name) |
|
||||||
|| !lcl.type.equals(currentLocal[i].type))) { |
|
||||||
if (lvi[i] != null) { |
|
||||||
lvi[i].end = info.instr.getPrevByAddr(); |
|
||||||
} |
|
||||||
lvi[i] = null; |
|
||||||
currentLocal[i] = lcl; |
|
||||||
if (currentLocal[i] != null |
|
||||||
&& currentLocal[i].name != null |
|
||||||
&& currentLocal[i].type != null) { |
|
||||||
lvi[i] = new LocalVariableInfo(); |
|
||||||
lvtEntries.addElement(lvi[i]); |
|
||||||
lvi[i].name = currentLocal[i].name; |
|
||||||
lvi[i].type = Main.getClassBundle() |
|
||||||
.getTypeAlias(currentLocal[i].type); |
|
||||||
lvi[i].start = info.instr; |
|
||||||
lvi[i].slot = i; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
lastInstr = info.instr; |
|
||||||
} |
|
||||||
for (int i=0; i< maxlocals; i++) { |
|
||||||
if (lvi[i] != null) |
|
||||||
lvi[i].end = lastInstr; |
|
||||||
} |
|
||||||
LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()]; |
|
||||||
lvtEntries.copyInto(lvt); |
|
||||||
bc.setLocalVariableTable(lvt); |
|
||||||
} |
|
||||||
|
|
||||||
public void dumpLocals() { |
|
||||||
Vector locals = new Vector(); |
|
||||||
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
|
||||||
GlobalOptions.err.println(info.instr.getDescription()); |
|
||||||
GlobalOptions.err.print("nextReads: "); |
|
||||||
for (int i=0; i<maxlocals; i++) |
|
||||||
if (info.nextReads[i] == null) |
|
||||||
GlobalOptions.err.print("-,"); |
|
||||||
else |
|
||||||
GlobalOptions.err.print(info.nextReads[i].instr.getAddr()+","); |
|
||||||
if (info.usedBySub != null) |
|
||||||
GlobalOptions.err.print(" usedBySub: "+info.usedBySub); |
|
||||||
if (info.retInfo != null) |
|
||||||
GlobalOptions.err.print(" ret info: " |
|
||||||
+info.retInfo.instr.getAddr()); |
|
||||||
if (info.jsrTargetInfo != null) |
|
||||||
GlobalOptions.err.print(" jsr info: " |
|
||||||
+info.jsrTargetInfo.instr.getAddr()); |
|
||||||
|
|
||||||
GlobalOptions.err.println(); |
|
||||||
if (info.local != null && !locals.contains(info.local)) |
|
||||||
locals.addElement(info.local); |
|
||||||
} |
|
||||||
Enumeration enum = locals.elements(); |
|
||||||
while (enum.hasMoreElements()) { |
|
||||||
LocalInfo li = (LocalInfo) enum.nextElement(); |
|
||||||
int slot = ((InstrInfo)li.usingInstrs.elementAt(0)) |
|
||||||
.instr.getLocalSlot(); |
|
||||||
GlobalOptions.err.print("Slot: "+slot+" conflicts:"); |
|
||||||
Enumeration enum1 = li.conflictingLocals.elements(); |
|
||||||
while (enum1.hasMoreElements()) { |
|
||||||
LocalInfo cfl = (LocalInfo)enum1.nextElement(); |
|
||||||
GlobalOptions.err.print(cfl.getFirstAddr()+", "); |
|
||||||
} |
|
||||||
GlobalOptions.err.println(); |
|
||||||
GlobalOptions.err.print(li.getFirstAddr()); |
|
||||||
GlobalOptions.err.print(" instrs: "); |
|
||||||
Enumeration enum2 = li.usingInstrs.elements(); |
|
||||||
while (enum2.hasMoreElements()) |
|
||||||
GlobalOptions.err.print(((InstrInfo)enum2.nextElement()) |
|
||||||
.instr.getAddr()+", "); |
|
||||||
GlobalOptions.err.println(); |
|
||||||
} |
|
||||||
GlobalOptions.err.println("-----------"); |
|
||||||
} |
|
||||||
|
|
||||||
public void transformCode(BytecodeInfo bytecode) { |
|
||||||
this.bc = bytecode; |
|
||||||
calcLocalInfo(); |
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_LOCALS) != 0) { |
|
||||||
GlobalOptions.err.println("Before Local Optimization: "); |
|
||||||
dumpLocals(); |
|
||||||
} |
|
||||||
stripLocals(); |
|
||||||
distributeLocals(); |
|
||||||
|
|
||||||
if ((GlobalOptions.debuggingFlags |
|
||||||
& GlobalOptions.DEBUG_LOCALS) != 0) { |
|
||||||
GlobalOptions.err.println("After Local Optimization: "); |
|
||||||
dumpLocals(); |
|
||||||
} |
|
||||||
|
|
||||||
firstInfo = null; |
|
||||||
changedInfos = null; |
|
||||||
instrInfos = null; |
|
||||||
paramLocals = null; |
|
||||||
} |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue