1
0
mirror of https://github.com/decatur/j2js-compiler.git synced 2025-01-18 12:25:42 +01:00

first commit

This commit is contained in:
decatur 2011-10-04 22:27:20 +02:00
commit 089e0cf208
144 changed files with 21780 additions and 0 deletions

12
.classpath Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="lib" path="libs/commons-io-1.4.jar"/>
<classpathentry kind="lib" path="libs/bcel-5.1.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
git.txt
pom.xml
src/main/resources/META-INF/*
src/site/**/*
src/test/**/*
launchConfig/**/*
target/**/*

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>j2js-compiler</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>

View File

@ -0,0 +1,271 @@
#Wed Sep 03 00:07:36 CEST 2008
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.5
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.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5
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_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_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=1
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=false
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_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.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.format_guardian_clause_on_one_line=false
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=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_member=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_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.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=space
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true

View File

@ -0,0 +1,6 @@
#Wed Sep 03 00:07:35 CEST 2008
eclipse.preferences.version=1
formatter_profile=_MyProfile
formatter_settings_version=11
internal.default.compliance=default
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return Returns the ${bare_field_name}.\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} The ${bare_field_name} to set.\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>

View File

@ -0,0 +1,6 @@
#Wed Oct 24 00:47:12 CEST 2007
DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;
USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;
USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;
USER_PREFERENCE=overrideGlobalPreferencesfalse
eclipse.preferences.version=1

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
A FreeBSD Licence
Copyright(c) 2011, the j2js Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD
PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
#j2js-compiler
A Java Bytecode to JavaScript Cross-Compiler.

BIN
libs/bcel-5.1.jar Normal file

Binary file not shown.

BIN
libs/commons-io-1.4.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,40 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.j2js.Const;
/**
* Copyright by Wolfgang Kuehn 2005
* Created on Feb 27, 2005
*/
public class Checker {
public static void main(String argv[]) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader(new File("src/com/j2js/Pass1.java")));
Pattern p = Pattern.compile(".*case\\s+Const\\.(\\w*)\\s*:.*");
HashSet<String> set = new HashSet<String>();
String line;
while ((line=reader.readLine())!=null) {
Matcher m = p.matcher(line);
if (m.matches()) {
String name = m.group(1);
//System.out.println("Adding " + name);
set.add(name);
}
}
int missingCount = 0;
for (int i=0; i<Const.instructionTypes.length; i++) {
String name = Const.instructionTypes[i].getName();
if (!set.contains(name.toUpperCase())) {
missingCount++;
System.out.println(name.toUpperCase());
}
}
System.out.println("Missing count: " + missingCount);
}
}

View File

@ -0,0 +1,67 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.j2js.Const;
import com.j2js.Form;
import com.j2js.InstructionType;
/**
* Copyright by Wolfgang Kuehn 2005
* Created on Feb 27, 2005
*/
public class Enhancer {
public static void main(String argv[]) throws Exception {
File source = new File("src/com/j2js/Pass1.java");
File temp = new File("temp/Pass1_" + new Date().getTime() + ".java");
if (!source.renameTo(temp)) {
throw new RuntimeException("Could not move " + source + " to "+ temp);
}
BufferedReader reader = new BufferedReader(new FileReader(temp));
FileWriter writer = new FileWriter(source);
Pattern p = Pattern.compile(".*case\\s+Const\\.(\\w*)\\s*:.*");
String line;
while ((line=reader.readLine())!=null) {
Matcher m = p.matcher(line);
if (m.matches()) {
String name = m.group(1);
System.out.println("Enhancing " + name);
int index = ((Integer) Const.class.getField(name).get(null)).intValue();
InstructionType it = Const.instructionTypes[index];
for (int i=0; i<it.getFormCount(); i++) {
Form form = it.getForm(i);
// Discard previously generated code.
reader.readLine();
reader.readLine();
String head = "\n //";
if (it.getFormCount() > 1) {
head += " (" + i + ")";
}
line += head + " Format: " + it.getName();
for (int j=0; j<form.getOperands().length; j++) {
Form.Value value = form.getOperands()[j];
line += ", " + value.name + "(" + value.type + ")";
}
line += head + " Operand stack: ...";
for (int j=0; j<form.getIns().length; j++) {
Form.Value value = form.getIns()[j];
line += ", " + value.name + "(" + value.type + ")";
}
line += " -> ...";
for (int j=0; j<form.getOuts().length; j++) {
Form.Value value = form.getOuts()[j];
line += ", " + value.name + "(" + value.type + ")";
}
}
}
writer.write(line + "\n");
}
writer.close();
}
}

View File

@ -0,0 +1,62 @@
/*
* Created on 20.09.2005
*/
package com.j2js;
import com.j2js.J2JSCompiler;
import java.util.ArrayList;
import com.j2js.dom.ASTNode;
import com.j2js.dom.Expression;
/**
* @author wolfgang
*/
public class ASTNodeStack extends ArrayList<ASTNode> {
public ASTNodeStack() {
super();
}
public ASTNodeStack(ASTNodeStack other) {
super(other);
}
public ASTNodeStack(Expression expression) {
super();
push(expression);
}
public Expression pop() {
if (size() == 0) throw new RuntimeException("Cannot pop empty stack");
return (Expression) remove(size() - 1);
}
public void push(ASTNode node) {
add(node);
}
public void rotate(int offset) {
if (offset == 0) return;
if (offset > size()) throw new IndexOutOfBoundsException();
ASTNode node = pop();
add(size()-offset, node);
}
public Expression peek() {
return peek(0);
}
private static Object safeCast(Object object, Class clazz) {
if (!clazz.isInstance(object)) {
throw new RuntimeException("Expected " + clazz + ", but was " + object);
}
return object;
}
public Expression peek(int offset) {
if (size()-1 < offset) return null;
return (Expression) ASTNodeStack.safeCast(get(size()-1-offset), Expression.class);
}
}

View File

@ -0,0 +1,28 @@
package com.j2js;
import java.util.Map;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.Visitor;
public class AnnotationAttribute extends Attribute {
Map<String, String>[] annotations;
protected AnnotationAttribute(byte tag, int nameIndex, int length, ConstantPool constantPool) {
super(tag, nameIndex, length, constantPool);
}
@Override
public void accept(Visitor arg0) {
// TODO Auto-generated method stub
}
@Override
public Attribute copy(ConstantPool arg0) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,58 @@
package com.j2js;
import java.io.DataInputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.AttributeReader;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantUtf8;
import com.j2js.assembly.ClassUnit;
import com.j2js.assembly.Project;
import com.j2js.assembly.Signature;
public class AnnotationReader implements AttributeReader{
private ClassUnit classUnit;
public AnnotationReader(ClassUnit theClassUnit) {
classUnit = theClassUnit;
}
public Attribute createAttribute(int name_index, int length, DataInputStream file, ConstantPool constantPool) {
Map<String, String>[] annotations = null;
// TODO: Annotation
try {
int attCount = file.readUnsignedShort();
annotations = new HashMap[attCount];
for (int j=0; j<attCount; j++) {
HashMap<String, String> map = new HashMap<String, String>();
annotations[j] = map;
int nameIndex = file.readUnsignedShort();
Constant constant = constantPool.getConstant(nameIndex);
Signature signature = Project.getSingleton().getSignature(((ConstantUtf8) constant).getBytes());
map.put("$signature", signature.toString());
int fieldCount = file.readUnsignedShort();
for (int i=0; i<fieldCount; i++) {
int fieldIndex = file.readUnsignedShort();
constant = constantPool.getConstant(fieldIndex);
String key = ((ConstantUtf8) constant).getBytes();
byte b = file.readByte();
fieldIndex = file.readUnsignedShort();
constant = constantPool.getConstant(fieldIndex);
String value = Pass1.constantToString(constant, constantPool);
map.put(key, value);
}
}
} catch (Exception e) {
}
AnnotationAttribute att = new AnnotationAttribute((byte) 0, name_index, length, constantPool);
att.annotations = annotations;
classUnit.annotations = annotations;
return att;
}
}

View File

@ -0,0 +1,435 @@
package com.j2js;
import com.j2js.J2JSCompiler;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import com.j2js.FileObject;
import com.j2js.Log;
import com.j2js.Utils;
import com.j2js.assembly.ClassUnit;
import com.j2js.assembly.ConstructorUnit;
import com.j2js.assembly.JavaScriptCompressor;
import com.j2js.assembly.JunkWriter;
import com.j2js.assembly.MemberUnit;
import com.j2js.assembly.ProcedureUnit;
import com.j2js.assembly.Project;
import com.j2js.assembly.Signature;
/**
*
*/
public class Assembly {
public List<String> entryPoints = new ArrayList<String>();
private final static String DECLARECLASS = "dcC";
private transient Log logger;
private transient String entryPointClassName;
private Project project;
private Set<Signature> taintedSignatures = new HashSet<Signature>();
private Set<Signature> unprocessedTaintedSignatures = new HashSet<Signature>();
String[] patterns;
private Collection<ClassUnit> resolvedTypes = new ArrayList<ClassUnit>();
private transient File targetLocation;
public Assembly() {
patterns = Utils.getProperty("j2js.taintIfInstantiated").split(";");
for (int i=0; i<patterns.length; i++) {
// Remove all whitespace, quote '.', '(', ')', and transform
// '*' to '.*'.
String pattern = patterns[i].replaceAll("\\s", "");
pattern = pattern.replaceAll("\\.", "\\\\.");
pattern = pattern.replaceAll("\\*", ".*");
pattern = pattern.replaceAll("\\(", "\\\\(");
pattern = pattern.replaceAll("\\)", "\\\\)");
patterns[i] = pattern;
}
}
/**
* Pipes a file on the class path into a stream.
*
* @param writer the sream into which to pipe
* @param classPath the array of directories in which to locate the file
* @param relativeFilePath the name of the file
*
* @throws IOException
*/
private void pipeFileToStream(Writer writer, String relativeFilePath) throws IOException {
FileObject fileObject = J2JSCompiler.compiler.fileManager.getFileForInput(relativeFilePath);
String content;
if (J2JSCompiler.compiler.isCompression()) {
JavaScriptCompressor compressor = new JavaScriptCompressor();
content = compressor.compress(fileObject.openInputStream());
} else {
content = IOUtils.toString(fileObject.openInputStream());
}
writer.write(content);
}
private void removeOldAssemblies(File assembly) {
final String numericPostfixPattern = "-[0-9]*$";
final String prefix = assembly.getName().replaceAll(numericPostfixPattern, "");
File[] oldAssemblies = assembly.getParentFile().listFiles(new FilenameFilter() {
public boolean accept(File dir1, String name) {
return name.matches(prefix + numericPostfixPattern);
}
});
if (oldAssemblies == null) {
return;
}
for (File oldAssemblyDir : oldAssemblies) {
for (File file : oldAssemblyDir.listFiles()) {
file.delete();
}
oldAssemblyDir.delete();
}
}
public int createAssembly() throws IOException {
logger = Log.getLogger();
logger.debug("Packing ...");
removeOldAssemblies(targetLocation);
String loaderName = J2JSCompiler.compiler.getTargetPlatform().toLowerCase();
Writer writer;
if ("javascript".equals(loaderName)) {
writer = new FileWriter(targetLocation);
pipeFileToStream(writer, "javascript/loaders/" + loaderName + ".js");
} else {
targetLocation.mkdirs();
writer = new JunkWriter(targetLocation);
}
writer.write("// Assembly generated by j2js " + Utils.getVersion() + " on " + Utils.currentTimeStamp() + "\n");
pipeFileToStream(writer, "javascript/runtime.js");
writer.write("j2js.assemblyVersion = 'j2js Assembly " + targetLocation.getName() + "@" + Utils.currentTimeStamp() + "';\n");
writer.write("j2js.userData = {};\n");
int classCount = 0;
for (ClassUnit fileUnit : project.getClasses()) {
if (!fileUnit.isTainted()) continue;
writer.write("j2js.");
writer.write(DECLARECLASS);
writer.write("(\"" + fileUnit.getSignature() + "\"");
writer.write(", " + fileUnit.getSignature().getId());
writer.write(");\n");
classCount++;
}
project.currentGeneratedMethods = 0;
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
Signature signature = project.getSignature(J2JSCompiler.compiler.getSingleEntryPoint());
ClassUnit clazz = project.getClassUnit(signature.className());
clazz.write(0, writer);
} else {
ClassUnit object = project.getJavaLangObject();
object.write(0, writer);
for (ClassUnit cu : project.getClasses()) {
// TODO Interface: Generate them nicely.
if (cu.isInterface) {
cu.write(0, writer);
}
}
// for (ClassUnit cu : project.getClasses()) {
// if (cu.isInterface && cu.getInterfaces().size() != 0) {
// cu.write(0, writer);
// }
// }
}
if (getProject().getOrCreateClassUnit("java.lang.String").isTainted()) {
writer.write("String.prototype.clazz = j2js.forName('java.lang.String');\n");
}
writer.write("j2js.onLoad('" + entryPointClassName + "#main(java.lang.String[])void');\n");
// String resourcePath = J2JSCompiler.compiler.resourcePath;
// if (resourcePath != null) {
// resolveResources(new File(J2JSCompiler.compiler.getBaseDir(), resourcePath), writer);
// }
writer.close();
if ("web".equals(loaderName)) {
Writer loader = new FileWriter(new File(targetLocation, "/0.js"));
loader.write("var j2js = {assemblySize:");
loader.write(Integer.toString(((JunkWriter) writer).getSize()));
loader.write("};\n");
pipeFileToStream(loader, "javascript/loaders/" + loaderName + ".js");
loader.close();
}
return project.currentGeneratedMethods;
}
// private void resolveResources(File resourcePath, Writer writer) throws FileNotFoundException, IOException {
// File cssPath = new File(resourcePath, "/style.css");
// BufferedReader reader = new BufferedReader(new FileReader(cssPath));
// StringBuffer buffer = new StringBuffer();
//
// do {
// String line = reader.readLine();
// if (line == null) break;
// buffer.append(line.trim());
// buffer.append(" ");
// } while (true);
//
// reader.close();
//
// writer.write("j2js.style = \"" + buffer.toString() + "\";\n");
// }
// private void writeDependency() {
// Iterator iter = taintedSignatures.iterator();
// while (iter.hasNext()) {
// Signature signature = (Signature) iter.next();
// logger.fine(signature + " <- " + signature.referer);
// }
// }
public void processTainted() {
while (unprocessedTaintedSignatures.size() > 0) {
processSingle(popSignature());
if (unprocessedTaintedSignatures.size() == 0) {
processOverWrittenMembers();
}
}
}
public void processSingle(Signature signature) {
ClassUnit clazz = resolve(signature.className());
String methodPart = signature.relativeSignature();
boolean found = false;
for (MemberUnit member : clazz.getMembers(methodPart)) {
taint(member);
found = true;
}
if (!found) {
//logger.severe("No such method: " + signature);
throw new RuntimeException("No such method: " + signature);
}
// MemberUnit member = clazz.getMember(methodPart);
// if (member != null) {
// taint(member);
// } else {
// logger.severe("No such method: " + signature);
// }
}
private ClassUnit resolve(String className) {
ClassUnit clazz = project.getOrCreateClassUnit(className);
if (className.startsWith("[")) {
project.resolve(clazz);
} else {
project.resolve(clazz);
taint(className + "#<clinit>()void");
}
resolvedTypes.add(clazz);
return clazz;
}
/**
* Taint the signatures of methods matching a pattern.
*/
private void taintImplicitelyAccessedMembers(ClassUnit clazz) {
// TODO: This method is called multiple times for each clazz. This
// should not be the case!
// System.out.println(clazz.toString());
for (MemberUnit member : clazz.getDeclaredMembers()) {
for (int i=0; i<patterns.length; i++) {
if (member.getAbsoluteSignature().toString().matches(patterns[i])) {
taint(member.getAbsoluteSignature());
}
}
}
}
/**
* Taints all members which overwrite another tainted member.
*/
private void taintIfSuperTainted(ClassUnit clazz) {
if (clazz.getName().equals("java.lang.Object")) return;
for (MemberUnit member : clazz.getDeclaredMembers()) {
for (ClassUnit superType : clazz.getSupertypes()) {
Signature signature = Project.getSingleton().getSignature(superType.getName(), member.getSignature().toString());
if (taintedSignatures.contains(signature)) {
taint(member);
}
}
}
}
/**
* Taint all signatures targeted by the specified method.
*/
private void taintTargetSignatures(ProcedureUnit method) {
for (Signature targetSignature : method.getTargetSignatures()) {
taint(targetSignature);
}
}
private void processOverWrittenMembers() {
Iterator<ClassUnit> classIterator = resolvedTypes.iterator();
while (classIterator.hasNext()) {
ClassUnit clazz = classIterator.next();
if (clazz.isConstructorTainted) taintIfSuperTainted(clazz);;
}
}
public void taint(String signature) {
signature = signature.replaceAll("\\s", "");
// if (signature.indexOf('*') != -1) {
// if (!signature.endsWith(".*")) {
// throw new RuntimeException("Package signature must end with '.*'");
// }
// signature = signature.substring(0, signature.length()-2);
// File[] files = Utils.resolvePackage(J2JSCompiler.compiler.getClassPath(), signature);
// for (int i=0; i<files.length; i++) {
// String name = files[i].getName();
// if (name.endsWith(".class")) {
// taint(signature + '.' + name.substring(0, name.length()-6));
// }
// }
// } else {
Signature s = Project.getSingleton().getSignature(signature);
if (s.isClass()) {
ClassUnit clazz = resolve(s.className());
for (MemberUnit member : clazz.getDeclaredMembers()) {
taint(member.getAbsoluteSignature());
}
} else {
taint(s);
}
// }
}
private Signature popSignature() {
Iterator<Signature> iter = unprocessedTaintedSignatures.iterator();
Signature signature = iter.next();
iter.remove();
return signature;
}
public void taint(Signature signature) {
if (!signature.toString().contains("#")) {
throw new IllegalArgumentException("Signature must be field or method: " + signature);
}
if (taintedSignatures.contains(signature)) return;
taintedSignatures.add(signature);
unprocessedTaintedSignatures.add(signature);
}
public void taint(MemberUnit member) {
member.setTainted();
// TODO: Tainting super types in neccesary for generating only?
member.getDeclaringClass().setSuperTainted();
if (member instanceof ProcedureUnit) {
taintTargetSignatures((ProcedureUnit) member);
if (member instanceof ConstructorUnit) {
member.getDeclaringClass().isConstructorTainted = true;
taintImplicitelyAccessedMembers(member.getDeclaringClass());
}
}
}
/**
* @see #getProject()
*/
public void setProject(Project project) {
this.project = project;
}
public Project getProject() {
return project;
}
/**
* @return Returns the entryPointClassName.
*/
public String getEntryPointClassName() {
return entryPointClassName;
}
/**
* <p>
* The static <code>main(String[])void</code> method of the specified class is executed
* after the assembly is loaded by the script engine.
* </p>
* <p>
* In web mode, the values of the URL query string are passed to this method.
* </p>
*
* @param entryPointClassName (required) the class signature
*/
public Assembly setEntryPointClassName(String entryPointClassName) {
this.entryPointClassName = entryPointClassName;
return this;
}
/**
* @return Returns the targetLocation.
*/
public File getTargetLocation() {
return targetLocation;
}
/**
* The assembly is written to the specified directory
*
* @param targetLocation (required) the directory the assembly is written to
*/
public void setTargetLocation(File targetLocation) {
this.targetLocation = targetLocation;
}
/**
* Signature of a field or method to include in the assembly.
* <p>
* <strong>Note</strong>: Normally you will only add those entrypoints which
* the static code analyser cannot detect, for example methods called through
* reflection.
* </p>
*
* @param memberSignature the member to include
*/
public void addEntryPoint(String memberSignature) {
entryPoints.add(memberSignature);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/*
* Created on 26.12.2005
* Copyright Wolfgang Kuehn 2005
*/
package com.j2js;
import java.io.File;
import javax.xml.transform.Result;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
/**
* @author kuehn
*/
public class ConstGenerator {
public static void main(String[] args) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
StreamSource xslSource = new StreamSource(new File("src/com/j2js/instructions.xsl"));
Transformer xltTransformer = factory.newTransformer(xslSource);
StreamSource xmlSource = new StreamSource(new File("src/com/j2js/instructions.xml"));
Result result = new StreamResult(new File("src/com/j2js/Const.java"));
xltTransformer.transform(xmlSource, result);
}
}

View File

@ -0,0 +1,105 @@
package com.j2js;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
/**
* Copyright by Wolfgang Kuehn 2005
* Created on Feb 26, 2005
*/
public class Diff {
private int lookAheadLines = 5;
private LineNumberReader in1;
private LineNumberReader in2;
private int skipLineCount = 0;
public Diff(Reader r1, Reader r2) {
in1 = new LineNumberReader(r1);
in2 = new LineNumberReader(r2);
}
public Diff(File f1, File f2) throws FileNotFoundException {
this(new FileReader(f1), new FileReader(f2));
}
public boolean apply() throws IOException {
boolean equal = true;
int lineCount = 0;
while (true) {
lineCount++;
String l1 = in1.readLine();
String l2 = in2.readLine();
if (l1==null || l2==null) {
break;
} else if (l1==null && l2!=null) {
equal = false;
System.out.println("File 2 extends File 1 at line " + in2.getLineNumber());
break;
} else if (l1!=null && l2==null) {
equal = false;
System.out.println("File 1 extends File 2 at line " + in1.getLineNumber());
break;
}
if (lineCount > skipLineCount && !l1.equals(l2)) {
equal = false;
System.out.println("Mismatch");
System.out.println("File 1 Line " + in1.getLineNumber() + ": " + l1);
System.out.println("File 2 Line " + in2.getLineNumber() + ": " + l2);
if (!sync()) {
break;
}
}
}
in1.close();
in2.close();
return equal;
}
private boolean sync() throws IOException {
int maxCharactersInLine = 200;
int readAheadLimit = lookAheadLines * maxCharactersInLine;
in2.mark(readAheadLimit);
in1.mark(readAheadLimit);
for (int i=0; i<lookAheadLines; i++) {
String l1 = in1.readLine();
if (l1==null) break;
for (int j=0; j<lookAheadLines; j++) {
String l2 = in2.readLine();
if (l2==null) break;
if (l1.equals(l2)) return true;
}
try {
in2.reset();
} catch (IOException e) {
return false;
}
}
return false;
}
/**
* @return Returns the skipLineCount.
*/
public int getSkipLineCount() {
return skipLineCount;
}
/**
* @param theSkipLineCount The skipLineCount to set.
*/
public void setSkipLineCount(int theSkipLineCount) {
skipLineCount = theSkipLineCount;
}
}

View File

@ -0,0 +1,53 @@
package com.j2js;
/*
* Created on May 27, 2004
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.CodeException;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.generic.Type;
import com.j2js.dom.*;
/**
* @author wolfgang
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class ExceptionHandler extends ASTNode {
private CodeException codeException;
public ExceptionHandler(CodeException theCodeException) {
codeException = theCodeException;
}
public int getStartPC() {
return codeException.getStartPC();
}
public int getEndPC() {
return codeException.getEndPC();
}
public int getHandlerPC() {
return codeException.getHandlerPC();
}
public Type getCatchType(ConstantPool cp) {
if (codeException.getCatchType() == 0) return null;
String signature = cp.getConstantString(codeException.getCatchType(), Constants.CONSTANT_Class);
return Type.getType("L" + signature +";");
}
public boolean isDefault() {
return codeException.getCatchType()==0;
}
}

View File

@ -0,0 +1,32 @@
package com.j2js;
/*
* Created on May 27, 2004
*/
import java.util.ArrayList;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.CodeException;
/**
* @author wolfgang
*/
public class ExceptionHandlers extends ArrayList<ExceptionHandler> {
public ExceptionHandlers(Code code) {
// Join all contiguous CodeExceptions with equal handler PC.
// This is to eliminate multi-entrant execption handlers.
CodeException previousCodeException = null;
for (CodeException codeException : code.getExceptionTable()) {
if (previousCodeException != null &&
previousCodeException.getHandlerPC() == codeException.getHandlerPC()) {
previousCodeException.setEndPC(codeException.getEndPC());
} else {
add(new ExceptionHandler(codeException));
}
previousCodeException = codeException;
}
}
}

View File

@ -0,0 +1,76 @@
package com.j2js;
import com.j2js.J2JSCompiler;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* A FileManager can resolve relative file names against a class path.
* <p>
* The file names "java/lang.package-info", "java/lang/package-info" and
* "java.lang.package-info" are valid and equivalent.
* </p>
*
* @author wolle
*/
public class FileManager {
private List<Object> path = new ArrayList<Object>();
/**
* Create a new FileManager.
*
* @param classPath list of file system directories or jar files.
*/
public FileManager(List<File> classPath) {
Log.getLogger().info("Resolving class path " + classPath);
// Replace all jar files on classPath by instances of JarFile.
// Non-existing files are sorted out.
for (File file : classPath) {
if (!file.exists()) {
J2JSCompiler.errorCount++;
Log.getLogger().error("Cannot find resource on class path: " + file.getAbsolutePath());
continue;
}
if (file.getName().endsWith(".jar")) {
try {
path.add(new JarFile(file));
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
path.add(file);
}
}
}
/**
* Resolves a file given by name along the class path.
*/
public FileObject getFileForInput(String relativeName) {
for (Object o : path) {
if (o instanceof JarFile) {
JarFile jarFile = (JarFile) o;
JarEntry entry = jarFile.getJarEntry(relativeName);
if (entry != null) {
return new FileObject(jarFile, entry);
}
} else {
File file = new File(((File) o), relativeName);
if (file.exists()) {
return new FileObject(file);
}
}
}
throw new RuntimeException("Could not find " + relativeName + " on class path");
}
}

View File

@ -0,0 +1,54 @@
package com.j2js;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* File abstraction for tools. In this context, file means an abstraction of regular
* files and other sources of data.
*
* @author wolle
*/
public class FileObject {
private long lastModified;
private InputStream in;
FileObject(JarFile jarFile, JarEntry entry) {
try {
in = jarFile.getInputStream(entry);
} catch (IOException e) {
throw new RuntimeException(e);
}
lastModified = entry.getTime();
}
FileObject(File file) {
try {
in = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
lastModified = file.lastModified();
}
/**
* Gets an InputStream for this file object.
*/
public InputStream openInputStream() throws IOException {
return in;
}
/**
* @return Returns the lastModified.
*/
public long getLastModified() {
return lastModified;
}
}

View File

@ -0,0 +1,109 @@
package com.j2js;
import org.apache.bcel.generic.Type;
/**
* @author wolfgang
*/
public class Form {
public static int CATEGORY1 = 1;
public static int CATEGORY2 = 2;
public static class Value {
public String type;
public String name;
public Value(String theType, String theName) {
type = theType;
name = theName;
}
public int getCategory() {
return type.equals("cat2") || type.equals("long") || type.equals("double")?CATEGORY2:CATEGORY1;
}
}
private int index;
private Form.Value[] ins;
private Form.Value[] outs;
private Form.Value[] operands;
private Type type;
/**
* @return Returns the ins.
*/
public Form.Value[] getIns() {
return ins;
}
/**
* @param theIns The ins to set.
*/
public void setIns(Form.Value[] theIns) {
ins = theIns;
}
/**
* @return Returns the operands.
*/
public Form.Value[] getOperands() {
return operands;
}
/**
* @param theOperands The operands to set.
*/
public void setOperands(Form.Value[] theOperands) {
operands = theOperands;
}
/**
* @return Returns the outs.
*/
public Form.Value[] getOuts() {
return outs;
}
/**
* @param theOuts The outs to set.
*/
public void setOuts(Form.Value[] theOuts) {
outs = theOuts;
if (theOuts.length != 1) return;
String s = theOuts[0].type;
if (s.equals("object")) type = Type.OBJECT;
else if (s.equals("int")) type = Type.INT;
else if (s.equals("short")) type = Type.SHORT;
else if (s.equals("byte")) type = Type.SHORT;
else if (s.equals("long")) type = Type.LONG;
else if (s.equals("float")) type = Type.FLOAT;
else if (s.equals("double")) type = Type.DOUBLE;
else if (!s.equals("cat1") && !s.equals("returnAddress") && !s.equals(""))
throw new RuntimeException("Unhandled type: " + s);
}
public int getOpStackDelta() {
return getOuts().length - getIns().length;
}
public Type getResultType() {
if (type == null) throw new RuntimeException("Result type is not available for " + this);
return type;
}
/**
* @return Returns the index.
*/
public int getIndex() {
return index;
}
/**
* @param theIndex The index to set.
*/
public void setIndex(int theIndex) {
index = theIndex;
}
}

View File

@ -0,0 +1,59 @@
package com.j2js;
/**
* @author wolfgang
*/
public class InstructionType {
private short code;
private String name;
private Form[] forms;
public InstructionType(short theCode, String theName, int formCount) {
code = theCode;
name = theName;
forms = new Form[formCount];
}
public int getFormCount() {
return forms.length;
}
public void setForm(Form form, int index) {
forms[index] = form;
form.setIndex(index);
}
public Form getForm(int index) {
return forms[index];
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param theName The name to set.
*/
public void setName(String theName) {
name = theName;
}
/**
* @return Returns the code.
*/
public short getCode() {
return code;
}
/**
* @param theCode The code to set.
*/
public void setCode(short theCode) {
code = theCode;
}
}

View File

@ -0,0 +1,357 @@
// Copyright 2011 The j2js Authors. All Rights Reserved.
//
// This file is part of j2js.
//
// j2js 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 3 of the License, or
// (at your option) any later version.
//
// j2js 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 j2js. If not, see <http://www.gnu.org/licenses/>.
package com.j2js;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.j2js.FileManager;
import com.j2js.Log;
import com.j2js.Utils;
import com.j2js.assembly.Project;
import com.j2js.visitors.JavaScriptGenerator;
/**
* The cross-compiler translates Java class files into JavaScript code and assembles all reachable code
* into assemblies.
* <p>
* For details please refer to the <a href="../../../compile.html">plugin description</a>.
*
* @author Wolfgang Kuehn
*/
public class J2JSCompiler {
public static J2JSCompiler compiler;
public static int errorCount = 0;
private File basedir;
private File cacheFile;
List<com.j2js.Assembly> assemblies = new ArrayList<Assembly>();
private List<File> classpath = new ArrayList<File>();
public FileManager fileManager;
public boolean optimize = true;
public boolean failOnError = true;
private boolean compression = true;
private String singleEntryPoint;
private String targetPlatform;
public int reductionLevel = 5;
private int junkSizeInKiloBytes = Integer.MAX_VALUE;
private boolean generateLineNumbers = false;
public int compileCount = 0;
public JavaScriptGenerator generator;
private Log logger;
// Begin main
public static void main(String argv[]) throws Exception {
if ( argv == null || argv.length != 4 ) {
StringBuffer sb = new StringBuffer();
sb.append("Usage: java ");
sb.append(J2JSCompiler.class.getName());
sb.append(" <basedir> <classpathElements> <entryPointClassName> <targetLocation>");
System.out.print(sb.toString());
return;
}
File basedir = new File(argv[0]);
String classpathElements = argv[1];
String entryPointClassName = argv[2];
Assembly assembly = new Assembly();
assembly.setEntryPointClassName(entryPointClassName);
assembly.setTargetLocation(new File(basedir, argv[3]));
J2JSCompiler compiler = new J2JSCompiler();
compiler.setBasedir(basedir);
compiler.addClasspathElements(classpathElements);
compiler.addAssembly(assembly);
compiler.setGenerateLineNumbers(true);
compiler.execute();
}
// End main
/**
* Create new compiler with the current directory as basedir.
*/
public J2JSCompiler() {
setBasedir(new File(System.getProperty("user.dir")));
setTargetPlatform("web");
}
public void execute() throws Exception {
if (logger == null) {
setLogger(new Log());
}
for (Assembly assembly : assemblies) {
execute(assembly);
}
}
private boolean isMavenExecution() {
return System.getProperty("localRepository") != null;
}
public void execute(Assembly assembly) throws Exception {
J2JSCompiler.compiler = this;
logger.info("Entry point is " + assembly.getEntryPointClassName() + "#main(java.lang.String[])void");
if (classpath == null) {
throw new RuntimeException("Field classPath must be set");
}
if (assembly.getEntryPointClassName() == null) {
throw new RuntimeException("Field assembly.entryPointClassName must be set");
}
if (cacheFile == null) {
setCacheFile(new File(basedir, "target/j2js.cache"));
}
if (assembly.getTargetLocation() == null) {
throw new RuntimeException("Field assembly.targetLocation must be set");
//assembly.setTargetLocation(new File(basedir, "target/classes/assemblies/" + assembly.getEntryPointClassName().replaceAll("\\.", "/")));
}
logger.info("Creating assembly " + assembly.getTargetLocation());
fileManager = new FileManager(classpath);
Project project = Project.createSingleton(getCacheFile());
assembly.setProject(project);
generator = new JavaScriptGenerator(project);
errorCount = 0;
assembly.addEntryPoint(assembly.getEntryPointClassName() + "#main(java.lang.String[])void");
for (String memberSignature : assembly.entryPoints) {
assembly.taint(memberSignature);
}
long startTime = System.currentTimeMillis();
// Used by the JavaScript JVM. The static code analyser would miss these.
String[] signatures = Utils.getProperty("j2js.preTaintedSignatures").split(";");
for (int i=0; i<signatures.length; i++) {
assembly.taint(signatures[i]);
}
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
assembly.processSingle(project.getSignature(getSingleEntryPoint()));
} else {
assembly.processTainted();
}
int methodCount;
try {
methodCount = assembly.createAssembly();
if (getCacheFile() != null) {
Project.write();
}
} catch (IOException e) {
throw new Exception("Error while creating assembly", e);
}
logger.info(
timesName("Compiled|Compiled", compileCount, "class|classes") +
", " + timesName("packed|packed", methodCount, "method|methods") + ".");
logger.info("Execution time was " + (System.currentTimeMillis()-startTime) + " millis.");
if (errorCount > 0) {
logger.error("There " + timesName("was|were", errorCount, "error|errors") + ".");
}
}
private String timesName(String verb, int count, String noun) {
String[] verbs = verb.split("\\|");
String[] nouns = noun.split("\\|");
int index = (count==1?0:1);
return verbs[index] + " " + count + " " + nouns[index];
}
public void setCompression(boolean isCompression) {
this.compression = isCompression;
}
public boolean isCompression() {
return compression;
}
/**
* For debugging. Internal use only.
*/
public void setSingleEntryPoint(String signature) {
singleEntryPoint = signature;
}
/**
* @see #setSingleEntryPoint(String)
*/
public String getSingleEntryPoint() {
return singleEntryPoint;
}
/**
* Sets one of the target platforms "web" or "javascript".
*
* @param targetPlatform optional; default is "web"
*/
public void setTargetPlatform(String targetPlatform) {
targetPlatform = targetPlatform.toLowerCase();
if ("web".equals(targetPlatform) || "javascript".equals(targetPlatform)) {
this.targetPlatform = targetPlatform;
} else {
throw new IllegalArgumentException("Target platform must be web or javascript");
}
}
/**
* @see #setTargetPlatform(String)
*/
public String getTargetPlatform() {
return targetPlatform;
}
public List<File> getClasspath() {
return classpath;
}
/**
* @param classpathElements (optional) additional class path elements
*/
public void addClasspathElements(List<File> classpathElements) {
classpath.addAll(classpathElements);
}
/**
* @param classpathElement (optional) additional class path element
*/
public void addClasspathElement(File classpathElement) {
classpath.add(classpathElement);
}
/**
* Semicolon- or whitespace-separated list of class path elements.
*
* @param classPathElements (optional) additional class path elements
* @see #setClasspathElements(List)
*/
public void addClasspathElements(String classPathElements) {
String[] array = classPathElements.split("(;|,)");
for (String path : array) {
path = path.trim();
if (path.length() > 0) {
addClasspathElement(Utils.resolve(basedir, path));
}
}
}
public void setClasspathElements(List<String> classpathElements) {
for (Object part : classpathElements) {
addClasspathElements((String) part);
}
}
public void setFailOnError(boolean flag) {
failOnError = flag;
}
public boolean isFailOnError() {
return failOnError;
}
public File getCacheFile() {
return cacheFile;
}
public void setCacheFile(File theCacheFile) {
cacheFile = theCacheFile;
}
public List<com.j2js.Assembly> getAssemblies() {
return assemblies;
}
public void setAssemlies(List<com.j2js.Assembly> assemblies) {
this.assemblies = assemblies;
}
public void setGenerateLineNumbers(boolean theGenerateLineNumbers) {
generateLineNumbers = theGenerateLineNumbers;
}
public boolean isGenerateLineNumbers() {
return generateLineNumbers;
}
public void setJunkSizeInKiloBytes(int junkSizeInKiloBytes) {
if (junkSizeInKiloBytes < 1) {
throw new RuntimeException("Junk size must be greater than zero.");
}
this.junkSizeInKiloBytes = junkSizeInKiloBytes;
}
public int getJunkSizeInKiloBytes() {
return junkSizeInKiloBytes;
}
/**
* @return Returns the logger.
*/
public Log getLogger() {
return logger;
}
/**
* Sets the logger.
*/
public void setLogger(Log logger) {
this.logger = logger;
Log.logger = logger;
}
public void setBasedir(File basedir) {
this.basedir = basedir;
}
public File getBasedir() {
return basedir;
}
public void addAssembly(Assembly assembly) {
assemblies.add(assembly);
}
}

View File

@ -0,0 +1,76 @@
package com.j2js;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.LineNumber;
import org.apache.bcel.classfile.LineNumberTable;
import com.j2js.dom.ASTNode;
public class LineNumberCursor {
private class LineNumberComparator implements Comparator<LineNumber> {
public int compare(LineNumber arg0, LineNumber arg1) {
return arg0.getStartPC() - arg1.getStartPC();
}
}
private LineNumber[] lineNumbers = null;
private int index = 0;
private int markedLineNumber = -1;
private int length;
public LineNumberCursor(Code code) {
if (code == null) return;
LineNumberTable table = code.getLineNumberTable();
if (table == null) return;
lineNumbers = table.getLineNumberTable();
length = lineNumbers.length;
// TODO: Is table already ordered?
Arrays.sort(lineNumbers, new LineNumberComparator());
}
public boolean hasLineNumbers() {
return lineNumbers != null;
}
public int getLineNumber(ASTNode node) {
if (!hasLineNumbers()) return -1;
while (node.getBeginIndex() == Integer.MAX_VALUE && node.getPreviousSibling() != null) {
node = node.getPreviousSibling();
}
int pc = node.getBeginIndex();
L: if (pc > lineNumbers[index].getStartPC()) {
do {
if (index+1 == length) break L;
index ++;
} while (pc >= lineNumbers[index].getStartPC());
index --;
} else if (pc < lineNumbers[index].getStartPC()) {
do {
if (index == 0) break L;
index --;
} while (pc <= lineNumbers[index].getStartPC());
index ++;
}
return lineNumbers[index].getLineNumber();
}
public int getAndMarkLineNumber(ASTNode node) {
if (!hasLineNumbers()) return -1;
int lineNumber = getLineNumber(node);
if (lineNumber == markedLineNumber) return -1;
markedLineNumber = lineNumber;
return lineNumber;
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright 2005 by Wolfgang Kuehn
* Created on 04.10.2005
*/
package com.j2js;
/**
* @author wolfgang
*/
public class Log {
public static Log logger;
public static Log getLogger() {
return logger;
}
private int state = INFO;
/**
* @return Returns the state.
*/
public int getState() {
return state;
}
/**
* @param state The state to set.
*/
public void setState(int state) {
this.state = state;
}
public static final int DEBUG = 3;
public static final int INFO = 2;
public static final int WARN = 1;
public static final int ERROR = 0;
public void debug(CharSequence arg0, Throwable arg1) {
if (isDebugEnabled()) {
System.out.println("[DEBUG] " + arg0);
arg1.printStackTrace();
}
}
public void debug(CharSequence arg0) {
if (isDebugEnabled()) {
System.out.println("[DEBUG] " + arg0);
}
}
public void debug(Throwable arg0) {
if (isDebugEnabled()) {
arg0.printStackTrace();
}
}
public void error(CharSequence arg0, Throwable arg1) {
if (isErrorEnabled()) {
System.out.println("[ERROR] " + arg0);
arg1.printStackTrace();
}
}
public void error(CharSequence arg0) {
if (isErrorEnabled()) {
System.out.println("[ERROR] " + arg0);
}
}
public void error(Throwable arg0) {
if (isErrorEnabled()) {
arg0.printStackTrace();
}
}
public void info(CharSequence arg0, Throwable arg1) {
if (isInfoEnabled()) {
System.out.println("[INFO] " + arg0);
arg1.printStackTrace();
}
}
public void info(CharSequence arg0) {
if (isInfoEnabled()) {
System.out.println("[INFO] " + arg0);
}
}
public void info(Throwable arg0) {
if (isInfoEnabled()) {
arg0.printStackTrace();
}
}
public boolean isDebugEnabled() {
return state >= DEBUG;
}
public boolean isErrorEnabled() {
return state >= ERROR;
}
public boolean isInfoEnabled() {
return state >= INFO;
}
public boolean isWarnEnabled() {
return state >= WARN;
}
public void warn(CharSequence arg0, Throwable arg1) {
if (isWarnEnabled()) {
System.out.println("[WARNING] " + arg0);
arg1.printStackTrace();
}
}
public void warn(CharSequence arg0) {
if (isWarnEnabled()) {
System.out.println("[WARNING] " + arg0);
}
}
public void warn(Throwable arg0) {
if (isWarnEnabled()) {
arg0.printStackTrace();
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Created on 20.10.2004
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
package com.j2js;
import com.j2js.dom.ASTNode;
/**
* @author kuehn
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class OperandState {
int code;
int beginIndex;
int endIndex;
ASTNode stmt;
OperandState(int theCode) {
code = theCode;
}
OperandState(int theCode, int theBeginIndex, ASTNode theStmt) {
code = theCode;
beginIndex = theBeginIndex;
stmt = theStmt;
}
public String toString() {
return "State: " + code + " " + stmt;
}
}

View File

@ -0,0 +1,324 @@
package com.j2js;
import java.util.Iterator;
import java.util.List;
import org.apache.bcel.generic.Type;
import com.j2js.dom.ASTNode;
import com.j2js.dom.Assignable;
import com.j2js.dom.Assignment;
import com.j2js.dom.Block;
import com.j2js.dom.Expression;
import com.j2js.dom.FieldAccess;
import com.j2js.dom.InfixExpression;
import com.j2js.dom.MethodDeclaration;
import com.j2js.dom.NumberLiteral;
import com.j2js.dom.PStarExpression;
import com.j2js.dom.PostfixExpression;
import com.j2js.dom.PrefixExpression;
import com.j2js.dom.VariableBinding;
import com.j2js.dom.VariableDeclaration;
public class Optimizer {
private MethodDeclaration methodDecl;
private List tempDecls;
public Optimizer(MethodDeclaration theMethodDecl, List theTempDecls) {
methodDecl = theMethodDecl;
tempDecls = theTempDecls;
}
public static Expression negate(Expression expr) {
PrefixExpression pe = new PrefixExpression();
pe.setOperator(PrefixExpression.NOT);
pe.setOperand(expr);
return pe;
}
/**
* Simplifies the (possibly negated) expression.
*/
public static Expression simplifyBooleanExpression(Expression expr, boolean negate) {
if (expr instanceof PrefixExpression) {
PrefixExpression pe = (PrefixExpression) expr;
if (pe.getOperator() != PrefixExpression.NOT) return expr;
return simplifyBooleanExpression((Expression) pe.getOperand(), !negate);
}
if (expr instanceof InfixExpression && expr.getTypeBinding() == Type.BOOLEAN) {
InfixExpression in = (InfixExpression) expr;
InfixExpression.Operator op = in.getOperator();
if (negate) {
op = op.getComplement();
if (op != InfixExpression.Operator.CONDITIONAL_AND && op != InfixExpression.Operator.CONDITIONAL_OR)
negate = false;
}
InfixExpression out = new InfixExpression(op);
out.widen(in);
out.setOperands(simplifyBooleanExpression(in.getLeftOperand(), negate), simplifyBooleanExpression(in.getRightOperand(), negate));
return out;
}
if (negate) {
PrefixExpression pe = new PrefixExpression();
pe.setOperator(PrefixExpression.NOT);
pe.setOperand(expr);
return pe;
}
return expr;
}
private boolean representSameAssignables(Assignable a, Assignable b) {
if (!(a instanceof FieldAccess && b instanceof FieldAccess)) return false;
FieldAccess faa = (FieldAccess) a;
FieldAccess fab = (FieldAccess) b;
if (!faa.getName().equals(fab.getName())) return false;
if (faa.getExpression() instanceof VariableBinding && fab.getExpression() instanceof VariableBinding ) {
VariableBinding vba = (VariableBinding) faa.getExpression();
VariableBinding vbb = (VariableBinding) fab.getExpression();
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
}
return false;
}
/**
* Reduces occurences of
* temp = x;
* y = temp;
* to
* y = x;
*/
// private ASTNode bar1(ASTNode child, ASTNode next) {
// if (child instanceof Assignment && next instanceof Assignment) {
// Assignment a1 = (Assignment) child;
// Assignment a2 = (Assignment) next;
// if (a1.getLeftHandSide().equals(a2.getRightHandSide())) {
// a2.setRightHandSide(a1.getRightHandSide());
// child.getParentBlock().removeChild(child);
// return next;
// }
// }
// return child;
// }
private VariableBinding fetchVariableBinding(Expression expr, VariableDeclaration decl) {
ASTNode child = expr.getFirstChild();
while (child != null) {
if (child instanceof VariableBinding && ((VariableBinding) child).getVariableDeclaration() == decl)
return (VariableBinding) child;
VariableBinding vb = fetchVariableBinding((Expression) child, decl);
if (vb != null) return vb;
child = child.getNextSibling();
}
return null;
}
/**
* If the specified expression corresponds to
* xy + 1 or xy - (-1),
* returns the INCREMENT operator. If the specified expression corresponds to
* xy - 1 or xy + (-1),
* returns the DECREMENT operator. Otherwise, null is returned.
* @param expr
* @return
*/
private PStarExpression.Operator getOp(InfixExpression expr) {
NumberLiteral nl;
if (expr.getRightOperand() instanceof NumberLiteral) {
nl = (NumberLiteral) expr.getRightOperand();
} else return null;
PStarExpression.Operator op;
if (expr.getOperator() == InfixExpression.Operator.PLUS) {
op = PStarExpression.INCREMENT;
} else if (expr.getOperator() == InfixExpression.Operator.MINUS) {
op = PStarExpression.DECREMENT;
} else {
return null;
}
if (NumberLiteral.isOne(nl)) {
// We are ok.
} else if (NumberLiteral.isMinusOne(nl)) {
op = op.complement();
} else {
return null;
}
return op;
}
/**
* Reduces
* vb = x.y; (1)
* x.y = vb + 1; (2)
* ...
* expr(vb);
* to incremental form
* expr(x.y++);
* Likewise decrement.
*/
private boolean reduceXCrement(VariableDeclaration decl) {
Assignment a1 = null;
Assignment a2 = null;
VariableBinding vb1 = null;
VariableBinding vb2 = null;
Assignable fa1 = null;
Assignable fa2 = null;
InfixExpression sum = null;
Iterator iter = decl.vbs.iterator();
while (iter.hasNext()) {
VariableBinding vb = (VariableBinding) iter.next();
if (vb.getParentNode() instanceof Assignment) {
Assignment a = (Assignment) vb.getParentNode();
if (a.getLeftHandSide() == vb && a.getRightHandSide() instanceof Assignable) {
vb1 = vb;
a1 = a;
fa1 = (Assignable) a.getRightHandSide();
continue;
}
}
if (vb.getParentNode() instanceof InfixExpression) {
InfixExpression infix = (InfixExpression) vb.getParentNode();
if (infix.getParentNode() instanceof Assignment) {
Assignment a = (Assignment) infix.getParentNode();
if (a.getLeftHandSide() instanceof Assignable) {
vb2 = vb;
fa2 = (Assignable) a.getLeftHandSide();
a2 = a;
sum = infix;
continue;
}
}
}
}
if (a1 == null || a2 == null) return false;
if (!fa1.isSame(fa2)) return false;
PStarExpression.Operator operator = getOp(sum);
if (operator == null) return false;
PStarExpression p = new PostfixExpression();
p.setOperand((Expression) fa1);
p.setOperator(operator);
decl.vbs.remove(vb1);
decl.vbs.remove(vb2);
VariableBinding vb = decl.vbs.get(0);
vb.getParentBlock().replaceChild(p, vb);
Block b = a1.getParentBlock();
b.removeChild(a1);
b.removeChild(a2);
return true;
}
/**
* Reduces
* vb = x.y op z; (3)
* x.y = vb; (4)
* ...
* expr(vb);
* to incremental form
* expr(x.y op= z) or expr(++x.y);
* Likewise decrement.
*/
private boolean reduceYCrement(VariableDeclaration decl) {
Assignment a1 = null;
Assignment a2 = null;
VariableBinding vb1 = null;
VariableBinding vb2 = null;
Assignable fa1 = null;
Assignable fa2 = null;
InfixExpression infixExpr = null;
Iterator iter = decl.vbs.iterator();
while (iter.hasNext()) {
VariableBinding vb = (VariableBinding) iter.next();
if (!(vb.getParentNode() instanceof Assignment)) continue;
Assignment a = (Assignment) vb.getParentNode();
if (a.getRightHandSide() == vb && a.getLeftHandSide() instanceof Assignable) {
vb2 = vb;
a2 = a;
fa2 = (Assignable) a.getLeftHandSide();
continue;
}
if (a.getLeftHandSide() == vb && a.getRightHandSide() instanceof InfixExpression) {
InfixExpression infix = (InfixExpression) a.getRightHandSide();
if (!(infix.getLeftOperand() instanceof Assignable)) continue;
vb1 = vb;
a1 = a;
fa1 = (Assignable) infix.getLeftOperand();
infixExpr = infix;
continue;
}
}
if (a1 == null || a2 == null) return false;
if (!fa1.isSame(fa2)) return false;
decl.vbs.remove(vb1);
decl.vbs.remove(vb2);
VariableBinding vb = decl.vbs.get(0);
Expression replacement = null;
PStarExpression.Operator operator = getOp(infixExpr);
if (operator != null) {
PrefixExpression p = new PrefixExpression();
p.setOperand((Expression) fa1);
p.setOperator(operator);
replacement = p;
} else {
InfixExpression.Operator op = infixExpr.getOperator();
Assignment.Operator opp = Assignment.Operator.lookup(op.toString() + '=');
Assignment a = new Assignment(opp);
a.setLeftHandSide((Expression) fa2);
a.setRightHandSide(infixExpr.getRightOperand());
replacement = a;
}
vb.getParentBlock().replaceChild(replacement, vb);
Block b = a1.getParentBlock();
b.removeChild(a1);
b.removeChild(a2);
return true;
}
public void optimize() {
if (false) return;
// Review this code. For example j2js.fa(obj, name)++ is illegal!
Iterator iter = tempDecls.iterator();
while (iter.hasNext()) {
VariableDeclaration decl = (VariableDeclaration) iter.next();
int count = decl.vbs.size();
if (count == 3) {
if (reduceXCrement(decl)) {
iter.remove();
methodDecl.removeLocalVariable(decl.getName());
} else if (reduceYCrement(decl)) {
iter.remove();
methodDecl.removeLocalVariable(decl.getName());
}
}
}
}
}

View File

@ -0,0 +1,25 @@
package com.j2js;
import com.j2js.dom.ASTNode;
/**
* @author kuehn
*/
public class ParseException extends RuntimeException {
private ASTNode astNode;
public ParseException(String msg, ASTNode node) {
super(msg);
astNode = node;
}
public ParseException(Throwable cause, ASTNode node) {
super(cause);
astNode = node;
}
public ASTNode getAstNode() {
return astNode;
}
}

View File

@ -0,0 +1,204 @@
package com.j2js;
import com.j2js.J2JSCompiler;
import java.io.IOException;
import java.lang.reflect.Modifier;
import com.j2js.Pass1;
import com.j2js.ParseException;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.AttributeReader;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import com.j2js.assembly.ClassUnit;
import com.j2js.assembly.Project;
import com.j2js.assembly.Signature;
import com.j2js.dom.*;
/**
* @author wolfgang
*/
public class Parser {
public static String getResourcePath(String name) {
name = name.replace('.', '/') + ".class";
java.net.URL url = Parser.class.getClassLoader().getResource(name);
if (url == null) throw new RuntimeException("Resource not found: " + name);
return url.getPath();
}
private JavaClass jc;
private ClassUnit fileUnit;
public Parser(ClassUnit theFileUnit) {
fileUnit = theFileUnit;
fileUnit.annotations = null;
AttributeReader r = new AnnotationReader(fileUnit);
Attribute.addAttributeReader("RuntimeVisibleAnnotations", r);
try {
ClassParser cp = new ClassParser(fileUnit.getClassFile().openInputStream(), fileUnit.getName());
jc = cp.parse();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public TypeDeclaration parse() {
// Attribute[] attributes = jc.getAttributes();
// for (int i=0; i<attributes.length; i++) {
// Logger.getLogger().info(attributes[i].toString());
// }
org.apache.bcel.classfile.Method[] bcelMethods = jc.getMethods();
ObjectType type = new ObjectType(jc.getClassName());
TypeDeclaration typeDecl = new TypeDeclaration(type, jc.getAccessFlags());
fileUnit.isInterface = Modifier.isInterface(typeDecl.getAccess());
if (!type.getClassName().equals("java.lang.Object")) {
// For an interface, the super class is always java.lang.Object, see 4.1 VM Spec.
// TODO Interface: Why cant we ignore it?
//if (!Modifier.isInterface(typeDecl.getAccess())) {
ObjectType superType = new ObjectType(jc.getSuperclassName());
typeDecl.setSuperType(superType);
ClassUnit superUnit = Project.getSingleton().getOrCreateClassUnit(superType.getClassName());
fileUnit.setSuperUnit(superUnit);
//}
// TODO: This should be executed also for java.lang.Object.
String[] interfaceNames = jc.getInterfaceNames();
for (int i=0; i<interfaceNames.length; i++) {
ObjectType interfaceType = new ObjectType(interfaceNames[i]);
ClassUnit interfaceUnit = Project.getSingleton().getOrCreateClassUnit(interfaceType.getClassName());
fileUnit.addInterface(interfaceUnit);
}
}
Field[] fields = jc.getFields();
for (int i=0; i<fields.length; i++) {
Field field = fields[i];
VariableDeclaration variableDecl = new VariableDeclaration(VariableDeclaration.NON_LOCAL);
variableDecl.setName(field.getName());
variableDecl.setModifiers(field.getModifiers());
variableDecl.setType(field.getType());
typeDecl.addField(variableDecl);
}
for (int i=0; i<bcelMethods.length; i++) {
Method method = bcelMethods[i];
// Java 5 generates a "bridge synthetic" accessor method for some
// methods used in a generic context (for example Comparator.compare(Object, Object)
// will call Comparator.compare(String, String)). Those methods are essential!
//if (Modifier.isVolatile(method.getAccessFlags())) continue;
MethodBinding binding = MethodBinding.lookup(jc.getClassName(), method.getName(), method.getSignature());
if (J2JSCompiler.compiler.getSingleEntryPoint() != null) {
Signature signature = Project.getSingleton().getSignature(binding.toString());
String singleSignature = J2JSCompiler.compiler.getSingleEntryPoint();
if (!signature.toString().equals(singleSignature)) continue;
}
MethodDeclaration methodDecl = new MethodDeclaration(binding, method.getAccessFlags(), method.getCode());
typeDecl.addMethod(methodDecl);
parseMethod(typeDecl, methodDecl, method);
}
return typeDecl;
}
public void parseMethod(TypeDeclaration typeDecl, MethodDeclaration methodDecl, Method method) {
Type[] types = method.getArgumentTypes();
int offset;
if (Modifier.isStatic(methodDecl.getAccess())) {
offset = 0;
} else {
// Reference to this is first argument for member method.
offset = 1;
}
for (int i=0; i<types.length; i++) {
VariableDeclaration variableDecl = new VariableDeclaration(VariableDeclaration.LOCAL_PARAMETER);
variableDecl.setName(VariableDeclaration.getLocalVariableName(method, offset, 0));
variableDecl.setType(types[i]);
methodDecl.addParameter(variableDecl);
offset += types[i].getSize();
}
if (methodDecl.getCode() == null) return;
Log.getLogger().debug("Parsing " + methodDecl.toString());
Pass1 pass1 = new Pass1(jc);
try {
pass1.parse(method, methodDecl);
} catch (Throwable ex) {
ASTNode node = null;
if (ex instanceof ParseException) {
node = ((ParseException) ex).getAstNode();
} else {
node = Pass1.getCurrentNode();
}
if (J2JSCompiler.compiler.isFailOnError()) {
throw Utils.generateException(ex, methodDecl, node);
} else {
String msg = Utils.generateExceptionMessage(methodDecl, node);
J2JSCompiler.errorCount++;
Log.getLogger().error(msg + "\n" + Utils.stackTraceToString(ex));
}
Block body = new Block();
ThrowStatement throwStmt = new ThrowStatement();
MethodBinding binding = MethodBinding.lookup("java.lang.RuntimeException", "<init>", "(java/lang/String)V;");
ClassInstanceCreation cic = new ClassInstanceCreation(methodDecl, binding);
cic.addArgument(new StringLiteral("Unresolved decompilation problem"));
throwStmt.setExpression(cic);
body.appendChild(throwStmt);
methodDecl.setBody(body);
}
// Remove from body last expressionless return statement.
if (J2JSCompiler.compiler.optimize && methodDecl.getBody().getLastChild() instanceof ReturnStatement) {
ReturnStatement ret = (ReturnStatement) methodDecl.getBody().getLastChild();
if (ret.getExpression() == null) {
methodDecl.getBody().removeChild(ret);
}
}
Pass1.dump(methodDecl.getBody(), "Body of " + methodDecl.toString());
// if (typeDecl.getClassName().equals("java.lang.String")) {
// if (methodDecl.isInstanceConstructor()) {
//
// }
// }
return;
}
public ConstantPool getConstantPool() {
return jc.getConstantPool();
}
public String toString() {
return jc.getClassName();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,160 @@
package com.j2js;
import com.j2js.J2JSCompiler;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BasicType;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import com.j2js.dom.ASTNode;
import com.j2js.dom.MethodDeclaration;
/**
* @author j2js.com
*/
public final class Utils {
private static final String propertiesFile = "j2js.properties";
private static final Properties properties;
static {
properties = new Properties();
try {
properties.load(Utils.class.getClassLoader().getResourceAsStream(propertiesFile));
} catch (Exception e) {
J2JSCompiler.errorCount++;
Log.getLogger().error("Could not read from classpath: " + propertiesFile);
throw new RuntimeException(e);
}
}
private Utils() {}
public static String generateExceptionMessage(MethodDeclaration methodDecl, ASTNode node) {
String msg = null;
if (node != null) {
int line = methodDecl.getLineNumberCursor().getLineNumber(node);
if (line != -1) {
msg = "Error near line " + line;
}
}
if (msg == null) {
msg = "Error";
}
msg += " in " + methodDecl.getMethodBinding();
return msg;
}
public static RuntimeException generateException(Throwable e, MethodDeclaration methodDecl, ASTNode node) {
String msg = generateExceptionMessage(methodDecl, node);
J2JSCompiler.errorCount++;
Log.getLogger().error(msg);
return new RuntimeException(msg, e);
}
public static String stackTraceToString(Throwable e) {
StringWriter sw = new StringWriter();
PrintWriter writer = new PrintWriter(sw);
e.printStackTrace(writer);
writer.close();
return sw.getBuffer().toString();
}
public static String currentTimeStamp() {
return DateFormat.getDateTimeInstance().format(new Date());
}
public static String getVersion() {
return (String) properties.get("j2js.version");
}
public static String getProperty(String key) {
return (String) properties.get(key);
}
public static String getSignature(Type type) {
String signature;
if (type instanceof ArrayType) {
ArrayType aType = (ArrayType) type;
signature = getSignature(aType.getBasicType());
for (int i = 0; i<aType.getDimensions(); i++) {
signature += "[]";
}
} else if (type instanceof ObjectType) {
signature = ((ObjectType) type).getClassName();
} else {
if (!(type instanceof BasicType)) throw new RuntimeException();
signature = type.toString();
}
return signature;
}
public static String escape(String str) {
int len = str.length();
StringBuffer buf = new StringBuffer(len + 5);
char[] ch = str.toCharArray();
for (int i = 0; i < len; i++) {
switch (ch[i]) {
case '\\' :
buf.append("\\\\");
break;
case '\n' :
buf.append("\\n");
break;
case '\r' :
buf.append("\\r");
break;
case '\t' :
buf.append("\\t");
break;
case '\b' :
buf.append("\\b");
break;
case '"' :
buf.append("\\\"");
break;
default :
buf.append(ch[i]);
}
}
return '"' + buf.toString() + '"';
}
// public static File[] resolvePackage(File[] classPath, String signature) {
// File dir = resolve(classPath, signature.replaceAll("\\.", "/"));
// if (!dir.isDirectory()) {
// throw new RuntimeException("Package " + signature + " could not be resolved");
// }
// return dir.listFiles();
// }
/**
* If path is absolute, returns the file with the given path. Otherwise returns
* the file with path resolved against baseDir.
*/
public static File resolve(File baseDir, String path) {
File resolvedFile = new File(path);
if (!resolvedFile.isAbsolute()) {
resolvedFile = new File(baseDir, path);
}
return resolvedFile;
}
}

View File

@ -0,0 +1,288 @@
package com.j2js.assembly;
import com.j2js.J2JSCompiler;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import com.j2js.FileObject;
import com.j2js.Log;
/**
* Instances of ClassUnit represent classes and interfaces managed by a project.
*
* @author wolle
*/
public class ClassUnit extends Unit {
static final long serialVersionUID = 1;
// Time stamp at which unit was last compiled.
private long lastCompiled;
/**
* Returns the time stamp at which the class file was last modified.
*/
public long getLastModified() {
return getClassFile().getLastModified();
}
// All members declared by this class, mapped by relative signature.
private Map<String, MemberUnit> declaredMembers;
// The super class.
private ClassUnit superUnit;
// All interfaces implemented by this unit.
private Collection<ClassUnit> interfaces;
// All derived classes.
private Collection<ClassUnit> subUnits;
public boolean isInterface = false;
public boolean isConstructorTainted = false;
public Map<String, String>[] annotations;
private Project project;
// Transient fields start here.
private transient boolean isResolved = false;
// The class file of this unit.
private transient FileObject classFile;
public ClassUnit() {
}
public ClassUnit(Project theProject, Signature theSignature) {
project = theProject;
interfaces = new HashSet<ClassUnit>();
declaredMembers = new HashMap<String, MemberUnit>();
subUnits = new HashSet<ClassUnit>();
lastCompiled = -1;
setSignature(theSignature);
}
/**
* Reset all fields filled by compilation.
*/
void clear() {
// Do not remove registered subunits!
lastCompiled = -1;
removeInterfaces();
setSuperUnit(null);
declaredMembers.clear();
}
/**
* Returns true if this unit is up to date.
*/
public boolean isUpToDate() {
return lastCompiled >= getLastModified();
}
public Collection<ClassUnit> getInterfaces() {
return interfaces;
}
public void addInterface(ClassUnit interfaceUnit) {
interfaces.add(interfaceUnit);
//interfaceUnit.addSubUnit(this);
}
private void removeInterfaces() {
Iterator iter = interfaces.iterator();
while (iter.hasNext()) {
ClassUnit interfaceUnit = (ClassUnit) iter.next();
interfaceUnit.removeSubUnit(this);
iter.remove();
}
}
public void addSubUnit(ClassUnit subUnit) {
if (subUnit == null) throw new NullPointerException();
subUnits.add(subUnit);
}
public void removeSubUnit(ClassUnit subUnit) {
if (subUnit == null) throw new NullPointerException();
subUnits.remove(subUnit);
}
public Collection<ClassUnit> getSubUnits() {
return subUnits;
}
/**
* Returns the declared member with the specified signature.
*/
public MemberUnit getDeclaredMember(String signature) {
if (signature == null) throw new NullPointerException();
return declaredMembers.get(signature);
}
/**
* Returns all types to which this class can be converted, i.e., the collection of
* all supertypes and implemented interfaces and the class itself.
*/
public Collection<ClassUnit> getSupertypes() {
TypeCollector collector = new TypeCollector();
project.visitSuperTypes(this, collector);
return collector.collectedTypes;
}
/**
* Returns a member object that reflects the specified public member method of the class
* or interface represented by this Class object.
*/
// public MemberUnit getMember(String signature) {
// if (signature == null) throw new NullPointerException();
//
// ClassUnit clazz = this;
// do {
// MemberUnit member = clazz.getDeclaredMember(signature);
// if (member != null) return member;
// clazz = clazz.getSuperUnit();
// } while (clazz != null);
//
// return null;
// }
public Collection<MemberUnit> getMembers(String signature) {
if (signature == null) throw new NullPointerException();
ArrayList<MemberUnit> list = new ArrayList<MemberUnit>();
for (ClassUnit clazz : getSupertypes()) {
MemberUnit member = clazz.getDeclaredMember(signature);
if (member != null) list.add(member);
}
return list;
}
public Collection<MemberUnit> getDeclaredMembers() {
if (!isResolved) throw new RuntimeException("Class is not yet resolved: " + getName());
return declaredMembers.values();
}
public void addMemberUnit(MemberUnit unit) {
declaredMembers.put(unit.getSignature().toString(), unit);
}
public ClassUnit getSuperUnit() {
return superUnit;
}
public void setSuperUnit(ClassUnit theSuperUnit) {
if (superUnit != null) {
superUnit.removeSubUnit(this);
}
superUnit = theSuperUnit;
if (superUnit != null) {
superUnit.addSubUnit(this);
}
}
public void write(int depth, Writer writer) throws IOException {
if (!isTainted()) return;
Log.getLogger().debug(getIndent(depth) + this);
if (getData() != null) {
writer.write(getData());
} else {
// TODO: Is it correct to return so soon?
return;
}
if (interfaces.size() > 0) {
//Logger.getLogger().info("Class + " + this.getName() + " has interfaces: ");
writer.write("_T.interfaces = [");
int i = 0;
for (ClassUnit interFace : interfaces) {
//Logger.getLogger().info(">>>" + interFace.getName());
if (i++ > 0) writer.write(", ");
writer.write(String.valueOf(interFace.getSignature().getId()));
}
writer.write("];\n");
}
if (annotations != null) {
writer.write("_T.annotations = ");
Serializer serializer = new Serializer(writer);
serializer.serialize(annotations);
writer.write(";\n");
}
for (MemberUnit member : getDeclaredMembers()) {
if (member.isTainted()) {
member.write(depth + 1, writer);
if (member instanceof ProcedureUnit) {
project.currentGeneratedMethods++;
writer.flush();
}
}
}
for (ClassUnit child : getSubUnits()) {
// TODO Interface: Interfaces must not extend java.lang.Object!
//if (!child.isInterface) {
child.write(depth + 1, writer);
//}
}
}
void setSignature(Signature theSignature) {
super.setSignature(theSignature);
}
public FileObject getClassFile() {
if (classFile == null) {
classFile = J2JSCompiler.compiler.fileManager.getFileForInput(
getSignature().toString().replaceAll("\\.", "/") + ".class");
}
return classFile;
}
public void setLastCompiled(long theLastCompiled) {
lastCompiled = theLastCompiled;
}
public boolean isResolved() {
return isResolved;
}
public void setSuperTainted() {
ClassUnit clazz = this;
do {
clazz.setTainted();
clazz = clazz.getSuperUnit();
} while (clazz != null);
for (ClassUnit i : interfaces) {
i.setSuperTainted();
}
}
public void setResolved(boolean theIsResolved) {
isResolved = theIsResolved;
}
public String getName() {
return getSignature().className();
}
public Project getProject() {
return project;
}
}

View File

@ -0,0 +1,14 @@
package com.j2js.assembly;
/**
* ConstructorUnit provides information about, and access to, a single constructor for a class.
*
* @author wolle
*/
public class ConstructorUnit extends ProcedureUnit {
public ConstructorUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
super(theSignature, theDeclaringClazz);
}
}

View File

@ -0,0 +1,21 @@
package com.j2js.assembly;
import java.io.IOException;
import java.io.Writer;
/**
* A FieldUnit provides information about, and dynamic access to, a single field of a class or an interface.
*
* @author wolle
*/
public class FieldUnit extends MemberUnit {
public FieldUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
super(theSignature, theDeclaringClazz);
}
void write(int depth, Writer writer) throws IOException {
return;
}
}

View File

@ -0,0 +1,69 @@
package com.j2js.assembly;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JavaScriptCompressor {
private int CODE = 0;
private int LINECOMMENT = 1;
private int MULTILINECOMMENT = 2;
private int STRING = 3;
public String compress(InputStream input) throws FileNotFoundException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuffer buffer = new StringBuffer();
int state = CODE;
char c;
char lastC = 0;
do {
int i = reader.read();
if (i == -1) break;
c = (char) i;
if (state == LINECOMMENT) {
if (c == '\n') {
state = CODE;
buffer.append(c);
} // else ignore character.
} else if (state == MULTILINECOMMENT) {
if (c == '/' && lastC == '*') {
state = CODE;
} // else ignore character.
} else if (state == STRING) {
if (c == '"') {
state = CODE;
}
buffer.append(c);
} else if (c == '/' && lastC == c) {
state = LINECOMMENT;
buffer.deleteCharAt(buffer.length()-1);
} else if (c == '*' && lastC == '/') {
state = MULTILINECOMMENT;
buffer.deleteCharAt(buffer.length()-1);
} else if (c == '"') {
state = STRING;
buffer.append(c);
} else {
int length = buffer.length();
if (length > 0 && Character.isWhitespace(c) && Character.isWhitespace(buffer.charAt(length-1))) {
} else {
buffer.append(c);
}
}
lastC = c;
} while (true);
reader.close();
return buffer.toString();
}
}

View File

@ -0,0 +1,81 @@
package com.j2js.assembly;
import com.j2js.J2JSCompiler;
import java.io.File;
import java.io.FileWriter;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.StringWriter;
import com.j2js.Log;
public class JunkWriter extends FilterWriter {
private File assembly;
private int junkCount = 0;
private int sizeOfCurrentJunk;
private int sizeOfAllJunks = 0;
public JunkWriter(File assembly) throws IOException {
super(new StringWriter());
this.assembly = assembly;
startNewJunk();
}
private void startNewJunk() throws IOException {
sizeOfAllJunks += sizeOfCurrentJunk;
if (junkCount > 0) {
write("j2js.loadScript(" + sizeOfAllJunks + ");");
out.flush();
out.close();
}
Log logger = Log.getLogger();
String newJunkName = (junkCount + 1) + ".js";
logger.info("Creating assembly " + newJunkName);
out = new FileWriter(new File(assembly, newJunkName));
sizeOfCurrentJunk = 0;
junkCount++;
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
super.write(cbuf, off, len);
sizeOfCurrentJunk += len;
}
@Override
public void write(int c) throws IOException {
super.write(c);
sizeOfCurrentJunk++;
}
@Override
public void write(String str, int off, int len) throws IOException {
super.write(str, off, len);
sizeOfCurrentJunk += len;
}
@Override
public void flush() throws IOException {
super.flush();
if (sizeOfCurrentJunk/1024 > J2JSCompiler.compiler.getJunkSizeInKiloBytes()) {
startNewJunk();
}
}
@Override
public void close() throws IOException {
sizeOfAllJunks += sizeOfCurrentJunk;
// Set to 0 in case super.close() calls flush().
sizeOfCurrentJunk = 0;
super.close();
}
public int getSize() {
return sizeOfAllJunks;
}
}

View File

@ -0,0 +1,32 @@
package com.j2js.assembly;
/**
* The MemberUnit class is the base class for Field, Method and Constructor objects.
*
* @author wolle
*/
public abstract class MemberUnit extends Unit {
// The class to which this method belongs.
ClassUnit declaringClass;
MemberUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
setSignature(theSignature);
declaringClass = theDeclaringClazz;
declaringClass.addMemberUnit(this);
}
public ClassUnit getDeclaringClass() {
return declaringClass;
}
public Signature getAbsoluteSignature() {
Signature s = Project.getSingleton().getSignature(declaringClass.toString(), getSignature().toString());
return s;
}
public String toString() {
return declaringClass.getName() + "#" + super.toString();
}
}

View File

@ -0,0 +1,14 @@
package com.j2js.assembly;
/**
* A MethodUnit provides information about, and access to, a single method on a class or interface.
*
* @author wolle
*/
public class MethodUnit extends ProcedureUnit {
public MethodUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
super(theSignature, theDeclaringClazz);
}
}

View File

@ -0,0 +1,51 @@
package com.j2js.assembly;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import com.j2js.Log;
public abstract class ProcedureUnit extends MemberUnit {
// Set of all member signatures targeted by this method.
private Collection<Signature> targetSignatures = new HashSet<Signature>();
public ProcedureUnit(Signature theSignature, ClassUnit theDeclaringClazz) {
super(theSignature, theDeclaringClazz);
}
public void addTarget(Signature targetSignature) {
if (!targetSignature.toString().contains("#")) {
throw new IllegalArgumentException("Signature must be field or method: " + targetSignature);
}
//Logger.getLogger().info("Adding " + this + " -> " + targetSignature);
targetSignatures.add(targetSignature);
}
public void removeTargets() {
Iterator iter = targetSignatures.iterator();
while (iter.hasNext()) {
iter.next();
iter.remove();
}
}
void write(int depth, Writer writer) throws IOException {
if (getData() == null) return;
Log.getLogger().debug(getIndent(depth) + getSignature());
writer.write(getData());
}
public String getData() {
if (!declaringClass.isResolved()) throw new RuntimeException("Class must be resolved");
return super.getData();
}
public Collection<Signature> getTargetSignatures() {
return targetSignatures;
}
}

View File

@ -0,0 +1,330 @@
package com.j2js.assembly;
import com.j2js.J2JSCompiler;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
import com.j2js.Log;
import com.j2js.Utils;
import com.j2js.dom.ArrayCreation;
import com.j2js.dom.FieldAccess;
import com.j2js.dom.MethodBinding;
import com.j2js.dom.MethodDeclaration;
import com.j2js.dom.MethodInvocation;
import com.j2js.dom.TypeDeclaration;
public class Project implements Serializable {
static final long serialVersionUID = 0;
private static Project singleton;
// All managed classes mapped by class name.
private Map<String, ClassUnit> classesByName;
private ClassUnit javaLangObject;
private boolean compressed;
private boolean generateLineNumbers;
private Map<String, Signature> signatures;
private transient Stack<Integer> ids;
private transient int currentId;
private transient int currentIndex;
public transient int currentGeneratedMethods;
public static Project getSingleton() {
if (singleton == null) throw new NullPointerException();
return singleton;
}
public static Project createSingleton(File cacheFile) {
if (cacheFile != null && cacheFile.exists()) {
Log.getLogger().info("Using cache " + cacheFile);
try {
read(cacheFile);
} catch (Exception e) {
Log.getLogger().warn("Could not read cache:\n" + e.getMessage());
}
}
if (singleton == null ||
singleton.compressed != J2JSCompiler.compiler.isCompression() ||
singleton.generateLineNumbers != J2JSCompiler.compiler.isGenerateLineNumbers()) {
// Cache does not exist, could not be read, or compression does not match.
singleton = new Project();
singleton.clear();
}
return singleton;
}
private static void read(File file) throws Exception {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
singleton = (Project) ois.readObject();
ois.close();
}
public static void write() throws IOException {
File file = J2JSCompiler.compiler.getCacheFile();
if (file.exists() && !file.canWrite()) {
throw new IOException("Cannot write " + file);
}
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(singleton);
oos.close();
}
public Signature getArraySignature(Type type) {
String signatureString = type.getSignature();
/* Examples:
* L[java.lang.Integer;; -> [java.lang.Integer;
* L[I; -> [I
*/
if (!signatureString.startsWith("L") || !signatureString.endsWith(";")) {
throw new RuntimeException("Not a class signature: " + signatureString);
}
signatureString = signatureString.substring(1, signatureString.length()-1);
return getSignature(signatureString);
}
/**
* All request for a signature delegate to this method.
*/
public Signature getSignature(String signatureString) {
if (signatureString.endsWith(";")) {
//throw new RuntimeException("Invalid signature: " + signatureString);
}
signatureString = signatureString.replaceAll("/", ".");
Signature signature = signatures.get(signatureString);
if (signature == null) {
signature = new Signature(signatureString, getUniqueId());
signatures.put(signatureString, signature);
}
return signature;
}
public Signature getSignature(String className, String relativeSignature) {
return getSignature(className + '#' + relativeSignature);
}
public Signature getSignature(FieldAccess fa) {
return getSignature(fa.getType().getClassName(), fa.getName());
}
private int getUniqueId() {
if (ids == null) {
ids = new Stack<Integer>();
for (Signature signature : signatures.values()) {
ids.add(signature.getId());
}
Collections.sort(ids);
}
while (currentIndex<ids.size() && ids.get(currentIndex) == currentId) {
currentId += 1;
currentIndex += 1;
}
currentId++;
return currentId - 1;
}
private void clear() {
classesByName = new HashMap<String, ClassUnit>();
javaLangObject = null;
signatures = new HashMap<String, Signature>();
ids = null;
currentId = 0;
currentIndex = 0;
compressed = J2JSCompiler.compiler.isCompression();
generateLineNumbers = J2JSCompiler.compiler.isGenerateLineNumbers();
}
public void remove(ClassUnit clazz) {
classesByName.remove(clazz);
}
void visitSuperTypes(ClassUnit clazz, TypeVisitor visitor) {
visitor.visit(clazz);
ClassUnit superClass = clazz.getSuperUnit();
if (superClass != null) {
visitSuperTypes(superClass, visitor);
}
for (ClassUnit interfaceUnit : clazz.getInterfaces()) {
visitor.visit(interfaceUnit);
visitSuperTypes(interfaceUnit, visitor);
}
}
public ClassUnit getJavaLangObject() {
return javaLangObject;
}
public ClassUnit getClassUnit(String className) {
ClassUnit clazz = classesByName.get(className);
if (clazz != null) return clazz;
throw new RuntimeException("No such unit: " + className);
}
public ClassUnit getClassUnit(ReferenceType type) {
String signature;
if (type instanceof ArrayType) {
ArrayType aType = (ArrayType) type;
signature = Utils.getSignature(aType.getBasicType());
for (int i = 0; i<aType.getDimensions(); i++) {
signature += "[]";
}
} else {
signature = Utils.getSignature(type);
}
return getClassUnit(signature);
}
public ClassUnit getOrCreateClassUnit(String className) {
ClassUnit classUnit = classesByName.get(className);
if (classUnit != null) return classUnit;
Signature signature = Project.singleton.getSignature(className);
classUnit = new ClassUnit(this, signature);
classesByName.put(className, classUnit);
if (className.equals("java.lang.Object")) {
javaLangObject = classUnit;
}
return classUnit;
}
private MemberUnit getMemberUnitOrNull(String className, Signature signature) {
ClassUnit classUnit = getOrCreateClassUnit(className);
if (classUnit == null) return null;
return classUnit.getDeclaredMember(signature.toString());
}
private MemberUnit getMemberUnit(String className, Signature signature) {
MemberUnit unit = getMemberUnitOrNull(className, signature);
if (unit == null) {
throw new RuntimeException("No such unit: " + className + "#"+ signature);
}
return unit;
}
public ProcedureUnit getProcedureUnit(MethodBinding methodBinding) {
Signature signature = Project.singleton.getSignature(methodBinding.getRelativeSignature());
String className = methodBinding.getDeclaringClass().getClassName();
return (ProcedureUnit) getMemberUnit(className, signature);
}
public ProcedureUnit getOrCreateProcedureUnit(MethodBinding methodBinding) {
Signature signature = Project.singleton.getSignature(methodBinding.getRelativeSignature());
String className = methodBinding.getDeclaringClass().getClassName();
return (ProcedureUnit) getOrCreateMemberUnit(className, signature);
}
private MemberUnit getOrCreateMemberUnit(String className, Signature signature) {
MemberUnit member = getMemberUnitOrNull(className, signature);
if (member == null) {
ClassUnit clazz = getClassUnit(className);
if (signature.isMethod()) {
member = new MethodUnit(signature, clazz);
} else if (signature.isConstructor()) {
member = new ConstructorUnit(signature, clazz);
} else {
member = new FieldUnit(signature, clazz);
}
}
return member;
}
// public Unit getOrCreateUnit(String signature) {
// String array[] = signature.split("#");
// Unit unit;
// if (array.length == 1) {
// unit = getOrCreateClassUnit(signature);
// } else {
// unit = getOrCreateMemberUnit(array[0], Project.singleton.getSignature(array[1]));
// }
// return unit;
// }
public FieldUnit getOrCreateFieldUnit(ObjectType type, String name) {
return (FieldUnit) getOrCreateMemberUnit(type.getClassName(), Project.singleton.getSignature(name));
}
public void addReference(MethodDeclaration decl, FieldAccess fa) {
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
source.addTarget(Project.singleton.getSignature(fa));
}
public void addReference(MethodDeclaration decl, MethodInvocation invocation) {
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
source.addTarget(Project.singleton.getSignature(invocation.getMethodBinding().toString()));
}
public void addReference(MethodDeclaration decl, ArrayCreation ac) {
ProcedureUnit source = getOrCreateProcedureUnit(decl.getMethodBinding());
Signature signature = Project.getSingleton().getArraySignature(ac.getTypeBinding());
for (int i = 0; i<ac.getDimensions().size(); i++) {
// TODO: Target must be a field or method. Is length the right way?
source.addTarget(Project.singleton.getSignature(signature.toString().substring(i)+"#length"));
}
}
/**
* Returns a live collection of all classes managed by this project.
*/
public Collection<ClassUnit> getClasses() {
return classesByName.values();
}
public void resolve(ClassUnit clazz) {
if (clazz.isResolved()) return;
if (clazz.getName().startsWith("[")) {
// This is an array type and not a class.
clazz.setSuperUnit(getJavaLangObject());
//clazz.setTainted();
clazz.setResolved(true);
// We need a member (and we chose length) in addReference(..) to taint the class.
new FieldUnit(getSignature("length"), clazz);
TypeDeclaration typeDecl = new TypeDeclaration(new ObjectType(clazz.getName()), 0);
typeDecl.setSuperType(Type.OBJECT);
typeDecl.visit(J2JSCompiler.compiler.generator);
} else {
TypeResolver resolver = new TypeResolver(this, J2JSCompiler.compiler.generator);
visitSuperTypes(clazz, resolver);
}
}
}

View File

@ -0,0 +1,153 @@
package com.j2js.assembly;
import java.util.List;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
public class Serializer {
private Writer writer;
private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
/** Creates a new instance of Serializer */
public Serializer(Writer theWriter) {
writer = theWriter;
}
public void serialize(Object object) throws NotSerializableException {
try {
this.serializeInternal(object);
} catch (IOException e) {
throw new NotSerializableException(e.getMessage());
}
}
private void serializeInternal(Object object) throws IOException {
if (object==null) {
writer.write("null");
} else if (object instanceof String) {
quote((String)object);
} else if (object instanceof Number) {
numberToString((Number) object);
} else if (object instanceof Map) {
serializeMap((Map) object);
} else if (object instanceof List) {
serializeArray((List) object);
} else if (object.getClass().isArray()) {
serializeArray((Object[]) object);// && object.getClass().getComponentType().equals(Double.TYPE) double[]) object);
} else if (object instanceof Boolean) {
writer.write(((Boolean)object).toString());
} else if (object instanceof Date) {
quote(dateFormatter.format((Date) object));
} else {
throw serializeError("Unknown object type " + object.getClass().toString());
}
}
private void serializeArray(List list) throws IOException {
String sep = "";
writer.write('[');
for (Object o : list) {
writer.write(sep);
sep = ",";
this.serializeInternal(o);
}
writer.write(']');
}
private void serializeArray(Object[] array) throws IOException {
String sep = "";
writer.write('[');
for (int i=0; i<array.length; i++) {
writer.write(sep);
sep = ",";
serializeInternal(array[i]);
}
writer.write(']');
}
private void serializeMap(Map<String, ?> map) throws IOException {
String sep = "";
writer.write('{');
for (String key : map.keySet()) {
writer.write(sep);
sep = ",";
Object value = map.get(key);
if (key.matches("\\w*")) {
writer.write(key);
} else {
writer.write("\"" + key + "\"");
}
writer.write(':');
this.serializeInternal(value);
}
writer.write('}');
}
/**
* Stream a numeric value.
* @exception NotSerializableException If number is infinite or not a number.
* @param n A Number
* @return A String.
*/
private void numberToString(Number n) throws IOException {
if (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN())) {
throw serializeError("Can only serialize finite numbers");
}
if (n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN())) {
throw serializeError("Can only serialize finite numbers");
}
writer.write(n.toString().toLowerCase());
}
private void numberToString(double n) throws IOException {
writer.write(String.valueOf(n));
}
/**
* Stream a string in double quotes " with the following backslash replacements:
* " -> \"
* \ -> \\
* @param string A String
*/
private void quote(String s) throws IOException {
if (s == null) {
writer.write("null");
return;
}
writer.write('"');
int l = s.length();
for (int i=0; i<l; i++) {
char c = s.charAt(i);
switch (c) {
case '\"':
writer.write("\\\"");
break;
case '\\':
writer.write("\\\\");
break;
case '\r':
writer.write("\\r");
break;
case '\n':
writer.write("\\n");
break;
default:
writer.write(c);
}
}
writer.write('"');
}
private NotSerializableException serializeError(String message) {
return new NotSerializableException(message);
}
}

View File

@ -0,0 +1,106 @@
package com.j2js.assembly;
import com.j2js.J2JSCompiler;
import java.io.Serializable;
/**
* An instance of class Signature represents the signature of
* a field, a constructor, a method, or a class.
*
* @author wolle
*/
public class Signature implements Serializable {
private String signatureString;
private int id;
Signature(String theSignatureString, int theId) {
signatureString = theSignatureString;
id = theId;
}
/**
* Examples:
* Ljava.lang.Integer; -> java.lang.Integer
* L[I; -> [I
*/
// public String getClassName() {
// if (!signatureString.startsWith("L") || !signatureString.endsWith(";")) {
// throw new RuntimeException("Not a class signature: " + signatureString);
// }
// return signatureString.substring(1, signatureString.length()-1);
// }
public int hashCode() {
return signatureString.hashCode();
}
public boolean equals(Object obj) {
if (obj instanceof Signature) {
return signatureString.equals(((Signature) obj).signatureString);
}
return false;
}
public String toString() {
return signatureString;
}
public boolean isClass() {
return signatureString.indexOf('#') == -1;
}
public boolean isArrayType() {
return isClass() && signatureString.startsWith("[");
}
public boolean isConstructor() {
return signatureString.startsWith("<init>");
}
public boolean isMethod() {
return !isConstructor() && signatureString.indexOf('(') != -1;
}
public boolean isField() {
return !isClass() && signatureString.indexOf('(') == -1;
}
public String className() {
String array[] = signatureString.split("#");
//if (array[0].startsWith("[")) array[0] = array[0].substring(1);
return array[0];
}
public String relativeSignature() {
String array[] = signatureString.split("#");
if (array.length != 2) {
throw new RuntimeException("Not a method signature: " + this);
}
return array[1];
}
/**
* Returns the relative signature.
*/
public Signature relative() {
return Project.getSingleton().getSignature(relativeSignature());
}
public int getId() {
return id;
}
public String getCommentedId() {
StringBuffer sb = new StringBuffer();
sb.append(String.valueOf(getId()));
if (!J2JSCompiler.compiler.isCompression()) {
sb.append(" /*");
sb.append(toString());
sb.append("*/");
}
return sb.toString();
}
}

View File

@ -0,0 +1,13 @@
package com.j2js.assembly;
import java.util.Collection;
import java.util.HashSet;
public class TypeCollector implements TypeVisitor {
Collection<ClassUnit> collectedTypes = new HashSet<ClassUnit>();
public void visit(ClassUnit clazz) {
collectedTypes.add(clazz);
}
}

View File

@ -0,0 +1,77 @@
package com.j2js.assembly;
import com.j2js.J2JSCompiler;
import com.j2js.Log;
import com.j2js.Parser;
import com.j2js.dom.TypeDeclaration;
import com.j2js.visitors.JavaScriptGenerator;
public class TypeResolver implements TypeVisitor {
private JavaScriptGenerator generator;
private Project project;
public TypeResolver(Project theProject, JavaScriptGenerator theGenerator) {
project = theProject;
generator = theGenerator;
}
public void visit(ClassUnit clazz) {
if (clazz.isResolved()) return;
Log logger = Log.getLogger();
if (clazz.getSignature().toString().startsWith("[")) {
// Class is an array class without class file: Do nothing.
} else if (!clazz.isUpToDate()) {
clazz.clear();
try {
compile(clazz);
J2JSCompiler.compiler.compileCount++;
} catch (RuntimeException ex) {
J2JSCompiler.errorCount++;
logger.error(ex.toString());
//ex.printStackTrace();
if (J2JSCompiler.compiler.failOnError) {
throw ex;
}
}
} else {
logger.debug("Up to date: " + clazz);
}
clazz.setResolved(true);
}
/**
* Compiles the unit.
*/
private void compile(ClassUnit classUnit) {
if (classUnit.getClassFile() == null) {
Log.getLogger().warn("Cannot read " + classUnit.getClassFile());
return;
}
Log.getLogger().info("Cross-Compiling " + classUnit);
TypeDeclaration typeDecl = parse(classUnit);
// TODO
//if (!Modifier.isInterface(typeDecl.getAccess())) {
typeDecl.visit(generator);
//}
// Set not current date but date of last modification. This is
// independent of system clock.
classUnit.setLastCompiled(classUnit.getLastModified());
}
private TypeDeclaration parse(ClassUnit classUnit) {
Parser parser = new Parser(classUnit);
TypeDeclaration typeDecl = parser.parse();
return typeDecl;
}
}

View File

@ -0,0 +1,5 @@
package com.j2js.assembly;
public interface TypeVisitor {
public void visit(ClassUnit clazz);
}

View File

@ -0,0 +1,62 @@
package com.j2js.assembly;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import com.j2js.Log;
public abstract class Unit implements Serializable {
private Signature signature;
private String data;
private transient boolean isTainted = false;
private static transient String[] indentPerDepth = new String[10];
public Unit() {
}
abstract void write(int depth, Writer writer) throws IOException;
String getIndent(int depth) {
String indent = indentPerDepth[depth];
if (indent == null) {
indent = "";
for (int i=0; i<depth; i++) indent += '\t';
}
return indent;
}
public String toString() {
return signature.toString();
}
public Signature getSignature() {
return signature;
}
void setSignature(Signature theSignature) {
signature = theSignature;
}
public String getData() {
return data;
}
public void setData(String theData) {
data = theData;
}
public boolean isTainted() {
return isTainted;
}
public void setTainted() {
if (!isTainted) Log.getLogger().debug("Taint " + this);
isTainted = true;
}
}

View File

@ -0,0 +1,84 @@
package com.j2js.builder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "j2js-configuration")
public class Configuration {
@XmlElement(name = "basedir")
public File basedir = new File(".");
@XmlElement(name = "uaCommand", required = true)
public String uaCommand;
@XmlElement(name = "uaArg")
public List<String> uaArgs = new ArrayList<String>();
@XmlElement(name = "devModeWebSocketURL", required = true)
public URI devModeWebSocketURL;
@XmlElement(name = "devModeHttpURL", required = true)
public URI devModeHttpURL;
public void write(OutputStream os) {
try {
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(this, os);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Configuration read() {
File file = new File(System.getProperty("user.home") + "/.m2/j2js.xml");
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException("Could not read file " + file);
}
System.out.println("Reading j2js configuration from " + file);
return Configuration.read(is);
}
public static Configuration read(InputStream inStream) {
JAXBContext context;
try {
context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
return (Configuration) um.unmarshal(inStream);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// public ApplicationConfiguration getApplicationConfiguration(String applicationName) {
// if ( applicationName == null ) {
// throw new NullPointerException("applicationName cannot be null.");
// }
//
// for (ApplicationConfiguration applConfig : applications) {
// if ( applicationName.equals(applConfig.applicationName) ) {
// return applConfig;
// }
// }
//
// return null;
// }
}

View File

@ -0,0 +1,29 @@
package com.j2js.cfg;
import com.j2js.dom.BooleanExpression;
public class ConditionalEdge extends Edge {
private BooleanExpression expression;
private boolean negate = false;
ConditionalEdge(Graph graph, Node theSource, Node theTarget) {
super(graph, theSource, theTarget);
}
public BooleanExpression getBooleanExpression() {
return expression;
}
public void setBooleanExpression(BooleanExpression expr) {
expression = expr;
}
public boolean isNegate() {
return negate;
}
public void setNegate(boolean theNegate) {
negate = theNegate;
}
}

View File

@ -0,0 +1,387 @@
package com.j2js.cfg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import com.j2js.ASTNodeStack;
import com.j2js.cfg.transformation.Transformation;
import com.j2js.dom.ASTNode;
import com.j2js.dom.Block;
import com.j2js.dom.BooleanExpression;
import com.j2js.dom.InfixExpression;
import com.j2js.dom.TryStatement;
/**
* Instances of this class represent a Control Flow Graph CFG.
*/
public class ControlFlowGraph extends Graph {
// Ordering is only used by method getNodeAt().
private SortedMap<Integer, Node> nodesByPc = new TreeMap<Integer, Node>();
// The single entry point of control.
private Node sourceNode;
private List tryStatements;
public ControlFlowGraph(List theTryStatements) {
tryStatements = theTryStatements;
}
/**
* Returns the try statement which contains the specified node.
*/
private TryStatement selectTryStatement(Node node) {
int pc = node.getInitialPc();
for (int i=0; i<tryStatements.size(); i++) {
TryStatement tryStmt = (TryStatement) tryStatements.get(i);
Block block = tryStmt.getTryBlock();
if (pc >= block.getBeginIndex() && pc <= block.getEndIndex()) return tryStmt;
}
return null;
}
public Node createNode(int pc) {
return createNode(pc, Node.class);
}
public Node getOrCreateNode(int pc) {
Node node = getNode(pc);
if (node == null) {
node = createNode(pc, Node.class);
}
return node;
}
public Node createNode(int pc, Class nodeClass) {
if (pc < 0) throw new RuntimeException("Program counter may not be negative");
Node node = super.createNode(nodeClass);
node.setInitialPc(pc);
if (nodesByPc.put(node.getInitialPc(), node) != null) {
throw new RuntimeException("Node already exists: " + node);
}
if (pc == 0) sourceNode = node;
return node;
}
/**
* Returns the largest (w.r. to its initial pc) node closest to the specified pc.
*/
public Node getNodeAt(int pc) {
int minPcDelta = Integer.MAX_VALUE;
Node node = null;
for (Node n : getNodes()) {
if (n.getInitialPc() <= pc && pc-n.getInitialPc() < minPcDelta) {
minPcDelta = pc-n.getInitialPc();
node = n;
if (minPcDelta == 0) return node;
}
}
if (node == null) {
throw new RuntimeException("No node at pc " + pc);
}
return node;
}
/**
* Splits a node at the given pc value into two nodes nodeA and nodeB.
* nodeB will start at pc and will have the outbound edges of the original node, and an
* extra edge is added from nodeA to nodeB.
*/
public Node split(Node node, int pc) {
if (node.block.getBeginIndex() >= pc) throw new RuntimeException("Block must contain program counter");
Node nodeB = createNode(pc);
// Reroot all outbound edges at nodeB.
for (Edge edge : new ArrayList<Edge>(node.getOutEdges())) {
edge.reroot(nodeB);
}
addEdge(node, nodeB);
// Transfer code starting at pc to nodeB.
ASTNode astNode = node.block.getFirstChild();
while (astNode != null) {
if (astNode.getBeginIndex() >= pc) {
node.setCurrentPc(astNode.getBeginIndex()-1);
nodeB.block.appendChildren(astNode, node.block.getLastChild());
break;
}
astNode = astNode.getNextSibling();
}
// Transfer stack to nodeB.
nodeB.stack = node.stack;
node.stack = new ASTNodeStack();
return nodeB;
}
public Node[] getOrSplitNodeAt(Node currentNode, int pc) {
Node targetNode = getNodeAt(pc);
if (targetNode.getInitialPc() != pc) {
// No node starts at target pc. We have to split the node.
Node nodeB = split(targetNode, pc);
if (targetNode == currentNode) {
currentNode = nodeB;
}
targetNode = nodeB;
}
return new Node[]{currentNode, targetNode};
}
/**
* Redirect all incoming edges for try bodys to its try header.
*/
private void processTrys() {
for (int i=0; i<tryStatements.size(); i++) {
TryStatement stmt = (TryStatement) tryStatements.get(i);
TryHeaderNode header = stmt.header;
Node tryNode = header.getTryBody();
if (tryNode == sourceNode) sourceNode = header;
for (Edge edge : new ArrayList<Edge>(tryNode.getInEdges())) {
int pc = edge.source.getInitialPc();
if (pc >= stmt.getBeginIndex() && pc <= stmt.getEndIndex()) continue;
if (edge.source == header) continue;
edge.redirect(header);
}
}
}
/**
* Reroots all local edges exiting a try body at the corresponding try header.
*/
private void processTrys2() {
for (Node node: nodesByPc.values()) {
TryStatement sourceTry = selectTryStatement(node);
if (sourceTry == null) continue;
for (Edge edge : node.getOutEdges()) {
if (edge.target.getInEdges().size() != 1) {
continue;
}
TryStatement targetTry = selectTryStatement(edge.target);
if (targetTry == null || targetTry != sourceTry) {
edge.reroot(sourceTry.header);
}
}
}
}
/**
* Reroot the fall through successor directly at the try header.
*/
private void processTrys1() {
for (int i=0; i<tryStatements.size(); i++) {
TryStatement stmt = (TryStatement) tryStatements.get(i);
TryHeaderNode header = stmt.header;
Node finallyNode = header.getFinallyNode();
if (finallyNode == null) continue;
Iterator iter = finallyNode.jsrCallers.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
// TODO: Be independant of pc!
if (node.getInitialPc() > finallyNode.getInitialPc()) {
removeInEdges(node);
addEdge(header, node);
node.setDomParent(header);
}
}
}
}
public Node getSource() {
return sourceNode;
}
public Node getNode(int pc) {
return nodesByPc.get(pc);
}
/**
* Finds the set of all successors of the specified predecessor which are not dominated by it.
* Each node in this set is then marked as a global target of the predecessor.
* If the predecessor is a branch, then a newly created node will function as the referer.
*/
private void markGlobalTargets(Node predecessor) {
for (Edge edge : predecessor.getOutEdges()) {
Node target = edge.target;
if (target.getDomParent() == predecessor)
continue;
if (predecessor.isBranch()) {
Node node = createNode(Node.class);
edge.redirect(node);
node.setDomParent(predecessor);
edge = addEdge(node, target);
}
}
}
/**
* For each node in tree, mark global targets.
*/
void visitToMark(Node node) {
// Be concurrent safe.
for (Node child : new ArrayList<Node>(node.getDomChildren())) {
visitToMark(child);
}
markGlobalTargets(node);
}
/**
* Recursively (depth first) traverses the dominator tree rooted at the specified node and post-processes
* all possible reductions.
*/
void visit(Node node) {
// Be concurrent safe.
for (Node child : new ArrayList<Node>(node.getDomChildren())) {
visit(child);
}
do {
Transformation t = Transformation.select(this, node);
if (t == null) break;
node = t.apply();
dump("After transformation");
} while (true);
if (node.getDomChildren().size() > 0) {
throw new RuntimeException("Could not reduce graph at " + node);
}
}
public void replaceNode(Node node, Node newNode) {
super.replaceNode(node, newNode);
if (newNode != null) {
nodesByPc.put(node.getInitialPc(), newNode);
} else {
nodesByPc.remove(node.getInitialPc());
}
if (node == sourceNode) {
if (newNode == null) {
throw new RuntimeException("Cannot remove source node " + sourceNode);
}
sourceNode = newNode;
}
}
public Block reduce() {
processTrys();
processTrys2();
dump("Before Shortcuts");
processShortcuts();
DominatorTree builder = new DominatorTree(this);
builder.build();
processTrys1();
visitToMark(getSource());
dump("Begin reduce");
visit(getSource());
if (size() != 1) {
throw new RuntimeException("Could not reduce graph");
}
Block block = new Block();
rollOut(getSource(), block);
return block;
}
/**
* Performs an OR or AND shortcut on two branches A and B by replacing them with new node A&B or A|B.
*/
boolean performAndOrShortcut(Node a, Node b) {
if (b.getInEdges().size() != 1) return false;
if (b.block.getChildCount() > 0) {
// Node b is not a mere conditional.
return false;
}
ConditionalEdge aToC;
ConditionalEdge bToC;
boolean isOR = true;
while(true) {
aToC = a.getConditionalEdge(isOR);
bToC = b.getConditionalEdge(isOR);
if (bToC.target == aToC.target) break;
if (!isOR) return false;
isOR = false;
}
if (aToC.target.getInEdges().size() != 2) return false;
ConditionalEdge bToD = b.getConditionalEdge(!isOR);
ConditionalEdge aToB = a.getConditionalEdge(!isOR);
aToB.redirect(bToD.target);
removeEdge(bToC);
removeEdge(bToD);
removeNode(b);
InfixExpression infix = new InfixExpression(
isOR?InfixExpression.Operator.CONDITIONAL_OR:InfixExpression.Operator.CONDITIONAL_AND);
// Note that the order aToC, then bToC is important.
infix.setOperands(
aToC.getBooleanExpression().getExpression(),
bToC.getBooleanExpression().getExpression());
BooleanExpression be = new BooleanExpression(infix);
aToC.setBooleanExpression(be);
aToB.setBooleanExpression(be);
logger.debug("Created shortcut and removed " + b);
return true;
}
public void processShortcuts() {
Collection<Node> branches = new HashSet<Node>();
for (Node node : getNodes()) {
if (node.isBranch()) branches.add(node);
}
L: while (true) {
Iterator<Node> iter = branches.iterator();
while (iter.hasNext()) {
Node branch = iter.next();
for (Node node: branch.succs()) {
if (node.isBranch() && performAndOrShortcut(branch, node)) {
branches.remove(node);
continue L;
}
}
}
break L;
}
}
}

View File

@ -0,0 +1,233 @@
package com.j2js.cfg;
import java.util.*;
import com.j2js.Log;
/**
* Class to build the dominator tree of a given control flow graph.
* The algorithm is according Purdum-Moore, which isn't as fast as Lengauer-Tarjan, but a lot simpler.
*/
public class DominatorTree {
private ControlFlowGraph graph;
public DominatorTree(ControlFlowGraph theGraph) {
graph = theGraph;
}
/**
* Sets the pre-order index of a node.
*/
private void visit(Node node, Collection<Node> visited) {
// Establish preorder index.
node.setPreOrderIndex(visited.size());
visited.add(node);
for (Node succ : node.succs()) {
if (! visited.contains(succ)) {
visit(succ, visited);
}
}
}
/**
* Builds the dominator tree and store it in the respective nodes.
* It will remove all unreachable nodes on the way!
*/
public void build() {
// Construct list of nodes in pre-order order.
ArrayList<Node> preOrder = new ArrayList<Node>();
visit(graph.getSource(), preOrder);
// Remove unreachable nodes.
for (Node node : new ArrayList<Node>(graph.getNodes())) {
if (!preOrder.contains(node)) {
Log.getLogger().warn("Unreachable code detected and removed");
//Logger.getLogger().info("Removed " + node);
graph.removeInEdges(node);
graph.removeOutEdges(node);
graph.removeNode(node);
} else if (node.getPreOrderIndex() == -1) {
throw new RuntimeException("Pre-order not set for " + node);
}
}
int size = graph.size(); // The number of vertices in the cfg
Map snkPreds = new HashMap(); // The predacessor vertices from the sink
// Determine the predacessors of the cfg's sink node
//insertEdgesToSink(graph, snkPreds, reverse);
// Get the index of the root
int rootIndex = graph.getSource().getPreOrderIndex();
if (rootIndex < 0 || rootIndex >= size) throw new RuntimeException("Root index out of range");
// Bit matrix indicating the dominators of each node.
// If bit j of dom[i] is set, then node j dominates node i.
BitSet[] domMatrix = new BitSet[size];
// Initially, all the bits in the dominance matrix are set, except
// for the root node. The root node is initialized to have itself
// as an immediate dominator.
for (int i = 0; i < size; i++) {
BitSet domVector = new BitSet(size);
if (i == rootIndex) {
// Only root dominates root.
domVector.set(rootIndex);
}
else {
// Assume that all nodes dominate non-root node i.
domVector.set(0, size);
}
domMatrix[i] = domVector;
}
// Did the dominator bit vector array change?
boolean changed;
do {
changed = false;
// Fetch all nodes in pre-order.
Iterator nodes = preOrder.iterator();
// Compute the dominators of each node in the cfg. We iterate
// over every node in the cfg. The dominators of a node N are
// found by taking the intersection of the dominator bit vectors
// of each predacessor of N and unioning that with N. This
// process is repeated until no changes are made to any dominator
// bit vector.
while (nodes.hasNext()) {
Node node = (Node) nodes.next();
int i = node.getPreOrderIndex();
if (i < 0 || i >= size) throw new RuntimeException("Unreachable node " + node);
// We already know the dominators of the root, keep looking
if (i == rootIndex) {
continue;
}
BitSet oldSet = domMatrix[i];
// domVector := intersection of dom(pred) for all pred(node).
BitSet domVector = new BitSet(size);
domVector.or(oldSet);
Collection preds = node.preds();
Iterator e = preds.iterator();
// Find the intersection of the dominators of node's
// predacessors.
while (e.hasNext()) {
Node pred = (Node) e.next();
int j = pred.getPreOrderIndex();
if (j == -1) throw new RuntimeException("Unreachable node " + pred);
domVector.and(domMatrix[j]);
}
// Don't forget to account for the sink node if node is a
// leaf node. Appearantly, there are not edges between
// leaf nodes and the sink node!
preds = (Collection) snkPreds.get(node);
if (preds != null) {
e = preds.iterator();
while (e.hasNext()) {
Node pred = (Node) e.next();
int j = pred.getPreOrderIndex();
domVector.and(domMatrix[j]);
}
}
// Include yourself in your dominators?!
domVector.set(i);
// If the set changed, set the changed bit.
if (!domVector.equals(oldSet)) {
changed = true;
domMatrix[i] = domVector;
}
}
} while (changed);
// Once we have the predacessor bit vectors all squared away, we can
// determine which vertices dominate which vertices.
// Initialize each node's (post)dominator parent and children
for (Node node : graph.getNodes()) {
node.setDomParent(null);
node.getDomChildren().clear();
}
// A node's immediate dominator is its closest dominator. So, we
// start with the dominators, dom(b), of a node, b. To find the
// imediate dominator of b, we remove all nodes from dom(b) that
// dominate any node in dom(b).
for (Node node : graph.getNodes()) {
int i = node.getPreOrderIndex();
if (i < 0 || i >= size) throw new RuntimeException("Unreachable node " + node);
if (i == rootIndex) {
continue;
}
// Find the immediate dominator
// idom := dom(node) - dom(dom(node)) - node
BitSet domVector = domMatrix[i];
BitSet idom = new BitSet(size);
idom.or(domVector);
idom.clear(i);
for (int j = 0; j < size; j++) {
if (i != j && domVector.get(j)) {
// idom = idom - (domMatrix[j] - {j})
BitSet b = new BitSet(size);
// Complement of domMatrix[j].
b.or(domMatrix[j]); b.flip(0, size);
b.set(j);
idom.and(b);
}
}
Node parent = null;
// A node should only have one immediate dominator.
for (int j = 0; j < size; j++) {
if (idom.get(j)) {
Node p = preOrder.get(j);
if (parent != null)
throw new RuntimeException(node + " has more than one immediate dominator: " + parent + " and " + p);
parent = p;
}
}
if (parent == null)
throw new RuntimeException(node + " has 0 immediate dominators");
node.setDomParent(parent);
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2005 by Wolfgang Kuehn
* Created on 12.11.2005
*/
package com.j2js.cfg;
/**
* @author wolfgang
*/
public class Edge {
private Graph graph;
public Node source;
public Node target;
public EdgeType type;
private Node orgSource;
Edge(Graph theGraph, Node theSource, Node theTarget) {
graph = theGraph;
source = theSource;
target = theTarget;
}
public boolean equals(Object other) {
if (other == null || !(other instanceof Edge)) return false;
Edge otherEdge = (Edge) other;
return source.getId().equals(otherEdge.source.getId()) && target.getId().equals(otherEdge.target.getId());
}
/**
* Replace the target of this edge.
*/
public void reroot(Node newSource) {
source.outEdges.remove(this);
newSource.outEdges.add(this);
source = newSource;
}
/**
* Replace the target of this edge.
*/
public void redirect(Node newTarget) {
target.inEdges.remove(this);
newTarget.inEdges.add(this);
target = newTarget;
}
/**
* Returns true if this edge is a backward (i.e. loop) edge.
*/
public boolean isBackEdge() {
return target.isDomAncestor(source);
}
public boolean isGlobal() {
return orgSource != null;
}
public String toString() {
String s = getClass().getName();
// Extract unqualified class name.
s = s.substring(s.lastIndexOf('.')+1);
return s + " " + source.getId() + " -> " + target.getId();
}
public Node getOrgSource() {
if (orgSource == null) {
return source;
}
return orgSource;
}
public void setOrgSource(Node theOrgSource) {
orgSource = theOrgSource;
}
}

View File

@ -0,0 +1,17 @@
package com.j2js.cfg;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class EdgeCollections {
public static Set<Node> getSources(Collection<Edge> edges) {
HashSet<Node> sources = new HashSet<Node>();
for (Edge edge : edges) {
sources.add(edge.source);
}
return sources;
}
}

View File

@ -0,0 +1,17 @@
package com.j2js.cfg;
public class EdgeType {
public static EdgeType FINALLY = new EdgeType("Finally");
public static EdgeType CATCH = new EdgeType("Catch");
public static EdgeType TRYBODY = new EdgeType("TryBody");
private String name;
private EdgeType(String theName) {
name = theName;
}
public String toString() {
return name;
}
}

View File

@ -0,0 +1,286 @@
package com.j2js.cfg;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.j2js.Log;
import com.j2js.cfg.Node;
import com.j2js.dom.Block;
import com.j2js.dom.BooleanExpression;
import com.j2js.dom.BreakStatement;
import com.j2js.dom.IfStatement;
public abstract class Graph {
private Map<String, Node> nodes = new HashMap<String, Node>();
int nodeIdSequence = 0;
Log logger = Log.getLogger();
public Graph() {
}
public Node getNodeById(String id) {
return nodes.get(id);
}
public Node createNode(Class nodeClass) {
return createNode(nodeClass, Integer.toString(nodeIdSequence++, 26));
}
public Node createNode(Class nodeClass, String id) {
Node node;
try {
Constructor constructor = nodeClass.getConstructor(new Class[]{Graph.class});
node = (Node) constructor.newInstance(new Object[] {this});
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
node.id = id;
nodes.put(id, node);
return node;
}
/**
* Returns true if node set A is contained in node set B.
*/
public boolean isContained(Set nodesA, Node[] nodesB) {
Set<Node> foo = new HashSet<Node>(Arrays.asList(nodesB));
return foo.containsAll(nodesA);
}
/**
* Redirects all inbound edges of a node to another node.
*/
public void replaceAsTarget(Node oldTarget, Node newTarget) {
for (Edge edge : new ArrayList<Edge>(oldTarget.getInEdges())) {
edge.redirect(newTarget);
}
}
public Edge removeEdge(Node source, Node target) {
Edge edge = getEdge(source, target);
return removeEdge(edge);
}
public Edge removeEdge(Edge edge) {
edge.source.getOutEdges().remove(edge);
edge.target.getInEdges().remove(edge);
return edge;
}
// public void replaceNodes(Node header, List nodes, Node newNode) {
// replaceNodes(header, (Node[]) nodes.toArray(new Node[nodes.size()]), newNode);
// }
public String getEdgeId(Node source, Node target) {
return source.getId() + "->" + target.getId();
}
public void addIfElseEdge(Node source, Node ifTarget, Node elseTarget, BooleanExpression be) {
ConditionalEdge ifEdge = (ConditionalEdge) addEdge(source, ifTarget, ConditionalEdge.class);
ifEdge.setBooleanExpression(be);
ConditionalEdge elseEdge = (ConditionalEdge) addEdge(source, elseTarget, ConditionalEdge.class);
elseEdge.setBooleanExpression(be);
elseEdge.setNegate(true);
}
public Edge addEdge(Node source, Node target) {
return addEdge(source, target, Edge.class);
}
public Edge addEdge(Node source, Node target, Class clazz) {
Edge edge = getEdge(source, target);
if (edge != null) {
// TODO: Why not allow adding multiple edges? This is possible
// anyway through reroot or redirect!
throw new RuntimeException("Edge already exists");
}
if (clazz.equals(Edge.class)) {
edge = new Edge(this, source, target);
} else if (clazz.equals(SwitchEdge.class)) {
edge = new SwitchEdge(this, source, target);
} else if (clazz.equals(ConditionalEdge.class)) {
edge = new ConditionalEdge(this, source, target);
} else {
throw new RuntimeException("Illegal edge class " + clazz);
}
source.addEdge(edge);
if (source != target) {
target.addEdge(edge);
}
return edge;
}
public Edge getEdge(Node source, Node target) {
for (Edge edge : source.getOutEdges()) {
if (edge.target == target) return edge;
}
return null;
}
public void removeNode(Node node) {
replaceNode(node, null);
}
public Set<Edge> removeOutEdges(Node node) {
Set<Edge> outEdges = new HashSet<Edge>(node.outEdges);
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
removeEdge(edge);
}
return outEdges;
}
/**
* Removes all in-edges to the specified node.
*
* @return the set of removed in-edges
*/
public Set removeInEdges(Node node) {
Set<Edge> inEdges = new HashSet<Edge>(node.inEdges);
Iterator<Edge> iter = inEdges.iterator();
while (iter.hasNext()) {
Edge edge = iter.next();
removeEdge(edge);
}
return inEdges;
}
public Set removeSelfEdges(Node node) {
Set<Edge> selfEdges = new HashSet<Edge>();
for (Edge edge: new HashSet<Edge>(node.outEdges)) {
if (edge.target != node) continue;
removeEdge(edge);
selfEdges.add(edge);
}
return selfEdges;
}
public void rerootGlobalOutEdges(Node node, Node newSource) {
Edge[] edges = node.getOutEdgesArray();
for (int i=0; i<edges.length; i++) {
Edge edge = edges[i];
if (edge.isGlobal()) {
edge.reroot(newSource);
}
}
}
public void rerootOutEdges(Node node, Node newSource, boolean localToGlobal) {
Edge[] edges = node.getOutEdgesArray();
for (int i=0; i<edges.length; i++) {
Edge edge = edges[i];
edge.reroot(newSource);
if (localToGlobal && !edge.isGlobal()) {
edge.setOrgSource(node);
}
}
}
public void replaceNode(Node oldNode, Node newNode) {
nodes.remove(oldNode.getId());
if (newNode != null) {
// Redirect all in-edges for oldNode to newNode.
replaceAsTarget(oldNode, newNode);
// Reroot all out-edges from oldNode at newNode, making local edges global.
rerootOutEdges(oldNode, newNode, true);
newNode.setDomParent(oldNode.getDomParent());
for (Node child : new ArrayList<Node>(oldNode.getDomChildren())) {
child.setDomParent(newNode);
}
}
if (oldNode.inEdges.size() > 0 || oldNode.outEdges.size() > 0)
throw new RuntimeException("Cannot replace node with edges");
oldNode.setDomParent(null);
}
public Collection<Node> getNodes() {
return nodes.values();
}
public int size() {
return getNodes().size();
}
public Block reduceDumb() {
Block block = new Block();
for (Node node : getNodes()) {
block.appendChild(node.block);
if (node.isBranch()) {
IfStatement ifStmt = new IfStatement();
ConditionalEdge cEdge = node.getConditionalEdge(true);
ifStmt.setExpression(cEdge.getBooleanExpression().getExpression());
ifStmt.setIfBlock(new Block());
Block targetBlock = cEdge.target.block;
ifStmt.getIfBlock().appendChild(new BreakStatement(targetBlock));
ifStmt.setElseBlock(new Block());
targetBlock = node.getConditionalEdge(false).target.block;
ifStmt.getElseBlock().appendChild(new BreakStatement(targetBlock));
block.appendChild(ifStmt);
} else {
for (Edge e : node.getOutEdges()) {
BreakStatement bStmt = new BreakStatement(e.target.block);
node.block.appendChild(bStmt);
}
}
}
return block;
}
boolean isTarget(Node n, Set edgeSet) {
Iterator iter = edgeSet.iterator();
while (iter.hasNext()) {
Edge e = (Edge) iter.next();
if (n == e.target) return true;
}
return false;
}
public void rollOut(Node node, Block targetBlock) {
if (node.trans != null) {
node.trans.rollOut(targetBlock);
} else {
targetBlock.appendChildren(node.block);
}
}
public void dump(String msg) {
StringBuffer sb = new StringBuffer();
sb.append(msg + " ...\n");
for (Node node : getNodes()) {
sb.append(node.describe() + "\n");
//dump(node.block, "Block");
}
sb.append("... " + msg);
logger.debug(sb.toString());
}
}

View File

@ -0,0 +1,334 @@
/*
* Copyright 2005 by Wolfgang Kuehn
* Created on 12.11.2005
*/
package com.j2js.cfg;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import com.j2js.ASTNodeStack;
import com.j2js.cfg.transformation.Transformation;
import com.j2js.dom.Block;
import com.j2js.dom.Expression;
import com.j2js.dom.IfStatement;
/**
* @author wolfgang
*/
public class Node {
public class Reference {
public Node source;
public boolean isBackward = false;
}
public static int NON_HEADER = 0;
public static int REDUCIBLE = 1;
public static int IRREDUCIBLE = 2;
String id;
Set<Edge> inEdges = new LinkedHashSet<Edge>();
Set<Edge> outEdges = new LinkedHashSet<Edge>();
Graph graph;
private int currentPc = -1;
private int initialPc = -1;
public ASTNodeStack stack = new ASTNodeStack();
public Block block = new Block();
public boolean closed = false;
protected int preOrderIndex = -1;
private Node domParent; // Block that (immediately) dominates this Block
private Set<Node> domChildren = new HashSet<Node>(); // Blocks that this Block dominates
IfStatement ifStmt;
public Expression switchExpression;
public Transformation trans;
public Collection<Node> jsrCallers = new HashSet<Node>();
public boolean isSwitchHeader = false;
public Node(Graph theGraph, int pc) {
this(theGraph);
setInitialPc(pc);
}
public Node(Graph theGraph) {
graph = theGraph;
}
public int getComplexity() {
Node node = this;
int complexity = 0;
while (node.trans != null) {
complexity++;
node = node.trans.header;
}
return complexity;
}
/**
* @return Returns the pc.
*/
public int getCurrentPc() {
return currentPc;
}
/**
* @param pc The pc to set.
*/
public void setCurrentPc(int pc) {
currentPc = pc;
}
public void close() {
closed = true;
}
public void addEdge(Edge e) {
if (e.source == this) {
if (!outEdges.add(e)) {
throw new RuntimeException("\n" + this + "\nalready bound to " + e);
}
}
if (e.target == this) {
if (!inEdges.add(e)) {
throw new RuntimeException("" + this + " already bound to " + e);
}
}
}
public String toString() {
String s = getClass().getName();
// Same as getClass().getSimpleName() in JDK 5.0.
s = s.replaceFirst(".*\\.", "");
s += " " + id + "[" + initialPc + ", " + currentPc + "]";
//if (preOrderIndex >= 0) s += " preIndex=" + preOrderIndex;
if (domParent != null) s += " dominated by " + domParent.id;
if (isLoopHeader()) s += " LH";
return s;
}
public String describe() {
String s = toString();
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge e = (Edge) iter.next();
s += "\n\t" + e;
}
return s;
}
/**
* @return Returns the inEdges.
*/
public Set<Edge> getInEdges() {
return inEdges;
}
public Edge getSelfEdge() {
Iterator iterator = inEdges.iterator();
while (iterator.hasNext()) {
Edge edge = (Edge) iterator.next();
if (edge.source == this) return edge;
}
return null;
}
// public Set getGlobalInEdges() {
// HashSet set = new HashSet();
// Iterator iterator = inEdges.iterator();
// while (iterator.hasNext()) {
// Edge edge = (Edge) iterator.next();
// if (edge.global) set.add(edge);
// }
// return set;
// }
// public Set getForewardOutEdges() {
// HashSet set = new HashSet();
// Iterator iterator = outEdges.iterator();
// while (iterator.hasNext()) {
// Edge edge = (Edge) iterator.next();
// if (!edge.isBackEdge()) set.add(edge);
// }
// return set;
// }
/**
* @return Returns the outEdges.
*/
public Set<Edge> getOutEdges() {
return outEdges;
}
public Edge[] getOutEdgesArray() {
return outEdges.toArray(new Edge[outEdges.size()]);
}
public Edge[] getInEdgesArray() {
return inEdges.toArray(new Edge[inEdges.size()]);
}
public int getPreOrderIndex() {
return preOrderIndex;
}
public void setPreOrderIndex(int thePreOrderIndex) {
preOrderIndex = thePreOrderIndex;
}
public Set<Node> succs() {
Set<Node> list = new LinkedHashSet<Node>();
Edge[] edges = getOutEdgesArray();
for (int i=edges.length-1; i>=0; i--) {
list.add(edges[i].target);
}
return list;
}
public Set<Node> preds() {
Set<Node> list = new LinkedHashSet<Node>();
Iterator iter = inEdges.iterator();
while (iter.hasNext()) {
Edge e = (Edge) iter.next();
list.add(e.source);
}
return list;
}
public Node getPred() {
int count = inEdges.size();
if (count != 1) throw new RuntimeException("Requested unique predecessor, found " + count);
return inEdges.iterator().next().source;
}
public Node getSucc() {
return getOutEdge().target;
}
public Edge getLocalOutEdgeOrNull() {
Edge outEdge = null;
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (outEdge != null) new RuntimeException("Found multiple local out-edges");
outEdge = edge;
}
return outEdge;
}
public Edge getOutEdge() {
int count = outEdges.size();
if (count != 1) throw new RuntimeException("Requested unique successor, found " + count);
return outEdges.iterator().next();
}
/**
* Return true if this node is equal to or dominates the specified node.
*/
public boolean isDomAncestor(Node node) {
do {
if (node == null) return false;
if (node == this) return true;
node = node.getDomParent();
} while (true);
}
public Set<Node> getDomChildren() {
return domChildren;
}
public Node getDomChild() {
if (domChildren.size() != 1) throw new RuntimeException("Node must have single child");
return getDomChildren().iterator().next();
}
public Node getDomParent() {
return domParent;
}
public void setDomParent(Node newDomParent) {
// If this Block already had a dominator specified, remove
// it from its dominator's children.
if (domParent != null) {
domParent.domChildren.remove(this);
}
domParent = newDomParent;
// Add this Block to its new dominator's children.
if (domParent != null) {
domParent.domChildren.add(this);
}
}
public boolean isBranch() {
Edge[] edges = getOutEdgesArray();
if (edges.length != 2) return false;
if (edges[0] instanceof ConditionalEdge && edges[1] instanceof ConditionalEdge) return true;
if ((edges[0] instanceof ConditionalEdge) || (edges[1] instanceof ConditionalEdge))
throw new RuntimeException("Node must not have mixed edges");
return false;
}
/**
* Returns either the true or false edge.
*/
public ConditionalEdge getConditionalEdge(boolean trueFalse) {
if (!isBranch()) throw new RuntimeException("Node must be a branch");
Iterator<Edge> iter = outEdges.iterator();
Edge edge = iter.next();
if (!trueFalse) edge = iter.next();
return (ConditionalEdge) edge;
}
public String getId() {
return id;
}
public int getInitialPc() {
return initialPc;
}
public Graph getGraph() {
return graph;
}
public void setInitialPc(int theInitialPc) {
initialPc = theInitialPc;
currentPc = theInitialPc;
}
public boolean isLoopHeader() {
Iterator iter = inEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (edge.isBackEdge()) return true;
}
return false;
}
public boolean hasSelfEdges() {
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (edge.target == this) return true;
}
return false;
}
// public void replaceEdge(Edge oldEdge, Edge newEdge) {
// source.outEdges.remove(this);
// newSource.outEdges.add(this);
// source = newSource;
// }
}

View File

@ -0,0 +1,14 @@
package com.j2js.cfg;
import java.util.ArrayList;
import java.util.List;
import com.j2js.dom.NumberLiteral;
public class SwitchEdge extends Edge {
public List<NumberLiteral> expressions = new ArrayList<NumberLiteral>();
SwitchEdge(Graph graph, Node theSource, Node theTarget) {
super(graph, theSource, theTarget);
}
}

View File

@ -0,0 +1,74 @@
package com.j2js.cfg;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.j2js.dom.TryStatement;
public class TryHeaderNode extends Node {
public TryStatement tryStmt;
public TryHeaderNode(Graph theGraph) {
super(theGraph);
}
public void setTryBody(Node theTryBody) {
Edge edge = graph.addEdge(this, theTryBody);
edge.type = EdgeType.TRYBODY;
}
public void setFinallyNode(Node theFinallyNode) {
Edge edge = graph.addEdge(this, theFinallyNode);
edge.type = EdgeType.FINALLY;
//finallyNode = theFinallyNode;
}
public void addCatchNode(Node node) {
Edge edge = graph.addEdge(this, node);
edge.type = EdgeType.CATCH;
//catchNodes.add(node);
}
public Node getSuccessor() {
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (edge.type == null) return edge.target;
}
return null;
}
public Node getTryBody() {
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (edge.type == EdgeType.TRYBODY) return edge.target;
}
throw new RuntimeException();
}
public Node getFinallyNode() {
Iterator iter = outEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (edge.type == EdgeType.FINALLY) return edge.target;
}
return null;
}
public List<Node> getCatchNodes() {
List<Node> catchNodes = new ArrayList<Node>();
for (Edge edge : outEdges) {
if (edge.type == EdgeType.CATCH) catchNodes.add(edge.target);
}
return catchNodes;
}
public TryStatement getTryStatement() {
return tryStmt;
}
}

View File

@ -0,0 +1,11 @@
package com.j2js.cfg;
public class WrapperNode extends Node{
Node node;
public WrapperNode(Graph theGraph) {
super(theGraph);
}
}

View File

@ -0,0 +1,47 @@
package com.j2js.cfg.transformation;
import java.util.Iterator;
import java.util.Set;
import com.j2js.cfg.Edge;
import com.j2js.dom.Block;
import com.j2js.dom.BooleanLiteral;
import com.j2js.dom.WhileStatement;
public class Loop extends Transformation {
private Set selfEdges;
public boolean applies_() {
return header.hasSelfEdges();
}
public void apply_() {
// Remove self edges.
selfEdges = graph.removeSelfEdges(header);
}
void rollOut_(Block block) {
WhileStatement loopStmt = new WhileStatement();
Block loopBody = new Block();
loopStmt.setBlock(loopBody);
loopStmt.setExpression(new BooleanLiteral(true));
block.appendChild(loopStmt);
Iterator iter = selfEdges.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (!edge.isGlobal()) continue;
loopStmt.isLabeled();
produceJump(edge, loopStmt);
}
graph.rollOut(header, loopBody);
}
public String toString() {
return super.toString() + "(" + header + ")";
}
}

View File

@ -0,0 +1,77 @@
package com.j2js.cfg.transformation;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.j2js.cfg.ControlFlowGraph;
import com.j2js.cfg.Edge;
import com.j2js.cfg.EdgeCollections;
import com.j2js.cfg.Node;
import com.j2js.dom.Block;
/**
* @author wolfgang
*/
public class Merge extends Transformation {
private Node tail;
private Set inEdgesForTail;
public Merge() {
}
public Merge(ControlFlowGraph theGraph) {
graph = theGraph;
}
public boolean applies_() {
HashSet<Node> headerSet = new HashSet<Node>();
headerSet.add(header);
for (Node child : header.getDomChildren()) {
if (EdgeCollections.getSources(child.getInEdges()).equals(headerSet)) {
tail = child;
return true;
}
}
return false;
}
public void apply_() {
// Remove all in-edges to Tail.
inEdgesForTail = graph.removeInEdges(tail);
// Reroot all out-edges from Tail.
graph.rerootOutEdges(tail, newNode, false);
//Remove Tail.
graph.removeNode(tail);
}
void rollOut_(Block block) {
Block labeledBlock = block;
Iterator iter = inEdgesForTail.iterator();
while (iter.hasNext()) {
Edge edge = (Edge) iter.next();
if (!edge.isGlobal()) continue;
if (labeledBlock == block) {
labeledBlock = new Block();
block.appendChild(labeledBlock);
}
produceJump(edge, labeledBlock);
}
graph.rollOut(header, labeledBlock);
graph.rollOut(tail, block);
block.appendChildren(newNode.block);
}
public String toString() {
return super.toString() + "(" + header + ", " + tail + ")";
}
}

View File

@ -0,0 +1,83 @@
package com.j2js.cfg.transformation;
import java.util.ArrayList;
import java.util.List;
import com.j2js.cfg.Edge;
import com.j2js.cfg.Node;
import com.j2js.cfg.SwitchEdge;
import com.j2js.dom.Block;
import com.j2js.dom.NumberLiteral;
import com.j2js.dom.SwitchCase;
import com.j2js.dom.SwitchStatement;
/**
*/
public class Switch extends Transformation {
private List<Node> caseGroups = new ArrayList<Node>();
private List<List<NumberLiteral>> caseGroupExpressions = new ArrayList<List<NumberLiteral>>();
public boolean applies_() {
return header.isSwitchHeader;
}
private void removeFallThroughEdgesl() {
Edge prevPotentialFallThroughEdge = null;
for (Edge e : header.getOutEdges()) {
if (!(e instanceof SwitchEdge)) continue;
SwitchEdge edge = (SwitchEdge) e;
Node caseGroup = edge.target;
if (prevPotentialFallThroughEdge != null && prevPotentialFallThroughEdge.target == caseGroup) {
// This is a fall through edge.
graph.removeEdge(prevPotentialFallThroughEdge);
}
prevPotentialFallThroughEdge = caseGroup.getLocalOutEdgeOrNull();
}
}
void apply_() {
removeFallThroughEdgesl();
for (Edge e : new ArrayList<Edge>(header.getOutEdges())) {
if (!(e instanceof SwitchEdge)) continue;
SwitchEdge edge = (SwitchEdge) e;
Node caseGroup = edge.target;
caseGroups.add(caseGroup);
caseGroupExpressions.add(edge.expressions);
graph.rerootOutEdges(caseGroup, newNode, true);
graph.removeOutEdges(caseGroup);
graph.removeInEdges(caseGroup);
graph.removeNode(caseGroup);
}
}
void rollOut_(Block block) {
SwitchStatement switchStmt = new SwitchStatement();
switchStmt.setExpression(header.switchExpression);
for (int i=0; i<caseGroups.size(); i++) {
Node scNode = caseGroups.get(i);
SwitchCase switchCase = new SwitchCase(scNode.getInitialPc());
switchCase.setExpressions(caseGroupExpressions.get(i));
switchStmt.appendChild(switchCase);
graph.rollOut(scNode, switchCase);
}
block.appendChild(switchStmt);
}
public String toString() {
String s = super.toString() + "(" + header;
for (int i=0; i<caseGroups.size(); i++) {
s += ", " + caseGroups.get(i);
}
return s + ")";
}
}

View File

@ -0,0 +1,116 @@
package com.j2js.cfg.transformation;
import com.j2js.Log;
import com.j2js.Optimizer;
import com.j2js.cfg.ConditionalEdge;
import com.j2js.cfg.ControlFlowGraph;
import com.j2js.cfg.Edge;
import com.j2js.cfg.Graph;
import com.j2js.cfg.Node;
import com.j2js.dom.Block;
import com.j2js.dom.BooleanExpression;
import com.j2js.dom.BreakStatement;
import com.j2js.dom.ContinueStatement;
import com.j2js.dom.Expression;
import com.j2js.dom.IfStatement;
public abstract class Transformation {
static Class[] transformations = new Class[] {
Switch.class,
Try.class,
//If.class,
//IfElse.class,
Loop.class,
// Merge must be applied after Loop.
Merge.class
};
public static Transformation select(Graph graph, Node node) {
for (int i=0; i<transformations.length; i++) {
Transformation t = fetch(i);
if (t.applies(node)) {
return t;
}
}
return null;
}
static Transformation fetch(int index) {
Transformation t = null;
try {
t = (Transformation) transformations[index].newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return t;
}
ControlFlowGraph graph;
public Node header;
Node newNode;
public Transformation() {
}
public Node apply() {
newNode = graph.createNode(Node.class);
newNode.setInitialPc(header.getInitialPc());
newNode.trans = this;
apply_();
// Remove Header.
graph.replaceNode(header, newNode);
Log.getLogger().debug(toString() + " -> " + newNode);
return newNode;
}
public boolean applies(Node node) {
graph = (ControlFlowGraph) node.getGraph();
header = node;
return applies_();
}
abstract boolean applies_();
abstract void apply_();
abstract void rollOut_(Block block);
public void rollOut(Block block) {
rollOut_(block);
block.appendChildren(newNode.block);
}
void produceJump(Edge edge, Block labeledBlock) {
Node referer = edge.getOrgSource();
Block breakBlock;
if (edge instanceof ConditionalEdge) {
ConditionalEdge condEdge = (ConditionalEdge) edge;
BooleanExpression condExpr = condEdge.getBooleanExpression();
Expression expr = Optimizer.simplifyBooleanExpression(condExpr.getExpression(), condEdge.isNegate());
IfStatement ifStmt = new IfStatement();
ifStmt.setExpression(expr);
referer.block.appendChild(ifStmt);
Block ifBlock = new Block();
ifStmt.setIfBlock(ifBlock);
breakBlock = ifBlock;
} else {
breakBlock = referer.block;
}
if (edge.isBackEdge()) {
breakBlock.appendChild(new ContinueStatement(labeledBlock));
} else {
breakBlock.appendChild(new BreakStatement(labeledBlock));
}
}
public String toString() {
return getClass().getName();
}
}

View File

@ -0,0 +1,77 @@
package com.j2js.cfg.transformation;
import java.util.Iterator;
import java.util.List;
import com.j2js.cfg.Node;
import com.j2js.cfg.TryHeaderNode;
import com.j2js.dom.Block;
import com.j2js.dom.CatchClause;
import com.j2js.dom.TryStatement;
public class Try extends Transformation {
private Node tryBodyNode;
private List catchNodes;
private Node finallyNode;
boolean applies_() {
return header instanceof TryHeaderNode;
}
void apply_() {
TryHeaderNode head = (TryHeaderNode) header;
catchNodes = head.getCatchNodes();
for (Node catchNode : head.getCatchNodes()) {
graph.rerootOutEdges(catchNode, newNode, false);
graph.removeInEdges(catchNode);
graph.removeNode(catchNode);
}
tryBodyNode = head.getTryBody();
graph.rerootOutEdges(tryBodyNode, newNode, false);
graph.removeInEdges(tryBodyNode);
graph.removeNode(tryBodyNode);
finallyNode = head.getFinallyNode();
if (finallyNode != null) {
Block b = finallyNode.block;
// Remove return address.
b.removeChild(b.getFirstChild());
// Remove return statement.
b.removeChild(b.getLastChild());
graph.rerootOutEdges(finallyNode, newNode, false);
graph.removeInEdges(finallyNode);
graph.removeNode(finallyNode);
}
}
void rollOut_(Block block) {
TryHeaderNode head = (TryHeaderNode) header;
TryStatement stmt = head.getTryStatement();
block.appendChild(stmt);
graph.rollOut(tryBodyNode, stmt.getTryBlock());
if (finallyNode != null) {
stmt.setFinallyBlock(new Block());
graph.rollOut(finallyNode, stmt.getFinallyBlock());
}
CatchClause cc = (CatchClause) stmt.getCatchStatements().getFirstChild();
Iterator iter = catchNodes.iterator();
while (iter.hasNext()) {
Node catchNode = (Node) iter.next();
graph.rollOut(catchNode, cc);
cc = (CatchClause) cc.getNextSibling();
}
}
public String toString() {
return super.toString() + "(" + header + ")";
}
}

View File

@ -0,0 +1,200 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/*
* Statement.java
*
* Created on 21. Mai 2004, 11:45
*/
/**
*
* @author kuehn
*/
public class ASTNode {
public static final int BEFORE = 0;
public static final int AFTER = 1;
public static final int SAME = 2;
public static final int CONTAINS = 3;
public static final int ISCONTAINED = 4;
int beginIndex = Integer.MAX_VALUE;
int endIndex = Integer.MIN_VALUE;
private ASTNode parent = null;
private ASTNode previousSibling = null;
private ASTNode nextSibling = null;
private int stackDelta = 0;
public ASTNode() {
super();
}
public ASTNode(int theBeginIndex, int theEndIndex) {
setRange(theBeginIndex, theEndIndex);
}
/**
* @return Returns the stackDelta.
*/
public int getStackDelta() {
return stackDelta;
}
/**
* @param theStackDelta The stackDelta to set.
*/
public void setStackDelta(int theStackDelta) {
stackDelta = theStackDelta;
}
public void widen(ASTNode node) {
leftWiden(node.beginIndex);
rightWiden(node.endIndex);
}
public void leftWiden(int targetBeginIndex) {
if (targetBeginIndex < beginIndex) beginIndex = targetBeginIndex;
}
public void rightWiden(int targetEndIndex) {
if (targetEndIndex > endIndex) endIndex = targetEndIndex;
}
public void setRange(int theBeginIndex, int theEndIndex) {
setBeginIndex(theBeginIndex);
setEndIndex(theEndIndex);
}
// private void checkRange() {
// if (endIndex!=Integer.MIN_VALUE && beginIndex!=Integer.MAX_VALUE && endIndex<beginIndex) {
// throw new RuntimeException("Begin index greater than end index: " + beginIndex + ">" + endIndex);
// }
// }
/** Getter for property beginIndex.
* @return Value of property beginIndex.
*/
public int getBeginIndex() {
return beginIndex;
}
/** Setter for property beginIndex.
* @param theBeginIndex New value of property beginIndex.
*/
public void setBeginIndex(int theBeginIndex) {
beginIndex = theBeginIndex;
}
/** Getter for property endIndex.
* @return Value of property endIndex.
*/
public int getEndIndex() {
return endIndex;
}
/** Setter for property endIndex.
* @param endIndex New value of property endIndex.
*/
public void setEndIndex(int theEndIndex) {
endIndex = theEndIndex;
}
public boolean isRightSiblingOf(ASTNode leftSibling) {
for (ASTNode node=this; node!=null; node=node.getPreviousSibling()) {
if (node == leftSibling) {
return true;
}
}
return false;
}
public ASTNode rightMostSibling() {
for (ASTNode node=this;;) {
if (node.getNextSibling() == null) {
return node;
}
node = node.getNextSibling();
}
}
public boolean isAncestorOf(ASTNode node) {
do {
node = node.getParentNode();
if (node == this) {
return true;
}
} while (node != null);
return false;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
if (getBeginIndex() != Integer.MAX_VALUE) {
sb.append("[");
sb.append(getBeginIndex());
sb.append(", ");
sb.append(getEndIndex());
sb.append("]");
}
return sb.toString();
}
/**
* @return Returns the parent.
*/
public ASTNode getParentNode() {
return parent;
}
public Block getParentBlock() {
return (Block) parent;
}
public Block getLogicalParentBlock() {
if (parent != null && parent.parent instanceof IfStatement) {
return (Block) parent.parent;
}
return (Block) parent;
}
/**
* @param theParent The parent to set.
*/
public void setParentNode(ASTNode theParent) {
parent = theParent;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the nextSibling.
*/
public ASTNode getNextSibling() {
return nextSibling;
}
/**
* @param theNextSibling The nextSibling to set.
*/
public void setNextSibling(ASTNode theNextSibling) {
nextSibling = theNextSibling;
}
/**
* @return Returns the previousSibling.
*/
public ASTNode getPreviousSibling() {
return previousSibling;
}
/**
* @param thePreviousSibling The previousSibling to set.
*/
public void setPreviousSibling(ASTNode thePreviousSibling) {
previousSibling = thePreviousSibling;
}
}

View File

@ -0,0 +1,54 @@
/*
* Created on Oct 31, 2004
*/
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class ArrayAccess extends Expression implements Assignable {
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public boolean isSame(Object obj) {
if (!(obj instanceof ArrayAccess)) return false;
ArrayAccess other = (ArrayAccess) obj;
if (getArray() instanceof VariableBinding && other.getArray() instanceof VariableBinding) {
VariableBinding vba = (VariableBinding) getArray();
VariableBinding vbb = (VariableBinding) other.getArray();
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
}
return false;
}
/**
* @return Returns the array.
*/
public Expression getArray() {
return (Expression) getChildAt(0);
}
/**
* @param array The array to set.
*/
public void setArray(Expression array) {
widen(array);
setChildAt(0, array);
}
/**
* @return Returns the index.
*/
public Expression getIndex() {
return (Expression) getChildAt(1);
}
/**
* @param index The index to set.
*/
public void setIndex(Expression index) {
widen(index);
setChildAt(1, index);
}
}

View File

@ -0,0 +1,50 @@
package com.j2js.dom;
import java.util.List;
import org.apache.bcel.generic.Type;
import com.j2js.assembly.Project;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class ArrayCreation extends Expression {
private List<ASTNode> dimensions;
private ArrayInitializer initializer;
public ArrayCreation(MethodDeclaration methodDecl, Type theType, List<ASTNode> theDimensions) {
type = theType;
dimensions = theDimensions;
for (ASTNode dimension : dimensions) {
this.widen(dimension);
}
Project.getSingleton().addReference(methodDecl, this);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the initializer.
*/
public ArrayInitializer getInitializer() {
return initializer;
}
/**
* @param theInitializer The initializer to set.
*/
public void setInitializer(ArrayInitializer theInitializer) {
initializer = theInitializer;
}
/**
* @return Returns the dimensions.
*/
public List<ASTNode> getDimensions() {
return dimensions;
}
}

View File

@ -0,0 +1,24 @@
package com.j2js.dom;
import java.util.List;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class ArrayInitializer extends Expression {
private List<Expression> expressions = new java.util.ArrayList<Expression>();
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the expressions.
*/
public List<Expression> getExpressions() {
return expressions;
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright 2005 by Wolfgang Kuehn
* Created on 16.10.2005
*/
package com.j2js.dom;
/**
* Tagging interface for all node types which are legal assignment targets.
*/
public interface Assignable {
/**
* Returns true if the specified Assignable corresponds to this Assignable.
*/
public boolean isSame(Object obj);
}

View File

@ -0,0 +1,96 @@
package com.j2js.dom;
import java.util.HashMap;
import com.j2js.visitors.AbstractVisitor;
/**
* @author kuehn
*/
public class Assignment extends Expression {
static public class Operator {
static private HashMap<String, Operator> opsByToken = new HashMap<String, Operator>();
static public Operator lookup(String token) {
return opsByToken.get(token);
}
static public Operator ASSIGN = new Operator("=");
static public Operator PLUS_ASSIGN = new Operator("+=");
static public Operator MINUS_ASSIGN = new Operator("-=");
static public Operator TIMES_ASSIGN = new Operator("*=");
static public Operator DIVIDE_ASSIGN = new Operator("/=");
static public Operator BIT_AND_ASSIGN = new Operator("&=");
static public Operator BIT_OR_ASSIGN = new Operator("|=");
static public Operator BIT_XOR_ASSIGN = new Operator("^=");
static public Operator REMAINDER_ASSIGN = new Operator("%=");
static public Operator LEFT_SHIFT_ASSIGN = new Operator("<<=");
static public Operator RIGHT_SHIFT_SIGNED_ASSIGN = new Operator(">>=");
static public Operator RIGHT_SHIFT_UNSIGNED_ASSIGN = new Operator(">>>=");
private String token;
Operator(String theToken) {
token = theToken;
opsByToken.put(theToken, this);
}
public String toString() {
return token;
}
}
private Operator operator;
public Assignment(Operator theOperator) {
super();
operator = theOperator;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @param rightHandSide The rightHandSide to set.
*/
public void setRightHandSide(Expression rightHandSide) {
widen(rightHandSide);
setChildAt(1, rightHandSide);
}
/**
* @return Returns the rightHandSide.
*/
public Expression getRightHandSide() {
return (Expression) getChildAt(1);
}
/**
* @param leftHandSide The leftHandSide to set.
*/
public void setLeftHandSide(Expression leftHandSide) {
setChildAt(0, leftHandSide);
}
/**
* @return Returns the leftHandSide.
*/
public Expression getLeftHandSide() {
return (Expression) getChildAt(0);
}
/**
* @return Returns the operator.
*/
public Operator getOperator() {
return operator;
}
/**
* @param theOerator The operator to set.
*/
public void setOperator(Operator theOperator) {
operator = theOperator;
}
}

View File

@ -0,0 +1,356 @@
package com.j2js.dom;
import com.j2js.Log;
import com.j2js.visitors.AbstractVisitor;
import org.w3c.dom.DOMException;
/*
* Block.java
*
* Created on 21. Mai 2004, 11:38
*/
public class Block extends ASTNode {
public static int TAG = 0;
private String label;
private ASTNode firstChild = null;
private ASTNode lastChild = null;
private int childCount = 0;
public Block() {
super();
}
public Block(int theBeginIndex) {
setBeginIndex(theBeginIndex);
}
public Block(int theBeginIndex, int theEndIndex) {
this(theBeginIndex);
setRange(theBeginIndex, theEndIndex);
}
// public Block getFooBlock() {
// Block block = this;
// while (block!=null) {
// if (!block.getClass().equals(Block.class)) {
// return block;
// }
// block = block.getParentBlock();
// }
// return this;
// }
public int getTargetPc() {
if (lastChild instanceof Jump) {
return ((Jump) lastChild).getTargetIndex();
}
return Integer.MAX_VALUE;
}
public int getTargetIndex() {
return beginIndex;
}
public void setBeginIndex(int theBeginIndex) {
super.setBeginIndex(theBeginIndex);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public void appendChildren(ASTNode begin, ASTNode end) {
if (begin == null || end == null) {
throw new RuntimeException("Illegal null parameters");
}
if (begin.getParentBlock() != null)
(begin.getParentBlock()).removeChildren(begin, end);
if (firstChild == null) {
setFirstChildInternal(begin);
} else {
ASTNode prev = getLastChild();
prev.setNextSibling(begin);
begin.setPreviousSibling(prev);
}
setLastChildInternal(end);
ASTNode node = begin;
while (node != null) {
node.setParentNode(this);
childCount++;
if (node == end) break;
node = node.getNextSibling();
}
}
/**
* Appends all children of the specified block to this block.
* @param sourceBlock
*/
public void appendChildren(Block sourceBlock) {
if (sourceBlock.getChildCount() > 0) {
appendChildren(sourceBlock.getFirstChild(), sourceBlock.getLastChild());
}
}
/**
* Sets the specified node at the index. Returns the replaced node, or null if the index
* was equal to the cild count.
*/
public ASTNode setChildAt(int index, ASTNode newChild) {
if (index == childCount) {
appendChild(newChild);
return null;
} else if (index < 0 || index > childCount) {
throw new RuntimeException("Index " + index + " out of range [0, " + childCount + "]");
}
return replaceChild(newChild, getChildAt(index));
}
public ASTNode getChildAt(int index) {
if (childCount == 0) {
throw new RuntimeException("Requested child at index " + index + ", but block has no children");
}
if (index < 0 || index >= childCount) {
throw new RuntimeException("Index " + index + " out of range [0, " + (childCount-1) + "]");
}
if (index == childCount-1) {
return getLastChild();
}
ASTNode node = getFirstChild();
int i = 0;
while (i < index) {
i++;
node = node.getNextSibling();
}
return node;
}
public ASTNode appendChild(ASTNode newChild) {
Log.getLogger().debug("Appending " + newChild + " to " + this);
unlink(newChild);
if (firstChild == null) {
newChild.setPreviousSibling(null);
setFirstChildInternal(newChild);
} else {
ASTNode prev = getLastChild();
prev.setNextSibling(newChild);
newChild.setPreviousSibling(prev);
}
setLastChildInternal(newChild);
newChild.setParentNode(this);
childCount++;
return newChild;
}
public ASTNode replaceChild(ASTNode newChild, ASTNode oldChild) {
Log.getLogger().debug("Replacing " + oldChild + " by " + newChild + " in " + this);
if (oldChild.getParentNode() != this) {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Node " + oldChild + " is not a child of " + this);
}
unlink(newChild);
if (oldChild.getPreviousSibling() != null) {
oldChild.getPreviousSibling().setNextSibling(newChild);
}
if (oldChild.getNextSibling() != null) {
oldChild.getNextSibling().setPreviousSibling(newChild);
}
newChild.setPreviousSibling(oldChild.getPreviousSibling());
newChild.setNextSibling(oldChild.getNextSibling());
newChild.setParentNode(this);
if (getFirstChild() == oldChild) {
setFirstChildInternal(newChild);
}
if (getLastChild() == oldChild) {
setLastChildInternal(newChild);
}
oldChild.setPreviousSibling(null);
oldChild.setNextSibling(null);
oldChild.setParentNode(null);
return oldChild;
}
public ASTNode removeChild(ASTNode oldChild) {
Log.getLogger().debug("Removing " + oldChild + " from " + this);
removeChildren(oldChild, oldChild);
oldChild.setPreviousSibling(null);
oldChild.setNextSibling(null);
return oldChild;
}
/**
* Removes all children from begin to end inclusively.
*/
private void removeChildren(ASTNode begin, ASTNode end) {
if (begin == null || end == null) throw new RuntimeException("Illegal null parameters");
ASTNode node = begin;
while (node!= null) {
if (node.getParentNode() != this) {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Node " + node + " is not a child of " + this);
}
node.setParentNode(null);
childCount--;
if (node == end) break;
node = node.getNextSibling();
}
if (node != end) {
throw new RuntimeException("Node " + end + " is not a right-sibling of " + begin);
}
if (begin.getPreviousSibling() != null) {
begin.getPreviousSibling().setNextSibling(end.getNextSibling());
}
if (end.getNextSibling() != null) {
end.getNextSibling().setPreviousSibling(begin.getPreviousSibling());
}
if (getFirstChild() == begin) {
setFirstChildInternal(end.getNextSibling());
}
if (getLastChild() == end) {
setLastChildInternal(begin.getPreviousSibling());
}
}
public void removeChildren() {
if (getFirstChild() != null) {
removeChildren(getFirstChild(), getLastChild());
}
}
public int getChildCount() {
return childCount;
}
/**
* Inserts the node newChild after the existing child node refChild.
* If refChild is null, insert newChild at the beginning of the list of children.
*
* @param newChild The node to insert
* @param refChild The reference node, i.e., the node before which the new node must be inserted
* @return
*/
// public ASTNode insertAfter(ASTNode newChild, ASTNode refChild) {
// if (refChild == null) {
// refChild = getFirstChild();
// } else {
// refChild = refChild.getNextSibling();
// }
// return insertBefore(newChild, refChild);
// }
/**
* Inserts the node newChild before the existing child node refChild.
* If refChild is null, insert newChild at the end of the list of children.
*
* @param newChild The node to insert
* @param refChild The reference node, i.e., the node before which the new node must be inserted
* @return
*/
public ASTNode insertBefore(ASTNode newChild, ASTNode refChild) {
if (refChild == null) {
return appendChild(newChild);
}
Log.getLogger().debug("Inserting " + newChild + " before " + refChild + " in " + this);
if (refChild.getParentNode() != this) {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Reference " + refChild + " is not a child of " + this);
}
unlink(newChild);
if (refChild.getPreviousSibling() != null) {
refChild.getPreviousSibling().setNextSibling(newChild);
}
newChild.setPreviousSibling(refChild.getPreviousSibling());
newChild.setNextSibling(refChild);
newChild.setParentNode(this);
childCount++;
refChild.setPreviousSibling(newChild);
if (getFirstChild() == refChild) {
setFirstChildInternal(newChild);
}
return newChild;
}
public void addStatements(java.util.List statements) {
for (int i=0; i<statements.size(); i++) {
appendChild((ASTNode)statements.get(i));
}
}
public ASTNode getFirstChild() {
return firstChild;
}
public ASTNode getLastChild() {
return lastChild;
}
/**
* @param firstChild The firstChild to set.
*/
private void setFirstChildInternal(ASTNode newFirstChild) {
firstChild = newFirstChild;
if (firstChild != null) {
firstChild.setPreviousSibling(null);
beginIndex = Math.min(beginIndex, firstChild.getBeginIndex());
}
}
/**
* @param lastChild The lastChild to set.
*/
private void setLastChildInternal(ASTNode newLastChild) {
lastChild = newLastChild;
if (lastChild != null) {
lastChild.setNextSibling(null);
endIndex = Math.max(endIndex, lastChild.getEndIndex());
}
}
/**
* If the specified node is contained in a tree, remove it.
*/
private void unlink(ASTNode node) {
if (node.getParentBlock() != null) {
node.getParentBlock().removeChild(node);
}
}
public String getLabel() {
if (label == null) throw new RuntimeException("Statement is not labeled");
return label;
}
public void setLabel(String theLabel) {
label = theLabel;
}
public boolean isLabeled() {
return label != null;
}
public String setLabeled() {
if (label == null) label = "L" + (++TAG);
return label;
}
}

View File

@ -0,0 +1,15 @@
package com.j2js.dom;
public class BooleanExpression implements Cloneable {
private Expression expression;
public BooleanExpression(Expression newExpression) {
expression = newExpression;
}
public Expression getExpression() {
return expression;
}
}

View File

@ -0,0 +1,36 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class BooleanLiteral extends Expression {
// Note: Never ever use TRUE as part of a DOM.
public static BooleanLiteral FALSE = new BooleanLiteral(false);
// Note: Never ever use TRUE as part of a DOM.
public static BooleanLiteral TRUE = new BooleanLiteral(true);
private boolean value;
public BooleanLiteral(boolean theValue) {
value = theValue;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the value.
*/
public boolean getValue() {
return value;
}
/**
* @param theValue The value to set.
*/
public void setValue(boolean theValue) {
value = theValue;
}
}

View File

@ -0,0 +1,67 @@
package com.j2js.dom;
/**
* @author wolfgang
*/
public class Branch extends Expression {
private int targetIndex = -1;
private ASTNode target;
public Branch() {
super();
}
public Branch(int theTargetIndex) {
setTargetIndex(theTargetIndex);
}
public boolean isBackward() {
return getTargetIndex() <= getBeginIndex();
}
/**
* @return Returns the targetIndex.
*/
public int getTargetIndex() {
return targetIndex;
}
/**
* @param theTargetIndex The targetIndex to set.
*/
public void setTargetIndex(int theTargetIndex) {
targetIndex = theTargetIndex;
}
public String toString() {
String s = getClass().getName()
+ "[" + getBeginIndex() + ", " + getEndIndex() + ", " + targetIndex + "] -> ";
if (target != null) {
Exception e = new Exception();
if (target == this) {
s += "self";
} else if (e.getStackTrace().length>20) {
s += "...";
} else {
s += "" + target.toString();
}
} else {
s += "null";
}
return s;
}
/**
* @return Returns the target.
*/
public ASTNode getTarget() {
return target;
}
/**
* @param theTarget The target to set.
*/
public void setTarget(ASTNode theTarget) {
target = theTarget;
if (theTarget != null) targetIndex = theTarget.getBeginIndex();
}
}

View File

@ -0,0 +1,19 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
public class BreakStatement extends LabeledJump {
public BreakStatement(String theLabel) {
super(theLabel);
}
public BreakStatement(Block block) {
super(block);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,31 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author kuehn
*/
public class CastExpression extends Expression {
private Expression expression;
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @param theExpression The expression to set.
*/
public void setExpression(Expression theExpression) {
widen(theExpression);
expression = theExpression;
}
/**
* @return Returns the expression.
*/
public Expression getExpression() {
return expression;
}
}

View File

@ -0,0 +1,45 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/*
* CatchStatement.java
*
* Created on 22. Mai 2004, 22:49
*/
/**
*
* @author kuehn
*/
public class CatchClause extends Block {
private VariableDeclaration exception;
/** Creates a new instance of CatchStatement */
//public CatchStatement() {
//}
public CatchClause(int theBeginIndex) {
super(theBeginIndex);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the exception.
*/
public VariableDeclaration getException() {
return exception;
}
/**
* @param theException The exception to set.
*/
public void setException(VariableDeclaration theException) {
exception = theException;
}
}

View File

@ -0,0 +1,24 @@
package com.j2js.dom;
import org.apache.bcel.generic.ObjectType;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class ClassInstanceCreation extends MethodInvocation {
public ClassInstanceCreation(ObjectType theType) {
type = theType;
}
public ClassInstanceCreation(MethodDeclaration methodDecl, MethodBinding methodBinding) {
super(methodDecl, methodBinding);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,22 @@
package com.j2js.dom;
import com.j2js.assembly.Signature;
import com.j2js.visitors.AbstractVisitor;
public class ClassLiteral extends Expression {
private Signature signature;
public ClassLiteral(Signature theSignature) {
signature = theSignature;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public Signature getSignature() {
return signature;
}
}

View File

@ -0,0 +1,41 @@
/*
* Created on Feb 13, 2005
*/
package com.j2js.dom;
/**
* Copyright by Wolfgang Kuehn 2005
*/
public class ConditionalBranch extends Branch {
private Expression expression;
public ConditionalBranch(int targetIndex) {
super(targetIndex);
}
/**
* This constructor is for testing purposes only!!
*/
public ConditionalBranch(int theBeginIndex, int theEndIndex, int targetIndex) {
super(targetIndex);
setExpression(new Expression(theBeginIndex, theEndIndex));
}
/**
* @return Returns the condition.
*/
public Expression getExpression() {
return expression;
}
/**
* @param condition The condition to set.
*/
public void setExpression(Expression theExpression) {
expression = theExpression;
widen(theExpression);
appendChild(theExpression);
}
}

View File

@ -0,0 +1,61 @@
/*
* Created on Sep 10, 2005
*/
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class ConditionalExpression extends Expression {
private Expression conditionExpression = null;
private Expression thenExpression = null;
private Expression elseExpression = null;
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the conditionExpression.
*/
public Expression getConditionExpression() {
return conditionExpression;
}
/**
* @param theConditionExpression The conditionExpression to set.
*/
public void setConditionExpression(Expression theConditionExpression) {
widen(theConditionExpression);
conditionExpression = theConditionExpression;
}
/**
* @return Returns the elseExpression.
*/
public Expression getElseExpression() {
return elseExpression;
}
/**
* @param theElseExpression The elseExpression to set.
*/
public void setElseExpression(Expression theElseExpression) {
widen(theElseExpression);
elseExpression = theElseExpression;
}
/**
* @return Returns the thenExpression.
*/
public Expression getThenExpression() {
return thenExpression;
}
/**
* @param theThenExpression The thenExpression to set.
*/
public void setThenExpression(Expression theThenExpression) {
widen(theThenExpression);
thenExpression = theThenExpression;
}
}

View File

@ -0,0 +1,16 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
public class ContinueStatement extends LabeledJump {
public ContinueStatement(Block block) {
super(block);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,32 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/*
* DoStatement.java
*
* Created on 21. Mai 2004, 17:30
*/
/**
*
* @author kuehn
*/
public class DoStatement extends LoopStatement {
public DoStatement() {
super();
}
public DoStatement(int theBeginIndex) {
super(theBeginIndex);
}
public DoStatement(int theBeginIndex, int theEndIndex) {
super(theBeginIndex, theEndIndex);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,52 @@
package com.j2js.dom;
import org.apache.bcel.generic.Type;
import com.j2js.Form;
/**
* Copyright by Wolfgang Kuehn 2005
* Created on Feb 17, 2005
*/
public class Expression extends Block implements Cloneable {
Type type = Type.UNKNOWN;
public Expression() {
super();
}
public Expression(int theBeginIndex, int theEndIndex) {
super(theBeginIndex, theEndIndex);
}
public Object clone() {
if (getChildCount() > 0) throw new RuntimeException("Cannot clone expression with children");
ASTNode node;
try {
node = (ASTNode) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
node.setParentNode(null);
node.setPreviousSibling(null);
node.setNextSibling(null);
return node;
}
public Type getTypeBinding() {
return type;
}
public void setTypeBinding(Type theType) {
type = theType;
}
public int getCategory() {
if (getTypeBinding().getType() == Type.LONG.getType()) return Form.CATEGORY2;
if (getTypeBinding().getType() == Type.DOUBLE.getType()) return Form.CATEGORY2;
return Form.CATEGORY1;
//return getTypeBinding().getType() == Type.LONG.getType() || getTypeBinding().getType() == Type.DOUBLE.getType()?Form.CATEGORY2:Form.CATEGORY1;
}
}

View File

@ -0,0 +1,85 @@
package com.j2js.dom;
import org.apache.bcel.generic.ObjectType;
import com.j2js.assembly.Project;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public abstract class FieldAccess extends Expression {
private String name;
private ObjectType type;
//private MethodDeclaration methodDecl;
public FieldAccess() {
}
public void initialize(MethodDeclaration methodDecl) {
Project.getSingleton().addReference(methodDecl, this);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
// if (!faa.getName().equals(fab.getName())) return false;
//
public boolean isSame(Object obj) {
if (!(obj instanceof FieldAccess)) return false;
FieldAccess other = (FieldAccess) obj;
if (!name.equals(other.name)) return false;
if (getExpression() instanceof VariableBinding && other.getExpression() instanceof VariableBinding) {
VariableBinding vba = (VariableBinding) getExpression();
VariableBinding vbb = (VariableBinding) other.getExpression();
return vba.getVariableDeclaration() == vbb.getVariableDeclaration();
}
return false;
}
/**
* @return Returns the expression.
*/
public Expression getExpression() {
return (Expression) getFirstChild();
}
/**
* @param expression The expression to set.
*/
public void setExpression(Expression expression) {
widen(expression);
removeChildren();
appendChild(expression);
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param theName The name to set.
*/
public void setName(String theName) {
name = theName;
}
public String toString() {
return super.toString() + " " + name;
}
public ObjectType getType() {
return type;
}
public void setType(ObjectType theType) {
if (type != null) throw new RuntimeException("Type is already set");
type = theType;
}
}

View File

@ -0,0 +1,14 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
public class FieldRead extends FieldAccess {
public FieldRead() {
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,14 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
public class FieldWrite extends FieldAccess implements Assignable {
public FieldWrite() {
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,13 @@
/*
* Copyright 2005 by Wolfgang Kuehn
* Created on 12.11.2005
*/
package com.j2js.dom;
/**
* @author wolfgang
*/
public class Goto extends ASTNode {
}

View File

@ -0,0 +1,46 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author kuehn
*/
public class IfStatement extends Block {
public IfStatement() {
super();
}
public Expression getExpression() {
return (Expression) getChildAt(0);
}
public void setExpression(Expression expression) {
widen(expression);
setChildAt(0, expression);
}
public Block getIfBlock() {
return (Block) getChildAt(1);
}
public void setIfBlock(Block block) {
widen(block);
setChildAt(1, block);
}
public Block getElseBlock() {
if (getChildCount() < 3) return null;
return (Block) getChildAt(2);
}
public void setElseBlock(Block block) {
widen(block);
setChildAt(2, block);
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,111 @@
package com.j2js.dom;
import com.j2js.visitors.AbstractVisitor;
/**
* @author kuehn
*/
public class InfixExpression extends Expression {
static public class Operator {
static public Operator CONDITIONAL_AND = new Operator("&&");
static public Operator CONDITIONAL_OR = new Operator("||");
static public Operator PLUS = new Operator("+");
static public Operator MINUS = new Operator("-");
static public Operator TIMES = new Operator("*");
static public Operator DIVIDE = new Operator("/");
static public Operator REMAINDER = new Operator("%");
static public Operator XOR = new Operator("^");
static public Operator AND = new Operator("&");
static public Operator OR = new Operator("|");
static public Operator EQUALS = new Operator("==");
static public Operator NOT_EQUALS = new Operator("!=");
static public Operator GREATER_EQUALS = new Operator(">=");
static public Operator GREATER = new Operator(">");
static public Operator LESS_EQUALS = new Operator("<=");
static public Operator LESS = new Operator("<");
static public Operator RIGHT_SHIFT_SIGNED = new Operator(">>");
static public Operator LEFT_SHIFT = new Operator("<<");
static public Operator RIGHT_SHIFT_UNSIGNED = new Operator(">>>");
static {
EQUALS.complement = NOT_EQUALS;
NOT_EQUALS.complement = EQUALS;
GREATER_EQUALS.complement = LESS;
GREATER.complement = LESS_EQUALS;
LESS_EQUALS.complement = GREATER;
LESS.complement = GREATER_EQUALS;
CONDITIONAL_AND.complement = CONDITIONAL_OR;
CONDITIONAL_OR.complement = CONDITIONAL_AND;
}
private String token;
private Operator complement;
Operator(String theToken) {
token = theToken;
}
public String toString() {
return token;
}
/**
* @return Returns the complement.
*/
public Operator getComplement() {
return complement;
}
}
private Operator operator;
public InfixExpression(Operator op) {
super();
operator = op;
if (operator.getComplement() != null) type = org.apache.bcel.generic.Type.BOOLEAN;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
/**
* @return Returns the leftOperand.
*/
public Expression getLeftOperand() {
return (Expression) getChildAt(0);
}
/**
* @param leftOperand The leftOperand to set.
*/
public void setOperands(Expression leftOperand, Expression rightOperand) {
widen(leftOperand);
widen(rightOperand);
removeChildren();
appendChild(leftOperand);
appendChild(rightOperand);
}
/**
* @return Returns the rightOperand.
*/
public Expression getRightOperand() {
return (Expression) getChildAt(1);
}
/**
* @return Returns the operator.
*/
public Operator getOperator() {
return operator;
}
/**
* @param theOperator The operator to set.
*/
public void setOperator(Operator theOperator) {
operator = theOperator;
}
}

View File

@ -0,0 +1,31 @@
package com.j2js.dom;
import org.apache.bcel.generic.Type;
import com.j2js.visitors.AbstractVisitor;
/**
* Copyright by Wolfgang Kuehn 2005
* Created on Feb 27, 2005
*/
public class InstanceofExpression extends Expression {
private Expression leftOperand;
private Type rightOperand;
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public Expression getLeftOperand() {
return leftOperand;
}
public void setLeftOperand(Expression theLeftOperand) {
leftOperand = theLeftOperand;
}
public Type getRightOperand() {
return rightOperand;
}
public void setRightOperand(Type theRightOperand) {
rightOperand = theRightOperand;
}
}

View File

@ -0,0 +1,20 @@
package com.j2js.dom;
/**
* @author wolfgang
*/
public class Jump extends Branch {
public Jump() {
super();
}
public Jump(int targetIndex) {
super(targetIndex);
}
// public Jump(int beginIndex, int endIndex, int targetIndex) {
// this(targetIndex);
// setRange(beginIndex, endIndex);
// }
}

View File

@ -0,0 +1,12 @@
package com.j2js.dom;
/**
* @author wolfgang
*/
public class JumpSubRoutine extends Branch {
public JumpSubRoutine(int targetIndex) {
super(targetIndex);
}
}

View File

@ -0,0 +1,20 @@
package com.j2js.dom;
abstract public class LabeledJump extends Jump {
String label;
public LabeledJump(String newLabel) {
super();
label = newLabel;
}
public LabeledJump(Block block) {
super();
label = block.setLabeled();
}
public String getLabel() {
return label;
}
}

View File

@ -0,0 +1,44 @@
package com.j2js.dom;
/*
* LoopStatement.java
*
* Created on 21. Mai 2004, 16:51
*/
/**
*
* @author kuehn
*/
public class LoopStatement extends Block {
public LoopStatement() {
super();
}
public LoopStatement(int theBeginIndex) {
super(theBeginIndex);
}
public LoopStatement(int theBeginIndex, int theEndIndex) {
super(theBeginIndex, theEndIndex);
}
public Expression getExpression() {
return (Expression) getChildAt(1);
}
public void setExpression(Expression expression) {
widen(expression);
setChildAt(1, expression);
}
public Block getBlock() {
return (Block) getChildAt(0);
}
public void setBlock(Block block) {
widen(block);
setChildAt(0, block);
}
}

View File

@ -0,0 +1,120 @@
/*
* Created on 29.01.2006
* Copyright Wolfgang Kuehn 2005
*/
package com.j2js.dom;
import java.util.HashMap;
import java.util.Map;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ConstantCP;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import com.j2js.Utils;
/**
* @author kuehn
*/
public class MethodBinding {
private static Map<String, MethodBinding> methodBindingsByKey = new HashMap<String, MethodBinding>();
public static MethodBinding lookup(int index, ConstantPool constantPool) {
ConstantCP methodRef = (ConstantCP) constantPool.getConstant(index);
ConstantNameAndType nameAndType = (ConstantNameAndType)
constantPool.getConstant(methodRef.getNameAndTypeIndex(), Constants.CONSTANT_NameAndType);
String name = nameAndType.getName(constantPool);
String signature = nameAndType.getSignature(constantPool);
return lookup(methodRef.getClass(constantPool), name, signature);
}
public static MethodBinding lookup(String className, String name, String signature) {
String key = className + "#" + name + signature;
MethodBinding binding = methodBindingsByKey.get(key);
if (binding != null) return binding;
binding = new MethodBinding();
binding.declaringClass = new ObjectType(className);
binding.name = name;
binding.parameterTypes = Type.getArgumentTypes(signature);
binding.returnType = Type.getReturnType(signature);
binding.signature = signature;
methodBindingsByKey.put(key, binding);
return binding;
}
private ObjectType declaringClass;
private String name;
private Type[] parameterTypes;
private Type returnType;
private String signature;
private MethodBinding() {
}
/**
* Returns the type binding representing the class or interface that declares this method or constructor.
*/
public ObjectType getDeclaringClass() {
return declaringClass;
}
/**
* Returns the name of the method declared in this binding.
*/
public String getName() {
return name;
}
/**
* Returns a list of type bindings representing the formal parameter types, in declaration order, of this method or constructor.
*/
public Type[] getParameterTypes() {
return parameterTypes;
}
/**
* Returns the binding for the return type of this method.
*/
public Type getReturnType() {
return returnType;
}
/**
* Returns whether this binding is for a constructor or a method.
*/
public boolean isConstructor() {
return "<init>".equals(name);
}
public String getSignature() {
return signature;
}
public String toString() {
return getDeclaringClass().getClassName() + "#" + getRelativeSignature();
}
public String getRelativeSignature() {
String signature = getName() + "(";
String sep = "";
for (int i = 0; i < getParameterTypes().length; i++) {
Type type = getParameterTypes()[i];
signature += sep + Utils.getSignature(type);
sep = ",";
}
signature += ")";
signature += Utils.getSignature(returnType);
return signature;
}
}

View File

@ -0,0 +1,134 @@
package com.j2js.dom;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.generic.Type;
import com.j2js.LineNumberCursor;
import com.j2js.assembly.Project;
import com.j2js.visitors.AbstractVisitor;
/**
* @author wolfgang
*/
public class MethodDeclaration extends ASTNode {
private String tempPrefix = "_";
private Block block;
private Map<String, VariableDeclaration> parameters = new LinkedHashMap<String, VariableDeclaration>();
private Map<String, VariableDeclaration> localVariables = new HashMap<String, VariableDeclaration>();
private int accessFlags;
private Code code;
private MethodBinding methodBinding;
private LineNumberCursor lineNumberCursor;
public MethodDeclaration(MethodBinding theMethodBinding, int theAccessFlags, Code theCode) {
methodBinding = theMethodBinding;
accessFlags = theAccessFlags;
code = theCode;
lineNumberCursor = new LineNumberCursor(code);
Project.getSingleton().getOrCreateProcedureUnit(methodBinding);
}
public int getAccess() {
return accessFlags;
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public boolean isInstanceConstructor() {
return methodBinding.getName().equals("<init>");
}
/**
* @return Returns the block.
*/
public Block getBody() {
return block;
}
/**
* @param theBlock The block to set.
*/
public void setBody(Block theBlock) {
block = theBlock;
theBlock.setParentNode(this);
}
public VariableBinding createVariableBinding(String name, Type type, boolean isWrite) {
if (type == null) throw new NullPointerException();
VariableDeclaration decl = getParameter(name);
if (decl == null) {
decl = getLocalVariable(name);
}
if (decl == null) {
decl = new VariableDeclaration(!isWrite);
decl.setName(name);
decl.setType(type);
addLocalVariable(decl);
}
VariableBinding binding = new VariableBinding(decl);
return binding;
}
private int vbCount = 0;
public VariableBinding createAnonymousVariableBinding(Type type, boolean isWrite) {
String name = tempPrefix + (vbCount++);
VariableBinding vb = createVariableBinding(name, type, isWrite);
vb.setTemporary(true);
return vb;
}
public void addParameter(VariableDeclaration variableDecl) {
parameters.put(variableDecl.getName(), variableDecl);
}
public Collection<VariableDeclaration> getParameters() {
return parameters.values();
}
public VariableDeclaration getParameter(String name) {
return parameters.get(name);
}
public void addLocalVariable(VariableDeclaration variableDecl) {
localVariables.put(variableDecl.getName(), variableDecl);
}
public void removeLocalVariable(String name) {
localVariables.remove(name);
}
public Collection<VariableDeclaration> getLocalVariables() {
return localVariables.values();
}
public VariableDeclaration getLocalVariable(String name) {
return localVariables.get(name);
}
public MethodBinding getMethodBinding() {
return methodBinding;
}
public String toString() {
return methodBinding.toString();
}
public Code getCode() {
return code;
}
public LineNumberCursor getLineNumberCursor() {
return lineNumberCursor;
}
}

View File

@ -0,0 +1,118 @@
package com.j2js.dom;
import java.util.List;
import org.apache.bcel.generic.Type;
import com.j2js.ASTNodeStack;
import com.j2js.assembly.Project;
import com.j2js.visitors.AbstractVisitor;
/**
* @author kuehn
*/
public class MethodInvocation extends Expression {
private Expression expression;
private MethodDeclaration methodDecl;
/**
* Special handling for superclass, private, and instance initialization method invocations.
*/
public boolean isSpecial = false;
private MethodBinding methodBinding;
public MethodInvocation() {
}
public MethodInvocation(MethodDeclaration theMethodDecl) {
methodDecl = theMethodDecl;
}
public MethodInvocation(MethodDeclaration theMethodDecl, MethodBinding theMethodBinding) {
methodDecl = theMethodDecl;
setMethodBinding(theMethodBinding);
}
public Type getTypeBinding() {
if (methodBinding == null) return super.getTypeBinding();
return methodBinding.getReturnType();
}
/**
* Returns true if this method invocation applies to a super class of the specified class.
*/
public boolean isSuper(String currentClassName) {
if (!isSpecial) return false;
// Use resolved class unless
// 1) the resolved method is not an instance initialization method,
if (methodBinding.isConstructor()) return false;
// 2) and the class of the resolved method is a superclass of the current class and
String name = methodBinding.getDeclaringClass().getClassName();
if (currentClassName.equals(name)) return false;
// TODO: The resolved class is different from the current class, but this does not imply that
// the resolved class is a superclass! Problem: How do we get this information without loading
// the class hierarchy?
return true;
}
/**
* @return Returns the arguments.
*/
public List getArguments() {
ASTNodeStack stack = new ASTNodeStack();
ASTNode node = getFirstChild();
if (expression != null) {
node = node.getNextSibling();
}
while (node != null) {
stack.add(node);
node = node.getNextSibling();
}
return stack;
}
/**
* @param arguments The arguments to set.
*/
public void addArgument(Expression argument) {
widen(argument);
appendChild(argument);
}
/**
* @return Returns the expression.
*/
public Expression getExpression() {
return expression;
}
/**
* @param expression The expression to set.
*/
public void setExpression(Expression targetExpression) {
if (expression != null) {
throw new RuntimeException("Expression is already set");
}
expression = targetExpression;
widen(expression);
insertBefore(expression, getFirstChild());
}
public void visit(AbstractVisitor visitor) {
visitor.visit(this);
}
public MethodBinding getMethodBinding() {
return methodBinding;
}
public void setMethodBinding(MethodBinding theMethodBinding) {
methodBinding = theMethodBinding;
Project.getSingleton().addReference(methodDecl, this);
}
}

Some files were not shown because too many files have changed in this diff Show More