Initial Jack import part 2.
Change-Id: Ic439604a1f030700d9049800fbf62422e0004d35
diff --git a/dexcomparator/.settings/org.eclipse.jdt.ui.prefs b/dexcomparator/.settings/org.eclipse.jdt.ui.prefs
index d44207b..ae892c8 100644
--- a/dexcomparator/.settings/org.eclipse.jdt.ui.prefs
+++ b/dexcomparator/.settings/org.eclipse.jdt.ui.prefs
@@ -4,7 +4,7 @@
formatter_profile=_Jack Format 100
formatter_settings_version=13
org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=com.google;android;antenna;antlr;ar;asposewobfuscated;asquare;atg;au;beaver;bibtex;bmsi;bsh;ccl;cern;ChartDirector;checkers;com;COM;common;contribs;corejava;cryptix;cybervillains;dalvik;danbikel;de;EDU;eg;eu;examples;fat;fit;fitlibrary;fmpp;freemarker;gnu;groovy;groovyjarjarantlr;groovyjarjarasm;hak;hep;ie;imageinfo;info;it;jal;Jama;japa;japacheckers;jas;jasmin;javancss;javanet;javassist;javazoom;java_cup;jcifs;jetty;JFlex;jj2000;jline;jp;JSci;jsr166y;junit;jxl;jxxload_help;kawa;kea;libcore;libsvm;lti;memetic;mt;mx4j;net;netscape;nl;nu;oauth;ognl;opennlp;oracle;org;penn2dg;pennconverter;pl;prefuse;proguard;repackage;scm;se;serp;simple;soot;sqlj;src;ssa;sun;sunlabs;tcl;testdata;testshell;testsuite;twitter4j;uk;ViolinStrings;weka;wet;winstone;woolfel;wowza;;java;javax;
+org.eclipse.jdt.ui.importorder=com.google;android;antenna;antlr;ar;asposewobfuscated;asquare;atg;au;beaver;bibtex;bmsi;bsh;ccl;cern;ChartDirector;checkers;com;COM;common;contribs;corejava;cryptix;cybervillains;dalvik;danbikel;de;EDU;eg;eu;examples;fat;fit;fitlibrary;fmpp;freemarker;gnu;groovy;groovyjarjarantlr;groovyjarjarasm;hak;hep;ie;imageinfo;info;it;jal;Jama;japa;japacheckers;jas;jasmin;javancss;javanet;javassist;javazoom;java_cup;jcifs;jetty;JFlex;jj2000;jline;jp;JSci;jsr166y;junit;jxl;jxxload_help;kawa;kea;libcore;libsvm;lti;memetic;mt;mx4j;net;netscape;nl;nu;oauth;ognl;opennlp;oracle;org;org.jf.dexlib.EncodedValue;penn2dg;pennconverter;pl;prefuse;proguard;repackage;scm;se;serp;simple;soot;sqlj;src;ssa;sun;sunlabs;tcl;testdata;testshell;testsuite;twitter4j;uk;ViolinStrings;weka;wet;winstone;woolfel;wowza;;java;javax;
org.eclipse.jdt.ui.javadoc=true
org.eclipse.jdt.ui.ondemandthreshold=999
org.eclipse.jdt.ui.staticondemandthreshold=999
diff --git a/dexcomparator/jackstyle.xml b/dexcomparator/jackstyle.xml
index 59286c8..76fa6e9 100644
--- a/dexcomparator/jackstyle.xml
+++ b/dexcomparator/jackstyle.xml
@@ -67,7 +67,7 @@
<module name="ImportOrder">
<!-- Checks for out of order import statements. -->
<property name="severity" value="warning"/>
- <property name="groups" value="com.google,*,java,javax"/>
+ <property name="groups" value="com.google,*,org,org.jf.dexlib.EncodedValue,*,java,javax"/>
<!-- This ensures that static imports go first. -->
<property name="option" value="top"/>
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
diff --git a/dexcomparator/src/com/android/jack/DexAnnotationsComparator.java b/dexcomparator/src/com/android/jack/DexAnnotationsComparator.java
index df7b2a7..529db1f 100644
--- a/dexcomparator/src/com/android/jack/DexAnnotationsComparator.java
+++ b/dexcomparator/src/com/android/jack/DexAnnotationsComparator.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack;
import com.android.jack.dx.rop.code.AccessFlags;
@@ -20,6 +36,7 @@
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.TypeListItem;
+
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
diff --git a/dx/.checkstyle b/dx/.checkstyle
new file mode 100644
index 0000000..16b1f09
--- /dev/null
+++ b/dx/.checkstyle
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+ <local-check-config name="Jack Checkstyle" location="jackstyle.xml" type="project" description="">
+ <additional-data name="protect-config-file" value="true"/>
+ </local-check-config>
+ <fileset name="all" enabled="true" check-config-name="Jack Checkstyle" local="true">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/dx/.project b/dx/.project
index b9adec6..08f639b 100644
--- a/dx/.project
+++ b/dx/.project
@@ -10,8 +10,14 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
</natures>
</projectDescription>
diff --git a/dx/.settings/org.eclipse.jdt.core.prefs b/dx/.settings/org.eclipse.jdt.core.prefs
index 8000cd6..942db7e 100644
--- a/dx/.settings/org.eclipse.jdt.core.prefs
+++ b/dx/.settings/org.eclipse.jdt.core.prefs
@@ -9,3 +9,329 @@
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field.count_dependent=1585|-1|1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable.count_dependent=1585|-1|1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method.count_dependent=1585|-1|1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package.count_dependent=1585|-1|1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=1040
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter.count_dependent=1040|-1|1040
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=1585
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type.count_dependent=1585|-1|1585
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation.count_dependent=16|-1|16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant.count_dependent=16|-1|16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression.count_dependent=16|4|80
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression.count_dependent=16|-1|16
+org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments=16
+org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments.count_dependent=16|-1|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_enum_constants.count_dependent=16|5|48
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_field_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_for_statement=16
+org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments=16
+org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments.count_dependent=16|-1|16
+org.eclipse.jdt.core.formatter.alignment_for_local_variable_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields.count_dependent=16|-1|16
+org.eclipse.jdt.core.formatter.alignment_for_new_anonymous_class=20
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration.count_dependent=16|5|80
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation.count_dependent=16|4|48
+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_enum_declaration.count_dependent=16|4|49
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration.count_dependent=16|4|48
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration.count_dependent=16|4|48
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration.count_dependent=16|4|48
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
+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=2
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+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=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.comment_new_line_at_start_of_html_paragraph=true
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.force_if_else_statement_brace=true
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=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_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=do not 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=do not 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=do not 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=do not 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_comment_prefix=do not 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=do not 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_try=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_semicolon_in_try_resources=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=do not 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_try=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_try=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_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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=3
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_comment_inline_tags=false
+org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation=true
+org.eclipse.jdt.core.formatter.wrap_non_simple_member_annotation=true
+org.eclipse.jdt.core.formatter.wrap_non_simple_package_annotation=true
+org.eclipse.jdt.core.formatter.wrap_non_simple_parameter_annotation=false
+org.eclipse.jdt.core.formatter.wrap_non_simple_type_annotation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.formatter.wrap_prefer_two_fragments=false
diff --git a/dx/.settings/org.eclipse.jdt.ui.prefs b/dx/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..238808d
--- /dev/null
+++ b/dx/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+formatter_profile=_Jack Format 100
+formatter_settings_version=13
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=com.google;android;antenna;antlr;ar;asposewobfuscated;asquare;atg;au;beaver;bibtex;bmsi;bsh;ccl;cern;ChartDirector;checkers;com;COM;common;contribs;corejava;cryptix;cybervillains;dalvik;danbikel;de;EDU;eg;eu;examples;fat;fit;fitlibrary;fmpp;freemarker;gnu;groovy;groovyjarjarantlr;groovyjarjarasm;hak;hep;ie;imageinfo;info;it;jal;Jama;japa;japacheckers;jas;jasmin;javancss;javanet;javassist;javazoom;java_cup;jcifs;jetty;JFlex;jj2000;jline;jp;JSci;jsr166y;junit;jxl;jxxload_help;kawa;kea;libcore;libsvm;lti;memetic;mt;mx4j;net;netscape;nl;nu;oauth;ognl;opennlp;oracle;org;penn2dg;pennconverter;pl;prefuse;proguard;repackage;scm;se;serp;simple;soot;sqlj;src;ssa;sun;sunlabs;tcl;testdata;testshell;testsuite;twitter4j;uk;ViolinStrings;weka;wet;winstone;woolfel;wowza;;java;javax;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
diff --git a/dx/jackstyle.xml b/dx/jackstyle.xml
new file mode 100644
index 0000000..59286c8
--- /dev/null
+++ b/dx/jackstyle.xml
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!-- This is a checkstyle configuration file. For descriptions of
+what the following rules do, please see the checkstyle configuration
+page at http://checkstyle.sourceforge.net/config.html -->
+
+<!-- Checks with numbered comments refer to recommendations made
+by Joshua Bloch in his book Effective Java -->
+
+<module name="Checker">
+ <property name="charset" value="UTF-8"/>
+ <module name="FileTabCharacter">
+ <!-- Checks that there are no tab characters in the file.
+ -->
+ </module>
+
+ <module name="RegexpSingleline">
+ <!-- Checks that FIXME is not used in comments. TODO is preferred.
+ -->
+ <property name="format" value="((//.*)|(\*.*))FIXME" />
+ <property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
+ </module>
+
+ <module name="RegexpSingleline">
+ <!-- Checks that TODOs are properly formatted.
+
+ The (?<!TODO\(.{0,100}) makes the regex ignore any secondary TODO's on the line
+ so that things like //TODO(bob): remove this TODO on 1/1/2020 don't trigger a warning
+ because of the second TODO. (The {0,100} is because java doesn't recoginize arbitrary
+ length look backs, but we know each java line should be < 100 chars.)
+ -->
+ <property name="format" value="((//.*)|(\*.*))(?<!TODO\(.{0,100})(TODO[^(])|(TODO\([^)]*$)" />
+ <property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."' />
+ </module>
+
+
+ <!-- All Java AST specific tests live under TreeWalker module. -->
+ <module name="TreeWalker">
+
+ <!--
+
+ IMPORT CHECKS
+
+ -->
+
+ <module name="RedundantImport">
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="AvoidStarImport">
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="UnusedImports">
+ <!-- DPL is a notable violator of this rule. -->
+ <property name="severity" value="error"/>
+ <!-- Imports used only in Javadoc are tolerated. -->
+ <property name="processJavadoc" value="true"/>
+ <message
+ key="import.unused"
+ value="Unused import: {0}." />
+ </module>
+
+ <module name="ImportOrder">
+ <!-- Checks for out of order import statements. -->
+ <property name="severity" value="warning"/>
+ <property name="groups" value="com.google,*,java,javax"/>
+ <!-- This ensures that static imports go first. -->
+ <property name="option" value="top"/>
+ <property name="tokens" value="STATIC_IMPORT, IMPORT"/>
+ </module>
+
+ <!--
+
+ NAMING CHECKS
+
+ -->
+
+ <!-- Item 38 - Adhere to generally accepted naming conventions -->
+
+ <module name="PackageName">
+ <!-- Validates identifiers for package names against the
+ supplied expression. -->
+ <!-- Here the default checkstyle rule restricts package name parts to
+ seven characters, this is not in line with common practice at Google.
+ -->
+ <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="TypeNameCheck">
+ <metadata name="altname" value="TypeName"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="StaticVariableNameCheck">
+ <!-- Validates static, non-final fields against the supplied
+ expression "^[a-z][a-zA-Z0-9]*?$". -->
+ <metadata name="altname" value="StaticVariableName"/>
+ <property name="applyToPublic" value="true"/>
+ <property name="applyToProtected" value="true"/>
+ <property name="applyToPackage" value="true"/>
+ <property name="applyToPrivate" value="true"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*?$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="MemberNameCheck">
+ <!-- Validates non-static members against the supplied expression. -->
+ <metadata name="altname" value="MemberName"/>
+ <property name="applyToPublic" value="true"/>
+ <property name="applyToProtected" value="true"/>
+ <property name="applyToPackage" value="true"/>
+ <property name="applyToPrivate" value="true"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*?$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="MethodNameCheck">
+ <!-- Validates identifiers for method names. -->
+ <metadata name="altname" value="MethodName"/>
+ <property name="format" value="^[a-z][a-zA-Z0-9]*([a-zA-Z0-9]+)*$"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="ParameterName">
+ <!-- Validates identifiers for method parameters against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="LocalFinalVariableName">
+ <!-- Validates identifiers for local final variables against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="LocalVariableName">
+ <!-- Validates identifiers for local variables against the
+ expression "^[a-z][a-zA-Z0-9]*$". -->
+ <property name="severity" value="warning"/>
+ </module>
+
+
+ <!--
+
+ LENGTH and CODING CHECKS
+
+ -->
+
+ <module name="LineLength">
+ <!-- Checks if a line is too long. -->
+ <property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
+ <property name="severity" value="error"/>
+
+ <!--
+ The default ignore pattern exempts the following elements:
+ - import statements
+ - long URLs inside comments
+ -->
+
+ <property name="ignorePattern"
+ value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
+ default="^(package .*;\s*)|(import .*;\s*)|( *\* *https?://.*)|(\s*@[\w\.\$]+::\w+(?:\([^\(]*\)|\(\)\(\))?[,;]?)|(\s+\* \{@(link|see) [^\s][^\}]*\}[\.,;]?)$"/>
+ </module>
+
+ <module name="LeftCurly">
+ <!-- Checks for placement of the left curly brace ('{'). -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <module name="RightCurly">
+ <!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
+ the same line. e.g., the following example is fine:
+ <pre>
+ if {
+ ...
+ } else
+ </pre>
+ -->
+ <!-- This next example is not fine:
+ <pre>
+ if {
+ ...
+ }
+ else
+ </pre>
+ -->
+ <property name="option" value="same"/>
+ <property name="severity" value="warning"/>
+ </module>
+
+ <!-- Checks for braces around if and else blocks -->
+ <module name="NeedBraces">
+ <property name="severity" value="warning"/>
+ <property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
+ </module>
+
+ <module name="UpperEll">
+ <!-- Checks that long constants are defined with an upper ell.-->
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="FallThrough">
+ <!-- Warn about falling through to the next case statement. Similar to
+ javac -Xlint:fallthrough, but the check is suppressed if there is a single-line comment
+ on the last non-blank line preceding the fallen-into case.
+ -->
+ <property name="reliefPattern"
+ value=".*"/>
+ <property name="severity" value="error"/>
+ </module>
+
+
+ <!--
+
+ MODIFIERS CHECKS
+
+ -->
+
+ <module name="ModifierOrder">
+ <!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
+ 8.4.3. The prescribed order is:
+ public, protected, private, abstract, static, final, transient, volatile,
+ synchronized, native, strictfp
+ -->
+ </module>
+
+
+ <!--
+
+ WHITESPACE CHECKS
+
+ -->
+
+ <module name="WhitespaceAround">
+ <!-- Checks that various tokens are surrounded by whitespace.
+ This includes most binary operators and keywords followed
+ by regular or curly braces.
+ -->
+ <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
+ BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
+ EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
+ LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
+ LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
+ MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
+ SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="WhitespaceAfter">
+ <!-- Checks that commas, semicolons and typecasts are followed by
+ whitespace.
+ -->
+ <property name="tokens" value="COMMA, SEMI, TYPECAST"/>
+ </module>
+
+ <module name="NoWhitespaceAfter">
+ <!-- Checks that there is no whitespace after various unary operators.
+ Linebreaks are allowed.
+ -->
+ <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
+ UNARY_PLUS"/>
+ <property name="allowLineBreaks" value="true"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="NoWhitespaceBefore">
+ <!-- Checks that there is no whitespace before various unary operators.
+ Linebreaks are allowed.
+ -->
+ <property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
+ <property name="allowLineBreaks" value="true"/>
+ <property name="severity" value="error"/>
+ </module>
+
+ <module name="ParenPad">
+ <!-- Checks that there is no whitespace before close parens or after
+ open parens.
+ -->
+ <property name="severity" value="warning"/>
+ </module>
+
+ <!--
+
+ MISC CHECKS
+
+ -->
+
+ </module>
+</module>
+
diff --git a/dx/src/com/android/jack/dx/Version.java b/dx/src/com/android/jack/dx/Version.java
index 1152dd8..2158cae 100644
--- a/dx/src/com/android/jack/dx/Version.java
+++ b/dx/src/com/android/jack/dx/Version.java
@@ -20,6 +20,6 @@
* Version number for dx.
*/
public class Version {
- /** {@code non-null;} version string */
- public static final String VERSION = "1.7";
+ /** {@code non-null;} version string */
+ public static final String VERSION = "1.7";
}
diff --git a/dx/src/com/android/jack/dx/dex/DexFormat.java b/dx/src/com/android/jack/dx/dex/DexFormat.java
index bf526bc..19da4f6 100644
--- a/dx/src/com/android/jack/dx/dex/DexFormat.java
+++ b/dx/src/com/android/jack/dx/dex/DexFormat.java
@@ -21,78 +21,78 @@
* files, and helper methods for same.
*/
public final class DexFormat {
- private DexFormat() {}
+ private DexFormat() {}
- /**
- * API level to target in order to produce the most modern file
- * format
- */
- public static final int API_CURRENT = 14;
+ /**
+ * API level to target in order to produce the most modern file
+ * format
+ */
+ public static final int API_CURRENT = 14;
- /** API level to target in order to suppress extended opcode usage */
- public static final int API_NO_EXTENDED_OPCODES = 13;
+ /** API level to target in order to suppress extended opcode usage */
+ public static final int API_NO_EXTENDED_OPCODES = 13;
- /**
- * file name of the primary {@code .dex} file inside an
- * application or library {@code .jar} file
- */
- public static final String DEX_IN_JAR_NAME = "classes.dex";
+ /**
+ * file name of the primary {@code .dex} file inside an
+ * application or library {@code .jar} file
+ */
+ public static final String DEX_IN_JAR_NAME = "classes.dex";
- /** common prefix for all dex file "magic numbers" */
- public static final String MAGIC_PREFIX = "dex\n";
+ /** common prefix for all dex file "magic numbers" */
+ public static final String MAGIC_PREFIX = "dex\n";
- /** common suffix for all dex file "magic numbers" */
- public static final String MAGIC_SUFFIX = "\0";
+ /** common suffix for all dex file "magic numbers" */
+ public static final String MAGIC_SUFFIX = "\0";
- /** dex file version number for the current format variant */
- public static final String VERSION_CURRENT = "036";
+ /** dex file version number for the current format variant */
+ public static final String VERSION_CURRENT = "036";
- /** dex file version number for API level 13 and earlier */
- public static final String VERSION_FOR_API_13 = "035";
+ /** dex file version number for API level 13 and earlier */
+ public static final String VERSION_FOR_API_13 = "035";
- /**
- * value used to indicate endianness of file contents
- */
- public static final int ENDIAN_TAG = 0x12345678;
+ /**
+ * value used to indicate endianness of file contents
+ */
+ public static final int ENDIAN_TAG = 0x12345678;
- /**
- * Returns the API level corresponding to the given magic number,
- * or {@code -1} if the given array is not a well-formed dex file
- * magic number.
- */
- public static int magicToApi(byte[] magic) {
- if (magic.length != 8) {
- return -1;
- }
-
- if ((magic[0] != 'd') || (magic[1] != 'e') || (magic[2] != 'x') || (magic[3] != '\n') ||
- (magic[7] != '\0')) {
- return -1;
- }
-
- String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]);
-
- if (version.equals(VERSION_CURRENT)) {
- return API_CURRENT;
- } else if (version.equals(VERSION_FOR_API_13)) {
- return 13;
- }
-
- return -1;
+ /**
+ * Returns the API level corresponding to the given magic number,
+ * or {@code -1} if the given array is not a well-formed dex file
+ * magic number.
+ */
+ public static int magicToApi(byte[] magic) {
+ if (magic.length != 8) {
+ return -1;
}
- /**
- * Returns the magic number corresponding to the given target API level.
- */
- public static String apiToMagic(int targetApiLevel) {
- String version;
-
- if (targetApiLevel >= API_CURRENT) {
- version = VERSION_CURRENT;
- } else {
- version = VERSION_FOR_API_13;
- }
-
- return MAGIC_PREFIX + version + MAGIC_SUFFIX;
+ if ((magic[0] != 'd') || (magic[1] != 'e') || (magic[2] != 'x') || (magic[3] != '\n')
+ || (magic[7] != '\0')) {
+ return -1;
}
+
+ String version = "" + ((char) magic[4]) + ((char) magic[5]) + ((char) magic[6]);
+
+ if (version.equals(VERSION_CURRENT)) {
+ return API_CURRENT;
+ } else if (version.equals(VERSION_FOR_API_13)) {
+ return 13;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the magic number corresponding to the given target API level.
+ */
+ public static String apiToMagic(int targetApiLevel) {
+ String version;
+
+ if (targetApiLevel >= API_CURRENT) {
+ version = VERSION_CURRENT;
+ } else {
+ version = VERSION_FOR_API_13;
+ }
+
+ return MAGIC_PREFIX + version + MAGIC_SUFFIX;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/DexOptions.java b/dx/src/com/android/jack/dx/dex/DexOptions.java
index 81cf288..2fda5c1 100644
--- a/dx/src/com/android/jack/dx/dex/DexOptions.java
+++ b/dx/src/com/android/jack/dx/dex/DexOptions.java
@@ -20,16 +20,16 @@
* Container for options used to control details of dex file generation.
*/
public class DexOptions {
- /** target API level */
- public int targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
+ /** target API level */
+ public int targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
- /** force generation of jumbo opcodes */
- public boolean forceJumbo = false;
+ /** force generation of jumbo opcodes */
+ public boolean forceJumbo = false;
- /**
- * Gets the dex file magic number corresponding to this instance.
- */
- public String getMagic() {
- return DexFormat.apiToMagic(targetApiLevel);
- }
+ /**
+ * Gets the dex file magic number corresponding to this instance.
+ */
+ public String getMagic() {
+ return DexFormat.apiToMagic(targetApiLevel);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/SizeOf.java b/dx/src/com/android/jack/dx/dex/SizeOf.java
index ae118d0..d9441ab 100644
--- a/dx/src/com/android/jack/dx/dex/SizeOf.java
+++ b/dx/src/com/android/jack/dx/dex/SizeOf.java
@@ -16,95 +16,98 @@
package com.android.jack.dx.dex;
+/**
+ * TODO(jack team)
+ */
public final class SizeOf {
- private SizeOf() {}
+ private SizeOf() {}
- public static final int UBYTE = 1;
- public static final int USHORT = 2;
- public static final int UINT = 4;
+ public static final int UBYTE = 1;
+ public static final int USHORT = 2;
+ public static final int UINT = 4;
- public static final int SIGNATURE = UBYTE * 20;
+ public static final int SIGNATURE = UBYTE * 20;
- /**
- * magic ubyte[8]
- * checksum uint
- * signature ubyte[20]
- * file_size uint
- * header_size uint
- * endian_tag uint
- * link_size uint
- * link_off uint
- * map_off uint
- * string_ids_size uint
- * string_ids_off uint
- * type_ids_size uint
- * type_ids_off uint
- * proto_ids_size uint
- * proto_ids_off uint
- * field_ids_size uint
- * field_ids_off uint
- * method_ids_size uint
- * method_ids_off uint
- * class_defs_size uint
- * class_defs_off uint
- * data_size uint
- * data_off uint
- */
- public static final int HEADER_ITEM = (8 * UBYTE) + UINT + SIGNATURE + (20 * UINT); // 0x70
+ /**
+ * magic ubyte[8]
+ * checksum uint
+ * signature ubyte[20]
+ * file_size uint
+ * header_size uint
+ * endian_tag uint
+ * link_size uint
+ * link_off uint
+ * map_off uint
+ * string_ids_size uint
+ * string_ids_off uint
+ * type_ids_size uint
+ * type_ids_off uint
+ * proto_ids_size uint
+ * proto_ids_off uint
+ * field_ids_size uint
+ * field_ids_off uint
+ * method_ids_size uint
+ * method_ids_off uint
+ * class_defs_size uint
+ * class_defs_off uint
+ * data_size uint
+ * data_off uint
+ */
+ public static final int HEADER_ITEM = (8 * UBYTE) + UINT + SIGNATURE + (20 * UINT); // 0x70
- /**
- * string_data_off uint
- */
- public static final int STRING_ID_ITEM = UINT;
+ /**
+ * string_data_off uint
+ */
+ public static final int STRING_ID_ITEM = UINT;
- /**
- * descriptor_idx uint
- */
- public static final int TYPE_ID_ITEM = UINT;
+ /**
+ * descriptor_idx uint
+ */
+ public static final int TYPE_ID_ITEM = UINT;
- /**
- * type_idx ushort
- */
- public static final int TYPE_ITEM = USHORT;
+ /**
+ * type_idx ushort
+ */
+ public static final int TYPE_ITEM = USHORT;
- /**
- * shorty_idx uint
- * return_type_idx uint
- * return_type_idx uint
- */
- public static final int PROTO_ID_ITEM = UINT + UINT + UINT;
+ /**
+ * shorty_idx uint
+ * return_type_idx uint
+ * return_type_idx uint
+ */
+ public static final int PROTO_ID_ITEM = UINT + UINT + UINT;
- /**
- * class_idx ushort
- * type_idx/proto_idx ushort
- * name_idx uint
- */
- public static final int MEMBER_ID_ITEM = USHORT + USHORT + UINT;
+ /**
+ * class_idx ushort
+ * type_idx/proto_idx ushort
+ * name_idx uint
+ */
+ public static final int MEMBER_ID_ITEM = USHORT + USHORT + UINT;
- /**
- * class_idx uint
- * access_flags uint
- * superclass_idx uint
- * interfaces_off uint
- * source_file_idx uint
- * annotations_off uint
- * class_data_off uint
- * static_values_off uint
- */
- public static final int CLASS_DEF_ITEM = 8 * UINT;
+ /**
+ * class_idx uint
+ * access_flags uint
+ * superclass_idx uint
+ * interfaces_off uint
+ * source_file_idx uint
+ * annotations_off uint
+ * class_data_off uint
+ * static_values_off uint
+ */
+ public static final int CLASS_DEF_ITEM = 8 * UINT;
- /**
- * type ushort
- * unused ushort
- * size uint
- * offset uint
- */
- public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT;
+ /**
+ * type ushort
+ * unused ushort
+ * size uint
+ * offset uint
+ */
+ public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT;
- /**
- * start_addr uint
- * insn_count ushort
- * handler_off ushort
- */
- public static final int TRY_ITEM = UINT + USHORT + USHORT;
+ /**
+ * start_addr uint
+ * insn_count ushort
+ * handler_off ushort
+ */
+ public static final int TRY_ITEM = UINT + USHORT + USHORT;
}
diff --git a/dx/src/com/android/jack/dx/dex/TableOfContents.java b/dx/src/com/android/jack/dx/dex/TableOfContents.java
index 11b7bfe..40f6e98 100644
--- a/dx/src/com/android/jack/dx/dex/TableOfContents.java
+++ b/dx/src/com/android/jack/dx/dex/TableOfContents.java
@@ -28,212 +28,230 @@
*/
public final class TableOfContents {
- /*
- * TODO: factor out ID constants.
- */
+ /*
+ * TODO(dx team): factor out ID constants.
+ */
- public final Section header = new Section(0x0000);
- public final Section stringIds = new Section(0x0001);
- public final Section typeIds = new Section(0x0002);
- public final Section protoIds = new Section(0x0003);
- public final Section fieldIds = new Section(0x0004);
- public final Section methodIds = new Section(0x0005);
- public final Section classDefs = new Section(0x0006);
- public final Section mapList = new Section(0x1000);
- public final Section typeLists = new Section(0x1001);
- public final Section annotationSetRefLists = new Section(0x1002);
- public final Section annotationSets = new Section(0x1003);
- public final Section classDatas = new Section(0x2000);
- public final Section codes = new Section(0x2001);
- public final Section stringDatas = new Section(0x2002);
- public final Section debugInfos = new Section(0x2003);
- public final Section annotations = new Section(0x2004);
- public final Section encodedArrays = new Section(0x2005);
- public final Section annotationsDirectories = new Section(0x2006);
- public final Section[] sections = {
- header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList,
- typeLists, annotationSetRefLists, annotationSets, classDatas, codes, stringDatas,
- debugInfos, annotations, encodedArrays, annotationsDirectories
- };
+ public final Section header = new Section(0x0000);
+ public final Section stringIds = new Section(0x0001);
+ public final Section typeIds = new Section(0x0002);
+ public final Section protoIds = new Section(0x0003);
+ public final Section fieldIds = new Section(0x0004);
+ public final Section methodIds = new Section(0x0005);
+ public final Section classDefs = new Section(0x0006);
+ public final Section mapList = new Section(0x1000);
+ public final Section typeLists = new Section(0x1001);
+ public final Section annotationSetRefLists = new Section(0x1002);
+ public final Section annotationSets = new Section(0x1003);
+ public final Section classDatas = new Section(0x2000);
+ public final Section codes = new Section(0x2001);
+ public final Section stringDatas = new Section(0x2002);
+ public final Section debugInfos = new Section(0x2003);
+ public final Section annotations = new Section(0x2004);
+ public final Section encodedArrays = new Section(0x2005);
+ public final Section annotationsDirectories = new Section(0x2006);
+ public final Section[] sections = {header,
+ stringIds,
+ typeIds,
+ protoIds,
+ fieldIds,
+ methodIds,
+ classDefs,
+ mapList,
+ typeLists,
+ annotationSetRefLists,
+ annotationSets,
+ classDatas,
+ codes,
+ stringDatas,
+ debugInfos,
+ annotations,
+ encodedArrays,
+ annotationsDirectories};
- public int checksum;
- public byte[] signature;
- public int fileSize;
- public int linkSize;
- public int linkOff;
- public int dataSize;
- public int dataOff;
+ public int checksum;
+ public byte[] signature;
+ public int fileSize;
+ public int linkSize;
+ public int linkOff;
+ public int dataSize;
+ public int dataOff;
- public TableOfContents() {
- signature = new byte[20];
+ public TableOfContents() {
+ signature = new byte[20];
+ }
+
+ public void readFrom(DexBuffer buffer) throws IOException {
+ readHeader(buffer.open(0));
+ readMap(buffer.open(mapList.off));
+ computeSizesFromOffsets();
+ }
+
+ private void readHeader(DexBuffer.Section headerIn) throws UnsupportedEncodingException {
+ byte[] magic = headerIn.readByteArray(8);
+ int apiTarget = DexFormat.magicToApi(magic);
+
+ if (apiTarget != DexFormat.API_NO_EXTENDED_OPCODES) {
+ throw new DexException("Unexpected magic: " + Arrays.toString(magic));
}
- public void readFrom(DexBuffer buffer) throws IOException {
- readHeader(buffer.open(0));
- readMap(buffer.open(mapList.off));
- computeSizesFromOffsets();
+ checksum = headerIn.readInt();
+ signature = headerIn.readByteArray(20);
+ fileSize = headerIn.readInt();
+ int headerSize = headerIn.readInt();
+ if (headerSize != SizeOf.HEADER_ITEM) {
+ throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
+ }
+ int endianTag = headerIn.readInt();
+ if (endianTag != DexFormat.ENDIAN_TAG) {
+ throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
+ }
+ linkSize = headerIn.readInt();
+ linkOff = headerIn.readInt();
+ mapList.off = headerIn.readInt();
+ if (mapList.off == 0) {
+ throw new DexException("Cannot merge dex files that do not contain a map");
+ }
+ stringIds.size = headerIn.readInt();
+ stringIds.off = headerIn.readInt();
+ typeIds.size = headerIn.readInt();
+ typeIds.off = headerIn.readInt();
+ protoIds.size = headerIn.readInt();
+ protoIds.off = headerIn.readInt();
+ fieldIds.size = headerIn.readInt();
+ fieldIds.off = headerIn.readInt();
+ methodIds.size = headerIn.readInt();
+ methodIds.off = headerIn.readInt();
+ classDefs.size = headerIn.readInt();
+ classDefs.off = headerIn.readInt();
+ dataSize = headerIn.readInt();
+ dataOff = headerIn.readInt();
+ }
+
+ private void readMap(DexBuffer.Section in) throws IOException {
+ int mapSize = in.readInt();
+ Section previous = null;
+ for (int i = 0; i < mapSize; i++) {
+ short type = in.readShort();
+ in.readShort(); // unused
+ Section section = getSection(type);
+ int size = in.readInt();
+ int offset = in.readInt();
+
+ if ((section.size != 0 && section.size != size)
+ || (section.off != -1 && section.off != offset)) {
+ throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type));
+ }
+
+ section.size = size;
+ section.off = offset;
+
+ if (previous != null && previous.off > section.off) {
+ throw new DexException("Map is unsorted at " + previous + ", " + section);
+ }
+
+ previous = section;
+ }
+ Arrays.sort(sections);
+ }
+
+ public void computeSizesFromOffsets() {
+ int end = dataOff + dataSize;
+ for (int i = sections.length - 1; i >= 0; i--) {
+ Section section = sections[i];
+ if (section.off == -1) {
+ continue;
+ }
+ if (section.off > end) {
+ throw new DexException("Map is unsorted at " + section);
+ }
+ section.byteCount = end - section.off;
+ end = section.off;
+ }
+ }
+
+ private Section getSection(short type) {
+ for (Section section : sections) {
+ if (section.type == type) {
+ return section;
+ }
+ }
+ throw new IllegalArgumentException("No such map item: " + type);
+ }
+
+ public void writeHeader(DexBuffer.Section out) throws IOException {
+ out.write(DexFormat.apiToMagic(DexFormat.API_NO_EXTENDED_OPCODES).getBytes("UTF-8"));
+ out.writeInt(checksum);
+ out.write(signature);
+ out.writeInt(fileSize);
+ out.writeInt(SizeOf.HEADER_ITEM);
+ out.writeInt(DexFormat.ENDIAN_TAG);
+ out.writeInt(linkSize);
+ out.writeInt(linkOff);
+ out.writeInt(mapList.off);
+ out.writeInt(stringIds.size);
+ out.writeInt(stringIds.off);
+ out.writeInt(typeIds.size);
+ out.writeInt(typeIds.off);
+ out.writeInt(protoIds.size);
+ out.writeInt(protoIds.off);
+ out.writeInt(fieldIds.size);
+ out.writeInt(fieldIds.off);
+ out.writeInt(methodIds.size);
+ out.writeInt(methodIds.off);
+ out.writeInt(classDefs.size);
+ out.writeInt(classDefs.off);
+ out.writeInt(dataSize);
+ out.writeInt(dataOff);
+ }
+
+ public void writeMap(DexBuffer.Section out) throws IOException {
+ int count = 0;
+ for (Section section : sections) {
+ if (section.exists()) {
+ count++;
+ }
}
- private void readHeader(DexBuffer.Section headerIn) throws UnsupportedEncodingException {
- byte[] magic = headerIn.readByteArray(8);
- int apiTarget = DexFormat.magicToApi(magic);
+ out.writeInt(count);
+ for (Section section : sections) {
+ if (section.exists()) {
+ out.writeShort(section.type);
+ out.writeShort((short) 0);
+ out.writeInt(section.size);
+ out.writeInt(section.off);
+ }
+ }
+ }
- if (apiTarget != DexFormat.API_NO_EXTENDED_OPCODES) {
- throw new DexException("Unexpected magic: " + Arrays.toString(magic));
- }
+ /**
+ * TODO(jack team)
+ */
+ public static class Section implements Comparable<Section> {
+ public final short type;
+ public int size = 0;
+ public int off = -1;
+ public int byteCount = 0;
- checksum = headerIn.readInt();
- signature = headerIn.readByteArray(20);
- fileSize = headerIn.readInt();
- int headerSize = headerIn.readInt();
- if (headerSize != SizeOf.HEADER_ITEM) {
- throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
- }
- int endianTag = headerIn.readInt();
- if (endianTag != DexFormat.ENDIAN_TAG) {
- throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
- }
- linkSize = headerIn.readInt();
- linkOff = headerIn.readInt();
- mapList.off = headerIn.readInt();
- if (mapList.off == 0) {
- throw new DexException("Cannot merge dex files that do not contain a map");
- }
- stringIds.size = headerIn.readInt();
- stringIds.off = headerIn.readInt();
- typeIds.size = headerIn.readInt();
- typeIds.off = headerIn.readInt();
- protoIds.size = headerIn.readInt();
- protoIds.off = headerIn.readInt();
- fieldIds.size = headerIn.readInt();
- fieldIds.off = headerIn.readInt();
- methodIds.size = headerIn.readInt();
- methodIds.off = headerIn.readInt();
- classDefs.size = headerIn.readInt();
- classDefs.off = headerIn.readInt();
- dataSize = headerIn.readInt();
- dataOff = headerIn.readInt();
+ public Section(int type) {
+ this.type = (short) type;
}
- private void readMap(DexBuffer.Section in) throws IOException {
- int mapSize = in.readInt();
- Section previous = null;
- for (int i = 0; i < mapSize; i++) {
- short type = in.readShort();
- in.readShort(); // unused
- Section section = getSection(type);
- int size = in.readInt();
- int offset = in.readInt();
-
- if ((section.size != 0 && section.size != size)
- || (section.off != -1 && section.off != offset)) {
- throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type));
- }
-
- section.size = size;
- section.off = offset;
-
- if (previous != null && previous.off > section.off) {
- throw new DexException("Map is unsorted at " + previous + ", " + section);
- }
-
- previous = section;
- }
- Arrays.sort(sections);
+ public boolean exists() {
+ return size > 0;
}
- public void computeSizesFromOffsets() {
- int end = dataOff + dataSize;
- for (int i = sections.length - 1; i >= 0; i--) {
- Section section = sections[i];
- if (section.off == -1) {
- continue;
- }
- if (section.off > end) {
- throw new DexException("Map is unsorted at " + section);
- }
- section.byteCount = end - section.off;
- end = section.off;
- }
+ @Override
+ public int compareTo(Section section) {
+ if (off != section.off) {
+ return off < section.off ? -1 : 1;
+ }
+ return 0;
}
- private Section getSection(short type) {
- for (Section section : sections) {
- if (section.type == type) {
- return section;
- }
- }
- throw new IllegalArgumentException("No such map item: " + type);
+ @Override
+ public String toString() {
+ return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size);
}
-
- public void writeHeader(DexBuffer.Section out) throws IOException {
- out.write(DexFormat.apiToMagic(DexFormat.API_NO_EXTENDED_OPCODES).getBytes("UTF-8"));
- out.writeInt(checksum);
- out.write(signature);
- out.writeInt(fileSize);
- out.writeInt(SizeOf.HEADER_ITEM);
- out.writeInt(DexFormat.ENDIAN_TAG);
- out.writeInt(linkSize);
- out.writeInt(linkOff);
- out.writeInt(mapList.off);
- out.writeInt(stringIds.size);
- out.writeInt(stringIds.off);
- out.writeInt(typeIds.size);
- out.writeInt(typeIds.off);
- out.writeInt(protoIds.size);
- out.writeInt(protoIds.off);
- out.writeInt(fieldIds.size);
- out.writeInt(fieldIds.off);
- out.writeInt(methodIds.size);
- out.writeInt(methodIds.off);
- out.writeInt(classDefs.size);
- out.writeInt(classDefs.off);
- out.writeInt(dataSize);
- out.writeInt(dataOff);
- }
-
- public void writeMap(DexBuffer.Section out) throws IOException {
- int count = 0;
- for (Section section : sections) {
- if (section.exists()) {
- count++;
- }
- }
-
- out.writeInt(count);
- for (Section section : sections) {
- if (section.exists()) {
- out.writeShort(section.type);
- out.writeShort((short) 0);
- out.writeInt(section.size);
- out.writeInt(section.off);
- }
- }
- }
-
- public static class Section implements Comparable<Section> {
- public final short type;
- public int size = 0;
- public int off = -1;
- public int byteCount = 0;
-
- public Section(int type) {
- this.type = (short) type;
- }
-
- public boolean exists() {
- return size > 0;
- }
-
- public int compareTo(Section section) {
- if (off != section.off) {
- return off < section.off ? -1 : 1;
- }
- return 0;
- }
-
- @Override public String toString() {
- return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/ArrayData.java b/dx/src/com/android/jack/dx/dex/code/ArrayData.java
index f8b7684..81f7ac0 100644
--- a/dx/src/com/android/jack/dx/dex/code/ArrayData.java
+++ b/dx/src/com/android/jack/dx/dex/code/ArrayData.java
@@ -19,8 +19,10 @@
import com.android.jack.dx.io.Opcodes;
import com.android.jack.dx.rop.code.RegisterSpecList;
import com.android.jack.dx.rop.code.SourcePosition;
-import com.android.jack.dx.rop.cst.*;
-import com.android.jack.dx.rop.type.Type;
+import com.android.jack.dx.rop.cst.Constant;
+import com.android.jack.dx.rop.cst.CstLiteral32;
+import com.android.jack.dx.rop.cst.CstLiteral64;
+import com.android.jack.dx.rop.cst.CstType;
import com.android.jack.dx.util.AnnotatedOutput;
import com.android.jack.dx.util.Hex;
@@ -30,171 +32,166 @@
* Pseudo-instruction which holds fill array data.
*/
public final class ArrayData extends VariableSizeInsn {
- /**
- * {@code non-null;} address representing the instruction that uses this
- * instance
- */
- private final CodeAddress user;
+ /**
+ * {@code non-null;} address representing the instruction that uses this
+ * instance
+ */
+ private final CodeAddress user;
- /** {@code non-null;} initial values to be filled into an array */
- private final ArrayList<Constant> values;
+ /** {@code non-null;} initial values to be filled into an array */
+ private final ArrayList<Constant> values;
- /** non-null: type of constant that initializes the array */
- private final Constant arrayType;
+ /** non-null: type of constant that initializes the array */
+ private final Constant arrayType;
- /** Width of the init value element */
- private final int elemWidth;
+ /** Width of the init value element */
+ private final int elemWidth;
- /** Length of the init list */
- private final int initLength;
+ /** Length of the init list */
+ private final int initLength;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param user {@code non-null;} address representing the instruction that
- * uses this instance
- * @param values {@code non-null;} initial values to be filled into an array
- */
- public ArrayData(SourcePosition position, CodeAddress user,
- ArrayList<Constant> values,
- Constant arrayType) {
- super(position, RegisterSpecList.EMPTY);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param user {@code non-null;} address representing the instruction that
+ * uses this instance
+ * @param values {@code non-null;} initial values to be filled into an array
+ */
+ public ArrayData(SourcePosition position, CodeAddress user, ArrayList<Constant> values,
+ Constant arrayType) {
+ super(position, RegisterSpecList.EMPTY);
- if (user == null) {
- throw new NullPointerException("user == null");
- }
-
- if (values == null) {
- throw new NullPointerException("values == null");
- }
-
- int sz = values.size();
-
- if (sz <= 0) {
- throw new IllegalArgumentException("Illegal number of init values");
- }
-
- this.arrayType = arrayType;
-
- if (arrayType == CstType.BYTE_ARRAY ||
- arrayType == CstType.BOOLEAN_ARRAY) {
- elemWidth = 1;
- } else if (arrayType == CstType.SHORT_ARRAY ||
- arrayType == CstType.CHAR_ARRAY) {
- elemWidth = 2;
- } else if (arrayType == CstType.INT_ARRAY ||
- arrayType == CstType.FLOAT_ARRAY) {
- elemWidth = 4;
- } else if (arrayType == CstType.LONG_ARRAY ||
- arrayType == CstType.DOUBLE_ARRAY) {
- elemWidth = 8;
- } else {
- throw new IllegalArgumentException("Unexpected constant type");
- }
- this.user = user;
- this.values = values;
- initLength = values.size();
+ if (user == null) {
+ throw new NullPointerException("user == null");
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- int sz = initLength;
- // Note: the unit here is 16-bit
- return 4 + ((sz * elemWidth) + 1) / 2;
+ if (values == null) {
+ throw new NullPointerException("values == null");
}
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out) {
- int sz = values.size();
+ int sz = values.size();
- out.writeShort(Opcodes.FILL_ARRAY_DATA_PAYLOAD);
- out.writeShort(elemWidth);
- out.writeInt(initLength);
-
-
- // For speed reasons, replicate the for loop in each case
- switch (elemWidth) {
- case 1: {
- for (int i = 0; i < sz; i++) {
- Constant cst = values.get(i);
- out.writeByte((byte) ((CstLiteral32) cst).getIntBits());
- }
- break;
- }
- case 2: {
- for (int i = 0; i < sz; i++) {
- Constant cst = values.get(i);
- out.writeShort((short) ((CstLiteral32) cst).getIntBits());
- }
- break;
- }
- case 4: {
- for (int i = 0; i < sz; i++) {
- Constant cst = values.get(i);
- out.writeInt(((CstLiteral32) cst).getIntBits());
- }
- break;
- }
- case 8: {
- for (int i = 0; i < sz; i++) {
- Constant cst = values.get(i);
- out.writeLong(((CstLiteral64) cst).getLongBits());
- }
- break;
- }
- default:
- break;
- }
-
- // Pad one byte to make the size of data table multiples of 16-bits
- if (elemWidth == 1 && (sz % 2 != 0)) {
- out.writeByte(0x00);
- }
+ if (sz <= 0) {
+ throw new IllegalArgumentException("Illegal number of init values");
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new ArrayData(getPosition(), user, values, arrayType);
+ this.arrayType = arrayType;
+
+ if (arrayType == CstType.BYTE_ARRAY || arrayType == CstType.BOOLEAN_ARRAY) {
+ elemWidth = 1;
+ } else if (arrayType == CstType.SHORT_ARRAY || arrayType == CstType.CHAR_ARRAY) {
+ elemWidth = 2;
+ } else if (arrayType == CstType.INT_ARRAY || arrayType == CstType.FLOAT_ARRAY) {
+ elemWidth = 4;
+ } else if (arrayType == CstType.LONG_ARRAY || arrayType == CstType.DOUBLE_ARRAY) {
+ elemWidth = 8;
+ } else {
+ throw new IllegalArgumentException("Unexpected constant type");
}
+ this.user = user;
+ this.values = values;
+ initLength = values.size();
+ }
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- StringBuffer sb = new StringBuffer(100);
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ int sz = initLength;
+ // Note: the unit here is 16-bit
+ return 4 + ((sz * elemWidth) + 1) / 2;
+ }
- int sz = values.size();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out) {
+ int sz = values.size();
+
+ out.writeShort(Opcodes.FILL_ARRAY_DATA_PAYLOAD);
+ out.writeShort(elemWidth);
+ out.writeInt(initLength);
+
+
+ // For speed reasons, replicate the for loop in each case
+ switch (elemWidth) {
+ case 1: {
for (int i = 0; i < sz; i++) {
- sb.append("\n ");
- sb.append(i);
- sb.append(": ");
- sb.append(values.get(i).toHuman());
+ Constant cst = values.get(i);
+ out.writeByte((byte) ((CstLiteral32) cst).getIntBits());
}
-
- return sb.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- int baseAddress = user.getAddress();
- StringBuffer sb = new StringBuffer(100);
- int sz = values.size();
-
- sb.append("fill-array-data-payload // for fill-array-data @ ");
- sb.append(Hex.u2(baseAddress));
-
+ break;
+ }
+ case 2: {
for (int i = 0; i < sz; i++) {
- sb.append("\n ");
- sb.append(i);
- sb.append(": ");
- sb.append(values.get(i).toHuman());
+ Constant cst = values.get(i);
+ out.writeShort((short) ((CstLiteral32) cst).getIntBits());
}
-
- return sb.toString();
+ break;
+ }
+ case 4: {
+ for (int i = 0; i < sz; i++) {
+ Constant cst = values.get(i);
+ out.writeInt(((CstLiteral32) cst).getIntBits());
+ }
+ break;
+ }
+ case 8: {
+ for (int i = 0; i < sz; i++) {
+ Constant cst = values.get(i);
+ out.writeLong(((CstLiteral64) cst).getLongBits());
+ }
+ break;
+ }
+ default:
+ break;
}
+
+ // Pad one byte to make the size of data table multiples of 16-bits
+ if (elemWidth == 1 && (sz % 2 != 0)) {
+ out.writeByte(0x00);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new ArrayData(getPosition(), user, values, arrayType);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ int sz = values.size();
+ for (int i = 0; i < sz; i++) {
+ sb.append("\n ");
+ sb.append(i);
+ sb.append(": ");
+ sb.append(values.get(i).toHuman());
+ }
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ int baseAddress = user.getAddress();
+ StringBuffer sb = new StringBuffer(100);
+ int sz = values.size();
+
+ sb.append("fill-array-data-payload // for fill-array-data @ ");
+ sb.append(Hex.u2(baseAddress));
+
+ for (int i = 0; i < sz; i++) {
+ sb.append("\n ");
+ sb.append(i);
+ sb.append(": ");
+ sb.append(values.get(i).toHuman());
+ }
+
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/BlockAddresses.java b/dx/src/com/android/jack/dx/dex/code/BlockAddresses.java
index 4ec10f8..693c342 100644
--- a/dx/src/com/android/jack/dx/dex/code/BlockAddresses.java
+++ b/dx/src/com/android/jack/dx/dex/code/BlockAddresses.java
@@ -28,116 +28,116 @@
* start address, end address, and last instruction address.
*/
public final class BlockAddresses {
- /** {@code non-null;} array containing addresses for the start of each basic
- * block (indexed by basic block label) */
- private final CodeAddress[] starts;
+ /** {@code non-null;} array containing addresses for the start of each basic
+ * block (indexed by basic block label) */
+ private final CodeAddress[] starts;
- /** {@code non-null;} array containing addresses for the final instruction
- * of each basic block (indexed by basic block label) */
- private final CodeAddress[] lasts;
+ /** {@code non-null;} array containing addresses for the final instruction
+ * of each basic block (indexed by basic block label) */
+ private final CodeAddress[] lasts;
- /** {@code non-null;} array containing addresses for the end (just past the
- * final instruction) of each basic block (indexed by basic block
- * label) */
- private final CodeAddress[] ends;
+ /** {@code non-null;} array containing addresses for the end (just past the
+ * final instruction) of each basic block (indexed by basic block
+ * label) */
+ private final CodeAddress[] ends;
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the method to have block addresses for
- */
- public BlockAddresses(RopMethod method) {
- BasicBlockList blocks = method.getBlocks();
- int maxLabel = blocks.getMaxLabel();
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the method to have block addresses for
+ */
+ public BlockAddresses(RopMethod method) {
+ BasicBlockList blocks = method.getBlocks();
+ int maxLabel = blocks.getMaxLabel();
- this.starts = new CodeAddress[maxLabel];
- this.lasts = new CodeAddress[maxLabel];
- this.ends = new CodeAddress[maxLabel];
+ this.starts = new CodeAddress[maxLabel];
+ this.lasts = new CodeAddress[maxLabel];
+ this.ends = new CodeAddress[maxLabel];
- setupArrays(method);
+ setupArrays(method);
+ }
+
+ /**
+ * Gets the instance for the start of the given block.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getStart(BasicBlock block) {
+ return starts[block.getLabel()];
+ }
+
+ /**
+ * Gets the instance for the start of the block with the given label.
+ *
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getStart(int label) {
+ return starts[label];
+ }
+
+ /**
+ * Gets the instance for the final instruction of the given block.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getLast(BasicBlock block) {
+ return lasts[block.getLabel()];
+ }
+
+ /**
+ * Gets the instance for the final instruction of the block with
+ * the given label.
+ *
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getLast(int label) {
+ return lasts[label];
+ }
+
+ /**
+ * Gets the instance for the end (address after the final instruction)
+ * of the given block.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getEnd(BasicBlock block) {
+ return ends[block.getLabel()];
+ }
+
+ /**
+ * Gets the instance for the end (address after the final instruction)
+ * of the block with the given label.
+ *
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
+ */
+ public CodeAddress getEnd(int label) {
+ return ends[label];
+ }
+
+ /**
+ * Sets up the address arrays.
+ */
+ private void setupArrays(RopMethod method) {
+ BasicBlockList blocks = method.getBlocks();
+ int sz = blocks.size();
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = blocks.get(i);
+ int label = one.getLabel();
+ Insn insn = one.getInsns().get(0);
+
+ starts[label] = new CodeAddress(insn.getPosition());
+
+ SourcePosition pos = one.getLastInsn().getPosition();
+
+ lasts[label] = new CodeAddress(pos);
+ ends[label] = new CodeAddress(pos);
}
-
- /**
- * Gets the instance for the start of the given block.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getStart(BasicBlock block) {
- return starts[block.getLabel()];
- }
-
- /**
- * Gets the instance for the start of the block with the given label.
- *
- * @param label {@code non-null;} the label of the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getStart(int label) {
- return starts[label];
- }
-
- /**
- * Gets the instance for the final instruction of the given block.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getLast(BasicBlock block) {
- return lasts[block.getLabel()];
- }
-
- /**
- * Gets the instance for the final instruction of the block with
- * the given label.
- *
- * @param label {@code non-null;} the label of the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getLast(int label) {
- return lasts[label];
- }
-
- /**
- * Gets the instance for the end (address after the final instruction)
- * of the given block.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getEnd(BasicBlock block) {
- return ends[block.getLabel()];
- }
-
- /**
- * Gets the instance for the end (address after the final instruction)
- * of the block with the given label.
- *
- * @param label {@code non-null;} the label of the block in question
- * @return {@code non-null;} the appropriate instance
- */
- public CodeAddress getEnd(int label) {
- return ends[label];
- }
-
- /**
- * Sets up the address arrays.
- */
- private void setupArrays(RopMethod method) {
- BasicBlockList blocks = method.getBlocks();
- int sz = blocks.size();
-
- for (int i = 0; i < sz; i++) {
- BasicBlock one = blocks.get(i);
- int label = one.getLabel();
- Insn insn = one.getInsns().get(0);
-
- starts[label] = new CodeAddress(insn.getPosition());
-
- SourcePosition pos = one.getLastInsn().getPosition();
-
- lasts[label] = new CodeAddress(pos);
- ends[label] = new CodeAddress(pos);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/CatchBuilder.java b/dx/src/com/android/jack/dx/dex/code/CatchBuilder.java
index 9b19792..978fe70 100644
--- a/dx/src/com/android/jack/dx/dex/code/CatchBuilder.java
+++ b/dx/src/com/android/jack/dx/dex/code/CatchBuilder.java
@@ -24,25 +24,25 @@
* Interface for the construction of {@link CatchTable} instances.
*/
public interface CatchBuilder {
- /**
- * Builds and returns the catch table for this instance.
- *
- * @return {@code non-null;} the constructed table
- */
- public CatchTable build();
+ /**
+ * Builds and returns the catch table for this instance.
+ *
+ * @return {@code non-null;} the constructed table
+ */
+ public CatchTable build();
- /**
- * Gets whether this instance has any catches at all (either typed
- * or catch-all).
- *
- * @return whether this instance has any catches at all
- */
- public boolean hasAnyCatches();
+ /**
+ * Gets whether this instance has any catches at all (either typed
+ * or catch-all).
+ *
+ * @return whether this instance has any catches at all
+ */
+ public boolean hasAnyCatches();
- /**
- * Gets the set of catch types associated with this instance.
- *
- * @return {@code non-null;} the set of catch types
- */
- public HashSet<Type> getCatchTypes();
+ /**
+ * Gets the set of catch types associated with this instance.
+ *
+ * @return {@code non-null;} the set of catch types
+ */
+ public HashSet<Type> getCatchTypes();
}
diff --git a/dx/src/com/android/jack/dx/dex/code/CatchHandlerList.java b/dx/src/com/android/jack/dx/dex/code/CatchHandlerList.java
index 1f5ae6d..cfec0ab 100644
--- a/dx/src/com/android/jack/dx/dex/code/CatchHandlerList.java
+++ b/dx/src/com/android/jack/dx/dex/code/CatchHandlerList.java
@@ -23,216 +23,218 @@
/**
* Ordered list of (exception type, handler address) entries.
*/
-public final class CatchHandlerList extends FixedSizeList
- implements Comparable<CatchHandlerList> {
- /** {@code non-null;} empty instance */
- public static final CatchHandlerList EMPTY = new CatchHandlerList(0);
+public final class CatchHandlerList extends FixedSizeList implements Comparable<CatchHandlerList> {
+ /** {@code non-null;} empty instance */
+ public static final CatchHandlerList EMPTY = new CatchHandlerList(0);
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size {@code >= 0;} the size of the list
- */
- public CatchHandlerList(int size) {
- super(size);
- }
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size {@code >= 0;} the size of the list
+ */
+ public CatchHandlerList(int size) {
+ super(size);
+ }
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public Entry get(int n) {
- return (Entry) get0(n);
- }
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Entry get(int n) {
+ return (Entry) get0(n);
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return toHuman("", "");
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return toHuman("", "");
+ }
- /**
- * Get the human form of this instance, prefixed on each line
- * with the string.
- *
- * @param prefix {@code non-null;} the prefix for every line
- * @param header {@code non-null;} the header for the first line (after the
- * first prefix)
- * @return {@code non-null;} the human form
- */
- public String toHuman(String prefix, String header) {
- StringBuilder sb = new StringBuilder(100);
- int size = size();
+ /**
+ * Get the human form of this instance, prefixed on each line
+ * with the string.
+ *
+ * @param prefix {@code non-null;} the prefix for every line
+ * @param header {@code non-null;} the header for the first line (after the
+ * first prefix)
+ * @return {@code non-null;} the human form
+ */
+ public String toHuman(String prefix, String header) {
+ StringBuilder sb = new StringBuilder(100);
+ int size = size();
+ sb.append(prefix);
+ sb.append(header);
+ sb.append("catch ");
+
+ for (int i = 0; i < size; i++) {
+ Entry entry = get(i);
+
+ if (i != 0) {
+ sb.append(",\n");
sb.append(prefix);
- sb.append(header);
- sb.append("catch ");
+ sb.append(" ");
+ }
- for (int i = 0; i < size; i++) {
- Entry entry = get(i);
+ if ((i == (size - 1)) && catchesAll()) {
+ sb.append("<any>");
+ } else {
+ sb.append(entry.getExceptionType().toHuman());
+ }
- if (i != 0) {
- sb.append(",\n");
- sb.append(prefix);
- sb.append(" ");
- }
-
- if ((i == (size - 1)) && catchesAll()) {
- sb.append("<any>");
- } else {
- sb.append(entry.getExceptionType().toHuman());
- }
-
- sb.append(" -> ");
- sb.append(Hex.u2or4(entry.getHandler()));
- }
-
- return sb.toString();
+ sb.append(" -> ");
+ sb.append(Hex.u2or4(entry.getHandler()));
}
- /**
- * Returns whether or not this instance ends with a "catch-all"
- * handler.
- *
- * @return {@code true} if this instance ends with a "catch-all"
- * handler or {@code false} if not
- */
- public boolean catchesAll() {
- int size = size();
+ return sb.toString();
+ }
- if (size == 0) {
- return false;
- }
+ /**
+ * Returns whether or not this instance ends with a "catch-all"
+ * handler.
+ *
+ * @return {@code true} if this instance ends with a "catch-all"
+ * handler or {@code false} if not
+ */
+ public boolean catchesAll() {
+ int size = size();
- Entry last = get(size - 1);
- return last.getExceptionType().equals(CstType.OBJECT);
+ if (size == 0) {
+ return false;
}
+ Entry last = get(size - 1);
+ return last.getExceptionType().equals(CstType.OBJECT);
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param exceptionType {@code non-null;} type of exception handled
+ * @param handler {@code >= 0;} exception handler address
+ */
+ public void set(int n, CstType exceptionType, int handler) {
+ set0(n, new Entry(exceptionType, handler));
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
+ */
+ public void set(int n, Entry entry) {
+ set0(n, entry);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(CatchHandlerList other) {
+ if (this == other) {
+ // Easy out.
+ return 0;
+ }
+
+ int thisSize = size();
+ int otherSize = other.size();
+ int checkSize = Math.min(thisSize, otherSize);
+
+ for (int i = 0; i < checkSize; i++) {
+ Entry thisEntry = get(i);
+ Entry otherEntry = other.get(i);
+ int compare = thisEntry.compareTo(otherEntry);
+ if (compare != 0) {
+ return compare;
+ }
+ }
+
+ if (thisSize < otherSize) {
+ return -1;
+ } else if (thisSize > otherSize) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Entry in the list.
+ */
+ public static class Entry implements Comparable<Entry> {
+ /** {@code non-null;} type of exception handled */
+ private final CstType exceptionType;
+
+ /** {@code >= 0;} exception handler address */
+ private final int handler;
+
/**
- * Sets the entry at the given index.
+ * Constructs an instance.
*
- * @param n {@code >= 0, < size();} which index
* @param exceptionType {@code non-null;} type of exception handled
* @param handler {@code >= 0;} exception handler address
*/
- public void set(int n, CstType exceptionType, int handler) {
- set0(n, new Entry(exceptionType, handler));
- }
+ public Entry(CstType exceptionType, int handler) {
+ if (handler < 0) {
+ throw new IllegalArgumentException("handler < 0");
+ }
- /**
- * Sets the entry at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param entry {@code non-null;} the entry to set at {@code n}
- */
- public void set(int n, Entry entry) {
- set0(n, entry);
+ if (exceptionType == null) {
+ throw new NullPointerException("exceptionType == null");
+ }
+
+ this.handler = handler;
+ this.exceptionType = exceptionType;
}
/** {@inheritDoc} */
- public int compareTo(CatchHandlerList other) {
- if (this == other) {
- // Easy out.
- return 0;
- }
+ @Override
+ public int hashCode() {
+ return (handler * 31) + exceptionType.hashCode();
+ }
- int thisSize = size();
- int otherSize = other.size();
- int checkSize = Math.min(thisSize, otherSize);
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Entry) {
+ return (compareTo((Entry) other) == 0);
+ }
- for (int i = 0; i < checkSize; i++) {
- Entry thisEntry = get(i);
- Entry otherEntry = other.get(i);
- int compare = thisEntry.compareTo(otherEntry);
- if (compare != 0) {
- return compare;
- }
- }
+ return false;
+ }
- if (thisSize < otherSize) {
- return -1;
- } else if (thisSize > otherSize) {
- return 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Entry other) {
+ if (handler < other.handler) {
+ return -1;
+ } else if (handler > other.handler) {
+ return 1;
+ }
- return 0;
+ return exceptionType.compareTo(other.exceptionType);
}
/**
- * Entry in the list.
+ * Gets the exception type handled.
+ *
+ * @return {@code non-null;} the exception type
*/
- public static class Entry implements Comparable<Entry> {
- /** {@code non-null;} type of exception handled */
- private final CstType exceptionType;
-
- /** {@code >= 0;} exception handler address */
- private final int handler;
-
- /**
- * Constructs an instance.
- *
- * @param exceptionType {@code non-null;} type of exception handled
- * @param handler {@code >= 0;} exception handler address
- */
- public Entry(CstType exceptionType, int handler) {
- if (handler < 0) {
- throw new IllegalArgumentException("handler < 0");
- }
-
- if (exceptionType == null) {
- throw new NullPointerException("exceptionType == null");
- }
-
- this.handler = handler;
- this.exceptionType = exceptionType;
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return (handler * 31) + exceptionType.hashCode();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (other instanceof Entry) {
- return (compareTo((Entry) other) == 0);
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- public int compareTo(Entry other) {
- if (handler < other.handler) {
- return -1;
- } else if (handler > other.handler) {
- return 1;
- }
-
- return exceptionType.compareTo(other.exceptionType);
- }
-
- /**
- * Gets the exception type handled.
- *
- * @return {@code non-null;} the exception type
- */
- public CstType getExceptionType() {
- return exceptionType;
- }
-
- /**
- * Gets the handler address.
- *
- * @return {@code >= 0;} the handler address
- */
- public int getHandler() {
- return handler;
- }
+ public CstType getExceptionType() {
+ return exceptionType;
}
+
+ /**
+ * Gets the handler address.
+ *
+ * @return {@code >= 0;} the handler address
+ */
+ public int getHandler() {
+ return handler;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/CatchTable.java b/dx/src/com/android/jack/dx/dex/code/CatchTable.java
index 6e10e8a..54fc432 100644
--- a/dx/src/com/android/jack/dx/dex/code/CatchTable.java
+++ b/dx/src/com/android/jack/dx/dex/code/CatchTable.java
@@ -16,7 +16,6 @@
package com.android.jack.dx.dex.code;
-import com.android.jack.dx.rop.cst.CstType;
import com.android.jack.dx.util.FixedSizeList;
/**
@@ -24,169 +23,170 @@
* addresses for which it is valid and an associated {@link
* CatchHandlerList}.
*/
-public final class CatchTable extends FixedSizeList
- implements Comparable<CatchTable> {
- /** {@code non-null;} empty instance */
- public static final CatchTable EMPTY = new CatchTable(0);
+public final class CatchTable extends FixedSizeList implements Comparable<CatchTable> {
+ /** {@code non-null;} empty instance */
+ public static final CatchTable EMPTY = new CatchTable(0);
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size {@code >= 0;} the size of the table
- */
- public CatchTable(int size) {
- super(size);
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size {@code >= 0;} the size of the table
+ */
+ public CatchTable(int size) {
+ super(size);
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Entry get(int n) {
+ return (Entry) get0(n);
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
+ */
+ public void set(int n, Entry entry) {
+ set0(n, entry);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(CatchTable other) {
+ if (this == other) {
+ // Easy out.
+ return 0;
}
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public Entry get(int n) {
- return (Entry) get0(n);
+ int thisSize = size();
+ int otherSize = other.size();
+ int checkSize = Math.min(thisSize, otherSize);
+
+ for (int i = 0; i < checkSize; i++) {
+ Entry thisEntry = get(i);
+ Entry otherEntry = other.get(i);
+ int compare = thisEntry.compareTo(otherEntry);
+ if (compare != 0) {
+ return compare;
+ }
}
+ if (thisSize < otherSize) {
+ return -1;
+ } else if (thisSize > otherSize) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Entry in a catch list.
+ */
+ public static class Entry implements Comparable<Entry> {
+ /** {@code >= 0;} start address */
+ private final int start;
+
+ /** {@code > start;} end address (exclusive) */
+ private final int end;
+
+ /** {@code non-null;} list of catch handlers */
+ private final CatchHandlerList handlers;
+
/**
- * Sets the entry at the given index.
+ * Constructs an instance.
*
- * @param n {@code >= 0, < size();} which index
- * @param entry {@code non-null;} the entry to set at {@code n}
+ * @param start {@code >= 0;} start address
+ * @param end {@code > start;} end address (exclusive)
+ * @param handlers {@code non-null;} list of catch handlers
*/
- public void set(int n, Entry entry) {
- set0(n, entry);
+ public Entry(int start, int end, CatchHandlerList handlers) {
+ if (start < 0) {
+ throw new IllegalArgumentException("start < 0");
+ }
+
+ if (end <= start) {
+ throw new IllegalArgumentException("end <= start");
+ }
+
+ if (handlers.isMutable()) {
+ throw new IllegalArgumentException("handlers.isMutable()");
+ }
+
+ this.start = start;
+ this.end = end;
+ this.handlers = handlers;
}
/** {@inheritDoc} */
- public int compareTo(CatchTable other) {
- if (this == other) {
- // Easy out.
- return 0;
- }
+ @Override
+ public int hashCode() {
+ int hash = (start * 31) + end;
+ hash = (hash * 31) + handlers.hashCode();
+ return hash;
+ }
- int thisSize = size();
- int otherSize = other.size();
- int checkSize = Math.min(thisSize, otherSize);
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Entry) {
+ return (compareTo((Entry) other) == 0);
+ }
- for (int i = 0; i < checkSize; i++) {
- Entry thisEntry = get(i);
- Entry otherEntry = other.get(i);
- int compare = thisEntry.compareTo(otherEntry);
- if (compare != 0) {
- return compare;
- }
- }
+ return false;
+ }
- if (thisSize < otherSize) {
- return -1;
- } else if (thisSize > otherSize) {
- return 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Entry other) {
+ if (start < other.start) {
+ return -1;
+ } else if (start > other.start) {
+ return 1;
+ }
- return 0;
+ if (end < other.end) {
+ return -1;
+ } else if (end > other.end) {
+ return 1;
+ }
+
+ return handlers.compareTo(other.handlers);
}
/**
- * Entry in a catch list.
+ * Gets the start address.
+ *
+ * @return {@code >= 0;} the start address
*/
- public static class Entry implements Comparable<Entry> {
- /** {@code >= 0;} start address */
- private final int start;
-
- /** {@code > start;} end address (exclusive) */
- private final int end;
-
- /** {@code non-null;} list of catch handlers */
- private final CatchHandlerList handlers;
-
- /**
- * Constructs an instance.
- *
- * @param start {@code >= 0;} start address
- * @param end {@code > start;} end address (exclusive)
- * @param handlers {@code non-null;} list of catch handlers
- */
- public Entry(int start, int end, CatchHandlerList handlers) {
- if (start < 0) {
- throw new IllegalArgumentException("start < 0");
- }
-
- if (end <= start) {
- throw new IllegalArgumentException("end <= start");
- }
-
- if (handlers.isMutable()) {
- throw new IllegalArgumentException("handlers.isMutable()");
- }
-
- this.start = start;
- this.end = end;
- this.handlers = handlers;
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- int hash = (start * 31) + end;
- hash = (hash * 31) + handlers.hashCode();
- return hash;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (other instanceof Entry) {
- return (compareTo((Entry) other) == 0);
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- public int compareTo(Entry other) {
- if (start < other.start) {
- return -1;
- } else if (start > other.start) {
- return 1;
- }
-
- if (end < other.end) {
- return -1;
- } else if (end > other.end) {
- return 1;
- }
-
- return handlers.compareTo(other.handlers);
- }
-
- /**
- * Gets the start address.
- *
- * @return {@code >= 0;} the start address
- */
- public int getStart() {
- return start;
- }
-
- /**
- * Gets the end address (exclusive).
- *
- * @return {@code > start;} the end address (exclusive)
- */
- public int getEnd() {
- return end;
- }
-
- /**
- * Gets the handlers.
- *
- * @return {@code non-null;} the handlers
- */
- public CatchHandlerList getHandlers() {
- return handlers;
- }
+ public int getStart() {
+ return start;
}
+
+ /**
+ * Gets the end address (exclusive).
+ *
+ * @return {@code > start;} the end address (exclusive)
+ */
+ public int getEnd() {
+ return end;
+ }
+
+ /**
+ * Gets the handlers.
+ *
+ * @return {@code non-null;} the handlers
+ */
+ public CatchHandlerList getHandlers() {
+ return handlers;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/CodeAddress.java b/dx/src/com/android/jack/dx/dex/code/CodeAddress.java
index bb4904d..28a3c9a 100644
--- a/dx/src/com/android/jack/dx/dex/code/CodeAddress.java
+++ b/dx/src/com/android/jack/dx/dex/code/CodeAddress.java
@@ -27,65 +27,65 @@
* human-oriented or binary file).
*/
public final class CodeAddress extends ZeroSizeInsn {
- /** If this address should bind closely to the following real instruction */
- private final boolean bindsClosely;
+ /** If this address should bind closely to the following real instruction */
+ private final boolean bindsClosely;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- */
- public CodeAddress(SourcePosition position) {
- this(position, false);
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ */
+ public CodeAddress(SourcePosition position) {
+ this(position, false);
+ }
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param bindsClosely if the address should bind closely to the following
- * real instruction.
- */
- public CodeAddress(SourcePosition position, boolean bindsClosely) {
- super(position);
- this.bindsClosely = bindsClosely;
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param bindsClosely if the address should bind closely to the following
+ * real instruction.
+ */
+ public CodeAddress(SourcePosition position, boolean bindsClosely) {
+ super(position);
+ this.bindsClosely = bindsClosely;
+ }
- /** {@inheritDoc} */
- @Override
- public final DalvInsn withRegisters(RegisterSpecList registers) {
- return new CodeAddress(getPosition());
- }
+ /** {@inheritDoc} */
+ @Override
+ public final DalvInsn withRegisters(RegisterSpecList registers) {
+ return new CodeAddress(getPosition());
+ }
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return null;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return null;
+ }
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- return "code-address";
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ return "code-address";
+ }
- /**
- * Gets whether this address binds closely to the following "real"
- * (non-zero-length) instruction.
- *
- * When a prefix is added to an instruction (for example, to move a value
- * from a high register to a low register), this determines whether this
- * {@code CodeAddress} will point to the prefix, or to the instruction
- * itself.
- *
- * If bindsClosely is true, the address will point to the instruction
- * itself, otherwise it will point to the prefix (if any)
- *
- * @return true if this address binds closely to the next real instruction
- */
- public boolean getBindsClosely() {
- return bindsClosely;
- }
+ /**
+ * Gets whether this address binds closely to the following "real"
+ * (non-zero-length) instruction.
+ *
+ * When a prefix is added to an instruction (for example, to move a value
+ * from a high register to a low register), this determines whether this
+ * {@code CodeAddress} will point to the prefix, or to the instruction
+ * itself.
+ *
+ * If bindsClosely is true, the address will point to the instruction
+ * itself, otherwise it will point to the prefix (if any)
+ *
+ * @return true if this address binds closely to the next real instruction
+ */
+ public boolean getBindsClosely() {
+ return bindsClosely;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/CstInsn.java b/dx/src/com/android/jack/dx/dex/code/CstInsn.java
index a83e485..bf3cdb2 100644
--- a/dx/src/com/android/jack/dx/dex/code/CstInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/CstInsn.java
@@ -25,181 +25,179 @@
* to all the normal instruction information.
*/
public final class CstInsn extends FixedSizeInsn {
- /** {@code non-null;} the constant argument for this instruction */
- private final Constant constant;
+ /** {@code non-null;} the constant argument for this instruction */
+ private final Constant constant;
- /**
- * {@code >= -1;} the constant pool index for {@link #constant}, or
- * {@code -1} if not yet set
- */
- private int index;
+ /**
+ * {@code >= -1;} the constant pool index for {@link #constant}, or
+ * {@code -1} if not yet set
+ */
+ private int index;
- /**
- * {@code >= -1;} the constant pool index for the class reference in
- * {@link #constant} if any, or {@code -1} if not yet set
- */
- private int classIndex;
+ /**
+ * {@code >= -1;} the constant pool index for the class reference in
+ * {@link #constant} if any, or {@code -1} if not yet set
+ */
+ private int classIndex;
- /**
- * Constructs an instance. The output address of this instance is
- * initially unknown ({@code -1}) as is the constant pool index.
- *
- * @param opcode the opcode; one of the constants from {@link Dops}
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} register list, including a
- * result register if appropriate (that is, registers may be either
- * ins or outs)
- * @param constant {@code non-null;} constant argument
- */
- public CstInsn(Dop opcode, SourcePosition position,
- RegisterSpecList registers, Constant constant) {
- super(opcode, position, registers);
+ /**
+ * Constructs an instance. The output address of this instance is
+ * initially unknown ({@code -1}) as is the constant pool index.
+ *
+ * @param opcode the opcode; one of the constants from {@link Dops}
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
+ * result register if appropriate (that is, registers may be either
+ * ins or outs)
+ * @param constant {@code non-null;} constant argument
+ */
+ public CstInsn(Dop opcode, SourcePosition position, RegisterSpecList registers,
+ Constant constant) {
+ super(opcode, position, registers);
- if (constant == null) {
- throw new NullPointerException("constant == null");
- }
-
- this.constant = constant;
- this.index = -1;
- this.classIndex = -1;
+ if (constant == null) {
+ throw new NullPointerException("constant == null");
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withOpcode(Dop opcode) {
- CstInsn result =
- new CstInsn(opcode, getPosition(), getRegisters(), constant);
+ this.constant = constant;
+ this.index = -1;
+ this.classIndex = -1;
+ }
- if (index >= 0) {
- result.setIndex(index);
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withOpcode(Dop opcode) {
+ CstInsn result = new CstInsn(opcode, getPosition(), getRegisters(), constant);
- if (classIndex >= 0) {
- result.setClassIndex(classIndex);
- }
-
- return result;
+ if (index >= 0) {
+ result.setIndex(index);
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- CstInsn result =
- new CstInsn(getOpcode(), getPosition(), registers, constant);
-
- if (index >= 0) {
- result.setIndex(index);
- }
-
- if (classIndex >= 0) {
- result.setClassIndex(classIndex);
- }
-
- return result;
+ if (classIndex >= 0) {
+ result.setClassIndex(classIndex);
}
- /**
- * Gets the constant argument.
- *
- * @return {@code non-null;} the constant argument
- */
- public Constant getConstant() {
- return constant;
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ CstInsn result = new CstInsn(getOpcode(), getPosition(), registers, constant);
+
+ if (index >= 0) {
+ result.setIndex(index);
}
- /**
- * Gets the constant's index. It is only valid to call this after
- * {@link #setIndex} has been called.
- *
- * @return {@code >= 0;} the constant pool index
- */
- public int getIndex() {
- if (index < 0) {
- throw new RuntimeException("index not yet set for " + constant);
- }
-
- return index;
+ if (classIndex >= 0) {
+ result.setClassIndex(classIndex);
}
- /**
- * Returns whether the constant's index has been set for this instance.
- *
- * @see #setIndex
- *
- * @return {@code true} iff the index has been set
- */
- public boolean hasIndex() {
- return (index >= 0);
+ return result;
+ }
+
+ /**
+ * Gets the constant argument.
+ *
+ * @return {@code non-null;} the constant argument
+ */
+ public Constant getConstant() {
+ return constant;
+ }
+
+ /**
+ * Gets the constant's index. It is only valid to call this after
+ * {@link #setIndex} has been called.
+ *
+ * @return {@code >= 0;} the constant pool index
+ */
+ public int getIndex() {
+ if (index < 0) {
+ throw new RuntimeException("index not yet set for " + constant);
}
- /**
- * Sets the constant's index. It is only valid to call this method once
- * per instance.
- *
- * @param index {@code >= 0;} the constant pool index
- */
- public void setIndex(int index) {
- if (index < 0) {
- throw new IllegalArgumentException("index < 0");
- }
+ return index;
+ }
- if (this.index >= 0) {
- throw new RuntimeException("index already set");
- }
+ /**
+ * Returns whether the constant's index has been set for this instance.
+ *
+ * @see #setIndex
+ *
+ * @return {@code true} iff the index has been set
+ */
+ public boolean hasIndex() {
+ return (index >= 0);
+ }
- this.index = index;
+ /**
+ * Sets the constant's index. It is only valid to call this method once
+ * per instance.
+ *
+ * @param index {@code >= 0;} the constant pool index
+ */
+ public void setIndex(int index) {
+ if (index < 0) {
+ throw new IllegalArgumentException("index < 0");
}
- /**
- * Gets the constant's class index. It is only valid to call this after
- * {@link #setClassIndex} has been called.
- *
- * @return {@code >= 0;} the constant's class's constant pool index
- */
- public int getClassIndex() {
- if (classIndex < 0) {
- throw new RuntimeException("class index not yet set");
- }
-
- return classIndex;
+ if (this.index >= 0) {
+ throw new RuntimeException("index already set");
}
- /**
- * Returns whether the constant's class index has been set for this
- * instance.
- *
- * @see #setClassIndex
- *
- * @return {@code true} iff the index has been set
- */
- public boolean hasClassIndex() {
- return (classIndex >= 0);
+ this.index = index;
+ }
+
+ /**
+ * Gets the constant's class index. It is only valid to call this after
+ * {@link #setClassIndex} has been called.
+ *
+ * @return {@code >= 0;} the constant's class's constant pool index
+ */
+ public int getClassIndex() {
+ if (classIndex < 0) {
+ throw new RuntimeException("class index not yet set");
}
- /**
- * Sets the constant's class index. This is the constant pool index
- * for the class referred to by this instance's constant. Only
- * reference constants have a class, so it is only on instances
- * with reference constants that this method should ever be
- * called. It is only valid to call this method once per instance.
- *
- * @param index {@code >= 0;} the constant's class's constant pool index
- */
- public void setClassIndex(int index) {
- if (index < 0) {
- throw new IllegalArgumentException("index < 0");
- }
+ return classIndex;
+ }
- if (this.classIndex >= 0) {
- throw new RuntimeException("class index already set");
- }
+ /**
+ * Returns whether the constant's class index has been set for this
+ * instance.
+ *
+ * @see #setClassIndex
+ *
+ * @return {@code true} iff the index has been set
+ */
+ public boolean hasClassIndex() {
+ return (classIndex >= 0);
+ }
- this.classIndex = index;
+ /**
+ * Sets the constant's class index. This is the constant pool index
+ * for the class referred to by this instance's constant. Only
+ * reference constants have a class, so it is only on instances
+ * with reference constants that this method should ever be
+ * called. It is only valid to call this method once per instance.
+ *
+ * @param index {@code >= 0;} the constant's class's constant pool index
+ */
+ public void setClassIndex(int index) {
+ if (index < 0) {
+ throw new IllegalArgumentException("index < 0");
}
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return constant.toHuman();
+ if (this.classIndex >= 0) {
+ throw new RuntimeException("class index already set");
}
+
+ this.classIndex = index;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return constant.toHuman();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/DalvCode.java b/dx/src/com/android/jack/dx/dex/code/DalvCode.java
index e691ef1..bf92ad4 100644
--- a/dx/src/com/android/jack/dx/dex/code/DalvCode.java
+++ b/dx/src/com/android/jack/dx/dex/code/DalvCode.java
@@ -26,207 +26,206 @@
* corresponds to a {@code code} structure in a {@code .dex} file.
*/
public final class DalvCode {
- /**
- * how much position info to preserve; one of the static
- * constants in {@link PositionList}
- */
- private final int positionInfo;
+ /**
+ * how much position info to preserve; one of the static
+ * constants in {@link PositionList}
+ */
+ private final int positionInfo;
- /**
- * {@code null-ok;} the instruction list, ready for final processing;
- * nulled out in {@link #finishProcessingIfNecessary}
- */
- private OutputFinisher unprocessedInsns;
+ /**
+ * {@code null-ok;} the instruction list, ready for final processing;
+ * nulled out in {@link #finishProcessingIfNecessary}
+ */
+ private OutputFinisher unprocessedInsns;
- /**
- * {@code non-null;} unprocessed catch table;
- * nulled out in {@link #finishProcessingIfNecessary}
- */
- private CatchBuilder unprocessedCatches;
+ /**
+ * {@code non-null;} unprocessed catch table;
+ * nulled out in {@link #finishProcessingIfNecessary}
+ */
+ private CatchBuilder unprocessedCatches;
- /**
- * {@code null-ok;} catch table; set in
- * {@link #finishProcessingIfNecessary}
- */
- private CatchTable catches;
+ /**
+ * {@code null-ok;} catch table; set in
+ * {@link #finishProcessingIfNecessary}
+ */
+ private CatchTable catches;
- /**
- * {@code null-ok;} source positions list; set in
- * {@link #finishProcessingIfNecessary}
- */
- private PositionList positions;
+ /**
+ * {@code null-ok;} source positions list; set in
+ * {@link #finishProcessingIfNecessary}
+ */
+ private PositionList positions;
- /**
- * {@code null-ok;} local variable list; set in
- * {@link #finishProcessingIfNecessary}
- */
- private LocalList locals;
+ /**
+ * {@code null-ok;} local variable list; set in
+ * {@link #finishProcessingIfNecessary}
+ */
+ private LocalList locals;
- /**
- * {@code null-ok;} the processed instruction list; set in
- * {@link #finishProcessingIfNecessary}
- */
- private DalvInsnList insns;
+ /**
+ * {@code null-ok;} the processed instruction list; set in
+ * {@link #finishProcessingIfNecessary}
+ */
+ private DalvInsnList insns;
+ /**
+ * Constructs an instance.
+ *
+ * @param positionInfo how much position info to preserve; one of the
+ * static constants in {@link PositionList}
+ * @param unprocessedInsns {@code non-null;} the instruction list, ready
+ * for final processing
+ * @param unprocessedCatches {@code non-null;} unprocessed catch
+ * (exception handler) table
+ */
+ public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
+ CatchBuilder unprocessedCatches) {
+ if (unprocessedInsns == null) {
+ throw new NullPointerException("unprocessedInsns == null");
+ }
+
+ if (unprocessedCatches == null) {
+ throw new NullPointerException("unprocessedCatches == null");
+ }
+
+ this.positionInfo = positionInfo;
+ this.unprocessedInsns = unprocessedInsns;
+ this.unprocessedCatches = unprocessedCatches;
+ this.catches = null;
+ this.positions = null;
+ this.locals = null;
+ this.insns = null;
+ }
+
+ /**
+ * Finish up processing of the method.
+ */
+ private void finishProcessingIfNecessary() {
+ if (insns != null) {
+ return;
+ }
+
+ insns = unprocessedInsns.finishProcessingAndGetList();
+ positions = PositionList.make(insns, positionInfo);
+ locals = LocalList.make(insns);
+ catches = unprocessedCatches.build();
+
+ // Let them be gc'ed.
+ unprocessedInsns = null;
+ unprocessedCatches = null;
+ }
+
+ /**
+ * Assign indices in all instructions that need them, using the
+ * given callback to perform lookups. This must be called before
+ * {@link #getInsns}.
+ *
+ * @param callback {@code non-null;} callback object
+ */
+ public void assignIndices(AssignIndicesCallback callback) {
+ unprocessedInsns.assignIndices(callback);
+ }
+
+ /**
+ * Gets whether this instance has any position data to represent.
+ *
+ * @return {@code true} iff this instance has any position
+ * data to represent
+ */
+ public boolean hasPositions() {
+ return (positionInfo != PositionList.NONE) && unprocessedInsns.hasAnyPositionInfo();
+ }
+
+ /**
+ * Gets whether this instance has any local variable data to represent.
+ *
+ * @return {@code true} iff this instance has any local variable
+ * data to represent
+ */
+ public boolean hasLocals() {
+ return unprocessedInsns.hasAnyLocalInfo();
+ }
+
+ /**
+ * Gets whether this instance has any catches at all (either typed
+ * or catch-all).
+ *
+ * @return whether this instance has any catches at all
+ */
+ public boolean hasAnyCatches() {
+ return unprocessedCatches.hasAnyCatches();
+ }
+
+ /**
+ * Gets the set of catch types handled anywhere in the code.
+ *
+ * @return {@code non-null;} the set of catch types
+ */
+ public HashSet<Type> getCatchTypes() {
+ return unprocessedCatches.getCatchTypes();
+ }
+
+ /**
+ * Gets the set of all constants referred to by instructions in
+ * the code.
+ *
+ * @return {@code non-null;} the set of constants
+ */
+ public HashSet<Constant> getInsnConstants() {
+ return unprocessedInsns.getAllConstants();
+ }
+
+ /**
+ * Gets the list of instructions.
+ *
+ * @return {@code non-null;} the instruction list
+ */
+ public DalvInsnList getInsns() {
+ finishProcessingIfNecessary();
+ return insns;
+ }
+
+ /**
+ * Gets the catch (exception handler) table.
+ *
+ * @return {@code non-null;} the catch table
+ */
+ public CatchTable getCatches() {
+ finishProcessingIfNecessary();
+ return catches;
+ }
+
+ /**
+ * Gets the source positions list.
+ *
+ * @return {@code non-null;} the source positions list
+ */
+ public PositionList getPositions() {
+ finishProcessingIfNecessary();
+ return positions;
+ }
+
+ /**
+ * Gets the source positions list.
+ *
+ * @return {@code non-null;} the source positions list
+ */
+ public LocalList getLocals() {
+ finishProcessingIfNecessary();
+ return locals;
+ }
+
+ /**
+ * Class used as a callback for {@link #assignIndices}.
+ */
+ public static interface AssignIndicesCallback {
/**
- * Constructs an instance.
+ * Gets the index for the given constant.
*
- * @param positionInfo how much position info to preserve; one of the
- * static constants in {@link PositionList}
- * @param unprocessedInsns {@code non-null;} the instruction list, ready
- * for final processing
- * @param unprocessedCatches {@code non-null;} unprocessed catch
- * (exception handler) table
+ * @param cst {@code non-null;} the constant
+ * @return {@code >= -1;} the index or {@code -1} if the constant
+ * shouldn't actually be reified with an index
*/
- public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
- CatchBuilder unprocessedCatches) {
- if (unprocessedInsns == null) {
- throw new NullPointerException("unprocessedInsns == null");
- }
-
- if (unprocessedCatches == null) {
- throw new NullPointerException("unprocessedCatches == null");
- }
-
- this.positionInfo = positionInfo;
- this.unprocessedInsns = unprocessedInsns;
- this.unprocessedCatches = unprocessedCatches;
- this.catches = null;
- this.positions = null;
- this.locals = null;
- this.insns = null;
- }
-
- /**
- * Finish up processing of the method.
- */
- private void finishProcessingIfNecessary() {
- if (insns != null) {
- return;
- }
-
- insns = unprocessedInsns.finishProcessingAndGetList();
- positions = PositionList.make(insns, positionInfo);
- locals = LocalList.make(insns);
- catches = unprocessedCatches.build();
-
- // Let them be gc'ed.
- unprocessedInsns = null;
- unprocessedCatches = null;
- }
-
- /**
- * Assign indices in all instructions that need them, using the
- * given callback to perform lookups. This must be called before
- * {@link #getInsns}.
- *
- * @param callback {@code non-null;} callback object
- */
- public void assignIndices(AssignIndicesCallback callback) {
- unprocessedInsns.assignIndices(callback);
- }
-
- /**
- * Gets whether this instance has any position data to represent.
- *
- * @return {@code true} iff this instance has any position
- * data to represent
- */
- public boolean hasPositions() {
- return (positionInfo != PositionList.NONE)
- && unprocessedInsns.hasAnyPositionInfo();
- }
-
- /**
- * Gets whether this instance has any local variable data to represent.
- *
- * @return {@code true} iff this instance has any local variable
- * data to represent
- */
- public boolean hasLocals() {
- return unprocessedInsns.hasAnyLocalInfo();
- }
-
- /**
- * Gets whether this instance has any catches at all (either typed
- * or catch-all).
- *
- * @return whether this instance has any catches at all
- */
- public boolean hasAnyCatches() {
- return unprocessedCatches.hasAnyCatches();
- }
-
- /**
- * Gets the set of catch types handled anywhere in the code.
- *
- * @return {@code non-null;} the set of catch types
- */
- public HashSet<Type> getCatchTypes() {
- return unprocessedCatches.getCatchTypes();
- }
-
- /**
- * Gets the set of all constants referred to by instructions in
- * the code.
- *
- * @return {@code non-null;} the set of constants
- */
- public HashSet<Constant> getInsnConstants() {
- return unprocessedInsns.getAllConstants();
- }
-
- /**
- * Gets the list of instructions.
- *
- * @return {@code non-null;} the instruction list
- */
- public DalvInsnList getInsns() {
- finishProcessingIfNecessary();
- return insns;
- }
-
- /**
- * Gets the catch (exception handler) table.
- *
- * @return {@code non-null;} the catch table
- */
- public CatchTable getCatches() {
- finishProcessingIfNecessary();
- return catches;
- }
-
- /**
- * Gets the source positions list.
- *
- * @return {@code non-null;} the source positions list
- */
- public PositionList getPositions() {
- finishProcessingIfNecessary();
- return positions;
- }
-
- /**
- * Gets the source positions list.
- *
- * @return {@code non-null;} the source positions list
- */
- public LocalList getLocals() {
- finishProcessingIfNecessary();
- return locals;
- }
-
- /**
- * Class used as a callback for {@link #assignIndices}.
- */
- public static interface AssignIndicesCallback {
- /**
- * Gets the index for the given constant.
- *
- * @param cst {@code non-null;} the constant
- * @return {@code >= -1;} the index or {@code -1} if the constant
- * shouldn't actually be reified with an index
- */
- public int getIndex(Constant cst);
- }
+ public int getIndex(Constant cst);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/DalvInsn.java b/dx/src/com/android/jack/dx/dex/code/DalvInsn.java
index a6a501e..4667d2f 100644
--- a/dx/src/com/android/jack/dx/dex/code/DalvInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/DalvInsn.java
@@ -29,422 +29,420 @@
* Base class for Dalvik instructions.
*/
public abstract class DalvInsn {
- /**
- * the actual output address of this instance, if known, or
- * {@code -1} if not
- */
- private int address;
+ /**
+ * the actual output address of this instance, if known, or
+ * {@code -1} if not
+ */
+ private int address;
- /** the opcode; one of the constants from {@link Dops} */
- private final Dop opcode;
+ /** the opcode; one of the constants from {@link Dops} */
+ private final Dop opcode;
- /** {@code non-null;} source position */
- private final SourcePosition position;
+ /** {@code non-null;} source position */
+ private final SourcePosition position;
- /** {@code non-null;} list of register arguments */
- private final RegisterSpecList registers;
+ /** {@code non-null;} list of register arguments */
+ private final RegisterSpecList registers;
- /**
- * Makes a move instruction, appropriate and ideal for the given arguments.
- *
- * @param position {@code non-null;} source position information
- * @param dest {@code non-null;} destination register
- * @param src {@code non-null;} source register
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static SimpleInsn makeMove(SourcePosition position,
- RegisterSpec dest, RegisterSpec src) {
- boolean category1 = dest.getCategory() == 1;
- boolean reference = dest.getType().isReference();
- int destReg = dest.getReg();
- int srcReg = src.getReg();
- Dop opcode;
+ /**
+ * Makes a move instruction, appropriate and ideal for the given arguments.
+ *
+ * @param position {@code non-null;} source position information
+ * @param dest {@code non-null;} destination register
+ * @param src {@code non-null;} source register
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static SimpleInsn makeMove(SourcePosition position, RegisterSpec dest, RegisterSpec src) {
+ boolean category1 = dest.getCategory() == 1;
+ boolean reference = dest.getType().isReference();
+ int destReg = dest.getReg();
+ int srcReg = src.getReg();
+ Dop opcode;
- if ((srcReg | destReg) < 16) {
- opcode = reference ? Dops.MOVE_OBJECT :
- (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
- } else if (destReg < 256) {
- opcode = reference ? Dops.MOVE_OBJECT_FROM16 :
- (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
- } else {
- opcode = reference ? Dops.MOVE_OBJECT_16 :
- (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
- }
-
- return new SimpleInsn(opcode, position,
- RegisterSpecList.make(dest, src));
+ if ((srcReg | destReg) < 16) {
+ opcode = reference ? Dops.MOVE_OBJECT : (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
+ } else if (destReg < 256) {
+ opcode = reference ? Dops.MOVE_OBJECT_FROM16
+ : (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
+ } else {
+ opcode = reference ? Dops.MOVE_OBJECT_16 : (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
}
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * <p><b>Note:</b> In the unlikely event that an instruction takes
- * absolutely no registers (e.g., a {@code nop} or a
- * no-argument no-result static method call), then the given
- * register list may be passed as {@link
- * RegisterSpecList#EMPTY}.</p>
- *
- * @param opcode the opcode; one of the constants from {@link Dops}
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} register list, including a
- * result register if appropriate (that is, registers may be either
- * ins and outs)
- */
- public DalvInsn(Dop opcode, SourcePosition position,
- RegisterSpecList registers) {
- if (opcode == null) {
- throw new NullPointerException("opcode == null");
- }
+ return new SimpleInsn(opcode, position, RegisterSpecList.make(dest, src));
+ }
- if (position == null) {
- throw new NullPointerException("position == null");
- }
-
- if (registers == null) {
- throw new NullPointerException("registers == null");
- }
-
- this.address = -1;
- this.opcode = opcode;
- this.position = position;
- this.registers = registers;
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * <p><b>Note:</b> In the unlikely event that an instruction takes
+ * absolutely no registers (e.g., a {@code nop} or a
+ * no-argument no-result static method call), then the given
+ * register list may be passed as {@link
+ * RegisterSpecList#EMPTY}.</p>
+ *
+ * @param opcode the opcode; one of the constants from {@link Dops}
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
+ * result register if appropriate (that is, registers may be either
+ * ins and outs)
+ */
+ public DalvInsn(Dop opcode, SourcePosition position, RegisterSpecList registers) {
+ if (opcode == null) {
+ throw new NullPointerException("opcode == null");
}
- /** {@inheritDoc} */
- @Override
- public final String toString() {
- StringBuffer sb = new StringBuffer(100);
-
- sb.append(identifierString());
- sb.append(' ');
- sb.append(position);
-
- sb.append(": ");
- sb.append(opcode.getName());
-
- boolean needComma = false;
- if (registers.size() != 0) {
- sb.append(registers.toHuman(" ", ", ", null));
- needComma = true;
- }
-
- String extra = argString();
- if (extra != null) {
- if (needComma) {
- sb.append(',');
- }
- sb.append(' ');
- sb.append(extra);
- }
-
- return sb.toString();
+ if (position == null) {
+ throw new NullPointerException("position == null");
}
- /**
- * Gets whether the address of this instruction is known.
- *
- * @see #getAddress
- * @see #setAddress
- */
- public final boolean hasAddress() {
- return (address >= 0);
+ if (registers == null) {
+ throw new NullPointerException("registers == null");
}
- /**
- * Gets the output address of this instruction, if it is known. This throws
- * a {@code RuntimeException} if it has not yet been set.
- *
- * @see #setAddress
- *
- * @return {@code >= 0;} the output address
- */
- public final int getAddress() {
- if (address < 0) {
- throw new RuntimeException("address not yet known");
- }
+ this.address = -1;
+ this.opcode = opcode;
+ this.position = position;
+ this.registers = registers;
+ }
- return address;
+ /** {@inheritDoc} */
+ @Override
+ public final String toString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append(identifierString());
+ sb.append(' ');
+ sb.append(position);
+
+ sb.append(": ");
+ sb.append(opcode.getName());
+
+ boolean needComma = false;
+ if (registers.size() != 0) {
+ sb.append(registers.toHuman(" ", ", ", null));
+ needComma = true;
}
- /**
- * Gets the opcode.
- *
- * @return {@code non-null;} the opcode
- */
- public final Dop getOpcode() {
- return opcode;
+ String extra = argString();
+ if (extra != null) {
+ if (needComma) {
+ sb.append(',');
+ }
+ sb.append(' ');
+ sb.append(extra);
}
- /**
- * Gets the source position.
- *
- * @return {@code non-null;} the source position
- */
- public final SourcePosition getPosition() {
- return position;
+ return sb.toString();
+ }
+
+ /**
+ * Gets whether the address of this instruction is known.
+ *
+ * @see #getAddress
+ * @see #setAddress
+ */
+ public final boolean hasAddress() {
+ return (address >= 0);
+ }
+
+ /**
+ * Gets the output address of this instruction, if it is known. This throws
+ * a {@code RuntimeException} if it has not yet been set.
+ *
+ * @see #setAddress
+ *
+ * @return {@code >= 0;} the output address
+ */
+ public final int getAddress() {
+ if (address < 0) {
+ throw new RuntimeException("address not yet known");
}
- /**
- * Gets the register list for this instruction.
- *
- * @return {@code non-null;} the registers
- */
- public final RegisterSpecList getRegisters() {
- return registers;
+ return address;
+ }
+
+ /**
+ * Gets the opcode.
+ *
+ * @return {@code non-null;} the opcode
+ */
+ public final Dop getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Gets the source position.
+ *
+ * @return {@code non-null;} the source position
+ */
+ public final SourcePosition getPosition() {
+ return position;
+ }
+
+ /**
+ * Gets the register list for this instruction.
+ *
+ * @return {@code non-null;} the registers
+ */
+ public final RegisterSpecList getRegisters() {
+ return registers;
+ }
+
+ /**
+ * Returns whether this instance's opcode uses a result register.
+ * This method is a convenient shorthand for
+ * {@code getOpcode().hasResult()}.
+ *
+ * @return {@code true} iff this opcode uses a result register
+ */
+ public final boolean hasResult() {
+ return opcode.hasResult();
+ }
+
+ /**
+ * Gets the minimum distinct registers required for this instruction.
+ * Uses the given BitSet to determine which registers require
+ * replacement, and ignores registers that are already compatible.
+ * This assumes that the result (if any) can share registers with the
+ * sources (if any), that each source register is unique, and that
+ * (to be explicit here) category-2 values take up two consecutive
+ * registers.
+ *
+ * @param compatRegs {@code non-null;} set of compatible registers
+ * @return {@code >= 0;} the minimum distinct register requirement
+ */
+ public final int getMinimumRegisterRequirement(BitSet compatRegs) {
+ boolean hasResult = hasResult();
+ int regSz = registers.size();
+ int resultRequirement = 0;
+ int sourceRequirement = 0;
+
+ if (hasResult && !compatRegs.get(0)) {
+ resultRequirement = registers.get(0).getCategory();
}
- /**
- * Returns whether this instance's opcode uses a result register.
- * This method is a convenient shorthand for
- * {@code getOpcode().hasResult()}.
- *
- * @return {@code true} iff this opcode uses a result register
- */
- public final boolean hasResult() {
- return opcode.hasResult();
+ for (int i = hasResult ? 1 : 0; i < regSz; i++) {
+ if (!compatRegs.get(i)) {
+ sourceRequirement += registers.get(i).getCategory();
+ }
}
- /**
- * Gets the minimum distinct registers required for this instruction.
- * Uses the given BitSet to determine which registers require
- * replacement, and ignores registers that are already compatible.
- * This assumes that the result (if any) can share registers with the
- * sources (if any), that each source register is unique, and that
- * (to be explicit here) category-2 values take up two consecutive
- * registers.
- *
- * @param compatRegs {@code non-null;} set of compatible registers
- * @return {@code >= 0;} the minimum distinct register requirement
- */
- public final int getMinimumRegisterRequirement(BitSet compatRegs) {
- boolean hasResult = hasResult();
- int regSz = registers.size();
- int resultRequirement = 0;
- int sourceRequirement = 0;
+ return Math.max(sourceRequirement, resultRequirement);
+ }
- if (hasResult && !compatRegs.get(0)) {
- resultRequirement = registers.get(0).getCategory();
- }
+ /**
+ * Gets the instruction that is equivalent to this one, except that
+ * it uses sequential registers starting at {@code 0} (storing
+ * the result, if any, in register {@code 0} as well).
+ *
+ * @return {@code non-null;} the replacement
+ */
+ public DalvInsn getLowRegVersion() {
+ RegisterSpecList regs = registers.withExpandedRegisters(0, hasResult(), null);
+ return withRegisters(regs);
+ }
- for (int i = hasResult ? 1 : 0; i < regSz; i++) {
- if (!compatRegs.get(i)) {
- sourceRequirement += registers.get(i).getCategory();
- }
- }
+ /**
+ * Gets the instruction prefix required, if any, to use in an expanded
+ * version of this instance. Will not generate moves for registers
+ * marked compatible to the format by the given BitSet.
+ *
+ * @see #expandedVersion
+ *
+ * @param compatRegs {@code non-null;} set of compatible registers
+ * @return {@code null-ok;} the prefix, if any
+ */
+ public DalvInsn expandedPrefix(BitSet compatRegs) {
+ RegisterSpecList regs = registers;
+ boolean firstBit = compatRegs.get(0);
- return Math.max(sourceRequirement, resultRequirement);
+ if (hasResult()) {
+ compatRegs.set(0);
}
- /**
- * Gets the instruction that is equivalent to this one, except that
- * it uses sequential registers starting at {@code 0} (storing
- * the result, if any, in register {@code 0} as well).
- *
- * @return {@code non-null;} the replacement
- */
- public DalvInsn getLowRegVersion() {
- RegisterSpecList regs =
- registers.withExpandedRegisters(0, hasResult(), null);
- return withRegisters(regs);
+ regs = regs.subset(compatRegs);
+
+ if (hasResult()) {
+ compatRegs.set(0, firstBit);
}
- /**
- * Gets the instruction prefix required, if any, to use in an expanded
- * version of this instance. Will not generate moves for registers
- * marked compatible to the format by the given BitSet.
- *
- * @see #expandedVersion
- *
- * @param compatRegs {@code non-null;} set of compatible registers
- * @return {@code null-ok;} the prefix, if any
- */
- public DalvInsn expandedPrefix(BitSet compatRegs) {
- RegisterSpecList regs = registers;
- boolean firstBit = compatRegs.get(0);
-
- if (hasResult()) compatRegs.set(0);
-
- regs = regs.subset(compatRegs);
-
- if (hasResult()) compatRegs.set(0, firstBit);
-
- if (regs.size() == 0) return null;
-
- return new HighRegisterPrefix(position, regs);
+ if (regs.size() == 0) {
+ return null;
}
- /**
- * Gets the instruction suffix required, if any, to use in an expanded
- * version of this instance. Will not generate a move for a register
- * marked compatible to the format by the given BitSet.
- *
- * @see #expandedVersion
- *
- * @param compatRegs {@code non-null;} set of compatible registers
- * @return {@code null-ok;} the suffix, if any
- */
- public DalvInsn expandedSuffix(BitSet compatRegs) {
- if (hasResult() && !compatRegs.get(0)) {
- RegisterSpec r = registers.get(0);
- return makeMove(position, r, r.withReg(0));
- } else {
- return null;
- }
+ return new HighRegisterPrefix(position, regs);
+ }
+
+ /**
+ * Gets the instruction suffix required, if any, to use in an expanded
+ * version of this instance. Will not generate a move for a register
+ * marked compatible to the format by the given BitSet.
+ *
+ * @see #expandedVersion
+ *
+ * @param compatRegs {@code non-null;} set of compatible registers
+ * @return {@code null-ok;} the suffix, if any
+ */
+ public DalvInsn expandedSuffix(BitSet compatRegs) {
+ if (hasResult() && !compatRegs.get(0)) {
+ RegisterSpec r = registers.get(0);
+ return makeMove(position, r, r.withReg(0));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the instruction that is equivalent to this one, except that
+ * it replaces incompatible registers with sequential registers
+ * starting at {@code 0} (storing the result, if any, in register
+ * {@code 0} as well). The sequence of instructions from
+ * {@link #expandedPrefix} and {@link #expandedSuffix} (if non-null)
+ * surrounding the result of a call to this method are the expanded
+ * transformation of this instance, and it is guaranteed that the
+ * number of low registers used will be the number returned by
+ * {@link #getMinimumRegisterRequirement}.
+ *
+ * @param compatRegs {@code non-null;} set of compatible registers
+ * @return {@code non-null;} the replacement
+ */
+ public DalvInsn expandedVersion(BitSet compatRegs) {
+ RegisterSpecList regs = registers.withExpandedRegisters(0, hasResult(), compatRegs);
+ return withRegisters(regs);
+ }
+
+ /**
+ * Gets the short identifier for this instruction. This is its
+ * address, if assigned, or its identity hashcode if not.
+ *
+ * @return {@code non-null;} the identifier
+ */
+ public final String identifierString() {
+ if (address != -1) {
+ return String.format("%04x", address);
}
- /**
- * Gets the instruction that is equivalent to this one, except that
- * it replaces incompatible registers with sequential registers
- * starting at {@code 0} (storing the result, if any, in register
- * {@code 0} as well). The sequence of instructions from
- * {@link #expandedPrefix} and {@link #expandedSuffix} (if non-null)
- * surrounding the result of a call to this method are the expanded
- * transformation of this instance, and it is guaranteed that the
- * number of low registers used will be the number returned by
- * {@link #getMinimumRegisterRequirement}.
- *
- * @param compatRegs {@code non-null;} set of compatible registers
- * @return {@code non-null;} the replacement
- */
- public DalvInsn expandedVersion(BitSet compatRegs) {
- RegisterSpecList regs =
- registers.withExpandedRegisters(0, hasResult(), compatRegs);
- return withRegisters(regs);
+ return Hex.u4(System.identityHashCode(this));
+ }
+
+ /**
+ * Returns the string form of this instance suitable for inclusion in
+ * a human-oriented listing dump. This method will return {@code null}
+ * if this instance should not appear in a listing.
+ *
+ * @param prefix {@code non-null;} prefix before the address; each follow-on
+ * line will be indented to match as well
+ * @param width {@code >= 0;} the width of the output or {@code 0} for
+ * unlimited width
+ * @param noteIndices whether to include an explicit notation of
+ * constant pool indices
+ * @return {@code null-ok;} the string form or {@code null} if this
+ * instance should not appear in a listing
+ */
+ public final String listingString(String prefix, int width, boolean noteIndices) {
+ String insnPerSe = listingString0(noteIndices);
+
+ if (insnPerSe == null) {
+ return null;
}
- /**
- * Gets the short identifier for this instruction. This is its
- * address, if assigned, or its identity hashcode if not.
- *
- * @return {@code non-null;} the identifier
- */
- public final String identifierString() {
- if (address != -1) {
- return String.format("%04x", address);
- }
+ String addr = prefix + identifierString() + ": ";
+ int w1 = addr.length();
+ int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
- return Hex.u4(System.identityHashCode(this));
+ return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
+ }
+
+ /**
+ * Sets the output address.
+ *
+ * @param address {@code >= 0;} the output address
+ */
+ public final void setAddress(int address) {
+ if (address < 0) {
+ throw new IllegalArgumentException("address < 0");
}
- /**
- * Returns the string form of this instance suitable for inclusion in
- * a human-oriented listing dump. This method will return {@code null}
- * if this instance should not appear in a listing.
- *
- * @param prefix {@code non-null;} prefix before the address; each follow-on
- * line will be indented to match as well
- * @param width {@code >= 0;} the width of the output or {@code 0} for
- * unlimited width
- * @param noteIndices whether to include an explicit notation of
- * constant pool indices
- * @return {@code null-ok;} the string form or {@code null} if this
- * instance should not appear in a listing
- */
- public final String listingString(String prefix, int width,
- boolean noteIndices) {
- String insnPerSe = listingString0(noteIndices);
+ this.address = address;
+ }
- if (insnPerSe == null) {
- return null;
- }
+ /**
+ * Gets the address immediately after this instance. This is only
+ * calculable if this instance's address is known, and it is equal
+ * to the address plus the length of the instruction format of this
+ * instance's opcode.
+ *
+ * @return {@code >= 0;} the next address
+ */
+ public final int getNextAddress() {
+ return getAddress() + codeSize();
+ }
- String addr = prefix + identifierString() + ": ";
- int w1 = addr.length();
- int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
+ /**
+ * Gets the size of this instruction, in 16-bit code units.
+ *
+ * @return {@code >= 0;} the code size of this instruction
+ */
+ public abstract int codeSize();
- return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
- }
+ /**
+ * Writes this instance to the given output. This method should
+ * never annotate the output.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ public abstract void writeTo(AnnotatedOutput out);
- /**
- * Sets the output address.
- *
- * @param address {@code >= 0;} the output address
- */
- public final void setAddress(int address) {
- if (address < 0) {
- throw new IllegalArgumentException("address < 0");
- }
+ /**
+ * Returns an instance that is just like this one, except that its
+ * opcode is replaced by the one given, and its address is reset.
+ *
+ * @param opcode {@code non-null;} the new opcode
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract DalvInsn withOpcode(Dop opcode);
- this.address = address;
- }
+ /**
+ * Returns an instance that is just like this one, except that all
+ * register references have been offset by the given delta, and its
+ * address is reset.
+ *
+ * @param delta the amount to offset register references by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract DalvInsn withRegisterOffset(int delta);
- /**
- * Gets the address immediately after this instance. This is only
- * calculable if this instance's address is known, and it is equal
- * to the address plus the length of the instruction format of this
- * instance's opcode.
- *
- * @return {@code >= 0;} the next address
- */
- public final int getNextAddress() {
- return getAddress() + codeSize();
- }
+ /**
+ * Returns an instance that is just like this one, except that the
+ * register list is replaced by the given one, and its address is
+ * reset.
+ *
+ * @param registers {@code non-null;} new register list
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract DalvInsn withRegisters(RegisterSpecList registers);
- /**
- * Gets the size of this instruction, in 16-bit code units.
- *
- * @return {@code >= 0;} the code size of this instruction
- */
- public abstract int codeSize();
+ /**
+ * Gets the string form for any arguments to this instance. Subclasses
+ * must override this.
+ *
+ * @return {@code null-ok;} the string version of any arguments or
+ * {@code null} if there are none
+ */
+ protected abstract String argString();
- /**
- * Writes this instance to the given output. This method should
- * never annotate the output.
- *
- * @param out {@code non-null;} where to write to
- */
- public abstract void writeTo(AnnotatedOutput out);
-
- /**
- * Returns an instance that is just like this one, except that its
- * opcode is replaced by the one given, and its address is reset.
- *
- * @param opcode {@code non-null;} the new opcode
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract DalvInsn withOpcode(Dop opcode);
-
- /**
- * Returns an instance that is just like this one, except that all
- * register references have been offset by the given delta, and its
- * address is reset.
- *
- * @param delta the amount to offset register references by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract DalvInsn withRegisterOffset(int delta);
-
- /**
- * Returns an instance that is just like this one, except that the
- * register list is replaced by the given one, and its address is
- * reset.
- *
- * @param registers {@code non-null;} new register list
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract DalvInsn withRegisters(RegisterSpecList registers);
-
- /**
- * Gets the string form for any arguments to this instance. Subclasses
- * must override this.
- *
- * @return {@code null-ok;} the string version of any arguments or
- * {@code null} if there are none
- */
- protected abstract String argString();
-
- /**
- * Helper for {@link #listingString}, which returns the string
- * form of this instance suitable for inclusion in a
- * human-oriented listing dump, not including the instruction
- * address and without respect for any output formatting. This
- * method should return {@code null} if this instance should
- * not appear in a listing.
- *
- * @param noteIndices whether to include an explicit notation of
- * constant pool indices
- * @return {@code null-ok;} the listing string
- */
- protected abstract String listingString0(boolean noteIndices);
+ /**
+ * Helper for {@link #listingString}, which returns the string
+ * form of this instance suitable for inclusion in a
+ * human-oriented listing dump, not including the instruction
+ * address and without respect for any output formatting. This
+ * method should return {@code null} if this instance should
+ * not appear in a listing.
+ *
+ * @param noteIndices whether to include an explicit notation of
+ * constant pool indices
+ * @return {@code null-ok;} the listing string
+ */
+ protected abstract String listingString0(boolean noteIndices);
}
diff --git a/dx/src/com/android/jack/dx/dex/code/DalvInsnList.java b/dx/src/com/android/jack/dx/dex/code/DalvInsnList.java
index 80fe920..1d453d9 100644
--- a/dx/src/com/android/jack/dx/dex/code/DalvInsnList.java
+++ b/dx/src/com/android/jack/dx/dex/code/DalvInsnList.java
@@ -35,235 +35,231 @@
*/
public final class DalvInsnList extends FixedSizeList {
- /**
- * The amount of register space, in register units, required for this
- * code block. This may be greater than the largest observed register+
- * category because the method this code block exists in may
- * specify arguments that are unused by the method.
- */
- private final int regCount;
+ /**
+ * The amount of register space, in register units, required for this
+ * code block. This may be greater than the largest observed register+
+ * category because the method this code block exists in may
+ * specify arguments that are unused by the method.
+ */
+ private final int regCount;
- /**
- * Constructs and returns an immutable instance whose elements are
- * identical to the ones in the given list, in the same order.
- *
- * @param list {@code non-null;} the list to use for elements
- * @param regCount count, in register-units, of the number of registers
- * this code block requires.
- * @return {@code non-null;} an appropriately-constructed instance of this
- * class
- */
- public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list,
- int regCount) {
- int size = list.size();
- DalvInsnList result = new DalvInsnList(size, regCount);
+ /**
+ * Constructs and returns an immutable instance whose elements are
+ * identical to the ones in the given list, in the same order.
+ *
+ * @param list {@code non-null;} the list to use for elements
+ * @param regCount count, in register-units, of the number of registers
+ * this code block requires.
+ * @return {@code non-null;} an appropriately-constructed instance of this
+ * class
+ */
+ public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list, int regCount) {
+ int size = list.size();
+ DalvInsnList result = new DalvInsnList(size, regCount);
- for (int i = 0; i < size; i++) {
- result.set(i, list.get(i));
+ for (int i = 0; i < size; i++) {
+ result.set(i, list.get(i));
+ }
+
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public DalvInsnList(int size, int regCount) {
+ super(size);
+ this.regCount = regCount;
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public DalvInsn get(int n) {
+ return (DalvInsn) get0(n);
+ }
+
+ /**
+ * Sets the instruction at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param insn {@code non-null;} the instruction to set at {@code n}
+ */
+ public void set(int n, DalvInsn insn) {
+ set0(n, insn);
+ }
+
+ /**
+ * Gets the size of this instance, in 16-bit code units. This will only
+ * return a meaningful result if the instructions in this instance all
+ * have valid addresses.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int codeSize() {
+ int sz = size();
+
+ if (sz == 0) {
+ return 0;
+ }
+
+ DalvInsn last = get(sz - 1);
+ return last.getNextAddress();
+ }
+
+ /**
+ * Writes all the instructions in this instance to the given output
+ * destination.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ public void writeTo(AnnotatedOutput out) {
+ int startCursor = out.getCursor();
+ int sz = size();
+
+ if (out.annotates()) {
+ boolean verbose = out.isVerbose();
+
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = (DalvInsn) get0(i);
+ int codeBytes = insn.codeSize() * 2;
+ String s;
+
+ if ((codeBytes != 0) || verbose) {
+ s = insn.listingString(" ", out.getAnnotationWidth(), true);
+ } else {
+ s = null;
}
- result.setImmutable();
- return result;
+ if (s != null) {
+ out.annotate(codeBytes, s);
+ } else if (codeBytes != 0) {
+ out.annotate(codeBytes, "");
+ }
+ }
}
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public DalvInsnList(int size, int regCount) {
- super(size);
- this.regCount = regCount;
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = (DalvInsn) get0(i);
+ try {
+ insn.writeTo(out);
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex, "...while writing " + insn);
+ }
}
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public DalvInsn get(int n) {
- return (DalvInsn) get0(n);
+ // Sanity check of the amount written.
+ int written = (out.getCursor() - startCursor) / 2;
+ if (written != codeSize()) {
+ throw new RuntimeException(
+ "write length mismatch; expected " + codeSize() + " but actually wrote " + written);
+ }
+ }
+
+ /**
+ * Gets the minimum required register count implied by this
+ * instance. This includes any unused parameters that could
+ * potentially be at the top of the register space.
+ * @return {@code >= 0;} the required registers size
+ */
+ public int getRegistersSize() {
+ return regCount;
+ }
+
+ /**
+ * Gets the size of the outgoing arguments area required by this
+ * method. This is equal to the largest argument word count of any
+ * method referred to by this instance.
+ *
+ * @return {@code >= 0;} the required outgoing arguments size
+ */
+ public int getOutsSize() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = (DalvInsn) get0(i);
+
+ if (!(insn instanceof CstInsn)) {
+ continue;
+ }
+
+ Constant cst = ((CstInsn) insn).getConstant();
+
+ if (!(cst instanceof CstBaseMethodRef)) {
+ continue;
+ }
+
+ boolean isStatic = (insn.getOpcode().getFamily() == Opcodes.INVOKE_STATIC);
+ int count = ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
+
+ if (count > result) {
+ result = count;
+ }
}
- /**
- * Sets the instruction at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param insn {@code non-null;} the instruction to set at {@code n}
- */
- public void set(int n, DalvInsn insn) {
- set0(n, insn);
- }
+ return result;
+ }
- /**
- * Gets the size of this instance, in 16-bit code units. This will only
- * return a meaningful result if the instructions in this instance all
- * have valid addresses.
- *
- * @return {@code >= 0;} the size
- */
- public int codeSize() {
- int sz = size();
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
+ * @param verbose whether to be verbose; verbose output includes
+ * lines for zero-size instructions and explicit constant pool indices
+ */
+ public void debugPrint(Writer out, String prefix, boolean verbose) {
+ @SuppressWarnings("resource")
+ IndentingWriter iw = new IndentingWriter(out, 0, prefix);
+ int sz = size();
- if (sz == 0) {
- return 0;
+ try {
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = (DalvInsn) get0(i);
+ String s;
+
+ if ((insn.codeSize() != 0) || verbose) {
+ s = insn.listingString("", 0, verbose);
+ } else {
+ s = null;
}
- DalvInsn last = get(sz - 1);
- return last.getNextAddress();
- }
-
- /**
- * Writes all the instructions in this instance to the given output
- * destination.
- *
- * @param out {@code non-null;} where to write to
- */
- public void writeTo(AnnotatedOutput out) {
- int startCursor = out.getCursor();
- int sz = size();
-
- if (out.annotates()) {
- boolean verbose = out.isVerbose();
-
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = (DalvInsn) get0(i);
- int codeBytes = insn.codeSize() * 2;
- String s;
-
- if ((codeBytes != 0) || verbose) {
- s = insn.listingString(" ", out.getAnnotationWidth(),
- true);
- } else {
- s = null;
- }
-
- if (s != null) {
- out.annotate(codeBytes, s);
- } else if (codeBytes != 0) {
- out.annotate(codeBytes, "");
- }
- }
+ if (s != null) {
+ iw.write(s);
}
+ }
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = (DalvInsn) get0(i);
- try {
- insn.writeTo(out);
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while writing " + insn);
- }
- }
-
- // Sanity check of the amount written.
- int written = (out.getCursor() - startCursor) / 2;
- if (written != codeSize()) {
- throw new RuntimeException("write length mismatch; expected " +
- codeSize() + " but actually wrote " + written);
- }
+ iw.flush();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
}
+ }
- /**
- * Gets the minimum required register count implied by this
- * instance. This includes any unused parameters that could
- * potentially be at the top of the register space.
- * @return {@code >= 0;} the required registers size
- */
- public int getRegistersSize() {
- return regCount;
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
+ * @param verbose whether to be verbose; verbose output includes
+ * lines for zero-size instructions
+ */
+ public void debugPrint(OutputStream out, String prefix, boolean verbose) {
+ Writer w = new OutputStreamWriter(out);
+ debugPrint(w, prefix, verbose);
+
+ try {
+ w.flush();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
}
-
- /**
- * Gets the size of the outgoing arguments area required by this
- * method. This is equal to the largest argument word count of any
- * method referred to by this instance.
- *
- * @return {@code >= 0;} the required outgoing arguments size
- */
- public int getOutsSize() {
- int sz = size();
- int result = 0;
-
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = (DalvInsn) get0(i);
-
- if (!(insn instanceof CstInsn)) {
- continue;
- }
-
- Constant cst = ((CstInsn) insn).getConstant();
-
- if (!(cst instanceof CstBaseMethodRef)) {
- continue;
- }
-
- boolean isStatic =
- (insn.getOpcode().getFamily() == Opcodes.INVOKE_STATIC);
- int count =
- ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
-
- if (count > result) {
- result = count;
- }
- }
-
- return result;
- }
-
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} prefix to attach to each line of output
- * @param verbose whether to be verbose; verbose output includes
- * lines for zero-size instructions and explicit constant pool indices
- */
- public void debugPrint(Writer out, String prefix, boolean verbose) {
- IndentingWriter iw = new IndentingWriter(out, 0, prefix);
- int sz = size();
-
- try {
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = (DalvInsn) get0(i);
- String s;
-
- if ((insn.codeSize() != 0) || verbose) {
- s = insn.listingString("", 0, verbose);
- } else {
- s = null;
- }
-
- if (s != null) {
- iw.write(s);
- }
- }
-
- iw.flush();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} prefix to attach to each line of output
- * @param verbose whether to be verbose; verbose output includes
- * lines for zero-size instructions
- */
- public void debugPrint(OutputStream out, String prefix, boolean verbose) {
- Writer w = new OutputStreamWriter(out);
- debugPrint(w, prefix, verbose);
-
- try {
- w.flush();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/Dop.java b/dx/src/com/android/jack/dx/dex/code/Dop.java
index 5b390aa..0a0cbc2 100644
--- a/dx/src/com/android/jack/dx/dex/code/Dop.java
+++ b/dx/src/com/android/jack/dx/dex/code/Dop.java
@@ -23,151 +23,162 @@
* Representation of an opcode.
*/
public final class Dop {
- /** {@code Opcodes.isValid();} the opcode value itself */
- private final int opcode;
+ /** {@code Opcodes.isValid();} the opcode value itself */
+ private final int opcode;
- /** {@code Opcodes.isValid();} the opcode family */
- private final int family;
+ /** {@code Opcodes.isValid();} the opcode family */
+ private final int family;
- /**
- * {@code Opcodes.isValid();} what opcode (by number) to try next
- * when attempting to match an opcode to particular arguments;
- * {@code Opcodes.NO_NEXT} to indicate that this is the last
- * opcode to try in a particular chain
- */
- private final int nextOpcode;
+ /**
+ * {@code Opcodes.isValid();} what opcode (by number) to try next
+ * when attempting to match an opcode to particular arguments;
+ * {@code Opcodes.NO_NEXT} to indicate that this is the last
+ * opcode to try in a particular chain
+ */
+ private final int nextOpcode;
- /** {@code non-null;} the instruction format */
- private final InsnFormat format;
+ /** {@code non-null;} the instruction format */
+ private final InsnFormat format;
- /** whether this opcode uses a result register */
- private final boolean hasResult;
+ /** whether this opcode uses a result register */
+ private final boolean hasResult;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code Opcodes.isValid();} the opcode value
- * itself
- * @param family {@code Opcodes.isValid();} the opcode family
- * @param nextOpcode {@code Opcodes.isValid();} what opcode (by
- * number) to try next when attempting to match an opcode to
- * particular arguments; {@code Opcodes.NO_NEXT} to indicate that
- * this is the last opcode to try in a particular chain
- * @param format {@code non-null;} the instruction format
- * @param hasResult whether the opcode has a result register; if so it
- * is always the first register
- */
- public Dop(int opcode, int family, int nextOpcode, InsnFormat format,
- boolean hasResult) {
- if (!Opcodes.isValidShape(opcode)) {
- throw new IllegalArgumentException("bogus opcode");
- }
-
- if (!Opcodes.isValidShape(family)) {
- throw new IllegalArgumentException("bogus family");
- }
-
- if (!Opcodes.isValidShape(nextOpcode)) {
- throw new IllegalArgumentException("bogus nextOpcode");
- }
-
- if (format == null) {
- throw new NullPointerException("format == null");
- }
-
- this.opcode = opcode;
- this.family = family;
- this.nextOpcode = nextOpcode;
- this.format = format;
- this.hasResult = hasResult;
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code Opcodes.isValid();} the opcode value
+ * itself
+ * @param family {@code Opcodes.isValid();} the opcode family
+ * @param nextOpcode {@code Opcodes.isValid();} what opcode (by
+ * number) to try next when attempting to match an opcode to
+ * particular arguments; {@code Opcodes.NO_NEXT} to indicate that
+ * this is the last opcode to try in a particular chain
+ * @param format {@code non-null;} the instruction format
+ * @param hasResult whether the opcode has a result register; if so it
+ * is always the first register
+ */
+ public Dop(int opcode, int family, int nextOpcode, InsnFormat format, boolean hasResult) {
+ if (!Opcodes.isValidShape(opcode)) {
+ throw new IllegalArgumentException("bogus opcode");
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return getName();
+ if (!Opcodes.isValidShape(family)) {
+ throw new IllegalArgumentException("bogus family");
}
- /**
- * Gets the opcode value.
- *
- * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
- */
- public int getOpcode() {
- return opcode;
+ if (!Opcodes.isValidShape(nextOpcode)) {
+ throw new IllegalArgumentException("bogus nextOpcode");
}
- /**
- * Gets the opcode family. The opcode family is the unmarked (no
- * "/...") opcode that has equivalent semantics to this one.
- *
- * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode family
- */
- public int getFamily() {
- return family;
+ if (format == null) {
+ throw new NullPointerException("format == null");
}
- /**
- * Gets the instruction format.
- *
- * @return {@code non-null;} the instruction format
- */
- public InsnFormat getFormat() {
- return format;
+ this.opcode = opcode;
+ this.family = family;
+ this.nextOpcode = nextOpcode;
+ this.format = format;
+ this.hasResult = hasResult;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ /**
+ * Gets the opcode value.
+ *
+ * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
+ */
+ public int getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Gets the opcode family. The opcode family is the unmarked (no
+ * "/...") opcode that has equivalent semantics to this one.
+ *
+ * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode family
+ */
+ public int getFamily() {
+ return family;
+ }
+
+ /**
+ * Gets the instruction format.
+ *
+ * @return {@code non-null;} the instruction format
+ */
+ public InsnFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Returns whether this opcode uses a result register.
+ *
+ * @return {@code true} iff this opcode uses a result register
+ */
+ public boolean hasResult() {
+ return hasResult;
+ }
+
+ /**
+ * Gets the opcode name.
+ *
+ * @return {@code non-null;} the opcode name
+ */
+ public String getName() {
+ return OpcodeInfo.getName(opcode);
+ }
+
+ /**
+ * Gets the opcode value to try next when attempting to match an
+ * opcode to particular arguments. This returns {@code
+ * Opcodes.NO_NEXT} to indicate that this is the last opcode to
+ * try in a particular chain.
+ *
+ * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
+ */
+ public int getNextOpcode() {
+ return nextOpcode;
+ }
+
+ /**
+ * Gets the opcode for the opposite test of this instance. This is only
+ * valid for opcodes which are in fact tests.
+ *
+ * @return {@code non-null;} the opposite test
+ */
+ public Dop getOppositeTest() {
+ switch (opcode) {
+ case Opcodes.IF_EQ:
+ return Dops.IF_NE;
+ case Opcodes.IF_NE:
+ return Dops.IF_EQ;
+ case Opcodes.IF_LT:
+ return Dops.IF_GE;
+ case Opcodes.IF_GE:
+ return Dops.IF_LT;
+ case Opcodes.IF_GT:
+ return Dops.IF_LE;
+ case Opcodes.IF_LE:
+ return Dops.IF_GT;
+ case Opcodes.IF_EQZ:
+ return Dops.IF_NEZ;
+ case Opcodes.IF_NEZ:
+ return Dops.IF_EQZ;
+ case Opcodes.IF_LTZ:
+ return Dops.IF_GEZ;
+ case Opcodes.IF_GEZ:
+ return Dops.IF_LTZ;
+ case Opcodes.IF_GTZ:
+ return Dops.IF_LEZ;
+ case Opcodes.IF_LEZ:
+ return Dops.IF_GTZ;
}
- /**
- * Returns whether this opcode uses a result register.
- *
- * @return {@code true} iff this opcode uses a result register
- */
- public boolean hasResult() {
- return hasResult;
- }
-
- /**
- * Gets the opcode name.
- *
- * @return {@code non-null;} the opcode name
- */
- public String getName() {
- return OpcodeInfo.getName(opcode);
- }
-
- /**
- * Gets the opcode value to try next when attempting to match an
- * opcode to particular arguments. This returns {@code
- * Opcodes.NO_NEXT} to indicate that this is the last opcode to
- * try in a particular chain.
- *
- * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
- */
- public int getNextOpcode() {
- return nextOpcode;
- }
-
- /**
- * Gets the opcode for the opposite test of this instance. This is only
- * valid for opcodes which are in fact tests.
- *
- * @return {@code non-null;} the opposite test
- */
- public Dop getOppositeTest() {
- switch (opcode) {
- case Opcodes.IF_EQ: return Dops.IF_NE;
- case Opcodes.IF_NE: return Dops.IF_EQ;
- case Opcodes.IF_LT: return Dops.IF_GE;
- case Opcodes.IF_GE: return Dops.IF_LT;
- case Opcodes.IF_GT: return Dops.IF_LE;
- case Opcodes.IF_LE: return Dops.IF_GT;
- case Opcodes.IF_EQZ: return Dops.IF_NEZ;
- case Opcodes.IF_NEZ: return Dops.IF_EQZ;
- case Opcodes.IF_LTZ: return Dops.IF_GEZ;
- case Opcodes.IF_GEZ: return Dops.IF_LTZ;
- case Opcodes.IF_GTZ: return Dops.IF_LEZ;
- case Opcodes.IF_LEZ: return Dops.IF_GTZ;
- }
-
- throw new IllegalArgumentException("bogus opcode: " + this);
- }
+ throw new IllegalArgumentException("bogus opcode: " + this);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/Dops.java b/dx/src/com/android/jack/dx/dex/code/Dops.java
index 39ea0d3..acaff76 100644
--- a/dx/src/com/android/jack/dx/dex/code/Dops.java
+++ b/dx/src/com/android/jack/dx/dex/code/Dops.java
@@ -49,1181 +49,962 @@
* them.
*/
public final class Dops {
- /** {@code non-null;} array containing all the standard instances */
- private static final Dop[] DOPS;
+ /** {@code non-null;} array containing all the standard instances */
+ private static final Dop[] DOPS;
- /**
- * pseudo-opcode used for nonstandard formatted "instructions"
- * (which are mostly not actually instructions, though they do
- * appear in instruction lists). TODO: Retire the usage of this
- * constant.
- */
- public static final Dop SPECIAL_FORMAT =
- new Dop(Opcodes.SPECIAL_FORMAT, Opcodes.SPECIAL_FORMAT,
- Opcodes.NO_NEXT, SpecialFormat.THE_ONE, false);
+ /**
+ * pseudo-opcode used for nonstandard formatted "instructions"
+ * (which are mostly not actually instructions, though they do
+ * appear in instruction lists). TODO(dx team): Retire the usage of this
+ * constant.
+ */
+ public static final Dop SPECIAL_FORMAT = new Dop(Opcodes.SPECIAL_FORMAT, Opcodes.SPECIAL_FORMAT,
+ Opcodes.NO_NEXT, SpecialFormat.THE_ONE, false);
- // BEGIN(dops); GENERATED AUTOMATICALLY BY opcode-gen
- public static final Dop NOP =
- new Dop(Opcodes.NOP, Opcodes.NOP,
- Opcodes.NO_NEXT, Form10x.THE_ONE, false);
+ // BEGIN(dops); GENERATED AUTOMATICALLY BY opcode-gen
+ public static final Dop NOP =
+ new Dop(Opcodes.NOP, Opcodes.NOP, Opcodes.NO_NEXT, Form10x.THE_ONE, false);
- public static final Dop MOVE =
- new Dop(Opcodes.MOVE, Opcodes.MOVE,
- Opcodes.MOVE_FROM16, Form12x.THE_ONE, true);
+ public static final Dop MOVE =
+ new Dop(Opcodes.MOVE, Opcodes.MOVE, Opcodes.MOVE_FROM16, Form12x.THE_ONE, true);
- public static final Dop MOVE_FROM16 =
- new Dop(Opcodes.MOVE_FROM16, Opcodes.MOVE,
- Opcodes.MOVE_16, Form22x.THE_ONE, true);
+ public static final Dop MOVE_FROM16 =
+ new Dop(Opcodes.MOVE_FROM16, Opcodes.MOVE, Opcodes.MOVE_16, Form22x.THE_ONE, true);
- public static final Dop MOVE_16 =
- new Dop(Opcodes.MOVE_16, Opcodes.MOVE,
- Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+ public static final Dop MOVE_16 =
+ new Dop(Opcodes.MOVE_16, Opcodes.MOVE, Opcodes.NO_NEXT, Form32x.THE_ONE, true);
- public static final Dop MOVE_WIDE =
- new Dop(Opcodes.MOVE_WIDE, Opcodes.MOVE_WIDE,
- Opcodes.MOVE_WIDE_FROM16, Form12x.THE_ONE, true);
+ public static final Dop MOVE_WIDE = new Dop(Opcodes.MOVE_WIDE, Opcodes.MOVE_WIDE,
+ Opcodes.MOVE_WIDE_FROM16, Form12x.THE_ONE, true);
- public static final Dop MOVE_WIDE_FROM16 =
- new Dop(Opcodes.MOVE_WIDE_FROM16, Opcodes.MOVE_WIDE,
- Opcodes.MOVE_WIDE_16, Form22x.THE_ONE, true);
+ public static final Dop MOVE_WIDE_FROM16 = new Dop(Opcodes.MOVE_WIDE_FROM16, Opcodes.MOVE_WIDE,
+ Opcodes.MOVE_WIDE_16, Form22x.THE_ONE, true);
- public static final Dop MOVE_WIDE_16 =
- new Dop(Opcodes.MOVE_WIDE_16, Opcodes.MOVE_WIDE,
- Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+ public static final Dop MOVE_WIDE_16 =
+ new Dop(Opcodes.MOVE_WIDE_16, Opcodes.MOVE_WIDE, Opcodes.NO_NEXT, Form32x.THE_ONE, true);
- public static final Dop MOVE_OBJECT =
- new Dop(Opcodes.MOVE_OBJECT, Opcodes.MOVE_OBJECT,
- Opcodes.MOVE_OBJECT_FROM16, Form12x.THE_ONE, true);
+ public static final Dop MOVE_OBJECT = new Dop(Opcodes.MOVE_OBJECT, Opcodes.MOVE_OBJECT,
+ Opcodes.MOVE_OBJECT_FROM16, Form12x.THE_ONE, true);
- public static final Dop MOVE_OBJECT_FROM16 =
- new Dop(Opcodes.MOVE_OBJECT_FROM16, Opcodes.MOVE_OBJECT,
- Opcodes.MOVE_OBJECT_16, Form22x.THE_ONE, true);
+ public static final Dop MOVE_OBJECT_FROM16 = new Dop(Opcodes.MOVE_OBJECT_FROM16,
+ Opcodes.MOVE_OBJECT, Opcodes.MOVE_OBJECT_16, Form22x.THE_ONE, true);
- public static final Dop MOVE_OBJECT_16 =
- new Dop(Opcodes.MOVE_OBJECT_16, Opcodes.MOVE_OBJECT,
- Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+ public static final Dop MOVE_OBJECT_16 =
+ new Dop(Opcodes.MOVE_OBJECT_16, Opcodes.MOVE_OBJECT, Opcodes.NO_NEXT, Form32x.THE_ONE, true);
- public static final Dop MOVE_RESULT =
- new Dop(Opcodes.MOVE_RESULT, Opcodes.MOVE_RESULT,
- Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+ public static final Dop MOVE_RESULT =
+ new Dop(Opcodes.MOVE_RESULT, Opcodes.MOVE_RESULT, Opcodes.NO_NEXT, Form11x.THE_ONE, true);
- public static final Dop MOVE_RESULT_WIDE =
- new Dop(Opcodes.MOVE_RESULT_WIDE, Opcodes.MOVE_RESULT_WIDE,
- Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+ public static final Dop MOVE_RESULT_WIDE = new Dop(Opcodes.MOVE_RESULT_WIDE,
+ Opcodes.MOVE_RESULT_WIDE, Opcodes.NO_NEXT, Form11x.THE_ONE, true);
- public static final Dop MOVE_RESULT_OBJECT =
- new Dop(Opcodes.MOVE_RESULT_OBJECT, Opcodes.MOVE_RESULT_OBJECT,
- Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+ public static final Dop MOVE_RESULT_OBJECT = new Dop(Opcodes.MOVE_RESULT_OBJECT,
+ Opcodes.MOVE_RESULT_OBJECT, Opcodes.NO_NEXT, Form11x.THE_ONE, true);
- public static final Dop MOVE_EXCEPTION =
- new Dop(Opcodes.MOVE_EXCEPTION, Opcodes.MOVE_EXCEPTION,
- Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+ public static final Dop MOVE_EXCEPTION = new Dop(Opcodes.MOVE_EXCEPTION, Opcodes.MOVE_EXCEPTION,
+ Opcodes.NO_NEXT, Form11x.THE_ONE, true);
- public static final Dop RETURN_VOID =
- new Dop(Opcodes.RETURN_VOID, Opcodes.RETURN_VOID,
- Opcodes.NO_NEXT, Form10x.THE_ONE, false);
+ public static final Dop RETURN_VOID =
+ new Dop(Opcodes.RETURN_VOID, Opcodes.RETURN_VOID, Opcodes.NO_NEXT, Form10x.THE_ONE, false);
- public static final Dop RETURN =
- new Dop(Opcodes.RETURN, Opcodes.RETURN,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop RETURN =
+ new Dop(Opcodes.RETURN, Opcodes.RETURN, Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop RETURN_WIDE =
- new Dop(Opcodes.RETURN_WIDE, Opcodes.RETURN_WIDE,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop RETURN_WIDE =
+ new Dop(Opcodes.RETURN_WIDE, Opcodes.RETURN_WIDE, Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop RETURN_OBJECT =
- new Dop(Opcodes.RETURN_OBJECT, Opcodes.RETURN_OBJECT,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop RETURN_OBJECT = new Dop(Opcodes.RETURN_OBJECT, Opcodes.RETURN_OBJECT,
+ Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop CONST_4 =
- new Dop(Opcodes.CONST_4, Opcodes.CONST,
- Opcodes.CONST_16, Form11n.THE_ONE, true);
+ public static final Dop CONST_4 =
+ new Dop(Opcodes.CONST_4, Opcodes.CONST, Opcodes.CONST_16, Form11n.THE_ONE, true);
- public static final Dop CONST_16 =
- new Dop(Opcodes.CONST_16, Opcodes.CONST,
- Opcodes.CONST_HIGH16, Form21s.THE_ONE, true);
+ public static final Dop CONST_16 =
+ new Dop(Opcodes.CONST_16, Opcodes.CONST, Opcodes.CONST_HIGH16, Form21s.THE_ONE, true);
- public static final Dop CONST =
- new Dop(Opcodes.CONST, Opcodes.CONST,
- Opcodes.NO_NEXT, Form31i.THE_ONE, true);
+ public static final Dop CONST =
+ new Dop(Opcodes.CONST, Opcodes.CONST, Opcodes.NO_NEXT, Form31i.THE_ONE, true);
- public static final Dop CONST_HIGH16 =
- new Dop(Opcodes.CONST_HIGH16, Opcodes.CONST,
- Opcodes.CONST, Form21h.THE_ONE, true);
+ public static final Dop CONST_HIGH16 =
+ new Dop(Opcodes.CONST_HIGH16, Opcodes.CONST, Opcodes.CONST, Form21h.THE_ONE, true);
- public static final Dop CONST_WIDE_16 =
- new Dop(Opcodes.CONST_WIDE_16, Opcodes.CONST_WIDE,
- Opcodes.CONST_WIDE_HIGH16, Form21s.THE_ONE, true);
+ public static final Dop CONST_WIDE_16 = new Dop(Opcodes.CONST_WIDE_16, Opcodes.CONST_WIDE,
+ Opcodes.CONST_WIDE_HIGH16, Form21s.THE_ONE, true);
- public static final Dop CONST_WIDE_32 =
- new Dop(Opcodes.CONST_WIDE_32, Opcodes.CONST_WIDE,
- Opcodes.CONST_WIDE, Form31i.THE_ONE, true);
+ public static final Dop CONST_WIDE_32 =
+ new Dop(Opcodes.CONST_WIDE_32, Opcodes.CONST_WIDE, Opcodes.CONST_WIDE, Form31i.THE_ONE, true);
- public static final Dop CONST_WIDE =
- new Dop(Opcodes.CONST_WIDE, Opcodes.CONST_WIDE,
- Opcodes.NO_NEXT, Form51l.THE_ONE, true);
+ public static final Dop CONST_WIDE =
+ new Dop(Opcodes.CONST_WIDE, Opcodes.CONST_WIDE, Opcodes.NO_NEXT, Form51l.THE_ONE, true);
- public static final Dop CONST_WIDE_HIGH16 =
- new Dop(Opcodes.CONST_WIDE_HIGH16, Opcodes.CONST_WIDE,
- Opcodes.CONST_WIDE_32, Form21h.THE_ONE, true);
+ public static final Dop CONST_WIDE_HIGH16 = new Dop(Opcodes.CONST_WIDE_HIGH16, Opcodes.CONST_WIDE,
+ Opcodes.CONST_WIDE_32, Form21h.THE_ONE, true);
- public static final Dop CONST_STRING =
- new Dop(Opcodes.CONST_STRING, Opcodes.CONST_STRING,
- Opcodes.CONST_STRING_JUMBO, Form21c.THE_ONE, true);
+ public static final Dop CONST_STRING = new Dop(Opcodes.CONST_STRING, Opcodes.CONST_STRING,
+ Opcodes.CONST_STRING_JUMBO, Form21c.THE_ONE, true);
- public static final Dop CONST_STRING_JUMBO =
- new Dop(Opcodes.CONST_STRING_JUMBO, Opcodes.CONST_STRING,
- Opcodes.NO_NEXT, Form31c.THE_ONE, true);
+ public static final Dop CONST_STRING_JUMBO = new Dop(Opcodes.CONST_STRING_JUMBO,
+ Opcodes.CONST_STRING, Opcodes.NO_NEXT, Form31c.THE_ONE, true);
- public static final Dop CONST_CLASS =
- new Dop(Opcodes.CONST_CLASS, Opcodes.CONST_CLASS,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop CONST_CLASS =
+ new Dop(Opcodes.CONST_CLASS, Opcodes.CONST_CLASS, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop MONITOR_ENTER =
- new Dop(Opcodes.MONITOR_ENTER, Opcodes.MONITOR_ENTER,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop MONITOR_ENTER = new Dop(Opcodes.MONITOR_ENTER, Opcodes.MONITOR_ENTER,
+ Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop MONITOR_EXIT =
- new Dop(Opcodes.MONITOR_EXIT, Opcodes.MONITOR_EXIT,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop MONITOR_EXIT =
+ new Dop(Opcodes.MONITOR_EXIT, Opcodes.MONITOR_EXIT, Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop CHECK_CAST =
- new Dop(Opcodes.CHECK_CAST, Opcodes.CHECK_CAST,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop CHECK_CAST =
+ new Dop(Opcodes.CHECK_CAST, Opcodes.CHECK_CAST, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop INSTANCE_OF =
- new Dop(Opcodes.INSTANCE_OF, Opcodes.INSTANCE_OF,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop INSTANCE_OF =
+ new Dop(Opcodes.INSTANCE_OF, Opcodes.INSTANCE_OF, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop ARRAY_LENGTH =
- new Dop(Opcodes.ARRAY_LENGTH, Opcodes.ARRAY_LENGTH,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop ARRAY_LENGTH =
+ new Dop(Opcodes.ARRAY_LENGTH, Opcodes.ARRAY_LENGTH, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NEW_INSTANCE =
- new Dop(Opcodes.NEW_INSTANCE, Opcodes.NEW_INSTANCE,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop NEW_INSTANCE =
+ new Dop(Opcodes.NEW_INSTANCE, Opcodes.NEW_INSTANCE, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop NEW_ARRAY =
- new Dop(Opcodes.NEW_ARRAY, Opcodes.NEW_ARRAY,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop NEW_ARRAY =
+ new Dop(Opcodes.NEW_ARRAY, Opcodes.NEW_ARRAY, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop FILLED_NEW_ARRAY =
- new Dop(Opcodes.FILLED_NEW_ARRAY, Opcodes.FILLED_NEW_ARRAY,
- Opcodes.FILLED_NEW_ARRAY_RANGE, Form35c.THE_ONE, false);
+ public static final Dop FILLED_NEW_ARRAY = new Dop(Opcodes.FILLED_NEW_ARRAY,
+ Opcodes.FILLED_NEW_ARRAY, Opcodes.FILLED_NEW_ARRAY_RANGE, Form35c.THE_ONE, false);
- public static final Dop FILLED_NEW_ARRAY_RANGE =
- new Dop(Opcodes.FILLED_NEW_ARRAY_RANGE, Opcodes.FILLED_NEW_ARRAY,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop FILLED_NEW_ARRAY_RANGE = new Dop(Opcodes.FILLED_NEW_ARRAY_RANGE,
+ Opcodes.FILLED_NEW_ARRAY, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop FILL_ARRAY_DATA =
- new Dop(Opcodes.FILL_ARRAY_DATA, Opcodes.FILL_ARRAY_DATA,
- Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+ public static final Dop FILL_ARRAY_DATA = new Dop(Opcodes.FILL_ARRAY_DATA,
+ Opcodes.FILL_ARRAY_DATA, Opcodes.NO_NEXT, Form31t.THE_ONE, false);
- public static final Dop THROW =
- new Dop(Opcodes.THROW, Opcodes.THROW,
- Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+ public static final Dop THROW =
+ new Dop(Opcodes.THROW, Opcodes.THROW, Opcodes.NO_NEXT, Form11x.THE_ONE, false);
- public static final Dop GOTO =
- new Dop(Opcodes.GOTO, Opcodes.GOTO,
- Opcodes.GOTO_16, Form10t.THE_ONE, false);
+ public static final Dop GOTO =
+ new Dop(Opcodes.GOTO, Opcodes.GOTO, Opcodes.GOTO_16, Form10t.THE_ONE, false);
- public static final Dop GOTO_16 =
- new Dop(Opcodes.GOTO_16, Opcodes.GOTO,
- Opcodes.GOTO_32, Form20t.THE_ONE, false);
+ public static final Dop GOTO_16 =
+ new Dop(Opcodes.GOTO_16, Opcodes.GOTO, Opcodes.GOTO_32, Form20t.THE_ONE, false);
- public static final Dop GOTO_32 =
- new Dop(Opcodes.GOTO_32, Opcodes.GOTO,
- Opcodes.NO_NEXT, Form30t.THE_ONE, false);
+ public static final Dop GOTO_32 =
+ new Dop(Opcodes.GOTO_32, Opcodes.GOTO, Opcodes.NO_NEXT, Form30t.THE_ONE, false);
- public static final Dop PACKED_SWITCH =
- new Dop(Opcodes.PACKED_SWITCH, Opcodes.PACKED_SWITCH,
- Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+ public static final Dop PACKED_SWITCH = new Dop(Opcodes.PACKED_SWITCH, Opcodes.PACKED_SWITCH,
+ Opcodes.NO_NEXT, Form31t.THE_ONE, false);
- public static final Dop SPARSE_SWITCH =
- new Dop(Opcodes.SPARSE_SWITCH, Opcodes.SPARSE_SWITCH,
- Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+ public static final Dop SPARSE_SWITCH = new Dop(Opcodes.SPARSE_SWITCH, Opcodes.SPARSE_SWITCH,
+ Opcodes.NO_NEXT, Form31t.THE_ONE, false);
- public static final Dop CMPL_FLOAT =
- new Dop(Opcodes.CMPL_FLOAT, Opcodes.CMPL_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop CMPL_FLOAT =
+ new Dop(Opcodes.CMPL_FLOAT, Opcodes.CMPL_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop CMPG_FLOAT =
- new Dop(Opcodes.CMPG_FLOAT, Opcodes.CMPG_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop CMPG_FLOAT =
+ new Dop(Opcodes.CMPG_FLOAT, Opcodes.CMPG_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop CMPL_DOUBLE =
- new Dop(Opcodes.CMPL_DOUBLE, Opcodes.CMPL_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop CMPL_DOUBLE =
+ new Dop(Opcodes.CMPL_DOUBLE, Opcodes.CMPL_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop CMPG_DOUBLE =
- new Dop(Opcodes.CMPG_DOUBLE, Opcodes.CMPG_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop CMPG_DOUBLE =
+ new Dop(Opcodes.CMPG_DOUBLE, Opcodes.CMPG_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop CMP_LONG =
- new Dop(Opcodes.CMP_LONG, Opcodes.CMP_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop CMP_LONG =
+ new Dop(Opcodes.CMP_LONG, Opcodes.CMP_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop IF_EQ =
- new Dop(Opcodes.IF_EQ, Opcodes.IF_EQ,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_EQ =
+ new Dop(Opcodes.IF_EQ, Opcodes.IF_EQ, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_NE =
- new Dop(Opcodes.IF_NE, Opcodes.IF_NE,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_NE =
+ new Dop(Opcodes.IF_NE, Opcodes.IF_NE, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_LT =
- new Dop(Opcodes.IF_LT, Opcodes.IF_LT,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_LT =
+ new Dop(Opcodes.IF_LT, Opcodes.IF_LT, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_GE =
- new Dop(Opcodes.IF_GE, Opcodes.IF_GE,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_GE =
+ new Dop(Opcodes.IF_GE, Opcodes.IF_GE, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_GT =
- new Dop(Opcodes.IF_GT, Opcodes.IF_GT,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_GT =
+ new Dop(Opcodes.IF_GT, Opcodes.IF_GT, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_LE =
- new Dop(Opcodes.IF_LE, Opcodes.IF_LE,
- Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+ public static final Dop IF_LE =
+ new Dop(Opcodes.IF_LE, Opcodes.IF_LE, Opcodes.NO_NEXT, Form22t.THE_ONE, false);
- public static final Dop IF_EQZ =
- new Dop(Opcodes.IF_EQZ, Opcodes.IF_EQZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_EQZ =
+ new Dop(Opcodes.IF_EQZ, Opcodes.IF_EQZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop IF_NEZ =
- new Dop(Opcodes.IF_NEZ, Opcodes.IF_NEZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_NEZ =
+ new Dop(Opcodes.IF_NEZ, Opcodes.IF_NEZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop IF_LTZ =
- new Dop(Opcodes.IF_LTZ, Opcodes.IF_LTZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_LTZ =
+ new Dop(Opcodes.IF_LTZ, Opcodes.IF_LTZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop IF_GEZ =
- new Dop(Opcodes.IF_GEZ, Opcodes.IF_GEZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_GEZ =
+ new Dop(Opcodes.IF_GEZ, Opcodes.IF_GEZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop IF_GTZ =
- new Dop(Opcodes.IF_GTZ, Opcodes.IF_GTZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_GTZ =
+ new Dop(Opcodes.IF_GTZ, Opcodes.IF_GTZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop IF_LEZ =
- new Dop(Opcodes.IF_LEZ, Opcodes.IF_LEZ,
- Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+ public static final Dop IF_LEZ =
+ new Dop(Opcodes.IF_LEZ, Opcodes.IF_LEZ, Opcodes.NO_NEXT, Form21t.THE_ONE, false);
- public static final Dop AGET =
- new Dop(Opcodes.AGET, Opcodes.AGET,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET =
+ new Dop(Opcodes.AGET, Opcodes.AGET, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_WIDE =
- new Dop(Opcodes.AGET_WIDE, Opcodes.AGET_WIDE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_WIDE =
+ new Dop(Opcodes.AGET_WIDE, Opcodes.AGET_WIDE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_OBJECT =
- new Dop(Opcodes.AGET_OBJECT, Opcodes.AGET_OBJECT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_OBJECT =
+ new Dop(Opcodes.AGET_OBJECT, Opcodes.AGET_OBJECT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_BOOLEAN =
- new Dop(Opcodes.AGET_BOOLEAN, Opcodes.AGET_BOOLEAN,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_BOOLEAN =
+ new Dop(Opcodes.AGET_BOOLEAN, Opcodes.AGET_BOOLEAN, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_BYTE =
- new Dop(Opcodes.AGET_BYTE, Opcodes.AGET_BYTE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_BYTE =
+ new Dop(Opcodes.AGET_BYTE, Opcodes.AGET_BYTE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_CHAR =
- new Dop(Opcodes.AGET_CHAR, Opcodes.AGET_CHAR,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_CHAR =
+ new Dop(Opcodes.AGET_CHAR, Opcodes.AGET_CHAR, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AGET_SHORT =
- new Dop(Opcodes.AGET_SHORT, Opcodes.AGET_SHORT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AGET_SHORT =
+ new Dop(Opcodes.AGET_SHORT, Opcodes.AGET_SHORT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop APUT =
- new Dop(Opcodes.APUT, Opcodes.APUT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT =
+ new Dop(Opcodes.APUT, Opcodes.APUT, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_WIDE =
- new Dop(Opcodes.APUT_WIDE, Opcodes.APUT_WIDE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_WIDE =
+ new Dop(Opcodes.APUT_WIDE, Opcodes.APUT_WIDE, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_OBJECT =
- new Dop(Opcodes.APUT_OBJECT, Opcodes.APUT_OBJECT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_OBJECT =
+ new Dop(Opcodes.APUT_OBJECT, Opcodes.APUT_OBJECT, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_BOOLEAN =
- new Dop(Opcodes.APUT_BOOLEAN, Opcodes.APUT_BOOLEAN,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_BOOLEAN =
+ new Dop(Opcodes.APUT_BOOLEAN, Opcodes.APUT_BOOLEAN, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_BYTE =
- new Dop(Opcodes.APUT_BYTE, Opcodes.APUT_BYTE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_BYTE =
+ new Dop(Opcodes.APUT_BYTE, Opcodes.APUT_BYTE, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_CHAR =
- new Dop(Opcodes.APUT_CHAR, Opcodes.APUT_CHAR,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_CHAR =
+ new Dop(Opcodes.APUT_CHAR, Opcodes.APUT_CHAR, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop APUT_SHORT =
- new Dop(Opcodes.APUT_SHORT, Opcodes.APUT_SHORT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+ public static final Dop APUT_SHORT =
+ new Dop(Opcodes.APUT_SHORT, Opcodes.APUT_SHORT, Opcodes.NO_NEXT, Form23x.THE_ONE, false);
- public static final Dop IGET =
- new Dop(Opcodes.IGET, Opcodes.IGET,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET =
+ new Dop(Opcodes.IGET, Opcodes.IGET, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_WIDE =
- new Dop(Opcodes.IGET_WIDE, Opcodes.IGET_WIDE,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_WIDE =
+ new Dop(Opcodes.IGET_WIDE, Opcodes.IGET_WIDE, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_OBJECT =
- new Dop(Opcodes.IGET_OBJECT, Opcodes.IGET_OBJECT,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_OBJECT =
+ new Dop(Opcodes.IGET_OBJECT, Opcodes.IGET_OBJECT, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_BOOLEAN =
- new Dop(Opcodes.IGET_BOOLEAN, Opcodes.IGET_BOOLEAN,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_BOOLEAN =
+ new Dop(Opcodes.IGET_BOOLEAN, Opcodes.IGET_BOOLEAN, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_BYTE =
- new Dop(Opcodes.IGET_BYTE, Opcodes.IGET_BYTE,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_BYTE =
+ new Dop(Opcodes.IGET_BYTE, Opcodes.IGET_BYTE, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_CHAR =
- new Dop(Opcodes.IGET_CHAR, Opcodes.IGET_CHAR,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_CHAR =
+ new Dop(Opcodes.IGET_CHAR, Opcodes.IGET_CHAR, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IGET_SHORT =
- new Dop(Opcodes.IGET_SHORT, Opcodes.IGET_SHORT,
- Opcodes.NO_NEXT, Form22c.THE_ONE, true);
+ public static final Dop IGET_SHORT =
+ new Dop(Opcodes.IGET_SHORT, Opcodes.IGET_SHORT, Opcodes.NO_NEXT, Form22c.THE_ONE, true);
- public static final Dop IPUT =
- new Dop(Opcodes.IPUT, Opcodes.IPUT,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT =
+ new Dop(Opcodes.IPUT, Opcodes.IPUT, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_WIDE =
- new Dop(Opcodes.IPUT_WIDE, Opcodes.IPUT_WIDE,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_WIDE =
+ new Dop(Opcodes.IPUT_WIDE, Opcodes.IPUT_WIDE, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_OBJECT =
- new Dop(Opcodes.IPUT_OBJECT, Opcodes.IPUT_OBJECT,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_OBJECT =
+ new Dop(Opcodes.IPUT_OBJECT, Opcodes.IPUT_OBJECT, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_BOOLEAN =
- new Dop(Opcodes.IPUT_BOOLEAN, Opcodes.IPUT_BOOLEAN,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_BOOLEAN =
+ new Dop(Opcodes.IPUT_BOOLEAN, Opcodes.IPUT_BOOLEAN, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_BYTE =
- new Dop(Opcodes.IPUT_BYTE, Opcodes.IPUT_BYTE,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_BYTE =
+ new Dop(Opcodes.IPUT_BYTE, Opcodes.IPUT_BYTE, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_CHAR =
- new Dop(Opcodes.IPUT_CHAR, Opcodes.IPUT_CHAR,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_CHAR =
+ new Dop(Opcodes.IPUT_CHAR, Opcodes.IPUT_CHAR, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop IPUT_SHORT =
- new Dop(Opcodes.IPUT_SHORT, Opcodes.IPUT_SHORT,
- Opcodes.NO_NEXT, Form22c.THE_ONE, false);
+ public static final Dop IPUT_SHORT =
+ new Dop(Opcodes.IPUT_SHORT, Opcodes.IPUT_SHORT, Opcodes.NO_NEXT, Form22c.THE_ONE, false);
- public static final Dop SGET =
- new Dop(Opcodes.SGET, Opcodes.SGET,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET =
+ new Dop(Opcodes.SGET, Opcodes.SGET, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_WIDE =
- new Dop(Opcodes.SGET_WIDE, Opcodes.SGET_WIDE,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_WIDE =
+ new Dop(Opcodes.SGET_WIDE, Opcodes.SGET_WIDE, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_OBJECT =
- new Dop(Opcodes.SGET_OBJECT, Opcodes.SGET_OBJECT,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_OBJECT =
+ new Dop(Opcodes.SGET_OBJECT, Opcodes.SGET_OBJECT, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_BOOLEAN =
- new Dop(Opcodes.SGET_BOOLEAN, Opcodes.SGET_BOOLEAN,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_BOOLEAN =
+ new Dop(Opcodes.SGET_BOOLEAN, Opcodes.SGET_BOOLEAN, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_BYTE =
- new Dop(Opcodes.SGET_BYTE, Opcodes.SGET_BYTE,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_BYTE =
+ new Dop(Opcodes.SGET_BYTE, Opcodes.SGET_BYTE, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_CHAR =
- new Dop(Opcodes.SGET_CHAR, Opcodes.SGET_CHAR,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_CHAR =
+ new Dop(Opcodes.SGET_CHAR, Opcodes.SGET_CHAR, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SGET_SHORT =
- new Dop(Opcodes.SGET_SHORT, Opcodes.SGET_SHORT,
- Opcodes.NO_NEXT, Form21c.THE_ONE, true);
+ public static final Dop SGET_SHORT =
+ new Dop(Opcodes.SGET_SHORT, Opcodes.SGET_SHORT, Opcodes.NO_NEXT, Form21c.THE_ONE, true);
- public static final Dop SPUT =
- new Dop(Opcodes.SPUT, Opcodes.SPUT,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT =
+ new Dop(Opcodes.SPUT, Opcodes.SPUT, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_WIDE =
- new Dop(Opcodes.SPUT_WIDE, Opcodes.SPUT_WIDE,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_WIDE =
+ new Dop(Opcodes.SPUT_WIDE, Opcodes.SPUT_WIDE, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_OBJECT =
- new Dop(Opcodes.SPUT_OBJECT, Opcodes.SPUT_OBJECT,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_OBJECT =
+ new Dop(Opcodes.SPUT_OBJECT, Opcodes.SPUT_OBJECT, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_BOOLEAN =
- new Dop(Opcodes.SPUT_BOOLEAN, Opcodes.SPUT_BOOLEAN,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_BOOLEAN =
+ new Dop(Opcodes.SPUT_BOOLEAN, Opcodes.SPUT_BOOLEAN, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_BYTE =
- new Dop(Opcodes.SPUT_BYTE, Opcodes.SPUT_BYTE,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_BYTE =
+ new Dop(Opcodes.SPUT_BYTE, Opcodes.SPUT_BYTE, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_CHAR =
- new Dop(Opcodes.SPUT_CHAR, Opcodes.SPUT_CHAR,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_CHAR =
+ new Dop(Opcodes.SPUT_CHAR, Opcodes.SPUT_CHAR, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop SPUT_SHORT =
- new Dop(Opcodes.SPUT_SHORT, Opcodes.SPUT_SHORT,
- Opcodes.NO_NEXT, Form21c.THE_ONE, false);
+ public static final Dop SPUT_SHORT =
+ new Dop(Opcodes.SPUT_SHORT, Opcodes.SPUT_SHORT, Opcodes.NO_NEXT, Form21c.THE_ONE, false);
- public static final Dop INVOKE_VIRTUAL =
- new Dop(Opcodes.INVOKE_VIRTUAL, Opcodes.INVOKE_VIRTUAL,
- Opcodes.INVOKE_VIRTUAL_RANGE, Form35c.THE_ONE, false);
+ public static final Dop INVOKE_VIRTUAL = new Dop(Opcodes.INVOKE_VIRTUAL, Opcodes.INVOKE_VIRTUAL,
+ Opcodes.INVOKE_VIRTUAL_RANGE, Form35c.THE_ONE, false);
- public static final Dop INVOKE_SUPER =
- new Dop(Opcodes.INVOKE_SUPER, Opcodes.INVOKE_SUPER,
- Opcodes.INVOKE_SUPER_RANGE, Form35c.THE_ONE, false);
+ public static final Dop INVOKE_SUPER = new Dop(Opcodes.INVOKE_SUPER, Opcodes.INVOKE_SUPER,
+ Opcodes.INVOKE_SUPER_RANGE, Form35c.THE_ONE, false);
- public static final Dop INVOKE_DIRECT =
- new Dop(Opcodes.INVOKE_DIRECT, Opcodes.INVOKE_DIRECT,
- Opcodes.INVOKE_DIRECT_RANGE, Form35c.THE_ONE, false);
+ public static final Dop INVOKE_DIRECT = new Dop(Opcodes.INVOKE_DIRECT, Opcodes.INVOKE_DIRECT,
+ Opcodes.INVOKE_DIRECT_RANGE, Form35c.THE_ONE, false);
- public static final Dop INVOKE_STATIC =
- new Dop(Opcodes.INVOKE_STATIC, Opcodes.INVOKE_STATIC,
- Opcodes.INVOKE_STATIC_RANGE, Form35c.THE_ONE, false);
+ public static final Dop INVOKE_STATIC = new Dop(Opcodes.INVOKE_STATIC, Opcodes.INVOKE_STATIC,
+ Opcodes.INVOKE_STATIC_RANGE, Form35c.THE_ONE, false);
- public static final Dop INVOKE_INTERFACE =
- new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE,
- Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false);
+ public static final Dop INVOKE_INTERFACE = new Dop(Opcodes.INVOKE_INTERFACE,
+ Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false);
- public static final Dop INVOKE_VIRTUAL_RANGE =
- new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop INVOKE_VIRTUAL_RANGE = new Dop(Opcodes.INVOKE_VIRTUAL_RANGE,
+ Opcodes.INVOKE_VIRTUAL, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop INVOKE_SUPER_RANGE =
- new Dop(Opcodes.INVOKE_SUPER_RANGE, Opcodes.INVOKE_SUPER,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop INVOKE_SUPER_RANGE = new Dop(Opcodes.INVOKE_SUPER_RANGE,
+ Opcodes.INVOKE_SUPER, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop INVOKE_DIRECT_RANGE =
- new Dop(Opcodes.INVOKE_DIRECT_RANGE, Opcodes.INVOKE_DIRECT,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop INVOKE_DIRECT_RANGE = new Dop(Opcodes.INVOKE_DIRECT_RANGE,
+ Opcodes.INVOKE_DIRECT, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop INVOKE_STATIC_RANGE =
- new Dop(Opcodes.INVOKE_STATIC_RANGE, Opcodes.INVOKE_STATIC,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop INVOKE_STATIC_RANGE = new Dop(Opcodes.INVOKE_STATIC_RANGE,
+ Opcodes.INVOKE_STATIC, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop INVOKE_INTERFACE_RANGE =
- new Dop(Opcodes.INVOKE_INTERFACE_RANGE, Opcodes.INVOKE_INTERFACE,
- Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
+ public static final Dop INVOKE_INTERFACE_RANGE = new Dop(Opcodes.INVOKE_INTERFACE_RANGE,
+ Opcodes.INVOKE_INTERFACE, Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
- public static final Dop NEG_INT =
- new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NEG_INT =
+ new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NOT_INT =
- new Dop(Opcodes.NOT_INT, Opcodes.NOT_INT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NOT_INT =
+ new Dop(Opcodes.NOT_INT, Opcodes.NOT_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NEG_LONG =
- new Dop(Opcodes.NEG_LONG, Opcodes.NEG_LONG,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NEG_LONG =
+ new Dop(Opcodes.NEG_LONG, Opcodes.NEG_LONG, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NOT_LONG =
- new Dop(Opcodes.NOT_LONG, Opcodes.NOT_LONG,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NOT_LONG =
+ new Dop(Opcodes.NOT_LONG, Opcodes.NOT_LONG, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NEG_FLOAT =
- new Dop(Opcodes.NEG_FLOAT, Opcodes.NEG_FLOAT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NEG_FLOAT =
+ new Dop(Opcodes.NEG_FLOAT, Opcodes.NEG_FLOAT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop NEG_DOUBLE =
- new Dop(Opcodes.NEG_DOUBLE, Opcodes.NEG_DOUBLE,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop NEG_DOUBLE =
+ new Dop(Opcodes.NEG_DOUBLE, Opcodes.NEG_DOUBLE, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_LONG =
- new Dop(Opcodes.INT_TO_LONG, Opcodes.INT_TO_LONG,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_LONG =
+ new Dop(Opcodes.INT_TO_LONG, Opcodes.INT_TO_LONG, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_FLOAT =
- new Dop(Opcodes.INT_TO_FLOAT, Opcodes.INT_TO_FLOAT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_FLOAT =
+ new Dop(Opcodes.INT_TO_FLOAT, Opcodes.INT_TO_FLOAT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_DOUBLE =
- new Dop(Opcodes.INT_TO_DOUBLE, Opcodes.INT_TO_DOUBLE,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_DOUBLE =
+ new Dop(Opcodes.INT_TO_DOUBLE, Opcodes.INT_TO_DOUBLE, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop LONG_TO_INT =
- new Dop(Opcodes.LONG_TO_INT, Opcodes.LONG_TO_INT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop LONG_TO_INT =
+ new Dop(Opcodes.LONG_TO_INT, Opcodes.LONG_TO_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop LONG_TO_FLOAT =
- new Dop(Opcodes.LONG_TO_FLOAT, Opcodes.LONG_TO_FLOAT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop LONG_TO_FLOAT =
+ new Dop(Opcodes.LONG_TO_FLOAT, Opcodes.LONG_TO_FLOAT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop LONG_TO_DOUBLE =
- new Dop(Opcodes.LONG_TO_DOUBLE, Opcodes.LONG_TO_DOUBLE,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop LONG_TO_DOUBLE = new Dop(Opcodes.LONG_TO_DOUBLE, Opcodes.LONG_TO_DOUBLE,
+ Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop FLOAT_TO_INT =
- new Dop(Opcodes.FLOAT_TO_INT, Opcodes.FLOAT_TO_INT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop FLOAT_TO_INT =
+ new Dop(Opcodes.FLOAT_TO_INT, Opcodes.FLOAT_TO_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop FLOAT_TO_LONG =
- new Dop(Opcodes.FLOAT_TO_LONG, Opcodes.FLOAT_TO_LONG,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop FLOAT_TO_LONG =
+ new Dop(Opcodes.FLOAT_TO_LONG, Opcodes.FLOAT_TO_LONG, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop FLOAT_TO_DOUBLE =
- new Dop(Opcodes.FLOAT_TO_DOUBLE, Opcodes.FLOAT_TO_DOUBLE,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop FLOAT_TO_DOUBLE = new Dop(Opcodes.FLOAT_TO_DOUBLE,
+ Opcodes.FLOAT_TO_DOUBLE, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop DOUBLE_TO_INT =
- new Dop(Opcodes.DOUBLE_TO_INT, Opcodes.DOUBLE_TO_INT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop DOUBLE_TO_INT =
+ new Dop(Opcodes.DOUBLE_TO_INT, Opcodes.DOUBLE_TO_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop DOUBLE_TO_LONG =
- new Dop(Opcodes.DOUBLE_TO_LONG, Opcodes.DOUBLE_TO_LONG,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop DOUBLE_TO_LONG = new Dop(Opcodes.DOUBLE_TO_LONG, Opcodes.DOUBLE_TO_LONG,
+ Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop DOUBLE_TO_FLOAT =
- new Dop(Opcodes.DOUBLE_TO_FLOAT, Opcodes.DOUBLE_TO_FLOAT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop DOUBLE_TO_FLOAT = new Dop(Opcodes.DOUBLE_TO_FLOAT,
+ Opcodes.DOUBLE_TO_FLOAT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_BYTE =
- new Dop(Opcodes.INT_TO_BYTE, Opcodes.INT_TO_BYTE,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_BYTE =
+ new Dop(Opcodes.INT_TO_BYTE, Opcodes.INT_TO_BYTE, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_CHAR =
- new Dop(Opcodes.INT_TO_CHAR, Opcodes.INT_TO_CHAR,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_CHAR =
+ new Dop(Opcodes.INT_TO_CHAR, Opcodes.INT_TO_CHAR, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop INT_TO_SHORT =
- new Dop(Opcodes.INT_TO_SHORT, Opcodes.INT_TO_SHORT,
- Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+ public static final Dop INT_TO_SHORT =
+ new Dop(Opcodes.INT_TO_SHORT, Opcodes.INT_TO_SHORT, Opcodes.NO_NEXT, Form12x.THE_ONE, true);
- public static final Dop ADD_INT =
- new Dop(Opcodes.ADD_INT, Opcodes.ADD_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop ADD_INT =
+ new Dop(Opcodes.ADD_INT, Opcodes.ADD_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SUB_INT =
- new Dop(Opcodes.SUB_INT, Opcodes.SUB_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SUB_INT =
+ new Dop(Opcodes.SUB_INT, Opcodes.SUB_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop MUL_INT =
- new Dop(Opcodes.MUL_INT, Opcodes.MUL_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop MUL_INT =
+ new Dop(Opcodes.MUL_INT, Opcodes.MUL_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop DIV_INT =
- new Dop(Opcodes.DIV_INT, Opcodes.DIV_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop DIV_INT =
+ new Dop(Opcodes.DIV_INT, Opcodes.DIV_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop REM_INT =
- new Dop(Opcodes.REM_INT, Opcodes.REM_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop REM_INT =
+ new Dop(Opcodes.REM_INT, Opcodes.REM_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AND_INT =
- new Dop(Opcodes.AND_INT, Opcodes.AND_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AND_INT =
+ new Dop(Opcodes.AND_INT, Opcodes.AND_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop OR_INT =
- new Dop(Opcodes.OR_INT, Opcodes.OR_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop OR_INT =
+ new Dop(Opcodes.OR_INT, Opcodes.OR_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop XOR_INT =
- new Dop(Opcodes.XOR_INT, Opcodes.XOR_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop XOR_INT =
+ new Dop(Opcodes.XOR_INT, Opcodes.XOR_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SHL_INT =
- new Dop(Opcodes.SHL_INT, Opcodes.SHL_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SHL_INT =
+ new Dop(Opcodes.SHL_INT, Opcodes.SHL_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SHR_INT =
- new Dop(Opcodes.SHR_INT, Opcodes.SHR_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SHR_INT =
+ new Dop(Opcodes.SHR_INT, Opcodes.SHR_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop USHR_INT =
- new Dop(Opcodes.USHR_INT, Opcodes.USHR_INT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop USHR_INT =
+ new Dop(Opcodes.USHR_INT, Opcodes.USHR_INT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop ADD_LONG =
- new Dop(Opcodes.ADD_LONG, Opcodes.ADD_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop ADD_LONG =
+ new Dop(Opcodes.ADD_LONG, Opcodes.ADD_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SUB_LONG =
- new Dop(Opcodes.SUB_LONG, Opcodes.SUB_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SUB_LONG =
+ new Dop(Opcodes.SUB_LONG, Opcodes.SUB_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop MUL_LONG =
- new Dop(Opcodes.MUL_LONG, Opcodes.MUL_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop MUL_LONG =
+ new Dop(Opcodes.MUL_LONG, Opcodes.MUL_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop DIV_LONG =
- new Dop(Opcodes.DIV_LONG, Opcodes.DIV_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop DIV_LONG =
+ new Dop(Opcodes.DIV_LONG, Opcodes.DIV_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop REM_LONG =
- new Dop(Opcodes.REM_LONG, Opcodes.REM_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop REM_LONG =
+ new Dop(Opcodes.REM_LONG, Opcodes.REM_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop AND_LONG =
- new Dop(Opcodes.AND_LONG, Opcodes.AND_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop AND_LONG =
+ new Dop(Opcodes.AND_LONG, Opcodes.AND_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop OR_LONG =
- new Dop(Opcodes.OR_LONG, Opcodes.OR_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop OR_LONG =
+ new Dop(Opcodes.OR_LONG, Opcodes.OR_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop XOR_LONG =
- new Dop(Opcodes.XOR_LONG, Opcodes.XOR_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop XOR_LONG =
+ new Dop(Opcodes.XOR_LONG, Opcodes.XOR_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SHL_LONG =
- new Dop(Opcodes.SHL_LONG, Opcodes.SHL_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SHL_LONG =
+ new Dop(Opcodes.SHL_LONG, Opcodes.SHL_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SHR_LONG =
- new Dop(Opcodes.SHR_LONG, Opcodes.SHR_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SHR_LONG =
+ new Dop(Opcodes.SHR_LONG, Opcodes.SHR_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop USHR_LONG =
- new Dop(Opcodes.USHR_LONG, Opcodes.USHR_LONG,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop USHR_LONG =
+ new Dop(Opcodes.USHR_LONG, Opcodes.USHR_LONG, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop ADD_FLOAT =
- new Dop(Opcodes.ADD_FLOAT, Opcodes.ADD_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop ADD_FLOAT =
+ new Dop(Opcodes.ADD_FLOAT, Opcodes.ADD_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SUB_FLOAT =
- new Dop(Opcodes.SUB_FLOAT, Opcodes.SUB_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
-
- public static final Dop MUL_FLOAT =
- new Dop(Opcodes.MUL_FLOAT, Opcodes.MUL_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
-
- public static final Dop DIV_FLOAT =
- new Dop(Opcodes.DIV_FLOAT, Opcodes.DIV_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
-
- public static final Dop REM_FLOAT =
- new Dop(Opcodes.REM_FLOAT, Opcodes.REM_FLOAT,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SUB_FLOAT =
+ new Dop(Opcodes.SUB_FLOAT, Opcodes.SUB_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop ADD_DOUBLE =
- new Dop(Opcodes.ADD_DOUBLE, Opcodes.ADD_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop MUL_FLOAT =
+ new Dop(Opcodes.MUL_FLOAT, Opcodes.MUL_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SUB_DOUBLE =
- new Dop(Opcodes.SUB_DOUBLE, Opcodes.SUB_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop DIV_FLOAT =
+ new Dop(Opcodes.DIV_FLOAT, Opcodes.DIV_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop MUL_DOUBLE =
- new Dop(Opcodes.MUL_DOUBLE, Opcodes.MUL_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop REM_FLOAT =
+ new Dop(Opcodes.REM_FLOAT, Opcodes.REM_FLOAT, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop DIV_DOUBLE =
- new Dop(Opcodes.DIV_DOUBLE, Opcodes.DIV_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop ADD_DOUBLE =
+ new Dop(Opcodes.ADD_DOUBLE, Opcodes.ADD_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop REM_DOUBLE =
- new Dop(Opcodes.REM_DOUBLE, Opcodes.REM_DOUBLE,
- Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+ public static final Dop SUB_DOUBLE =
+ new Dop(Opcodes.SUB_DOUBLE, Opcodes.SUB_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop ADD_INT_2ADDR =
- new Dop(Opcodes.ADD_INT_2ADDR, Opcodes.ADD_INT,
- Opcodes.ADD_INT, Form12x.THE_ONE, true);
+ public static final Dop MUL_DOUBLE =
+ new Dop(Opcodes.MUL_DOUBLE, Opcodes.MUL_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop SUB_INT_2ADDR =
- new Dop(Opcodes.SUB_INT_2ADDR, Opcodes.SUB_INT,
- Opcodes.SUB_INT, Form12x.THE_ONE, true);
+ public static final Dop DIV_DOUBLE =
+ new Dop(Opcodes.DIV_DOUBLE, Opcodes.DIV_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop MUL_INT_2ADDR =
- new Dop(Opcodes.MUL_INT_2ADDR, Opcodes.MUL_INT,
- Opcodes.MUL_INT, Form12x.THE_ONE, true);
+ public static final Dop REM_DOUBLE =
+ new Dop(Opcodes.REM_DOUBLE, Opcodes.REM_DOUBLE, Opcodes.NO_NEXT, Form23x.THE_ONE, true);
- public static final Dop DIV_INT_2ADDR =
- new Dop(Opcodes.DIV_INT_2ADDR, Opcodes.DIV_INT,
- Opcodes.DIV_INT, Form12x.THE_ONE, true);
+ public static final Dop ADD_INT_2ADDR =
+ new Dop(Opcodes.ADD_INT_2ADDR, Opcodes.ADD_INT, Opcodes.ADD_INT, Form12x.THE_ONE, true);
- public static final Dop REM_INT_2ADDR =
- new Dop(Opcodes.REM_INT_2ADDR, Opcodes.REM_INT,
- Opcodes.REM_INT, Form12x.THE_ONE, true);
+ public static final Dop SUB_INT_2ADDR =
+ new Dop(Opcodes.SUB_INT_2ADDR, Opcodes.SUB_INT, Opcodes.SUB_INT, Form12x.THE_ONE, true);
- public static final Dop AND_INT_2ADDR =
- new Dop(Opcodes.AND_INT_2ADDR, Opcodes.AND_INT,
- Opcodes.AND_INT, Form12x.THE_ONE, true);
+ public static final Dop MUL_INT_2ADDR =
+ new Dop(Opcodes.MUL_INT_2ADDR, Opcodes.MUL_INT, Opcodes.MUL_INT, Form12x.THE_ONE, true);
- public static final Dop OR_INT_2ADDR =
- new Dop(Opcodes.OR_INT_2ADDR, Opcodes.OR_INT,
- Opcodes.OR_INT, Form12x.THE_ONE, true);
+ public static final Dop DIV_INT_2ADDR =
+ new Dop(Opcodes.DIV_INT_2ADDR, Opcodes.DIV_INT, Opcodes.DIV_INT, Form12x.THE_ONE, true);
- public static final Dop XOR_INT_2ADDR =
- new Dop(Opcodes.XOR_INT_2ADDR, Opcodes.XOR_INT,
- Opcodes.XOR_INT, Form12x.THE_ONE, true);
+ public static final Dop REM_INT_2ADDR =
+ new Dop(Opcodes.REM_INT_2ADDR, Opcodes.REM_INT, Opcodes.REM_INT, Form12x.THE_ONE, true);
- public static final Dop SHL_INT_2ADDR =
- new Dop(Opcodes.SHL_INT_2ADDR, Opcodes.SHL_INT,
- Opcodes.SHL_INT, Form12x.THE_ONE, true);
+ public static final Dop AND_INT_2ADDR =
+ new Dop(Opcodes.AND_INT_2ADDR, Opcodes.AND_INT, Opcodes.AND_INT, Form12x.THE_ONE, true);
- public static final Dop SHR_INT_2ADDR =
- new Dop(Opcodes.SHR_INT_2ADDR, Opcodes.SHR_INT,
- Opcodes.SHR_INT, Form12x.THE_ONE, true);
+ public static final Dop OR_INT_2ADDR =
+ new Dop(Opcodes.OR_INT_2ADDR, Opcodes.OR_INT, Opcodes.OR_INT, Form12x.THE_ONE, true);
- public static final Dop USHR_INT_2ADDR =
- new Dop(Opcodes.USHR_INT_2ADDR, Opcodes.USHR_INT,
- Opcodes.USHR_INT, Form12x.THE_ONE, true);
+ public static final Dop XOR_INT_2ADDR =
+ new Dop(Opcodes.XOR_INT_2ADDR, Opcodes.XOR_INT, Opcodes.XOR_INT, Form12x.THE_ONE, true);
- public static final Dop ADD_LONG_2ADDR =
- new Dop(Opcodes.ADD_LONG_2ADDR, Opcodes.ADD_LONG,
- Opcodes.ADD_LONG, Form12x.THE_ONE, true);
+ public static final Dop SHL_INT_2ADDR =
+ new Dop(Opcodes.SHL_INT_2ADDR, Opcodes.SHL_INT, Opcodes.SHL_INT, Form12x.THE_ONE, true);
- public static final Dop SUB_LONG_2ADDR =
- new Dop(Opcodes.SUB_LONG_2ADDR, Opcodes.SUB_LONG,
- Opcodes.SUB_LONG, Form12x.THE_ONE, true);
+ public static final Dop SHR_INT_2ADDR =
+ new Dop(Opcodes.SHR_INT_2ADDR, Opcodes.SHR_INT, Opcodes.SHR_INT, Form12x.THE_ONE, true);
- public static final Dop MUL_LONG_2ADDR =
- new Dop(Opcodes.MUL_LONG_2ADDR, Opcodes.MUL_LONG,
- Opcodes.MUL_LONG, Form12x.THE_ONE, true);
+ public static final Dop USHR_INT_2ADDR =
+ new Dop(Opcodes.USHR_INT_2ADDR, Opcodes.USHR_INT, Opcodes.USHR_INT, Form12x.THE_ONE, true);
- public static final Dop DIV_LONG_2ADDR =
- new Dop(Opcodes.DIV_LONG_2ADDR, Opcodes.DIV_LONG,
- Opcodes.DIV_LONG, Form12x.THE_ONE, true);
+ public static final Dop ADD_LONG_2ADDR =
+ new Dop(Opcodes.ADD_LONG_2ADDR, Opcodes.ADD_LONG, Opcodes.ADD_LONG, Form12x.THE_ONE, true);
- public static final Dop REM_LONG_2ADDR =
- new Dop(Opcodes.REM_LONG_2ADDR, Opcodes.REM_LONG,
- Opcodes.REM_LONG, Form12x.THE_ONE, true);
+ public static final Dop SUB_LONG_2ADDR =
+ new Dop(Opcodes.SUB_LONG_2ADDR, Opcodes.SUB_LONG, Opcodes.SUB_LONG, Form12x.THE_ONE, true);
- public static final Dop AND_LONG_2ADDR =
- new Dop(Opcodes.AND_LONG_2ADDR, Opcodes.AND_LONG,
- Opcodes.AND_LONG, Form12x.THE_ONE, true);
+ public static final Dop MUL_LONG_2ADDR =
+ new Dop(Opcodes.MUL_LONG_2ADDR, Opcodes.MUL_LONG, Opcodes.MUL_LONG, Form12x.THE_ONE, true);
- public static final Dop OR_LONG_2ADDR =
- new Dop(Opcodes.OR_LONG_2ADDR, Opcodes.OR_LONG,
- Opcodes.OR_LONG, Form12x.THE_ONE, true);
+ public static final Dop DIV_LONG_2ADDR =
+ new Dop(Opcodes.DIV_LONG_2ADDR, Opcodes.DIV_LONG, Opcodes.DIV_LONG, Form12x.THE_ONE, true);
- public static final Dop XOR_LONG_2ADDR =
- new Dop(Opcodes.XOR_LONG_2ADDR, Opcodes.XOR_LONG,
- Opcodes.XOR_LONG, Form12x.THE_ONE, true);
+ public static final Dop REM_LONG_2ADDR =
+ new Dop(Opcodes.REM_LONG_2ADDR, Opcodes.REM_LONG, Opcodes.REM_LONG, Form12x.THE_ONE, true);
- public static final Dop SHL_LONG_2ADDR =
- new Dop(Opcodes.SHL_LONG_2ADDR, Opcodes.SHL_LONG,
- Opcodes.SHL_LONG, Form12x.THE_ONE, true);
+ public static final Dop AND_LONG_2ADDR =
+ new Dop(Opcodes.AND_LONG_2ADDR, Opcodes.AND_LONG, Opcodes.AND_LONG, Form12x.THE_ONE, true);
- public static final Dop SHR_LONG_2ADDR =
- new Dop(Opcodes.SHR_LONG_2ADDR, Opcodes.SHR_LONG,
- Opcodes.SHR_LONG, Form12x.THE_ONE, true);
+ public static final Dop OR_LONG_2ADDR =
+ new Dop(Opcodes.OR_LONG_2ADDR, Opcodes.OR_LONG, Opcodes.OR_LONG, Form12x.THE_ONE, true);
- public static final Dop USHR_LONG_2ADDR =
- new Dop(Opcodes.USHR_LONG_2ADDR, Opcodes.USHR_LONG,
- Opcodes.USHR_LONG, Form12x.THE_ONE, true);
+ public static final Dop XOR_LONG_2ADDR =
+ new Dop(Opcodes.XOR_LONG_2ADDR, Opcodes.XOR_LONG, Opcodes.XOR_LONG, Form12x.THE_ONE, true);
- public static final Dop ADD_FLOAT_2ADDR =
- new Dop(Opcodes.ADD_FLOAT_2ADDR, Opcodes.ADD_FLOAT,
- Opcodes.ADD_FLOAT, Form12x.THE_ONE, true);
+ public static final Dop SHL_LONG_2ADDR =
+ new Dop(Opcodes.SHL_LONG_2ADDR, Opcodes.SHL_LONG, Opcodes.SHL_LONG, Form12x.THE_ONE, true);
- public static final Dop SUB_FLOAT_2ADDR =
- new Dop(Opcodes.SUB_FLOAT_2ADDR, Opcodes.SUB_FLOAT,
- Opcodes.SUB_FLOAT, Form12x.THE_ONE, true);
+ public static final Dop SHR_LONG_2ADDR =
+ new Dop(Opcodes.SHR_LONG_2ADDR, Opcodes.SHR_LONG, Opcodes.SHR_LONG, Form12x.THE_ONE, true);
- public static final Dop MUL_FLOAT_2ADDR =
- new Dop(Opcodes.MUL_FLOAT_2ADDR, Opcodes.MUL_FLOAT,
- Opcodes.MUL_FLOAT, Form12x.THE_ONE, true);
+ public static final Dop USHR_LONG_2ADDR =
+ new Dop(Opcodes.USHR_LONG_2ADDR, Opcodes.USHR_LONG, Opcodes.USHR_LONG, Form12x.THE_ONE, true);
- public static final Dop DIV_FLOAT_2ADDR =
- new Dop(Opcodes.DIV_FLOAT_2ADDR, Opcodes.DIV_FLOAT,
- Opcodes.DIV_FLOAT, Form12x.THE_ONE, true);
+ public static final Dop ADD_FLOAT_2ADDR =
+ new Dop(Opcodes.ADD_FLOAT_2ADDR, Opcodes.ADD_FLOAT, Opcodes.ADD_FLOAT, Form12x.THE_ONE, true);
- public static final Dop REM_FLOAT_2ADDR =
- new Dop(Opcodes.REM_FLOAT_2ADDR, Opcodes.REM_FLOAT,
- Opcodes.REM_FLOAT, Form12x.THE_ONE, true);
+ public static final Dop SUB_FLOAT_2ADDR =
+ new Dop(Opcodes.SUB_FLOAT_2ADDR, Opcodes.SUB_FLOAT, Opcodes.SUB_FLOAT, Form12x.THE_ONE, true);
- public static final Dop ADD_DOUBLE_2ADDR =
- new Dop(Opcodes.ADD_DOUBLE_2ADDR, Opcodes.ADD_DOUBLE,
- Opcodes.ADD_DOUBLE, Form12x.THE_ONE, true);
+ public static final Dop MUL_FLOAT_2ADDR =
+ new Dop(Opcodes.MUL_FLOAT_2ADDR, Opcodes.MUL_FLOAT, Opcodes.MUL_FLOAT, Form12x.THE_ONE, true);
- public static final Dop SUB_DOUBLE_2ADDR =
- new Dop(Opcodes.SUB_DOUBLE_2ADDR, Opcodes.SUB_DOUBLE,
- Opcodes.SUB_DOUBLE, Form12x.THE_ONE, true);
+ public static final Dop DIV_FLOAT_2ADDR =
+ new Dop(Opcodes.DIV_FLOAT_2ADDR, Opcodes.DIV_FLOAT, Opcodes.DIV_FLOAT, Form12x.THE_ONE, true);
- public static final Dop MUL_DOUBLE_2ADDR =
- new Dop(Opcodes.MUL_DOUBLE_2ADDR, Opcodes.MUL_DOUBLE,
- Opcodes.MUL_DOUBLE, Form12x.THE_ONE, true);
+ public static final Dop REM_FLOAT_2ADDR =
+ new Dop(Opcodes.REM_FLOAT_2ADDR, Opcodes.REM_FLOAT, Opcodes.REM_FLOAT, Form12x.THE_ONE, true);
- public static final Dop DIV_DOUBLE_2ADDR =
- new Dop(Opcodes.DIV_DOUBLE_2ADDR, Opcodes.DIV_DOUBLE,
- Opcodes.DIV_DOUBLE, Form12x.THE_ONE, true);
+ public static final Dop ADD_DOUBLE_2ADDR = new Dop(Opcodes.ADD_DOUBLE_2ADDR, Opcodes.ADD_DOUBLE,
+ Opcodes.ADD_DOUBLE, Form12x.THE_ONE, true);
- public static final Dop REM_DOUBLE_2ADDR =
- new Dop(Opcodes.REM_DOUBLE_2ADDR, Opcodes.REM_DOUBLE,
- Opcodes.REM_DOUBLE, Form12x.THE_ONE, true);
+ public static final Dop SUB_DOUBLE_2ADDR = new Dop(Opcodes.SUB_DOUBLE_2ADDR, Opcodes.SUB_DOUBLE,
+ Opcodes.SUB_DOUBLE, Form12x.THE_ONE, true);
- public static final Dop ADD_INT_LIT16 =
- new Dop(Opcodes.ADD_INT_LIT16, Opcodes.ADD_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop MUL_DOUBLE_2ADDR = new Dop(Opcodes.MUL_DOUBLE_2ADDR, Opcodes.MUL_DOUBLE,
+ Opcodes.MUL_DOUBLE, Form12x.THE_ONE, true);
- public static final Dop RSUB_INT =
- new Dop(Opcodes.RSUB_INT, Opcodes.RSUB_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop DIV_DOUBLE_2ADDR = new Dop(Opcodes.DIV_DOUBLE_2ADDR, Opcodes.DIV_DOUBLE,
+ Opcodes.DIV_DOUBLE, Form12x.THE_ONE, true);
- public static final Dop MUL_INT_LIT16 =
- new Dop(Opcodes.MUL_INT_LIT16, Opcodes.MUL_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop REM_DOUBLE_2ADDR = new Dop(Opcodes.REM_DOUBLE_2ADDR, Opcodes.REM_DOUBLE,
+ Opcodes.REM_DOUBLE, Form12x.THE_ONE, true);
- public static final Dop DIV_INT_LIT16 =
- new Dop(Opcodes.DIV_INT_LIT16, Opcodes.DIV_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop ADD_INT_LIT16 =
+ new Dop(Opcodes.ADD_INT_LIT16, Opcodes.ADD_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop REM_INT_LIT16 =
- new Dop(Opcodes.REM_INT_LIT16, Opcodes.REM_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop RSUB_INT =
+ new Dop(Opcodes.RSUB_INT, Opcodes.RSUB_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop AND_INT_LIT16 =
- new Dop(Opcodes.AND_INT_LIT16, Opcodes.AND_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop MUL_INT_LIT16 =
+ new Dop(Opcodes.MUL_INT_LIT16, Opcodes.MUL_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop OR_INT_LIT16 =
- new Dop(Opcodes.OR_INT_LIT16, Opcodes.OR_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop DIV_INT_LIT16 =
+ new Dop(Opcodes.DIV_INT_LIT16, Opcodes.DIV_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop XOR_INT_LIT16 =
- new Dop(Opcodes.XOR_INT_LIT16, Opcodes.XOR_INT,
- Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+ public static final Dop REM_INT_LIT16 =
+ new Dop(Opcodes.REM_INT_LIT16, Opcodes.REM_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop ADD_INT_LIT8 =
- new Dop(Opcodes.ADD_INT_LIT8, Opcodes.ADD_INT,
- Opcodes.ADD_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop AND_INT_LIT16 =
+ new Dop(Opcodes.AND_INT_LIT16, Opcodes.AND_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop RSUB_INT_LIT8 =
- new Dop(Opcodes.RSUB_INT_LIT8, Opcodes.RSUB_INT,
- Opcodes.RSUB_INT, Form22b.THE_ONE, true);
+ public static final Dop OR_INT_LIT16 =
+ new Dop(Opcodes.OR_INT_LIT16, Opcodes.OR_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop MUL_INT_LIT8 =
- new Dop(Opcodes.MUL_INT_LIT8, Opcodes.MUL_INT,
- Opcodes.MUL_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop XOR_INT_LIT16 =
+ new Dop(Opcodes.XOR_INT_LIT16, Opcodes.XOR_INT, Opcodes.NO_NEXT, Form22s.THE_ONE, true);
- public static final Dop DIV_INT_LIT8 =
- new Dop(Opcodes.DIV_INT_LIT8, Opcodes.DIV_INT,
- Opcodes.DIV_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop ADD_INT_LIT8 =
+ new Dop(Opcodes.ADD_INT_LIT8, Opcodes.ADD_INT, Opcodes.ADD_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop REM_INT_LIT8 =
- new Dop(Opcodes.REM_INT_LIT8, Opcodes.REM_INT,
- Opcodes.REM_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop RSUB_INT_LIT8 =
+ new Dop(Opcodes.RSUB_INT_LIT8, Opcodes.RSUB_INT, Opcodes.RSUB_INT, Form22b.THE_ONE, true);
- public static final Dop AND_INT_LIT8 =
- new Dop(Opcodes.AND_INT_LIT8, Opcodes.AND_INT,
- Opcodes.AND_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop MUL_INT_LIT8 =
+ new Dop(Opcodes.MUL_INT_LIT8, Opcodes.MUL_INT, Opcodes.MUL_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop OR_INT_LIT8 =
- new Dop(Opcodes.OR_INT_LIT8, Opcodes.OR_INT,
- Opcodes.OR_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop DIV_INT_LIT8 =
+ new Dop(Opcodes.DIV_INT_LIT8, Opcodes.DIV_INT, Opcodes.DIV_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop XOR_INT_LIT8 =
- new Dop(Opcodes.XOR_INT_LIT8, Opcodes.XOR_INT,
- Opcodes.XOR_INT_LIT16, Form22b.THE_ONE, true);
+ public static final Dop REM_INT_LIT8 =
+ new Dop(Opcodes.REM_INT_LIT8, Opcodes.REM_INT, Opcodes.REM_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop SHL_INT_LIT8 =
- new Dop(Opcodes.SHL_INT_LIT8, Opcodes.SHL_INT,
- Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+ public static final Dop AND_INT_LIT8 =
+ new Dop(Opcodes.AND_INT_LIT8, Opcodes.AND_INT, Opcodes.AND_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop SHR_INT_LIT8 =
- new Dop(Opcodes.SHR_INT_LIT8, Opcodes.SHR_INT,
- Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+ public static final Dop OR_INT_LIT8 =
+ new Dop(Opcodes.OR_INT_LIT8, Opcodes.OR_INT, Opcodes.OR_INT_LIT16, Form22b.THE_ONE, true);
- public static final Dop USHR_INT_LIT8 =
- new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT,
- Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+ public static final Dop XOR_INT_LIT8 =
+ new Dop(Opcodes.XOR_INT_LIT8, Opcodes.XOR_INT, Opcodes.XOR_INT_LIT16, Form22b.THE_ONE, true);
- // END(dops)
+ public static final Dop SHL_INT_LIT8 =
+ new Dop(Opcodes.SHL_INT_LIT8, Opcodes.SHL_INT, Opcodes.NO_NEXT, Form22b.THE_ONE, true);
- // Static initialization.
- static {
- DOPS = new Dop[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
+ public static final Dop SHR_INT_LIT8 =
+ new Dop(Opcodes.SHR_INT_LIT8, Opcodes.SHR_INT, Opcodes.NO_NEXT, Form22b.THE_ONE, true);
- set(SPECIAL_FORMAT);
+ public static final Dop USHR_INT_LIT8 =
+ new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT, Opcodes.NO_NEXT, Form22b.THE_ONE, true);
- // BEGIN(dops-init); GENERATED AUTOMATICALLY BY opcode-gen
- set(NOP);
- set(MOVE);
- set(MOVE_FROM16);
- set(MOVE_16);
- set(MOVE_WIDE);
- set(MOVE_WIDE_FROM16);
- set(MOVE_WIDE_16);
- set(MOVE_OBJECT);
- set(MOVE_OBJECT_FROM16);
- set(MOVE_OBJECT_16);
- set(MOVE_RESULT);
- set(MOVE_RESULT_WIDE);
- set(MOVE_RESULT_OBJECT);
- set(MOVE_EXCEPTION);
- set(RETURN_VOID);
- set(RETURN);
- set(RETURN_WIDE);
- set(RETURN_OBJECT);
- set(CONST_4);
- set(CONST_16);
- set(CONST);
- set(CONST_HIGH16);
- set(CONST_WIDE_16);
- set(CONST_WIDE_32);
- set(CONST_WIDE);
- set(CONST_WIDE_HIGH16);
- set(CONST_STRING);
- set(CONST_STRING_JUMBO);
- set(CONST_CLASS);
- set(MONITOR_ENTER);
- set(MONITOR_EXIT);
- set(CHECK_CAST);
- set(INSTANCE_OF);
- set(ARRAY_LENGTH);
- set(NEW_INSTANCE);
- set(NEW_ARRAY);
- set(FILLED_NEW_ARRAY);
- set(FILLED_NEW_ARRAY_RANGE);
- set(FILL_ARRAY_DATA);
- set(THROW);
- set(GOTO);
- set(GOTO_16);
- set(GOTO_32);
- set(PACKED_SWITCH);
- set(SPARSE_SWITCH);
- set(CMPL_FLOAT);
- set(CMPG_FLOAT);
- set(CMPL_DOUBLE);
- set(CMPG_DOUBLE);
- set(CMP_LONG);
- set(IF_EQ);
- set(IF_NE);
- set(IF_LT);
- set(IF_GE);
- set(IF_GT);
- set(IF_LE);
- set(IF_EQZ);
- set(IF_NEZ);
- set(IF_LTZ);
- set(IF_GEZ);
- set(IF_GTZ);
- set(IF_LEZ);
- set(AGET);
- set(AGET_WIDE);
- set(AGET_OBJECT);
- set(AGET_BOOLEAN);
- set(AGET_BYTE);
- set(AGET_CHAR);
- set(AGET_SHORT);
- set(APUT);
- set(APUT_WIDE);
- set(APUT_OBJECT);
- set(APUT_BOOLEAN);
- set(APUT_BYTE);
- set(APUT_CHAR);
- set(APUT_SHORT);
- set(IGET);
- set(IGET_WIDE);
- set(IGET_OBJECT);
- set(IGET_BOOLEAN);
- set(IGET_BYTE);
- set(IGET_CHAR);
- set(IGET_SHORT);
- set(IPUT);
- set(IPUT_WIDE);
- set(IPUT_OBJECT);
- set(IPUT_BOOLEAN);
- set(IPUT_BYTE);
- set(IPUT_CHAR);
- set(IPUT_SHORT);
- set(SGET);
- set(SGET_WIDE);
- set(SGET_OBJECT);
- set(SGET_BOOLEAN);
- set(SGET_BYTE);
- set(SGET_CHAR);
- set(SGET_SHORT);
- set(SPUT);
- set(SPUT_WIDE);
- set(SPUT_OBJECT);
- set(SPUT_BOOLEAN);
- set(SPUT_BYTE);
- set(SPUT_CHAR);
- set(SPUT_SHORT);
- set(INVOKE_VIRTUAL);
- set(INVOKE_SUPER);
- set(INVOKE_DIRECT);
- set(INVOKE_STATIC);
- set(INVOKE_INTERFACE);
- set(INVOKE_VIRTUAL_RANGE);
- set(INVOKE_SUPER_RANGE);
- set(INVOKE_DIRECT_RANGE);
- set(INVOKE_STATIC_RANGE);
- set(INVOKE_INTERFACE_RANGE);
- set(NEG_INT);
- set(NOT_INT);
- set(NEG_LONG);
- set(NOT_LONG);
- set(NEG_FLOAT);
- set(NEG_DOUBLE);
- set(INT_TO_LONG);
- set(INT_TO_FLOAT);
- set(INT_TO_DOUBLE);
- set(LONG_TO_INT);
- set(LONG_TO_FLOAT);
- set(LONG_TO_DOUBLE);
- set(FLOAT_TO_INT);
- set(FLOAT_TO_LONG);
- set(FLOAT_TO_DOUBLE);
- set(DOUBLE_TO_INT);
- set(DOUBLE_TO_LONG);
- set(DOUBLE_TO_FLOAT);
- set(INT_TO_BYTE);
- set(INT_TO_CHAR);
- set(INT_TO_SHORT);
- set(ADD_INT);
- set(SUB_INT);
- set(MUL_INT);
- set(DIV_INT);
- set(REM_INT);
- set(AND_INT);
- set(OR_INT);
- set(XOR_INT);
- set(SHL_INT);
- set(SHR_INT);
- set(USHR_INT);
- set(ADD_LONG);
- set(SUB_LONG);
- set(MUL_LONG);
- set(DIV_LONG);
- set(REM_LONG);
- set(AND_LONG);
- set(OR_LONG);
- set(XOR_LONG);
- set(SHL_LONG);
- set(SHR_LONG);
- set(USHR_LONG);
- set(ADD_FLOAT);
- set(SUB_FLOAT);
- set(MUL_FLOAT);
- set(DIV_FLOAT);
- set(REM_FLOAT);
- set(ADD_DOUBLE);
- set(SUB_DOUBLE);
- set(MUL_DOUBLE);
- set(DIV_DOUBLE);
- set(REM_DOUBLE);
- set(ADD_INT_2ADDR);
- set(SUB_INT_2ADDR);
- set(MUL_INT_2ADDR);
- set(DIV_INT_2ADDR);
- set(REM_INT_2ADDR);
- set(AND_INT_2ADDR);
- set(OR_INT_2ADDR);
- set(XOR_INT_2ADDR);
- set(SHL_INT_2ADDR);
- set(SHR_INT_2ADDR);
- set(USHR_INT_2ADDR);
- set(ADD_LONG_2ADDR);
- set(SUB_LONG_2ADDR);
- set(MUL_LONG_2ADDR);
- set(DIV_LONG_2ADDR);
- set(REM_LONG_2ADDR);
- set(AND_LONG_2ADDR);
- set(OR_LONG_2ADDR);
- set(XOR_LONG_2ADDR);
- set(SHL_LONG_2ADDR);
- set(SHR_LONG_2ADDR);
- set(USHR_LONG_2ADDR);
- set(ADD_FLOAT_2ADDR);
- set(SUB_FLOAT_2ADDR);
- set(MUL_FLOAT_2ADDR);
- set(DIV_FLOAT_2ADDR);
- set(REM_FLOAT_2ADDR);
- set(ADD_DOUBLE_2ADDR);
- set(SUB_DOUBLE_2ADDR);
- set(MUL_DOUBLE_2ADDR);
- set(DIV_DOUBLE_2ADDR);
- set(REM_DOUBLE_2ADDR);
- set(ADD_INT_LIT16);
- set(RSUB_INT);
- set(MUL_INT_LIT16);
- set(DIV_INT_LIT16);
- set(REM_INT_LIT16);
- set(AND_INT_LIT16);
- set(OR_INT_LIT16);
- set(XOR_INT_LIT16);
- set(ADD_INT_LIT8);
- set(RSUB_INT_LIT8);
- set(MUL_INT_LIT8);
- set(DIV_INT_LIT8);
- set(REM_INT_LIT8);
- set(AND_INT_LIT8);
- set(OR_INT_LIT8);
- set(XOR_INT_LIT8);
- set(SHL_INT_LIT8);
- set(SHR_INT_LIT8);
- set(USHR_INT_LIT8);
- // END(dops-init)
- }
+ // END(dops)
- /**
- * This class is uninstantiable.
- */
- private Dops() {
- // This space intentionally left blank.
- }
+ // Static initialization.
+ static {
+ DOPS = new Dop[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
- /**
- * Gets the {@link Dop} for the given opcode value.
- *
- * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
- * opcode value
- * @return {@code non-null;} the associated opcode instance
- */
- public static Dop get(int opcode) {
- int idx = opcode - Opcodes.MIN_VALUE;
+ set(SPECIAL_FORMAT);
- try {
- Dop result = DOPS[idx];
- if (result != null) {
- return result;
- }
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Fall through.
- }
+ // BEGIN(dops-init); GENERATED AUTOMATICALLY BY opcode-gen
+ set(NOP);
+ set(MOVE);
+ set(MOVE_FROM16);
+ set(MOVE_16);
+ set(MOVE_WIDE);
+ set(MOVE_WIDE_FROM16);
+ set(MOVE_WIDE_16);
+ set(MOVE_OBJECT);
+ set(MOVE_OBJECT_FROM16);
+ set(MOVE_OBJECT_16);
+ set(MOVE_RESULT);
+ set(MOVE_RESULT_WIDE);
+ set(MOVE_RESULT_OBJECT);
+ set(MOVE_EXCEPTION);
+ set(RETURN_VOID);
+ set(RETURN);
+ set(RETURN_WIDE);
+ set(RETURN_OBJECT);
+ set(CONST_4);
+ set(CONST_16);
+ set(CONST);
+ set(CONST_HIGH16);
+ set(CONST_WIDE_16);
+ set(CONST_WIDE_32);
+ set(CONST_WIDE);
+ set(CONST_WIDE_HIGH16);
+ set(CONST_STRING);
+ set(CONST_STRING_JUMBO);
+ set(CONST_CLASS);
+ set(MONITOR_ENTER);
+ set(MONITOR_EXIT);
+ set(CHECK_CAST);
+ set(INSTANCE_OF);
+ set(ARRAY_LENGTH);
+ set(NEW_INSTANCE);
+ set(NEW_ARRAY);
+ set(FILLED_NEW_ARRAY);
+ set(FILLED_NEW_ARRAY_RANGE);
+ set(FILL_ARRAY_DATA);
+ set(THROW);
+ set(GOTO);
+ set(GOTO_16);
+ set(GOTO_32);
+ set(PACKED_SWITCH);
+ set(SPARSE_SWITCH);
+ set(CMPL_FLOAT);
+ set(CMPG_FLOAT);
+ set(CMPL_DOUBLE);
+ set(CMPG_DOUBLE);
+ set(CMP_LONG);
+ set(IF_EQ);
+ set(IF_NE);
+ set(IF_LT);
+ set(IF_GE);
+ set(IF_GT);
+ set(IF_LE);
+ set(IF_EQZ);
+ set(IF_NEZ);
+ set(IF_LTZ);
+ set(IF_GEZ);
+ set(IF_GTZ);
+ set(IF_LEZ);
+ set(AGET);
+ set(AGET_WIDE);
+ set(AGET_OBJECT);
+ set(AGET_BOOLEAN);
+ set(AGET_BYTE);
+ set(AGET_CHAR);
+ set(AGET_SHORT);
+ set(APUT);
+ set(APUT_WIDE);
+ set(APUT_OBJECT);
+ set(APUT_BOOLEAN);
+ set(APUT_BYTE);
+ set(APUT_CHAR);
+ set(APUT_SHORT);
+ set(IGET);
+ set(IGET_WIDE);
+ set(IGET_OBJECT);
+ set(IGET_BOOLEAN);
+ set(IGET_BYTE);
+ set(IGET_CHAR);
+ set(IGET_SHORT);
+ set(IPUT);
+ set(IPUT_WIDE);
+ set(IPUT_OBJECT);
+ set(IPUT_BOOLEAN);
+ set(IPUT_BYTE);
+ set(IPUT_CHAR);
+ set(IPUT_SHORT);
+ set(SGET);
+ set(SGET_WIDE);
+ set(SGET_OBJECT);
+ set(SGET_BOOLEAN);
+ set(SGET_BYTE);
+ set(SGET_CHAR);
+ set(SGET_SHORT);
+ set(SPUT);
+ set(SPUT_WIDE);
+ set(SPUT_OBJECT);
+ set(SPUT_BOOLEAN);
+ set(SPUT_BYTE);
+ set(SPUT_CHAR);
+ set(SPUT_SHORT);
+ set(INVOKE_VIRTUAL);
+ set(INVOKE_SUPER);
+ set(INVOKE_DIRECT);
+ set(INVOKE_STATIC);
+ set(INVOKE_INTERFACE);
+ set(INVOKE_VIRTUAL_RANGE);
+ set(INVOKE_SUPER_RANGE);
+ set(INVOKE_DIRECT_RANGE);
+ set(INVOKE_STATIC_RANGE);
+ set(INVOKE_INTERFACE_RANGE);
+ set(NEG_INT);
+ set(NOT_INT);
+ set(NEG_LONG);
+ set(NOT_LONG);
+ set(NEG_FLOAT);
+ set(NEG_DOUBLE);
+ set(INT_TO_LONG);
+ set(INT_TO_FLOAT);
+ set(INT_TO_DOUBLE);
+ set(LONG_TO_INT);
+ set(LONG_TO_FLOAT);
+ set(LONG_TO_DOUBLE);
+ set(FLOAT_TO_INT);
+ set(FLOAT_TO_LONG);
+ set(FLOAT_TO_DOUBLE);
+ set(DOUBLE_TO_INT);
+ set(DOUBLE_TO_LONG);
+ set(DOUBLE_TO_FLOAT);
+ set(INT_TO_BYTE);
+ set(INT_TO_CHAR);
+ set(INT_TO_SHORT);
+ set(ADD_INT);
+ set(SUB_INT);
+ set(MUL_INT);
+ set(DIV_INT);
+ set(REM_INT);
+ set(AND_INT);
+ set(OR_INT);
+ set(XOR_INT);
+ set(SHL_INT);
+ set(SHR_INT);
+ set(USHR_INT);
+ set(ADD_LONG);
+ set(SUB_LONG);
+ set(MUL_LONG);
+ set(DIV_LONG);
+ set(REM_LONG);
+ set(AND_LONG);
+ set(OR_LONG);
+ set(XOR_LONG);
+ set(SHL_LONG);
+ set(SHR_LONG);
+ set(USHR_LONG);
+ set(ADD_FLOAT);
+ set(SUB_FLOAT);
+ set(MUL_FLOAT);
+ set(DIV_FLOAT);
+ set(REM_FLOAT);
+ set(ADD_DOUBLE);
+ set(SUB_DOUBLE);
+ set(MUL_DOUBLE);
+ set(DIV_DOUBLE);
+ set(REM_DOUBLE);
+ set(ADD_INT_2ADDR);
+ set(SUB_INT_2ADDR);
+ set(MUL_INT_2ADDR);
+ set(DIV_INT_2ADDR);
+ set(REM_INT_2ADDR);
+ set(AND_INT_2ADDR);
+ set(OR_INT_2ADDR);
+ set(XOR_INT_2ADDR);
+ set(SHL_INT_2ADDR);
+ set(SHR_INT_2ADDR);
+ set(USHR_INT_2ADDR);
+ set(ADD_LONG_2ADDR);
+ set(SUB_LONG_2ADDR);
+ set(MUL_LONG_2ADDR);
+ set(DIV_LONG_2ADDR);
+ set(REM_LONG_2ADDR);
+ set(AND_LONG_2ADDR);
+ set(OR_LONG_2ADDR);
+ set(XOR_LONG_2ADDR);
+ set(SHL_LONG_2ADDR);
+ set(SHR_LONG_2ADDR);
+ set(USHR_LONG_2ADDR);
+ set(ADD_FLOAT_2ADDR);
+ set(SUB_FLOAT_2ADDR);
+ set(MUL_FLOAT_2ADDR);
+ set(DIV_FLOAT_2ADDR);
+ set(REM_FLOAT_2ADDR);
+ set(ADD_DOUBLE_2ADDR);
+ set(SUB_DOUBLE_2ADDR);
+ set(MUL_DOUBLE_2ADDR);
+ set(DIV_DOUBLE_2ADDR);
+ set(REM_DOUBLE_2ADDR);
+ set(ADD_INT_LIT16);
+ set(RSUB_INT);
+ set(MUL_INT_LIT16);
+ set(DIV_INT_LIT16);
+ set(REM_INT_LIT16);
+ set(AND_INT_LIT16);
+ set(OR_INT_LIT16);
+ set(XOR_INT_LIT16);
+ set(ADD_INT_LIT8);
+ set(RSUB_INT_LIT8);
+ set(MUL_INT_LIT8);
+ set(DIV_INT_LIT8);
+ set(REM_INT_LIT8);
+ set(AND_INT_LIT8);
+ set(OR_INT_LIT8);
+ set(XOR_INT_LIT8);
+ set(SHL_INT_LIT8);
+ set(SHR_INT_LIT8);
+ set(USHR_INT_LIT8);
+ // END(dops-init)
+ }
- throw new IllegalArgumentException("bogus opcode");
- }
+ /**
+ * This class is uninstantiable.
+ */
+ private Dops() {
+ // This space intentionally left blank.
+ }
- /**
- * Gets the next {@link Dop} in the instruction fitting chain after the
- * given instance, if any.
- *
- * @param opcode {@code non-null;} the opcode
- * @param options {@code non-null;} options, used to determine
- * which opcodes are potentially off-limits
- * @return {@code null-ok;} the next opcode in the same family, in the
- * chain of opcodes to try, or {@code null} if the given opcode is
- * the last in its chain
- */
- public static Dop getNextOrNull(Dop opcode, DexOptions options) {
- int nextOpcode = opcode.getNextOpcode();
+ /**
+ * Gets the {@link Dop} for the given opcode value.
+ *
+ * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
+ * opcode value
+ * @return {@code non-null;} the associated opcode instance
+ */
+ public static Dop get(int opcode) {
+ int idx = opcode - Opcodes.MIN_VALUE;
- if (nextOpcode == Opcodes.NO_NEXT) {
- return null;
+ try {
+ Dop result = DOPS[idx];
+ if (result != null) {
+ return result;
}
-
- opcode = get(nextOpcode);
-
- return opcode;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Fall through.
}
- /**
- * Puts the given opcode into the table of all ops.
- *
- * @param opcode {@code non-null;} the opcode
- */
- private static void set(Dop opcode) {
- int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
- DOPS[idx] = opcode;
+ throw new IllegalArgumentException("bogus opcode");
+ }
+
+ /**
+ * Gets the next {@link Dop} in the instruction fitting chain after the
+ * given instance, if any.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param options {@code non-null;} options, used to determine
+ * which opcodes are potentially off-limits
+ * @return {@code null-ok;} the next opcode in the same family, in the
+ * chain of opcodes to try, or {@code null} if the given opcode is
+ * the last in its chain
+ */
+ public static Dop getNextOrNull(Dop opcode, DexOptions options) {
+ int nextOpcode = opcode.getNextOpcode();
+
+ if (nextOpcode == Opcodes.NO_NEXT) {
+ return null;
}
+
+ opcode = get(nextOpcode);
+
+ return opcode;
+ }
+
+ /**
+ * Puts the given opcode into the table of all ops.
+ *
+ * @param opcode {@code non-null;} the opcode
+ */
+ private static void set(Dop opcode) {
+ int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
+ DOPS[idx] = opcode;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/FixedSizeInsn.java b/dx/src/com/android/jack/dx/dex/code/FixedSizeInsn.java
index d3ab83c..5718b61 100644
--- a/dx/src/com/android/jack/dx/dex/code/FixedSizeInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/FixedSizeInsn.java
@@ -26,48 +26,47 @@
* includes most — but not all — instructions.
*/
public abstract class FixedSizeInsn extends DalvInsn {
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * <p><b>Note:</b> In the unlikely event that an instruction takes
- * absolutely no registers (e.g., a {@code nop} or a
- * no-argument no-result * static method call), then the given
- * register list may be passed as {@link
- * RegisterSpecList#EMPTY}.</p>
- *
- * @param opcode the opcode; one of the constants from {@link Dops}
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} register list, including a
- * result register if appropriate (that is, registers may be either
- * ins or outs)
- */
- public FixedSizeInsn(Dop opcode, SourcePosition position,
- RegisterSpecList registers) {
- super(opcode, position, registers);
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * <p><b>Note:</b> In the unlikely event that an instruction takes
+ * absolutely no registers (e.g., a {@code nop} or a
+ * no-argument no-result * static method call), then the given
+ * register list may be passed as {@link
+ * RegisterSpecList#EMPTY}.</p>
+ *
+ * @param opcode the opcode; one of the constants from {@link Dops}
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
+ * result register if appropriate (that is, registers may be either
+ * ins or outs)
+ */
+ public FixedSizeInsn(Dop opcode, SourcePosition position, RegisterSpecList registers) {
+ super(opcode, position, registers);
+ }
- /** {@inheritDoc} */
- @Override
- public final int codeSize() {
- return getOpcode().getFormat().codeSize();
- }
+ /** {@inheritDoc} */
+ @Override
+ public final int codeSize() {
+ return getOpcode().getFormat().codeSize();
+ }
- /** {@inheritDoc} */
- @Override
- public final void writeTo(AnnotatedOutput out) {
- getOpcode().getFormat().writeTo(out, this);
- }
+ /** {@inheritDoc} */
+ @Override
+ public final void writeTo(AnnotatedOutput out) {
+ getOpcode().getFormat().writeTo(out, this);
+ }
- /** {@inheritDoc} */
- @Override
- public final DalvInsn withRegisterOffset(int delta) {
- return withRegisters(getRegisters().withOffset(delta));
- }
+ /** {@inheritDoc} */
+ @Override
+ public final DalvInsn withRegisterOffset(int delta) {
+ return withRegisters(getRegisters().withOffset(delta));
+ }
- /** {@inheritDoc} */
- @Override
- protected final String listingString0(boolean noteIndices) {
- return getOpcode().getFormat().listingString(this, noteIndices);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected final String listingString0(boolean noteIndices) {
+ return getOpcode().getFormat().listingString(this, noteIndices);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/HighRegisterPrefix.java b/dx/src/com/android/jack/dx/dex/code/HighRegisterPrefix.java
index 424db5e..8f9b185 100644
--- a/dx/src/com/android/jack/dx/dex/code/HighRegisterPrefix.java
+++ b/dx/src/com/android/jack/dx/dex/code/HighRegisterPrefix.java
@@ -19,7 +19,6 @@
import com.android.jack.dx.rop.code.RegisterSpec;
import com.android.jack.dx.rop.code.RegisterSpecList;
import com.android.jack.dx.rop.code.SourcePosition;
-import com.android.jack.dx.rop.type.Type;
import com.android.jack.dx.util.AnnotatedOutput;
/**
@@ -30,118 +29,116 @@
* be met using a straightforward choice of a single opcode.
*/
public final class HighRegisterPrefix extends VariableSizeInsn {
- /** {@code null-ok;} cached instructions, if constructed */
- private SimpleInsn[] insns;
+ /** {@code null-ok;} cached instructions, if constructed */
+ private SimpleInsn[] insns;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} source registers
- */
- public HighRegisterPrefix(SourcePosition position,
- RegisterSpecList registers) {
- super(position, registers);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} source registers
+ */
+ public HighRegisterPrefix(SourcePosition position, RegisterSpecList registers) {
+ super(position, registers);
- if (registers.size() == 0) {
- throw new IllegalArgumentException("registers.size() == 0");
- }
-
- insns = null;
+ if (registers.size() == 0) {
+ throw new IllegalArgumentException("registers.size() == 0");
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- int result = 0;
+ insns = null;
+ }
- calculateInsnsIfNecessary();
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ int result = 0;
- for (SimpleInsn insn : insns) {
- result += insn.codeSize();
- }
+ calculateInsnsIfNecessary();
- return result;
+ for (SimpleInsn insn : insns) {
+ result += insn.codeSize();
}
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out) {
- calculateInsnsIfNecessary();
+ return result;
+ }
- for (SimpleInsn insn : insns) {
- insn.writeTo(out);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out) {
+ calculateInsnsIfNecessary();
+
+ for (SimpleInsn insn : insns) {
+ insn.writeTo(out);
+ }
+ }
+
+ /**
+ * Helper for {@link #codeSize} and {@link #writeTo} which sets up
+ * {@link #insns} if not already done.
+ */
+ private void calculateInsnsIfNecessary() {
+ if (insns != null) {
+ return;
}
- /**
- * Helper for {@link #codeSize} and {@link #writeTo} which sets up
- * {@link #insns} if not already done.
- */
- private void calculateInsnsIfNecessary() {
- if (insns != null) {
- return;
- }
+ RegisterSpecList registers = getRegisters();
+ int sz = registers.size();
- RegisterSpecList registers = getRegisters();
- int sz = registers.size();
+ insns = new SimpleInsn[sz];
- insns = new SimpleInsn[sz];
+ for (int i = 0, outAt = 0; i < sz; i++) {
+ RegisterSpec src = registers.get(i);
+ insns[i] = moveInsnFor(src, outAt);
+ outAt += src.getCategory();
+ }
+ }
- for (int i = 0, outAt = 0; i < sz; i++) {
- RegisterSpec src = registers.get(i);
- insns[i] = moveInsnFor(src, outAt);
- outAt += src.getCategory();
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new HighRegisterPrefix(getPosition(), registers);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ RegisterSpecList registers = getRegisters();
+ int sz = registers.size();
+ StringBuffer sb = new StringBuffer(100);
+
+ for (int i = 0, outAt = 0; i < sz; i++) {
+ RegisterSpec src = registers.get(i);
+ SimpleInsn insn = moveInsnFor(src, outAt);
+
+ if (i != 0) {
+ sb.append('\n');
+ }
+
+ sb.append(insn.listingString0(noteIndices));
+
+ outAt += src.getCategory();
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new HighRegisterPrefix(getPosition(), registers);
- }
+ return sb.toString();
+ }
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- RegisterSpecList registers = getRegisters();
- int sz = registers.size();
- StringBuffer sb = new StringBuffer(100);
-
- for (int i = 0, outAt = 0; i < sz; i++) {
- RegisterSpec src = registers.get(i);
- SimpleInsn insn = moveInsnFor(src, outAt);
-
- if (i != 0) {
- sb.append('\n');
- }
-
- sb.append(insn.listingString0(noteIndices));
-
- outAt += src.getCategory();
- }
-
- return sb.toString();
- }
-
- /**
- * Returns the proper move instruction for the given source spec
- * and destination index.
- *
- * @param src {@code non-null;} the source register spec
- * @param destIndex {@code >= 0;} the destination register index
- * @return {@code non-null;} the appropriate move instruction
- */
- private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
- return DalvInsn.makeMove(SourcePosition.NO_INFO,
- RegisterSpec.make(destIndex, src.getType()),
- src);
- }
+ /**
+ * Returns the proper move instruction for the given source spec
+ * and destination index.
+ *
+ * @param src {@code non-null;} the source register spec
+ * @param destIndex {@code >= 0;} the destination register index
+ * @return {@code non-null;} the appropriate move instruction
+ */
+ private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
+ return DalvInsn.makeMove(SourcePosition.NO_INFO, RegisterSpec.make(destIndex, src.getType()),
+ src);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/InsnFormat.java b/dx/src/com/android/jack/dx/dex/code/InsnFormat.java
index ab09b69..276d573 100644
--- a/dx/src/com/android/jack/dx/dex/code/InsnFormat.java
+++ b/dx/src/com/android/jack/dx/dex/code/InsnFormat.java
@@ -36,679 +36,691 @@
* representing such translations.
*/
public abstract class InsnFormat {
- /**
- * flag to enable/disable the new extended opcode formats; meant as a
- * temporary measure until VM support for the salient opcodes is
- * added. TODO: Remove this declaration when the VM can deal.
- */
- public static boolean ALLOW_EXTENDED_OPCODES = true;
+ /**
+ * flag to enable/disable the new extended opcode formats; meant as a
+ * temporary measure until VM support for the salient opcodes is
+ * added. TODO(dx team): Remove this declaration when the VM can deal.
+ */
+ public static final boolean ALLOW_EXTENDED_OPCODES = true;
- /**
- * Returns the string form, suitable for inclusion in a listing
- * dump, of the given instruction. The instruction must be of this
- * instance's format for proper operation.
- *
- * @param insn {@code non-null;} the instruction
- * @param noteIndices whether to include an explicit notation of
- * constant pool indices
- * @return {@code non-null;} the string form
- */
- public final String listingString(DalvInsn insn, boolean noteIndices) {
- String op = insn.getOpcode().getName();
- String arg = insnArgString(insn);
- String comment = insnCommentString(insn, noteIndices);
- StringBuilder sb = new StringBuilder(100);
+ /**
+ * Returns the string form, suitable for inclusion in a listing
+ * dump, of the given instruction. The instruction must be of this
+ * instance's format for proper operation.
+ *
+ * @param insn {@code non-null;} the instruction
+ * @param noteIndices whether to include an explicit notation of
+ * constant pool indices
+ * @return {@code non-null;} the string form
+ */
+ public final String listingString(DalvInsn insn, boolean noteIndices) {
+ String op = insn.getOpcode().getName();
+ String arg = insnArgString(insn);
+ String comment = insnCommentString(insn, noteIndices);
+ StringBuilder sb = new StringBuilder(100);
- sb.append(op);
+ sb.append(op);
- if (arg.length() != 0) {
- sb.append(' ');
- sb.append(arg);
- }
-
- if (comment.length() != 0) {
- sb.append(" // ");
- sb.append(comment);
- }
-
- return sb.toString();
+ if (arg.length() != 0) {
+ sb.append(' ');
+ sb.append(arg);
}
- /**
- * Returns the string form of the arguments to the given instruction.
- * The instruction must be of this instance's format. If the instruction
- * has no arguments, then the result should be {@code ""}, not
- * {@code null}.
- *
- * <p>Subclasses must override this method.</p>
- *
- * @param insn {@code non-null;} the instruction
- * @return {@code non-null;} the string form
- */
- public abstract String insnArgString(DalvInsn insn);
-
- /**
- * Returns the associated comment for the given instruction, if any.
- * The instruction must be of this instance's format. If the instruction
- * has no comment, then the result should be {@code ""}, not
- * {@code null}.
- *
- * <p>Subclasses must override this method.</p>
- *
- * @param insn {@code non-null;} the instruction
- * @param noteIndices whether to include an explicit notation of
- * constant pool indices
- * @return {@code non-null;} the string form
- */
- public abstract String insnCommentString(DalvInsn insn,
- boolean noteIndices);
-
- /**
- * Gets the code size of instructions that use this format. The
- * size is a number of 16-bit code units, not bytes. This should
- * throw an exception if this format is of variable size.
- *
- * @return {@code >= 0;} the instruction length in 16-bit code units
- */
- public abstract int codeSize();
-
- /**
- * Returns whether or not the given instruction's arguments will
- * fit in this instance's format. This includes such things as
- * counting register arguments, checking register ranges, and
- * making sure that additional arguments are of appropriate types
- * and are in-range. If this format has a branch target but the
- * instruction's branch offset is unknown, this method will simply
- * not check the offset.
- *
- * <p>Subclasses must override this method.</p>
- *
- * @param insn {@code non-null;} the instruction to check
- * @return {@code true} iff the instruction's arguments are
- * appropriate for this instance, or {@code false} if not
- */
- public abstract boolean isCompatible(DalvInsn insn);
-
- /**
- * Returns which of a given instruction's registers will fit in
- * this instance's format.
- *
- * <p>The default implementation of this method always returns
- * an empty BitSet. Subclasses must override this method if they
- * have registers.</p>
- *
- * @param insn {@code non-null;} the instruction to check
- * @return {@code non-null;} a BitSet flagging registers in the
- * register list that are compatible to this format
- */
- public BitSet compatibleRegs(DalvInsn insn) {
- return new BitSet();
+ if (comment.length() != 0) {
+ sb.append(" // ");
+ sb.append(comment);
}
- /**
- * Returns whether or not the given instruction's branch offset will
- * fit in this instance's format. This always returns {@code false}
- * for formats that don't include a branch offset.
- *
- * <p>The default implementation of this method always returns
- * {@code false}. Subclasses must override this method if they
- * include branch offsets.</p>
- *
- * @param insn {@code non-null;} the instruction to check
- * @return {@code true} iff the instruction's branch offset is
- * appropriate for this instance, or {@code false} if not
- */
- public boolean branchFits(TargetInsn insn) {
+ return sb.toString();
+ }
+
+ /**
+ * Returns the string form of the arguments to the given instruction.
+ * The instruction must be of this instance's format. If the instruction
+ * has no arguments, then the result should be {@code ""}, not
+ * {@code null}.
+ *
+ * <p>Subclasses must override this method.</p>
+ *
+ * @param insn {@code non-null;} the instruction
+ * @return {@code non-null;} the string form
+ */
+ public abstract String insnArgString(DalvInsn insn);
+
+ /**
+ * Returns the associated comment for the given instruction, if any.
+ * The instruction must be of this instance's format. If the instruction
+ * has no comment, then the result should be {@code ""}, not
+ * {@code null}.
+ *
+ * <p>Subclasses must override this method.</p>
+ *
+ * @param insn {@code non-null;} the instruction
+ * @param noteIndices whether to include an explicit notation of
+ * constant pool indices
+ * @return {@code non-null;} the string form
+ */
+ public abstract String insnCommentString(DalvInsn insn, boolean noteIndices);
+
+ /**
+ * Gets the code size of instructions that use this format. The
+ * size is a number of 16-bit code units, not bytes. This should
+ * throw an exception if this format is of variable size.
+ *
+ * @return {@code >= 0;} the instruction length in 16-bit code units
+ */
+ public abstract int codeSize();
+
+ /**
+ * Returns whether or not the given instruction's arguments will
+ * fit in this instance's format. This includes such things as
+ * counting register arguments, checking register ranges, and
+ * making sure that additional arguments are of appropriate types
+ * and are in-range. If this format has a branch target but the
+ * instruction's branch offset is unknown, this method will simply
+ * not check the offset.
+ *
+ * <p>Subclasses must override this method.</p>
+ *
+ * @param insn {@code non-null;} the instruction to check
+ * @return {@code true} iff the instruction's arguments are
+ * appropriate for this instance, or {@code false} if not
+ */
+ public abstract boolean isCompatible(DalvInsn insn);
+
+ /**
+ * Returns which of a given instruction's registers will fit in
+ * this instance's format.
+ *
+ * <p>The default implementation of this method always returns
+ * an empty BitSet. Subclasses must override this method if they
+ * have registers.</p>
+ *
+ * @param insn {@code non-null;} the instruction to check
+ * @return {@code non-null;} a BitSet flagging registers in the
+ * register list that are compatible to this format
+ */
+ public BitSet compatibleRegs(DalvInsn insn) {
+ return new BitSet();
+ }
+
+ /**
+ * Returns whether or not the given instruction's branch offset will
+ * fit in this instance's format. This always returns {@code false}
+ * for formats that don't include a branch offset.
+ *
+ * <p>The default implementation of this method always returns
+ * {@code false}. Subclasses must override this method if they
+ * include branch offsets.</p>
+ *
+ * @param insn {@code non-null;} the instruction to check
+ * @return {@code true} iff the instruction's branch offset is
+ * appropriate for this instance, or {@code false} if not
+ */
+ public boolean branchFits(TargetInsn insn) {
+ return false;
+ }
+
+ /**
+ * Writes the code units for the given instruction to the given
+ * output destination. The instruction must be of this instance's format.
+ *
+ * <p>Subclasses must override this method.</p>
+ *
+ * @param out {@code non-null;} the output destination to write to
+ * @param insn {@code non-null;} the instruction to write
+ */
+ public abstract void writeTo(AnnotatedOutput out, DalvInsn insn);
+
+ /**
+ * Helper method to return a register list string.
+ *
+ * @param list {@code non-null;} the list of registers
+ * @return {@code non-null;} the string form
+ */
+ protected static String regListString(RegisterSpecList list) {
+ int sz = list.size();
+ StringBuffer sb = new StringBuffer(sz * 5 + 2);
+
+ sb.append('{');
+
+ for (int i = 0; i < sz; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(list.get(i).regString());
+ }
+
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to return a register range string.
+ *
+ * @param list {@code non-null;} the list of registers (which must be
+ * sequential)
+ * @return {@code non-null;} the string form
+ */
+ protected static String regRangeString(RegisterSpecList list) {
+ int size = list.size();
+ StringBuilder sb = new StringBuilder(30);
+
+ sb.append("{");
+
+ switch (size) {
+ case 0: {
+ // Nothing to do.
+ break;
+ }
+ case 1: {
+ sb.append(list.get(0).regString());
+ break;
+ }
+ default: {
+ RegisterSpec lastReg = list.get(size - 1);
+ if (lastReg.getCategory() == 2) {
+ /*
+ * Add one to properly represent a list-final
+ * category-2 register.
+ */
+ lastReg = lastReg.withOffset(1);
+ }
+
+ sb.append(list.get(0).regString());
+ sb.append("..");
+ sb.append(lastReg.regString());
+ }
+ }
+
+ sb.append("}");
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to return a literal bits argument string.
+ *
+ * @param value the value
+ * @return {@code non-null;} the string form
+ */
+ protected static String literalBitsString(CstLiteralBits value) {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append('#');
+
+ if (value instanceof CstKnownNull) {
+ sb.append("null");
+ } else {
+ sb.append(value.typeName());
+ sb.append(' ');
+ sb.append(value.toHuman());
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to return a literal bits comment string.
+ *
+ * @param value the value
+ * @param width the width of the constant, in bits (used for displaying
+ * the uninterpreted bits; one of: {@code 4 8 16 32 64}
+ * @return {@code non-null;} the comment
+ */
+ protected static String literalBitsComment(CstLiteralBits value, int width) {
+ StringBuffer sb = new StringBuffer(20);
+
+ sb.append("#");
+
+ long bits;
+
+ if (value instanceof CstLiteral64) {
+ bits = ((CstLiteral64) value).getLongBits();
+ } else {
+ bits = value.getIntBits();
+ }
+
+ switch (width) {
+ case 4:
+ sb.append(Hex.uNibble((int) bits));
+ break;
+ case 8:
+ sb.append(Hex.u1((int) bits));
+ break;
+ case 16:
+ sb.append(Hex.u2((int) bits));
+ break;
+ case 32:
+ sb.append(Hex.u4((int) bits));
+ break;
+ case 64:
+ sb.append(Hex.u8(bits));
+ break;
+ default: {
+ throw new RuntimeException("shouldn't happen");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to return a branch address string.
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @return {@code non-null;} the string form of the instruction's
+ * branch target
+ */
+ protected static String branchString(DalvInsn insn) {
+ TargetInsn ti = (TargetInsn) insn;
+ int address = ti.getTargetAddress();
+
+ return (address == (char) address) ? Hex.u2(address) : Hex.u4(address);
+ }
+
+ /**
+ * Helper method to return the comment for a branch.
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @return {@code non-null;} the comment
+ */
+ protected static String branchComment(DalvInsn insn) {
+ TargetInsn ti = (TargetInsn) insn;
+ int offset = ti.getTargetOffset();
+
+ return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset);
+ }
+
+ /**
+ * Helper method to return the constant string for a {@link CstInsn}
+ * in human form.
+ *
+ * @param insn {@code non-null;} a constant-bearing instruction
+ * @return {@code non-null;} the human string form of the contained
+ * constant
+ */
+ protected static String cstString(DalvInsn insn) {
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
+
+ return cst instanceof CstString ? ((CstString) cst).toQuoted() : cst.toHuman();
+ }
+
+ /**
+ * Helper method to return an instruction comment for a constant.
+ *
+ * @param insn {@code non-null;} a constant-bearing instruction
+ * @return {@code non-null;} comment string representing the constant
+ */
+ protected static String cstComment(DalvInsn insn) {
+ CstInsn ci = (CstInsn) insn;
+
+ if (!ci.hasIndex()) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder(20);
+ int index = ci.getIndex();
+
+ sb.append(ci.getConstant().typeName());
+ sb.append('@');
+
+ if (index < 65536) {
+ sb.append(Hex.u2(index));
+ } else {
+ sb.append(Hex.u4(index));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to determine if a signed int value fits in a nibble.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range -8..+7
+ */
+ protected static boolean signedFitsInNibble(int value) {
+ return (value >= -8) && (value <= 7);
+ }
+
+ /**
+ * Helper method to determine if an unsigned int value fits in a nibble.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range 0..0xf
+ */
+ protected static boolean unsignedFitsInNibble(int value) {
+ return value == (value & 0xf);
+ }
+
+ /**
+ * Helper method to determine if a signed int value fits in a byte.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range -0x80..+0x7f
+ */
+ protected static boolean signedFitsInByte(int value) {
+ return (byte) value == value;
+ }
+
+ /**
+ * Helper method to determine if an unsigned int value fits in a byte.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range 0..0xff
+ */
+ protected static boolean unsignedFitsInByte(int value) {
+ return value == (value & 0xff);
+ }
+
+ /**
+ * Helper method to determine if a signed int value fits in a short.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range -0x8000..+0x7fff
+ */
+ protected static boolean signedFitsInShort(int value) {
+ return (short) value == value;
+ }
+
+ /**
+ * Helper method to determine if an unsigned int value fits in a short.
+ *
+ * @param value the value in question
+ * @return {@code true} iff it's in the range 0..0xffff
+ */
+ protected static boolean unsignedFitsInShort(int value) {
+ return value == (value & 0xffff);
+ }
+
+ /**
+ * Helper method to determine if a list of registers are sequential,
+ * including degenerate cases for empty or single-element lists.
+ *
+ * @param list {@code non-null;} the list of registers
+ * @return {@code true} iff the list is sequentially ordered
+ */
+ protected static boolean isRegListSequential(RegisterSpecList list) {
+ int sz = list.size();
+
+ if (sz < 2) {
+ return true;
+ }
+
+ int first = list.get(0).getReg();
+ int next = first;
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec one = list.get(i);
+ if (one.getReg() != next) {
return false;
+ }
+ next += one.getCategory();
}
- /**
- * Writes the code units for the given instruction to the given
- * output destination. The instruction must be of this instance's format.
- *
- * <p>Subclasses must override this method.</p>
- *
- * @param out {@code non-null;} the output destination to write to
- * @param insn {@code non-null;} the instruction to write
- */
- public abstract void writeTo(AnnotatedOutput out, DalvInsn insn);
+ return true;
+ }
- /**
- * Helper method to return a register list string.
- *
- * @param list {@code non-null;} the list of registers
- * @return {@code non-null;} the string form
- */
- protected static String regListString(RegisterSpecList list) {
- int sz = list.size();
- StringBuffer sb = new StringBuffer(sz * 5 + 2);
+ /**
+ * Helper method to extract the callout-argument index from an
+ * appropriate instruction.
+ *
+ * @param insn {@code non-null;} the instruction
+ * @return {@code >= 0;} the callout argument index
+ */
+ protected static int argIndex(DalvInsn insn) {
+ int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue();
- sb.append('{');
-
- for (int i = 0; i < sz; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(list.get(i).regString());
- }
-
- sb.append('}');
-
- return sb.toString();
+ if (arg < 0) {
+ throw new IllegalArgumentException("bogus insn");
}
- /**
- * Helper method to return a register range string.
- *
- * @param list {@code non-null;} the list of registers (which must be
- * sequential)
- * @return {@code non-null;} the string form
- */
- protected static String regRangeString(RegisterSpecList list) {
- int size = list.size();
- StringBuilder sb = new StringBuilder(30);
+ return arg;
+ }
- sb.append("{");
-
- switch (size) {
- case 0: {
- // Nothing to do.
- break;
- }
- case 1: {
- sb.append(list.get(0).regString());
- break;
- }
- default: {
- RegisterSpec lastReg = list.get(size - 1);
- if (lastReg.getCategory() == 2) {
- /*
- * Add one to properly represent a list-final
- * category-2 register.
- */
- lastReg = lastReg.withOffset(1);
- }
-
- sb.append(list.get(0).regString());
- sb.append("..");
- sb.append(lastReg.regString());
- }
- }
-
- sb.append("}");
-
- return sb.toString();
+ /**
+ * Helper method to combine an opcode and a second byte of data into
+ * the appropriate form for emitting into a code buffer.
+ *
+ * @param insn {@code non-null;} the instruction containing the opcode
+ * @param arg {@code 0..255;} arbitrary other byte value
+ * @return combined value
+ */
+ protected static short opcodeUnit(DalvInsn insn, int arg) {
+ if ((arg & 0xff) != arg) {
+ throw new IllegalArgumentException("arg out of range 0..255");
}
- /**
- * Helper method to return a literal bits argument string.
- *
- * @param value the value
- * @return {@code non-null;} the string form
- */
- protected static String literalBitsString(CstLiteralBits value) {
- StringBuffer sb = new StringBuffer(100);
+ int opcode = insn.getOpcode().getOpcode();
- sb.append('#');
-
- if (value instanceof CstKnownNull) {
- sb.append("null");
- } else {
- sb.append(value.typeName());
- sb.append(' ');
- sb.append(value.toHuman());
- }
-
- return sb.toString();
+ if ((opcode & 0xff) != opcode) {
+ throw new IllegalArgumentException("opcode out of range 0..255");
}
- /**
- * Helper method to return a literal bits comment string.
- *
- * @param value the value
- * @param width the width of the constant, in bits (used for displaying
- * the uninterpreted bits; one of: {@code 4 8 16 32 64}
- * @return {@code non-null;} the comment
- */
- protected static String literalBitsComment(CstLiteralBits value,
- int width) {
- StringBuffer sb = new StringBuffer(20);
+ return (short) (opcode | (arg << 8));
+ }
- sb.append("#");
+ /**
+ * Helper method to get an extended (16-bit) opcode out of an
+ * instruction, returning it as a code unit. The opcode
+ * <i>must</i> be an extended opcode.
+ *
+ * @param insn {@code non-null;} the instruction containing the
+ * extended opcode
+ * @return the opcode as a code unit
+ */
+ protected static short opcodeUnit(DalvInsn insn) {
+ int opcode = insn.getOpcode().getOpcode();
- long bits;
-
- if (value instanceof CstLiteral64) {
- bits = ((CstLiteral64) value).getLongBits();
- } else {
- bits = value.getIntBits();
- }
-
- switch (width) {
- case 4: sb.append(Hex.uNibble((int) bits)); break;
- case 8: sb.append(Hex.u1((int) bits)); break;
- case 16: sb.append(Hex.u2((int) bits)); break;
- case 32: sb.append(Hex.u4((int) bits)); break;
- case 64: sb.append(Hex.u8(bits)); break;
- default: {
- throw new RuntimeException("shouldn't happen");
- }
- }
-
- return sb.toString();
+ if ((opcode < 0x100) || (opcode > 0xffff)) {
+ throw new IllegalArgumentException("opcode out of range 0..65535");
}
- /**
- * Helper method to return a branch address string.
- *
- * @param insn {@code non-null;} the instruction in question
- * @return {@code non-null;} the string form of the instruction's
- * branch target
- */
- protected static String branchString(DalvInsn insn) {
- TargetInsn ti = (TargetInsn) insn;
- int address = ti.getTargetAddress();
+ return (short) opcode;
+ }
- return (address == (char) address) ? Hex.u2(address) : Hex.u4(address);
+ /**
+ * Helper method to combine two bytes into a code unit.
+ *
+ * @param low {@code 0..255;} low byte
+ * @param high {@code 0..255;} high byte
+ * @return combined value
+ */
+ protected static short codeUnit(int low, int high) {
+ if ((low & 0xff) != low) {
+ throw new IllegalArgumentException("low out of range 0..255");
}
- /**
- * Helper method to return the comment for a branch.
- *
- * @param insn {@code non-null;} the instruction in question
- * @return {@code non-null;} the comment
- */
- protected static String branchComment(DalvInsn insn) {
- TargetInsn ti = (TargetInsn) insn;
- int offset = ti.getTargetOffset();
-
- return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset);
+ if ((high & 0xff) != high) {
+ throw new IllegalArgumentException("high out of range 0..255");
}
- /**
- * Helper method to return the constant string for a {@link CstInsn}
- * in human form.
- *
- * @param insn {@code non-null;} a constant-bearing instruction
- * @return {@code non-null;} the human string form of the contained
- * constant
- */
- protected static String cstString(DalvInsn insn) {
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ return (short) (low | (high << 8));
+ }
- return cst instanceof CstString ? ((CstString) cst).toQuoted() : cst.toHuman();
+ /**
+ * Helper method to combine four nibbles into a code unit.
+ *
+ * @param n0 {@code 0..15;} low nibble
+ * @param n1 {@code 0..15;} medium-low nibble
+ * @param n2 {@code 0..15;} medium-high nibble
+ * @param n3 {@code 0..15;} high nibble
+ * @return combined value
+ */
+ protected static short codeUnit(int n0, int n1, int n2, int n3) {
+ if ((n0 & 0xf) != n0) {
+ throw new IllegalArgumentException("n0 out of range 0..15");
}
- /**
- * Helper method to return an instruction comment for a constant.
- *
- * @param insn {@code non-null;} a constant-bearing instruction
- * @return {@code non-null;} comment string representing the constant
- */
- protected static String cstComment(DalvInsn insn) {
- CstInsn ci = (CstInsn) insn;
-
- if (! ci.hasIndex()) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder(20);
- int index = ci.getIndex();
-
- sb.append(ci.getConstant().typeName());
- sb.append('@');
-
- if (index < 65536) {
- sb.append(Hex.u2(index));
- } else {
- sb.append(Hex.u4(index));
- }
-
- return sb.toString();
+ if ((n1 & 0xf) != n1) {
+ throw new IllegalArgumentException("n1 out of range 0..15");
}
- /**
- * Helper method to determine if a signed int value fits in a nibble.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range -8..+7
- */
- protected static boolean signedFitsInNibble(int value) {
- return (value >= -8) && (value <= 7);
+ if ((n2 & 0xf) != n2) {
+ throw new IllegalArgumentException("n2 out of range 0..15");
}
- /**
- * Helper method to determine if an unsigned int value fits in a nibble.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range 0..0xf
- */
- protected static boolean unsignedFitsInNibble(int value) {
- return value == (value & 0xf);
+ if ((n3 & 0xf) != n3) {
+ throw new IllegalArgumentException("n3 out of range 0..15");
}
- /**
- * Helper method to determine if a signed int value fits in a byte.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range -0x80..+0x7f
- */
- protected static boolean signedFitsInByte(int value) {
- return (byte) value == value;
+ return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12));
+ }
+
+ /**
+ * Helper method to combine two nibbles into a byte.
+ *
+ * @param low {@code 0..15;} low nibble
+ * @param high {@code 0..15;} high nibble
+ * @return {@code 0..255;} combined value
+ */
+ protected static int makeByte(int low, int high) {
+ if ((low & 0xf) != low) {
+ throw new IllegalArgumentException("low out of range 0..15");
}
- /**
- * Helper method to determine if an unsigned int value fits in a byte.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range 0..0xff
- */
- protected static boolean unsignedFitsInByte(int value) {
- return value == (value & 0xff);
+ if ((high & 0xf) != high) {
+ throw new IllegalArgumentException("high out of range 0..15");
}
- /**
- * Helper method to determine if a signed int value fits in a short.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range -0x8000..+0x7fff
- */
- protected static boolean signedFitsInShort(int value) {
- return (short) value == value;
- }
+ return low | (high << 4);
+ }
- /**
- * Helper method to determine if an unsigned int value fits in a short.
- *
- * @param value the value in question
- * @return {@code true} iff it's in the range 0..0xffff
- */
- protected static boolean unsignedFitsInShort(int value) {
- return value == (value & 0xffff);
- }
+ /**
+ * Writes one code unit to the given output destination.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0) {
+ out.writeShort(c0);
+ }
- /**
- * Helper method to determine if a list of registers are sequential,
- * including degenerate cases for empty or single-element lists.
- *
- * @param list {@code non-null;} the list of registers
- * @return {@code true} iff the list is sequentially ordered
- */
- protected static boolean isRegListSequential(RegisterSpecList list) {
- int sz = list.size();
+ /**
+ * Writes two code units to the given output destination.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, short c1) {
+ out.writeShort(c0);
+ out.writeShort(c1);
+ }
- if (sz < 2) {
- return true;
- }
+ /**
+ * Writes three code units to the given output destination.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1 code unit to write
+ * @param c2 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, short c1, short c2) {
+ out.writeShort(c0);
+ out.writeShort(c1);
+ out.writeShort(c2);
+ }
- int first = list.get(0).getReg();
- int next = first;
+ /**
+ * Writes four code units to the given output destination.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1 code unit to write
+ * @param c2 code unit to write
+ * @param c3 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, short c1, short c2, short c3) {
+ out.writeShort(c0);
+ out.writeShort(c1);
+ out.writeShort(c2);
+ out.writeShort(c3);
+ }
- for (int i = 0; i < sz; i++) {
- RegisterSpec one = list.get(i);
- if (one.getReg() != next) {
- return false;
- }
- next += one.getCategory();
- }
+ /**
+ * Writes five code units to the given output destination.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1 code unit to write
+ * @param c2 code unit to write
+ * @param c3 code unit to write
+ * @param c4 code unit to write
+ */
+ protected static void write(AnnotatedOutput out,
+ short c0,
+ short c1,
+ short c2,
+ short c3,
+ short c4) {
+ out.writeShort(c0);
+ out.writeShort(c1);
+ out.writeShort(c2);
+ out.writeShort(c3);
+ out.writeShort(c4);
+ }
- return true;
- }
+ /**
+ * Writes three code units to the given output destination, where the
+ * second and third are represented as single <code>int</code> and emitted
+ * in little-endian order.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1c2 code unit pair to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, int c1c2) {
+ write(out, c0, (short) c1c2, (short) (c1c2 >> 16));
+ }
- /**
- * Helper method to extract the callout-argument index from an
- * appropriate instruction.
- *
- * @param insn {@code non-null;} the instruction
- * @return {@code >= 0;} the callout argument index
- */
- protected static int argIndex(DalvInsn insn) {
- int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue();
+ /**
+ * Writes four code units to the given output destination, where the
+ * second and third are represented as single <code>int</code> and emitted
+ * in little-endian order.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1c2 code unit pair to write
+ * @param c3 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, int c1c2, short c3) {
+ write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3);
+ }
- if (arg < 0) {
- throw new IllegalArgumentException("bogus insn");
- }
+ /**
+ * Writes five code units to the given output destination, where the
+ * second and third are represented as single <code>int</code> and emitted
+ * in little-endian order.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1c2 code unit pair to write
+ * @param c3 code unit to write
+ * @param c4 code unit to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, int c1c2, short c3, short c4) {
+ write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3, c4);
+ }
- return arg;
- }
-
- /**
- * Helper method to combine an opcode and a second byte of data into
- * the appropriate form for emitting into a code buffer.
- *
- * @param insn {@code non-null;} the instruction containing the opcode
- * @param arg {@code 0..255;} arbitrary other byte value
- * @return combined value
- */
- protected static short opcodeUnit(DalvInsn insn, int arg) {
- if ((arg & 0xff) != arg) {
- throw new IllegalArgumentException("arg out of range 0..255");
- }
-
- int opcode = insn.getOpcode().getOpcode();
-
- if ((opcode & 0xff) != opcode) {
- throw new IllegalArgumentException("opcode out of range 0..255");
- }
-
- return (short) (opcode | (arg << 8));
- }
-
- /**
- * Helper method to get an extended (16-bit) opcode out of an
- * instruction, returning it as a code unit. The opcode
- * <i>must</i> be an extended opcode.
- *
- * @param insn {@code non-null;} the instruction containing the
- * extended opcode
- * @return the opcode as a code unit
- */
- protected static short opcodeUnit(DalvInsn insn) {
- int opcode = insn.getOpcode().getOpcode();
-
- if ((opcode < 0x100) || (opcode > 0xffff)) {
- throw new IllegalArgumentException("opcode out of range 0..65535");
- }
-
- return (short) opcode;
- }
-
- /**
- * Helper method to combine two bytes into a code unit.
- *
- * @param low {@code 0..255;} low byte
- * @param high {@code 0..255;} high byte
- * @return combined value
- */
- protected static short codeUnit(int low, int high) {
- if ((low & 0xff) != low) {
- throw new IllegalArgumentException("low out of range 0..255");
- }
-
- if ((high & 0xff) != high) {
- throw new IllegalArgumentException("high out of range 0..255");
- }
-
- return (short) (low | (high << 8));
- }
-
- /**
- * Helper method to combine four nibbles into a code unit.
- *
- * @param n0 {@code 0..15;} low nibble
- * @param n1 {@code 0..15;} medium-low nibble
- * @param n2 {@code 0..15;} medium-high nibble
- * @param n3 {@code 0..15;} high nibble
- * @return combined value
- */
- protected static short codeUnit(int n0, int n1, int n2, int n3) {
- if ((n0 & 0xf) != n0) {
- throw new IllegalArgumentException("n0 out of range 0..15");
- }
-
- if ((n1 & 0xf) != n1) {
- throw new IllegalArgumentException("n1 out of range 0..15");
- }
-
- if ((n2 & 0xf) != n2) {
- throw new IllegalArgumentException("n2 out of range 0..15");
- }
-
- if ((n3 & 0xf) != n3) {
- throw new IllegalArgumentException("n3 out of range 0..15");
- }
-
- return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12));
- }
-
- /**
- * Helper method to combine two nibbles into a byte.
- *
- * @param low {@code 0..15;} low nibble
- * @param high {@code 0..15;} high nibble
- * @return {@code 0..255;} combined value
- */
- protected static int makeByte(int low, int high) {
- if ((low & 0xf) != low) {
- throw new IllegalArgumentException("low out of range 0..15");
- }
-
- if ((high & 0xf) != high) {
- throw new IllegalArgumentException("high out of range 0..15");
- }
-
- return low | (high << 4);
- }
-
- /**
- * Writes one code unit to the given output destination.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0) {
- out.writeShort(c0);
- }
-
- /**
- * Writes two code units to the given output destination.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, short c1) {
- out.writeShort(c0);
- out.writeShort(c1);
- }
-
- /**
- * Writes three code units to the given output destination.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1 code unit to write
- * @param c2 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, short c1,
- short c2) {
- out.writeShort(c0);
- out.writeShort(c1);
- out.writeShort(c2);
- }
-
- /**
- * Writes four code units to the given output destination.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1 code unit to write
- * @param c2 code unit to write
- * @param c3 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, short c1,
- short c2, short c3) {
- out.writeShort(c0);
- out.writeShort(c1);
- out.writeShort(c2);
- out.writeShort(c3);
- }
-
- /**
- * Writes five code units to the given output destination.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1 code unit to write
- * @param c2 code unit to write
- * @param c3 code unit to write
- * @param c4 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, short c1,
- short c2, short c3, short c4) {
- out.writeShort(c0);
- out.writeShort(c1);
- out.writeShort(c2);
- out.writeShort(c3);
- out.writeShort(c4);
- }
-
- /**
- * Writes three code units to the given output destination, where the
- * second and third are represented as single <code>int</code> and emitted
- * in little-endian order.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1c2 code unit pair to write
- */
- protected static void write(AnnotatedOutput out, short c0, int c1c2) {
- write(out, c0, (short) c1c2, (short) (c1c2 >> 16));
- }
-
- /**
- * Writes four code units to the given output destination, where the
- * second and third are represented as single <code>int</code> and emitted
- * in little-endian order.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1c2 code unit pair to write
- * @param c3 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, int c1c2,
- short c3) {
- write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3);
- }
-
- /**
- * Writes five code units to the given output destination, where the
- * second and third are represented as single <code>int</code> and emitted
- * in little-endian order.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1c2 code unit pair to write
- * @param c3 code unit to write
- * @param c4 code unit to write
- */
- protected static void write(AnnotatedOutput out, short c0, int c1c2,
- short c3, short c4) {
- write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3, c4);
- }
-
- /**
- * Writes five code units to the given output destination, where the
- * second through fifth are represented as single <code>long</code>
- * and emitted in little-endian order.
- *
- * @param out {@code non-null;} where to write to
- * @param c0 code unit to write
- * @param c1c2c3c4 code unit quad to write
- */
- protected static void write(AnnotatedOutput out, short c0, long c1c2c3c4) {
- write(out, c0, (short) c1c2c3c4, (short) (c1c2c3c4 >> 16),
- (short) (c1c2c3c4 >> 32), (short) (c1c2c3c4 >> 48));
- }
+ /**
+ * Writes five code units to the given output destination, where the
+ * second through fifth are represented as single <code>long</code>
+ * and emitted in little-endian order.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param c0 code unit to write
+ * @param c1c2c3c4 code unit quad to write
+ */
+ protected static void write(AnnotatedOutput out, short c0, long c1c2c3c4) {
+ write(out,
+ c0,
+ (short) c1c2c3c4,
+ (short) (c1c2c3c4 >> 16),
+ (short) (c1c2c3c4 >> 32),
+ (short) (c1c2c3c4 >> 48));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/LocalEnd.java b/dx/src/com/android/jack/dx/dex/code/LocalEnd.java
index a72044a..897ef7c 100644
--- a/dx/src/com/android/jack/dx/dex/code/LocalEnd.java
+++ b/dx/src/com/android/jack/dx/dex/code/LocalEnd.java
@@ -27,64 +27,64 @@
* subsequent instruction, the indicated variable is no longer valid.
*/
public final class LocalEnd extends ZeroSizeInsn {
- /**
- * {@code non-null;} register spec representing the local variable ended
- * by this instance. <b>Note:</b> Technically, only the register
- * number needs to be recorded here as the rest of the information
- * is implicit in the ambient local variable state, but other code
- * will check the other info for consistency.
- */
- private final RegisterSpec local;
+ /**
+ * {@code non-null;} register spec representing the local variable ended
+ * by this instance. <b>Note:</b> Technically, only the register
+ * number needs to be recorded here as the rest of the information
+ * is implicit in the ambient local variable state, but other code
+ * will check the other info for consistency.
+ */
+ private final RegisterSpec local;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param local {@code non-null;} register spec representing the local
- * variable introduced by this instance
- */
- public LocalEnd(SourcePosition position, RegisterSpec local) {
- super(position);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param local {@code non-null;} register spec representing the local
+ * variable introduced by this instance
+ */
+ public LocalEnd(SourcePosition position, RegisterSpec local) {
+ super(position);
- if (local == null) {
- throw new NullPointerException("local == null");
- }
-
- this.local = local;
+ if (local == null) {
+ throw new NullPointerException("local == null");
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisterOffset(int delta) {
- return new LocalEnd(getPosition(), local.withOffset(delta));
- }
+ this.local = local;
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new LocalEnd(getPosition(), local);
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisterOffset(int delta) {
+ return new LocalEnd(getPosition(), local.withOffset(delta));
+ }
- /**
- * Gets the register spec representing the local variable ended
- * by this instance.
- *
- * @return {@code non-null;} the register spec
- */
- public RegisterSpec getLocal() {
- return local;
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new LocalEnd(getPosition(), local);
+ }
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return local.toString();
- }
+ /**
+ * Gets the register spec representing the local variable ended
+ * by this instance.
+ *
+ * @return {@code non-null;} the register spec
+ */
+ public RegisterSpec getLocal() {
+ return local;
+ }
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- return "local-end " + LocalStart.localString(local);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return local.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ return "local-end " + LocalStart.localString(local);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/LocalList.java b/dx/src/com/android/jack/dx/dex/code/LocalList.java
index 0a07a60..8f1c713 100644
--- a/dx/src/com/android/jack/dx/dex/code/LocalList.java
+++ b/dx/src/com/android/jack/dx/dex/code/LocalList.java
@@ -33,916 +33,895 @@
* and a type.
*/
public final class LocalList extends FixedSizeList {
- /** {@code non-null;} empty instance */
- public static final LocalList EMPTY = new LocalList(0);
+ /** {@code non-null;} empty instance */
+ public static final LocalList EMPTY = new LocalList(0);
- /** whether to run the self-check code */
- private static final boolean DEBUG = false;
+ /** whether to run the self-check code */
+ private static final boolean DEBUG = false;
+
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size {@code >= 0;} the size of the list
+ */
+ public LocalList(int size) {
+ super(size);
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Entry get(int n) {
+ return (Entry) get0(n);
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
+ */
+ public void set(int n, Entry entry) {
+ set0(n, entry);
+ }
+
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
+ */
+ public void debugPrint(PrintStream out, String prefix) {
+ int sz = size();
+
+ for (int i = 0; i < sz; i++) {
+ out.print(prefix);
+ out.println(get(i));
+ }
+ }
+
+ /**
+ * Disposition of a local entry.
+ */
+ public static enum Disposition {
+ /** local started (introduced) */
+ START,
+
+ /** local ended without being replaced */
+ END_SIMPLY,
+
+ /** local ended because it was directly replaced */
+ END_REPLACED,
+
+ /** local ended because it was moved to a different register */
+ END_MOVED,
/**
- * Constructs an instance. All indices initially contain {@code null}.
+ * local ended because the previous local clobbered this one
+ * (because it is category-2)
+ */
+ END_CLOBBERED_BY_PREV,
+
+ /**
+ * local ended because the next local clobbered this one
+ * (because this one is a category-2)
+ */
+ END_CLOBBERED_BY_NEXT;
+ }
+
+ /**
+ * Entry in a local list.
+ */
+ public static class Entry implements Comparable<Entry> {
+ /** {@code >= 0;} address */
+ private final int address;
+
+ /** {@code non-null;} disposition of the local */
+ private final Disposition disposition;
+
+ /** {@code non-null;} register spec representing the variable */
+ private final RegisterSpec spec;
+
+ /** {@code non-null;} variable type (derived from {@code spec}) */
+ private final CstType type;
+
+ /**
+ * Constructs an instance.
*
- * @param size {@code >= 0;} the size of the list
+ * @param address {@code >= 0;} address
+ * @param disposition {@code non-null;} disposition of the local
+ * @param spec {@code non-null;} register spec representing
+ * the variable
*/
- public LocalList(int size) {
- super(size);
+ public Entry(int address, Disposition disposition, RegisterSpec spec) {
+ if (address < 0) {
+ throw new IllegalArgumentException("address < 0");
+ }
+
+ if (disposition == null) {
+ throw new NullPointerException("disposition == null");
+ }
+
+ try {
+ if (spec.getLocalItem() == null) {
+ throw new NullPointerException("spec.getLocalItem() == null");
+ }
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("spec == null");
+ }
+
+ this.address = address;
+ this.disposition = disposition;
+ this.spec = spec;
+ this.type = spec.getLocalItem().getType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return Integer.toHexString(address) + " " + disposition + " " + spec;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Entry)) {
+ return false;
+ }
+
+ return (compareTo((Entry) other) == 0);
}
/**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
+ * Compares by (in priority order) address, end then start
+ * disposition (variants of end are all consistered
+ * equivalent), and spec.
*
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
+ * @param other {@code non-null;} entry to compare to
+ * @return {@code -1..1;} standard result of comparison
*/
- public Entry get(int n) {
- return (Entry) get0(n);
+ @Override
+ public int compareTo(Entry other) {
+ if (address < other.address) {
+ return -1;
+ } else if (address > other.address) {
+ return 1;
+ }
+
+ boolean thisIsStart = isStart();
+ boolean otherIsStart = other.isStart();
+
+ if (thisIsStart != otherIsStart) {
+ return thisIsStart ? 1 : -1;
+ }
+
+ return spec.compareTo(other.spec);
}
/**
- * Sets the entry at the given index.
+ * Gets the address.
*
- * @param n {@code >= 0, < size();} which index
- * @param entry {@code non-null;} the entry to set at {@code n}
+ * @return {@code >= 0;} the address
*/
- public void set(int n, Entry entry) {
- set0(n, entry);
+ public int getAddress() {
+ return address;
}
/**
- * Does a human-friendly dump of this instance.
+ * Gets the disposition.
*
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} prefix to attach to each line of output
+ * @return {@code non-null;} the disposition
*/
- public void debugPrint(PrintStream out, String prefix) {
- int sz = size();
-
- for (int i = 0; i < sz; i++) {
- out.print(prefix);
- out.println(get(i));
- }
+ public Disposition getDisposition() {
+ return disposition;
}
/**
- * Disposition of a local entry.
- */
- public static enum Disposition {
- /** local started (introduced) */
- START,
-
- /** local ended without being replaced */
- END_SIMPLY,
-
- /** local ended because it was directly replaced */
- END_REPLACED,
-
- /** local ended because it was moved to a different register */
- END_MOVED,
-
- /**
- * local ended because the previous local clobbered this one
- * (because it is category-2)
- */
- END_CLOBBERED_BY_PREV,
-
- /**
- * local ended because the next local clobbered this one
- * (because this one is a category-2)
- */
- END_CLOBBERED_BY_NEXT;
- }
-
- /**
- * Entry in a local list.
- */
- public static class Entry implements Comparable<Entry> {
- /** {@code >= 0;} address */
- private final int address;
-
- /** {@code non-null;} disposition of the local */
- private final Disposition disposition;
-
- /** {@code non-null;} register spec representing the variable */
- private final RegisterSpec spec;
-
- /** {@code non-null;} variable type (derived from {@code spec}) */
- private final CstType type;
-
- /**
- * Constructs an instance.
- *
- * @param address {@code >= 0;} address
- * @param disposition {@code non-null;} disposition of the local
- * @param spec {@code non-null;} register spec representing
- * the variable
- */
- public Entry(int address, Disposition disposition, RegisterSpec spec) {
- if (address < 0) {
- throw new IllegalArgumentException("address < 0");
- }
-
- if (disposition == null) {
- throw new NullPointerException("disposition == null");
- }
-
- try {
- if (spec.getLocalItem() == null) {
- throw new NullPointerException(
- "spec.getLocalItem() == null");
- }
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("spec == null");
- }
-
- this.address = address;
- this.disposition = disposition;
- this.spec = spec;
- this.type = spec.getLocalItem().getType();
- }
-
- /** {@inheritDoc} */
- public String toString() {
- return Integer.toHexString(address) + " " + disposition + " " +
- spec;
- }
-
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (!(other instanceof Entry)) {
- return false;
- }
-
- return (compareTo((Entry) other) == 0);
- }
-
- /**
- * Compares by (in priority order) address, end then start
- * disposition (variants of end are all consistered
- * equivalent), and spec.
- *
- * @param other {@code non-null;} entry to compare to
- * @return {@code -1..1;} standard result of comparison
- */
- public int compareTo(Entry other) {
- if (address < other.address) {
- return -1;
- } else if (address > other.address) {
- return 1;
- }
-
- boolean thisIsStart = isStart();
- boolean otherIsStart = other.isStart();
-
- if (thisIsStart != otherIsStart) {
- return thisIsStart ? 1 : -1;
- }
-
- return spec.compareTo(other.spec);
- }
-
- /**
- * Gets the address.
- *
- * @return {@code >= 0;} the address
- */
- public int getAddress() {
- return address;
- }
-
- /**
- * Gets the disposition.
- *
- * @return {@code non-null;} the disposition
- */
- public Disposition getDisposition() {
- return disposition;
- }
-
- /**
- * Gets whether this is a local start. This is just shorthand for
- * {@code getDisposition() == Disposition.START}.
- *
- * @return {@code true} iff this is a start
- */
- public boolean isStart() {
- return disposition == Disposition.START;
- }
-
- /**
- * Gets the variable name.
- *
- * @return {@code null-ok;} the variable name
- */
- public CstString getName() {
- return spec.getLocalItem().getName();
- }
-
- /**
- * Gets the variable signature.
- *
- * @return {@code null-ok;} the variable signature
- */
- public CstString getSignature() {
- return spec.getLocalItem().getSignature();
- }
-
- /**
- * Gets the variable's type.
- *
- * @return {@code non-null;} the type
- */
- public CstType getType() {
- return type;
- }
-
- /**
- * Gets the number of the register holding the variable.
- *
- * @return {@code >= 0;} the number of the register holding
- * the variable
- */
- public int getRegister() {
- return spec.getReg();
- }
-
- /**
- * Gets the RegisterSpec of the register holding the variable.
- *
- * @return {@code non-null;} RegisterSpec of the holding register.
- */
- public RegisterSpec getRegisterSpec() {
- return spec;
- }
-
- /**
- * Returns whether or not this instance matches the given spec.
- *
- * @param otherSpec {@code non-null;} the spec in question
- * @return {@code true} iff this instance matches
- * {@code spec}
- */
- public boolean matches(RegisterSpec otherSpec) {
- return spec.equalsUsingSimpleType(otherSpec);
- }
-
- /**
- * Returns whether or not this instance matches the spec in
- * the given instance.
- *
- * @param other {@code non-null;} another entry
- * @return {@code true} iff this instance's spec matches
- * {@code other}
- */
- public boolean matches(Entry other) {
- return matches(other.spec);
- }
-
- /**
- * Returns an instance just like this one but with the disposition
- * set as given.
- *
- * @param disposition {@code non-null;} the new disposition
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public Entry withDisposition(Disposition disposition) {
- if (disposition == this.disposition) {
- return this;
- }
-
- return new Entry(address, disposition, spec);
- }
- }
-
- /**
- * Constructs an instance for the given method, based on the given
- * block order and intermediate local information.
+ * Gets whether this is a local start. This is just shorthand for
+ * {@code getDisposition() == Disposition.START}.
*
- * @param insns {@code non-null;} instructions to convert
- * @return {@code non-null;} the constructed list
+ * @return {@code true} iff this is a start
*/
- public static LocalList make(DalvInsnList insns) {
- int sz = insns.size();
+ public boolean isStart() {
+ return disposition == Disposition.START;
+ }
+ /**
+ * Gets the variable name.
+ *
+ * @return {@code null-ok;} the variable name
+ */
+ public CstString getName() {
+ return spec.getLocalItem().getName();
+ }
+
+ /**
+ * Gets the variable signature.
+ *
+ * @return {@code null-ok;} the variable signature
+ */
+ public CstString getSignature() {
+ return spec.getLocalItem().getSignature();
+ }
+
+ /**
+ * Gets the variable's type.
+ *
+ * @return {@code non-null;} the type
+ */
+ public CstType getType() {
+ return type;
+ }
+
+ /**
+ * Gets the number of the register holding the variable.
+ *
+ * @return {@code >= 0;} the number of the register holding
+ * the variable
+ */
+ public int getRegister() {
+ return spec.getReg();
+ }
+
+ /**
+ * Gets the RegisterSpec of the register holding the variable.
+ *
+ * @return {@code non-null;} RegisterSpec of the holding register.
+ */
+ public RegisterSpec getRegisterSpec() {
+ return spec;
+ }
+
+ /**
+ * Returns whether or not this instance matches the given spec.
+ *
+ * @param otherSpec {@code non-null;} the spec in question
+ * @return {@code true} iff this instance matches
+ * {@code spec}
+ */
+ public boolean matches(RegisterSpec otherSpec) {
+ return spec.equalsUsingSimpleType(otherSpec);
+ }
+
+ /**
+ * Returns whether or not this instance matches the spec in
+ * the given instance.
+ *
+ * @param other {@code non-null;} another entry
+ * @return {@code true} iff this instance's spec matches
+ * {@code other}
+ */
+ public boolean matches(Entry other) {
+ return matches(other.spec);
+ }
+
+ /**
+ * Returns an instance just like this one but with the disposition
+ * set as given.
+ *
+ * @param disposition {@code non-null;} the new disposition
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public Entry withDisposition(Disposition disposition) {
+ if (disposition == this.disposition) {
+ return this;
+ }
+
+ return new Entry(address, disposition, spec);
+ }
+ }
+
+ /**
+ * Constructs an instance for the given method, based on the given
+ * block order and intermediate local information.
+ *
+ * @param insns {@code non-null;} instructions to convert
+ * @return {@code non-null;} the constructed list
+ */
+ public static LocalList make(DalvInsnList insns) {
+ int sz = insns.size();
+
+ /*
+ * Go through the insn list, looking for all the local
+ * variable pseudoinstructions, splitting out LocalSnapshots
+ * into separate per-variable starts, adding explicit ends
+ * wherever a variable is replaced or moved, and collecting
+ * these and all the other local variable "activity"
+ * together into an output list (without the other insns).
+ *
+ * Note: As of this writing, this method won't be handed any
+ * insn lists that contain local ends, but I (danfuzz) expect
+ * that to change at some point, when we start feeding that
+ * info explicitly into the rop layer rather than only trying
+ * to infer it. So, given that expectation, this code is
+ * written to deal with them.
+ */
+
+MakeState state = new MakeState(sz);
+
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = insns.get(i);
+
+ if (insn instanceof LocalSnapshot) {
+ RegisterSpecSet snapshot = ((LocalSnapshot) insn).getLocals();
+ state.snapshot(insn.getAddress(), snapshot);
+ } else if (insn instanceof LocalStart) {
+ RegisterSpec local = ((LocalStart) insn).getLocal();
+ state.startLocal(insn.getAddress(), local);
+ } else if (insn instanceof LocalEnd) {
+ RegisterSpec local = ((LocalEnd) insn).getLocal();
+ state.endLocal(insn.getAddress(), local);
+ }
+ }
+
+ LocalList result = state.finish();
+
+ if (DEBUG) {
+ debugVerify(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Debugging helper that verifies the constraint that a list doesn't
+ * contain any redundant local starts and that local ends that are
+ * due to replacements are properly annotated.
+ */
+ private static void debugVerify(LocalList locals) {
+ try {
+ debugVerify0(locals);
+ } catch (RuntimeException ex) {
+ int sz = locals.size();
+ for (int i = 0; i < sz; i++) {
+ System.err.println(locals.get(i));
+ }
+ throw ex;
+ }
+
+ }
+
+ /**
+ * Helper for {@link #debugVerify} which does most of the work.
+ */
+ private static void debugVerify0(LocalList locals) {
+ int sz = locals.size();
+ Entry[] active = new Entry[65536];
+
+ for (int i = 0; i < sz; i++) {
+ Entry e = locals.get(i);
+ int reg = e.getRegister();
+
+ if (e.isStart()) {
+ Entry already = active[reg];
+
+ if ((already != null) && e.matches(already)) {
+ throw new RuntimeException("redundant start at " + Integer.toHexString(e.getAddress())
+ + ": got " + e + "; had " + already);
+ }
+
+ active[reg] = e;
+ } else {
+ if (active[reg] == null) {
+ throw new RuntimeException("redundant end at " + Integer.toHexString(e.getAddress()));
+ }
+
+ int addr = e.getAddress();
+ boolean foundStart = false;
+
+ for (int j = i + 1; j < sz; j++) {
+ Entry test = locals.get(j);
+ if (test.getAddress() != addr) {
+ break;
+ }
+ if (test.getRegisterSpec().getReg() == reg) {
+ if (test.isStart()) {
+ if (e.getDisposition() != Disposition.END_REPLACED) {
+ throw new RuntimeException("improperly marked end at " + Integer.toHexString(addr));
+ }
+ foundStart = true;
+ } else {
+ throw new RuntimeException("redundant end at " + Integer.toHexString(addr));
+ }
+ }
+ }
+
+ if (!foundStart && (e.getDisposition() == Disposition.END_REPLACED)) {
+ throw new RuntimeException(
+ "improper end replacement claim at " + Integer.toHexString(addr));
+ }
+
+ active[reg] = null;
+ }
+ }
+ }
+
+ /**
+ * Intermediate state when constructing a local list.
+ */
+ public static class MakeState {
+ /** {@code non-null;} result being collected */
+ private final ArrayList<Entry> result;
+
+ /**
+ * {@code >= 0;} running count of nulled result entries, to help with
+ * sizing the final list
+ */
+ private int nullResultCount;
+
+ /** {@code null-ok;} current register mappings */
+ private RegisterSpecSet regs;
+
+ /** {@code null-ok;} result indices where local ends are stored */
+ private int[] endIndices;
+
+ /** {@code >= 0;} last address seen */
+ private int lastAddress;
+
+ /**
+ * Constructs an instance.
+ */
+ public MakeState(int initialSize) {
+ result = new ArrayList<Entry>(initialSize);
+ nullResultCount = 0;
+ regs = null;
+ endIndices = null;
+ lastAddress = 0;
+ }
+
+ /**
+ * Checks the address and other vitals as a prerequisite to
+ * further processing.
+ *
+ * @param address {@code >= 0;} address about to be processed
+ * @param reg {@code >= 0;} register number about to be processed
+ */
+ private void aboutToProcess(int address, int reg) {
+ boolean first = (endIndices == null);
+
+ if ((address == lastAddress) && !first) {
+ return;
+ }
+
+ if (address < lastAddress) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ if (first || (reg >= endIndices.length)) {
/*
- * Go through the insn list, looking for all the local
- * variable pseudoinstructions, splitting out LocalSnapshots
- * into separate per-variable starts, adding explicit ends
- * wherever a variable is replaced or moved, and collecting
- * these and all the other local variable "activity"
- * together into an output list (without the other insns).
- *
- * Note: As of this writing, this method won't be handed any
- * insn lists that contain local ends, but I (danfuzz) expect
- * that to change at some point, when we start feeding that
- * info explicitly into the rop layer rather than only trying
- * to infer it. So, given that expectation, this code is
- * written to deal with them.
+ * This is the first allocation of the state set and
+ * index array, or we need to grow. (The latter doesn't
+ * happen much; in fact, we have only ever observed
+ * it happening in test cases, never in "real" code.)
*/
+ int newSz = reg + 1;
+ RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
+ int[] newEnds = new int[newSz];
+ Arrays.fill(newEnds, -1);
- MakeState state = new MakeState(sz);
-
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = insns.get(i);
-
- if (insn instanceof LocalSnapshot) {
- RegisterSpecSet snapshot =
- ((LocalSnapshot) insn).getLocals();
- state.snapshot(insn.getAddress(), snapshot);
- } else if (insn instanceof LocalStart) {
- RegisterSpec local = ((LocalStart) insn).getLocal();
- state.startLocal(insn.getAddress(), local);
- } else if (insn instanceof LocalEnd) {
- RegisterSpec local = ((LocalEnd) insn).getLocal();
- state.endLocal(insn.getAddress(), local);
- }
+ if (!first) {
+ newRegs.putAll(regs);
+ System.arraycopy(endIndices, 0, newEnds, 0, endIndices.length);
}
- LocalList result = state.finish();
-
- if (DEBUG) {
- debugVerify(result);
- }
-
- return result;
+ regs = newRegs;
+ endIndices = newEnds;
+ }
}
/**
- * Debugging helper that verifies the constraint that a list doesn't
- * contain any redundant local starts and that local ends that are
- * due to replacements are properly annotated.
+ * Sets the local state at the given address to the given snapshot.
+ * The first call on this instance must be to this method, so that
+ * the register state can be properly sized.
+ *
+ * @param address {@code >= 0;} the address
+ * @param specs {@code non-null;} spec set representing the locals
*/
- private static void debugVerify(LocalList locals) {
- try {
- debugVerify0(locals);
- } catch (RuntimeException ex) {
- int sz = locals.size();
- for (int i = 0; i < sz; i++) {
- System.err.println(locals.get(i));
- }
- throw ex;
- }
+ public void snapshot(int address, RegisterSpecSet specs) {
+ if (DEBUG) {
+ System.err.printf("%04x snapshot %s\n", address, specs);
+ }
+ int sz = specs.getMaxSize();
+ aboutToProcess(address, sz - 1);
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec oldSpec = regs.get(i);
+ RegisterSpec newSpec = filterSpec(specs.get(i));
+
+ if (oldSpec == null) {
+ if (newSpec != null) {
+ startLocal(address, newSpec);
+ }
+ } else if (newSpec == null) {
+ endLocal(address, oldSpec);
+ } else if (!newSpec.equalsUsingSimpleType(oldSpec)) {
+ endLocal(address, oldSpec);
+ startLocal(address, newSpec);
+ }
+ }
+
+ if (DEBUG) {
+ System.err.printf("%04x snapshot done\n", address);
+ }
}
/**
- * Helper for {@link #debugVerify} which does most of the work.
+ * Starts a local at the given address.
+ *
+ * @param address {@code >= 0;} the address
+ * @param startedLocal {@code non-null;} spec representing the
+ * started local
*/
- private static void debugVerify0(LocalList locals) {
- int sz = locals.size();
- Entry[] active = new Entry[65536];
+ public void startLocal(int address, RegisterSpec startedLocal) {
+ if (DEBUG) {
+ System.err.printf("%04x start %s\n", address, startedLocal);
+ }
- for (int i = 0; i < sz; i++) {
- Entry e = locals.get(i);
- int reg = e.getRegister();
+ int regNum = startedLocal.getReg();
- if (e.isStart()) {
- Entry already = active[reg];
+ startedLocal = filterSpec(startedLocal);
+ aboutToProcess(address, regNum);
- if ((already != null) && e.matches(already)) {
- throw new RuntimeException("redundant start at " +
- Integer.toHexString(e.getAddress()) + ": got " +
- e + "; had " + already);
- }
+ RegisterSpec existingLocal = regs.get(regNum);
- active[reg] = e;
- } else {
- if (active[reg] == null) {
- throw new RuntimeException("redundant end at " +
- Integer.toHexString(e.getAddress()));
- }
+ if (startedLocal.equalsUsingSimpleType(existingLocal)) {
+ // Silently ignore a redundant start.
+ return;
+ }
- int addr = e.getAddress();
- boolean foundStart = false;
-
- for (int j = i + 1; j < sz; j++) {
- Entry test = locals.get(j);
- if (test.getAddress() != addr) {
- break;
- }
- if (test.getRegisterSpec().getReg() == reg) {
- if (test.isStart()) {
- if (e.getDisposition()
- != Disposition.END_REPLACED) {
- throw new RuntimeException(
- "improperly marked end at " +
- Integer.toHexString(addr));
- }
- foundStart = true;
- } else {
- throw new RuntimeException(
- "redundant end at " +
- Integer.toHexString(addr));
- }
- }
- }
-
- if (!foundStart &&
- (e.getDisposition() == Disposition.END_REPLACED)) {
- throw new RuntimeException(
- "improper end replacement claim at " +
- Integer.toHexString(addr));
- }
-
- active[reg] = null;
- }
- }
- }
-
- /**
- * Intermediate state when constructing a local list.
- */
- public static class MakeState {
- /** {@code non-null;} result being collected */
- private final ArrayList<Entry> result;
-
- /**
- * {@code >= 0;} running count of nulled result entries, to help with
- * sizing the final list
+ RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
+ if (movedLocal != null) {
+ /*
+ * The same variable was moved from one register to another.
+ * So add an end for its old location.
*/
- private int nullResultCount;
+ addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
+ }
- /** {@code null-ok;} current register mappings */
- private RegisterSpecSet regs;
+ int endAt = endIndices[regNum];
- /** {@code null-ok;} result indices where local ends are stored */
- private int[] endIndices;
-
- /** {@code >= 0;} last address seen */
- private int lastAddress;
-
- /**
- * Constructs an instance.
+ if (existingLocal != null) {
+ /*
+ * There is an existing (but non-matching) local.
+ * Add an explicit end for it.
*/
- public MakeState(int initialSize) {
- result = new ArrayList<Entry>(initialSize);
- nullResultCount = 0;
- regs = null;
- endIndices = null;
- lastAddress = 0;
- }
-
- /**
- * Checks the address and other vitals as a prerequisite to
- * further processing.
- *
- * @param address {@code >= 0;} address about to be processed
- * @param reg {@code >= 0;} register number about to be processed
+ add(address, Disposition.END_REPLACED, existingLocal);
+ } else if (endAt >= 0) {
+ /*
+ * Look for an end local for the same register at the
+ * same address. If found, then update it or delete
+ * it, depending on whether or not it represents the
+ * same variable as the one being started.
*/
- private void aboutToProcess(int address, int reg) {
- boolean first = (endIndices == null);
-
- if ((address == lastAddress) && !first) {
- return;
- }
-
- if (address < lastAddress) {
- throw new RuntimeException("shouldn't happen");
- }
-
- if (first || (reg >= endIndices.length)) {
- /*
- * This is the first allocation of the state set and
- * index array, or we need to grow. (The latter doesn't
- * happen much; in fact, we have only ever observed
- * it happening in test cases, never in "real" code.)
- */
- int newSz = reg + 1;
- RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
- int[] newEnds = new int[newSz];
- Arrays.fill(newEnds, -1);
-
- if (!first) {
- newRegs.putAll(regs);
- System.arraycopy(endIndices, 0, newEnds, 0,
- endIndices.length);
- }
-
- regs = newRegs;
- endIndices = newEnds;
- }
- }
-
- /**
- * Sets the local state at the given address to the given snapshot.
- * The first call on this instance must be to this method, so that
- * the register state can be properly sized.
- *
- * @param address {@code >= 0;} the address
- * @param specs {@code non-null;} spec set representing the locals
- */
- public void snapshot(int address, RegisterSpecSet specs) {
- if (DEBUG) {
- System.err.printf("%04x snapshot %s\n", address, specs);
- }
-
- int sz = specs.getMaxSize();
- aboutToProcess(address, sz - 1);
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec oldSpec = regs.get(i);
- RegisterSpec newSpec = filterSpec(specs.get(i));
-
- if (oldSpec == null) {
- if (newSpec != null) {
- startLocal(address, newSpec);
- }
- } else if (newSpec == null) {
- endLocal(address, oldSpec);
- } else if (! newSpec.equalsUsingSimpleType(oldSpec)) {
- endLocal(address, oldSpec);
- startLocal(address, newSpec);
- }
- }
-
- if (DEBUG) {
- System.err.printf("%04x snapshot done\n", address);
- }
- }
-
- /**
- * Starts a local at the given address.
- *
- * @param address {@code >= 0;} the address
- * @param startedLocal {@code non-null;} spec representing the
- * started local
- */
- public void startLocal(int address, RegisterSpec startedLocal) {
- if (DEBUG) {
- System.err.printf("%04x start %s\n", address, startedLocal);
- }
-
- int regNum = startedLocal.getReg();
-
- startedLocal = filterSpec(startedLocal);
- aboutToProcess(address, regNum);
-
- RegisterSpec existingLocal = regs.get(regNum);
-
- if (startedLocal.equalsUsingSimpleType(existingLocal)) {
- // Silently ignore a redundant start.
- return;
- }
-
- RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
- if (movedLocal != null) {
- /*
- * The same variable was moved from one register to another.
- * So add an end for its old location.
- */
- addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
- }
-
- int endAt = endIndices[regNum];
-
- if (existingLocal != null) {
- /*
- * There is an existing (but non-matching) local.
- * Add an explicit end for it.
- */
- add(address, Disposition.END_REPLACED, existingLocal);
- } else if (endAt >= 0) {
- /*
- * Look for an end local for the same register at the
- * same address. If found, then update it or delete
- * it, depending on whether or not it represents the
- * same variable as the one being started.
- */
- Entry endEntry = result.get(endAt);
- if (endEntry.getAddress() == address) {
- if (endEntry.matches(startedLocal)) {
- /*
- * There was already an end local for the same
- * variable at the same address. This turns
- * out to be superfluous, as we are starting
- * up the exact same local. This situation can
- * happen when a single local variable got
- * somehow "split up" during intermediate
- * processing. In any case, rather than represent
- * the end-then-start, just remove the old end.
- */
- result.set(endAt, null);
- nullResultCount++;
- regs.put(startedLocal);
- endIndices[regNum] = -1;
- return;
- } else {
- /*
- * There was a different variable ended at the
- * same address. Update it to indicate that
- * it was ended due to a replacement (rather than
- * ending for no particular reason).
- */
- endEntry = endEntry.withDisposition(
- Disposition.END_REPLACED);
- result.set(endAt, endEntry);
- }
- }
- }
-
+ Entry endEntry = result.get(endAt);
+ if (endEntry.getAddress() == address) {
+ if (endEntry.matches(startedLocal)) {
/*
- * The code above didn't find and remove an unnecessary
- * local end, so we now have to add one or more entries to
- * the output to capture the transition.
+ * There was already an end local for the same
+ * variable at the same address. This turns
+ * out to be superfluous, as we are starting
+ * up the exact same local. This situation can
+ * happen when a single local variable got
+ * somehow "split up" during intermediate
+ * processing. In any case, rather than represent
+ * the end-then-start, just remove the old end.
*/
-
- /*
- * If the local just below (in the register set at reg-1)
- * is of category-2, then it is ended by this new start.
- */
- if (regNum > 0) {
- RegisterSpec justBelow = regs.get(regNum - 1);
- if ((justBelow != null) && justBelow.isCategory2()) {
- addOrUpdateEnd(address,
- Disposition.END_CLOBBERED_BY_NEXT,
- justBelow);
- }
- }
-
- /*
- * Similarly, if this local is category-2, then the local
- * just above (if any) is ended by the start now being
- * emitted.
- */
- if (startedLocal.isCategory2()) {
- RegisterSpec justAbove = regs.get(regNum + 1);
- if (justAbove != null) {
- addOrUpdateEnd(address,
- Disposition.END_CLOBBERED_BY_PREV,
- justAbove);
- }
- }
-
- /*
- * TODO: Add an end for the same local in a different reg,
- * if any (that is, if the local migrates from vX to vY,
- * we should note that as a local end in vX).
- */
-
- add(address, Disposition.START, startedLocal);
- }
-
- /**
- * Ends a local at the given address, using the disposition
- * {@code END_SIMPLY}.
- *
- * @param address {@code >= 0;} the address
- * @param endedLocal {@code non-null;} spec representing the
- * local being ended
- */
- public void endLocal(int address, RegisterSpec endedLocal) {
- endLocal(address, endedLocal, Disposition.END_SIMPLY);
- }
-
- /**
- * Ends a local at the given address.
- *
- * @param address {@code >= 0;} the address
- * @param endedLocal {@code non-null;} spec representing the
- * local being ended
- * @param disposition reason for the end
- */
- public void endLocal(int address, RegisterSpec endedLocal,
- Disposition disposition) {
- if (DEBUG) {
- System.err.printf("%04x end %s\n", address, endedLocal);
- }
-
- int regNum = endedLocal.getReg();
-
- endedLocal = filterSpec(endedLocal);
- aboutToProcess(address, regNum);
-
- int endAt = endIndices[regNum];
-
- if (endAt >= 0) {
- /*
- * The local in the given register is already ended.
- * Silently return without adding anything to the result.
- */
- return;
- }
-
- // Check for start and end at the same address.
- if (checkForEmptyRange(address, endedLocal)) {
- return;
- }
-
- add(address, disposition, endedLocal);
- }
-
- /**
- * Helper for {@link #endLocal}, which handles the cases where
- * and end local is issued at the same address as a start local
- * for the same register. If this case is found, then this
- * method will remove the start (as the local was never actually
- * active), update the {@link #endIndices} to be accurate, and
- * if needed update the newly-active end to reflect an altered
- * disposition.
- *
- * @param address {@code >= 0;} the address
- * @param endedLocal {@code non-null;} spec representing the
- * local being ended
- * @return {@code true} iff this method found the case in question
- * and adjusted things accordingly
- */
- private boolean checkForEmptyRange(int address,
- RegisterSpec endedLocal) {
- int at = result.size() - 1;
- Entry entry;
-
- // Look for a previous entry at the same address.
- for (/*at*/; at >= 0; at--) {
- entry = result.get(at);
-
- if (entry == null) {
- continue;
- }
-
- if (entry.getAddress() != address) {
- // We didn't find any match at the same address.
- return false;
- }
-
- if (entry.matches(endedLocal)) {
- break;
- }
- }
-
- /*
- * In fact, we found that the endedLocal had started at the
- * same address, so do all the requisite cleanup.
- */
-
- regs.remove(endedLocal);
- result.set(at, null);
+ result.set(endAt, null);
nullResultCount++;
-
- int regNum = endedLocal.getReg();
- boolean found = false;
- entry = null;
-
- // Now look back further to update where the register ended.
- for (at--; at >= 0; at--) {
- entry = result.get(at);
-
- if (entry == null) {
- continue;
- }
-
- if (entry.getRegisterSpec().getReg() == regNum) {
- found = true;
- break;
- }
- }
-
- if (found) {
- // We found an end for the same register.
- endIndices[regNum] = at;
-
- if (entry.getAddress() == address) {
- /*
- * It's still the same address, so update the
- * disposition.
- */
- result.set(at,
- entry.withDisposition(Disposition.END_SIMPLY));
- }
- }
-
- return true;
- }
-
- /**
- * Converts a given spec into the form acceptable for use in a
- * local list. This, in particular, transforms the "known
- * null" type into simply {@code Object}. This method needs to
- * be called for any spec that is on its way into a locals
- * list.
- *
- * <p>This isn't necessarily the cleanest way to achieve the
- * goal of not representing known nulls in a locals list, but
- * it gets the job done.</p>
- *
- * @param orig {@code null-ok;} the original spec
- * @return {@code null-ok;} an appropriately modified spec, or the
- * original if nothing needs to be done
- */
- private static RegisterSpec filterSpec(RegisterSpec orig) {
- if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
- return orig.withType(Type.OBJECT);
- }
-
- return orig;
- }
-
- /**
- * Adds an entry to the result, updating the adjunct tables
- * accordingly.
- *
- * @param address {@code >= 0;} the address
- * @param disposition {@code non-null;} the disposition
- * @param spec {@code non-null;} spec representing the local
- */
- private void add(int address, Disposition disposition,
- RegisterSpec spec) {
- int regNum = spec.getReg();
-
- result.add(new Entry(address, disposition, spec));
-
- if (disposition == Disposition.START) {
- regs.put(spec);
- endIndices[regNum] = -1;
- } else {
- regs.remove(spec);
- endIndices[regNum] = result.size() - 1;
- }
- }
-
- /**
- * Adds or updates an end local (changing its disposition). If
- * this would cause an empty range for a local, this instead
- * removes the local entirely.
- *
- * @param address {@code >= 0;} the address
- * @param disposition {@code non-null;} the disposition
- * @param spec {@code non-null;} spec representing the local
- */
- private void addOrUpdateEnd(int address, Disposition disposition,
- RegisterSpec spec) {
- if (disposition == Disposition.START) {
- throw new RuntimeException("shouldn't happen");
- }
-
- int regNum = spec.getReg();
- int endAt = endIndices[regNum];
-
- if (endAt >= 0) {
- // There is a previous end.
- Entry endEntry = result.get(endAt);
- if ((endEntry.getAddress() == address) &&
- endEntry.getRegisterSpec().equals(spec)) {
- /*
- * The end is for the right address and variable, so
- * update it.
- */
- result.set(endAt, endEntry.withDisposition(disposition));
- regs.remove(spec); // TODO: Is this line superfluous?
- return;
- }
- }
-
- endLocal(address, spec, disposition);
- }
-
- /**
- * Finishes processing altogether and gets the result.
- *
- * @return {@code non-null;} the result list
- */
- public LocalList finish() {
- aboutToProcess(Integer.MAX_VALUE, 0);
-
- int resultSz = result.size();
- int finalSz = resultSz - nullResultCount;
-
- if (finalSz == 0) {
- return EMPTY;
- }
-
+ regs.put(startedLocal);
+ endIndices[regNum] = -1;
+ return;
+ } else {
/*
- * Collect an array of only the non-null entries, and then
- * sort it to get a consistent order for everything: Local
- * ends and starts for a given address could come in any
- * order, but we want ends before starts as well as
- * registers in order (within ends or starts).
+ * There was a different variable ended at the
+ * same address. Update it to indicate that
+ * it was ended due to a replacement (rather than
+ * ending for no particular reason).
*/
-
- Entry[] resultArr = new Entry[finalSz];
-
- if (resultSz == finalSz) {
- result.toArray(resultArr);
- } else {
- int at = 0;
- for (Entry e : result) {
- if (e != null) {
- resultArr[at++] = e;
- }
- }
- }
-
- Arrays.sort(resultArr);
-
- LocalList resultList = new LocalList(finalSz);
-
- for (int i = 0; i < finalSz; i++) {
- resultList.set(i, resultArr[i]);
- }
-
- resultList.setImmutable();
- return resultList;
+ endEntry = endEntry.withDisposition(Disposition.END_REPLACED);
+ result.set(endAt, endEntry);
+ }
}
+ }
+
+ /*
+ * The code above didn't find and remove an unnecessary
+ * local end, so we now have to add one or more entries to
+ * the output to capture the transition.
+ */
+
+/*
+ * If the local just below (in the register set at reg-1)
+ * is of category-2, then it is ended by this new start.
+ */
+ if (regNum > 0) {
+ RegisterSpec justBelow = regs.get(regNum - 1);
+ if ((justBelow != null) && justBelow.isCategory2()) {
+ addOrUpdateEnd(address, Disposition.END_CLOBBERED_BY_NEXT, justBelow);
+ }
+ }
+
+ /*
+ * Similarly, if this local is category-2, then the local
+ * just above (if any) is ended by the start now being
+ * emitted.
+ */
+ if (startedLocal.isCategory2()) {
+ RegisterSpec justAbove = regs.get(regNum + 1);
+ if (justAbove != null) {
+ addOrUpdateEnd(address, Disposition.END_CLOBBERED_BY_PREV, justAbove);
+ }
+ }
+
+ /*
+ * TODO(dx team): Add an end for the same local in a different reg,
+ * if any (that is, if the local migrates from vX to vY,
+ * we should note that as a local end in vX).
+ */
+
+add(address, Disposition.START, startedLocal);
}
+
+ /**
+ * Ends a local at the given address, using the disposition
+ * {@code END_SIMPLY}.
+ *
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
+ */
+ public void endLocal(int address, RegisterSpec endedLocal) {
+ endLocal(address, endedLocal, Disposition.END_SIMPLY);
+ }
+
+ /**
+ * Ends a local at the given address.
+ *
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
+ * @param disposition reason for the end
+ */
+ public void endLocal(int address, RegisterSpec endedLocal, Disposition disposition) {
+ if (DEBUG) {
+ System.err.printf("%04x end %s\n", address, endedLocal);
+ }
+
+ int regNum = endedLocal.getReg();
+
+ endedLocal = filterSpec(endedLocal);
+ aboutToProcess(address, regNum);
+
+ int endAt = endIndices[regNum];
+
+ if (endAt >= 0) {
+ /*
+ * The local in the given register is already ended.
+ * Silently return without adding anything to the result.
+ */
+ return;
+ }
+
+ // Check for start and end at the same address.
+ if (checkForEmptyRange(address, endedLocal)) {
+ return;
+ }
+
+ add(address, disposition, endedLocal);
+ }
+
+ /**
+ * Helper for {@link #endLocal}, which handles the cases where
+ * and end local is issued at the same address as a start local
+ * for the same register. If this case is found, then this
+ * method will remove the start (as the local was never actually
+ * active), update the {@link #endIndices} to be accurate, and
+ * if needed update the newly-active end to reflect an altered
+ * disposition.
+ *
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
+ * @return {@code true} iff this method found the case in question
+ * and adjusted things accordingly
+ */
+ private boolean checkForEmptyRange(int address, RegisterSpec endedLocal) {
+ int at = result.size() - 1;
+ Entry entry;
+
+ // Look for a previous entry at the same address.
+ for (/*at*/; at >= 0; at--) {
+ entry = result.get(at);
+
+ if (entry == null) {
+ continue;
+ }
+
+ if (entry.getAddress() != address) {
+ // We didn't find any match at the same address.
+ return false;
+ }
+
+ if (entry.matches(endedLocal)) {
+ break;
+ }
+ }
+
+ /*
+ * In fact, we found that the endedLocal had started at the
+ * same address, so do all the requisite cleanup.
+ */
+
+regs.remove(endedLocal);
+ result.set(at, null);
+ nullResultCount++;
+
+ int regNum = endedLocal.getReg();
+ boolean found = false;
+ entry = null;
+
+ // Now look back further to update where the register ended.
+ for (at--; at >= 0; at--) {
+ entry = result.get(at);
+
+ if (entry == null) {
+ continue;
+ }
+
+ if (entry.getRegisterSpec().getReg() == regNum) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ // We found an end for the same register.
+ endIndices[regNum] = at;
+
+ if (entry.getAddress() == address) {
+ /*
+ * It's still the same address, so update the
+ * disposition.
+ */
+ result.set(at, entry.withDisposition(Disposition.END_SIMPLY));
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Converts a given spec into the form acceptable for use in a
+ * local list. This, in particular, transforms the "known
+ * null" type into simply {@code Object}. This method needs to
+ * be called for any spec that is on its way into a locals
+ * list.
+ *
+ * <p>This isn't necessarily the cleanest way to achieve the
+ * goal of not representing known nulls in a locals list, but
+ * it gets the job done.</p>
+ *
+ * @param orig {@code null-ok;} the original spec
+ * @return {@code null-ok;} an appropriately modified spec, or the
+ * original if nothing needs to be done
+ */
+ private static RegisterSpec filterSpec(RegisterSpec orig) {
+ if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
+ return orig.withType(Type.OBJECT);
+ }
+
+ return orig;
+ }
+
+ /**
+ * Adds an entry to the result, updating the adjunct tables
+ * accordingly.
+ *
+ * @param address {@code >= 0;} the address
+ * @param disposition {@code non-null;} the disposition
+ * @param spec {@code non-null;} spec representing the local
+ */
+ private void add(int address, Disposition disposition, RegisterSpec spec) {
+ int regNum = spec.getReg();
+
+ result.add(new Entry(address, disposition, spec));
+
+ if (disposition == Disposition.START) {
+ regs.put(spec);
+ endIndices[regNum] = -1;
+ } else {
+ regs.remove(spec);
+ endIndices[regNum] = result.size() - 1;
+ }
+ }
+
+ /**
+ * Adds or updates an end local (changing its disposition). If
+ * this would cause an empty range for a local, this instead
+ * removes the local entirely.
+ *
+ * @param address {@code >= 0;} the address
+ * @param disposition {@code non-null;} the disposition
+ * @param spec {@code non-null;} spec representing the local
+ */
+ private void addOrUpdateEnd(int address, Disposition disposition, RegisterSpec spec) {
+ if (disposition == Disposition.START) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ int regNum = spec.getReg();
+ int endAt = endIndices[regNum];
+
+ if (endAt >= 0) {
+ // There is a previous end.
+ Entry endEntry = result.get(endAt);
+ if ((endEntry.getAddress() == address) && endEntry.getRegisterSpec().equals(spec)) {
+ /*
+ * The end is for the right address and variable, so
+ * update it.
+ */
+ result.set(endAt, endEntry.withDisposition(disposition));
+ regs.remove(spec); // TODO(dx team): Is this line superfluous?
+ return;
+ }
+ }
+
+ endLocal(address, spec, disposition);
+ }
+
+ /**
+ * Finishes processing altogether and gets the result.
+ *
+ * @return {@code non-null;} the result list
+ */
+ public LocalList finish() {
+ aboutToProcess(Integer.MAX_VALUE, 0);
+
+ int resultSz = result.size();
+ int finalSz = resultSz - nullResultCount;
+
+ if (finalSz == 0) {
+ return EMPTY;
+ }
+
+ /*
+ * Collect an array of only the non-null entries, and then
+ * sort it to get a consistent order for everything: Local
+ * ends and starts for a given address could come in any
+ * order, but we want ends before starts as well as
+ * registers in order (within ends or starts).
+ */
+
+Entry[] resultArr = new Entry[finalSz];
+
+ if (resultSz == finalSz) {
+ result.toArray(resultArr);
+ } else {
+ int at = 0;
+ for (Entry e : result) {
+ if (e != null) {
+ resultArr[at++] = e;
+ }
+ }
+ }
+
+ Arrays.sort(resultArr);
+
+ LocalList resultList = new LocalList(finalSz);
+
+ for (int i = 0; i < finalSz; i++) {
+ resultList.set(i, resultArr[i]);
+ }
+
+ resultList.setImmutable();
+ return resultList;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/LocalSnapshot.java b/dx/src/com/android/jack/dx/dex/code/LocalSnapshot.java
index 01f3943..d14a9a2 100644
--- a/dx/src/com/android/jack/dx/dex/code/LocalSnapshot.java
+++ b/dx/src/com/android/jack/dx/dex/code/LocalSnapshot.java
@@ -27,70 +27,70 @@
* the instance in an instruction array.
*/
public final class LocalSnapshot extends ZeroSizeInsn {
- /** {@code non-null;} local state associated with this instance */
- private final RegisterSpecSet locals;
+ /** {@code non-null;} local state associated with this instance */
+ private final RegisterSpecSet locals;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param locals {@code non-null;} associated local variable state
- */
- public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) {
- super(position);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param locals {@code non-null;} associated local variable state
+ */
+ public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) {
+ super(position);
- if (locals == null) {
- throw new NullPointerException("locals == null");
- }
-
- this.locals = locals;
+ if (locals == null) {
+ throw new NullPointerException("locals == null");
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisterOffset(int delta) {
- return new LocalSnapshot(getPosition(), locals.withOffset(delta));
+ this.locals = locals;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisterOffset(int delta) {
+ return new LocalSnapshot(getPosition(), locals.withOffset(delta));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new LocalSnapshot(getPosition(), locals);
+ }
+
+ /**
+ * Gets the local state associated with this instance.
+ *
+ * @return {@code non-null;} the state
+ */
+ public RegisterSpecSet getLocals() {
+ return locals;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return locals.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ int sz = locals.size();
+ int max = locals.getMaxSize();
+ StringBuffer sb = new StringBuffer(100 + sz * 40);
+
+ sb.append("local-snapshot");
+
+ for (int i = 0; i < max; i++) {
+ RegisterSpec spec = locals.get(i);
+ if (spec != null) {
+ sb.append("\n ");
+ sb.append(LocalStart.localString(spec));
+ }
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new LocalSnapshot(getPosition(), locals);
- }
-
- /**
- * Gets the local state associated with this instance.
- *
- * @return {@code non-null;} the state
- */
- public RegisterSpecSet getLocals() {
- return locals;
- }
-
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return locals.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- int sz = locals.size();
- int max = locals.getMaxSize();
- StringBuffer sb = new StringBuffer(100 + sz * 40);
-
- sb.append("local-snapshot");
-
- for (int i = 0; i < max; i++) {
- RegisterSpec spec = locals.get(i);
- if (spec != null) {
- sb.append("\n ");
- sb.append(LocalStart.localString(spec));
- }
- }
-
- return sb.toString();
- }
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/LocalStart.java b/dx/src/com/android/jack/dx/dex/code/LocalStart.java
index 9b8a400..5d5f6ab 100644
--- a/dx/src/com/android/jack/dx/dex/code/LocalStart.java
+++ b/dx/src/com/android/jack/dx/dex/code/LocalStart.java
@@ -27,72 +27,72 @@
* is bound.
*/
public final class LocalStart extends ZeroSizeInsn {
- /**
- * {@code non-null;} register spec representing the local variable introduced
- * by this instance
- */
- private final RegisterSpec local;
+ /**
+ * {@code non-null;} register spec representing the local variable introduced
+ * by this instance
+ */
+ private final RegisterSpec local;
- /**
- * Returns the local variable listing string for a single register spec.
- *
- * @param spec {@code non-null;} the spec to convert
- * @return {@code non-null;} the string form
- */
- public static String localString(RegisterSpec spec) {
- return spec.regString() + ' ' + spec.getLocalItem().toString() + ": " +
- spec.getTypeBearer().toHuman();
+ /**
+ * Returns the local variable listing string for a single register spec.
+ *
+ * @param spec {@code non-null;} the spec to convert
+ * @return {@code non-null;} the string form
+ */
+ public static String localString(RegisterSpec spec) {
+ return spec.regString() + ' ' + spec.getLocalItem().toString() + ": "
+ + spec.getTypeBearer().toHuman();
+ }
+
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param local {@code non-null;} register spec representing the local
+ * variable introduced by this instance
+ */
+ public LocalStart(SourcePosition position, RegisterSpec local) {
+ super(position);
+
+ if (local == null) {
+ throw new NullPointerException("local == null");
}
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param local {@code non-null;} register spec representing the local
- * variable introduced by this instance
- */
- public LocalStart(SourcePosition position, RegisterSpec local) {
- super(position);
+ this.local = local;
+ }
- if (local == null) {
- throw new NullPointerException("local == null");
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisterOffset(int delta) {
+ return new LocalStart(getPosition(), local.withOffset(delta));
+ }
- this.local = local;
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new LocalStart(getPosition(), local);
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisterOffset(int delta) {
- return new LocalStart(getPosition(), local.withOffset(delta));
- }
+ /**
+ * Gets the register spec representing the local variable introduced
+ * by this instance.
+ *
+ * @return {@code non-null;} the register spec
+ */
+ public RegisterSpec getLocal() {
+ return local;
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new LocalStart(getPosition(), local);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return local.toString();
+ }
- /**
- * Gets the register spec representing the local variable introduced
- * by this instance.
- *
- * @return {@code non-null;} the register spec
- */
- public RegisterSpec getLocal() {
- return local;
- }
-
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return local.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- return "local-start " + localString(local);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ return "local-start " + localString(local);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/OddSpacer.java b/dx/src/com/android/jack/dx/dex/code/OddSpacer.java
index c9166f5..8924659 100644
--- a/dx/src/com/android/jack/dx/dex/code/OddSpacer.java
+++ b/dx/src/com/android/jack/dx/dex/code/OddSpacer.java
@@ -28,49 +28,49 @@
* require it.
*/
public final class OddSpacer extends VariableSizeInsn {
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- */
- public OddSpacer(SourcePosition position) {
- super(position, RegisterSpecList.EMPTY);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ */
+ public OddSpacer(SourcePosition position) {
+ super(position, RegisterSpecList.EMPTY);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return (getAddress() & 1);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out) {
+ if (codeSize() != 0) {
+ out.writeShort(InsnFormat.codeUnit(Opcodes.NOP, 0));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new OddSpacer(getPosition());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ if (codeSize() == 0) {
+ return null;
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return (getAddress() & 1);
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out) {
- if (codeSize() != 0) {
- out.writeShort(InsnFormat.codeUnit(Opcodes.NOP, 0));
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new OddSpacer(getPosition());
- }
-
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- if (codeSize() == 0) {
- return null;
- }
-
- return "nop // spacer";
- }
+ return "nop // spacer";
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/OutputCollector.java b/dx/src/com/android/jack/dx/dex/code/OutputCollector.java
index 3225b24..6c12f4c 100644
--- a/dx/src/com/android/jack/dx/dex/code/OutputCollector.java
+++ b/dx/src/com/android/jack/dx/dex/code/OutputCollector.java
@@ -29,93 +29,93 @@
* instance.
*/
public final class OutputCollector {
- /**
- * {@code non-null;} the associated finisher (which holds the instruction
- * list in-progress)
- */
- private final OutputFinisher finisher;
+ /**
+ * {@code non-null;} the associated finisher (which holds the instruction
+ * list in-progress)
+ */
+ private final OutputFinisher finisher;
- /**
- * {@code null-ok;} suffix for the output, or {@code null} if the suffix
- * has been appended to the main output (by {@link #appendSuffixToOutput})
- */
- private ArrayList<DalvInsn> suffix;
+ /**
+ * {@code null-ok;} suffix for the output, or {@code null} if the suffix
+ * has been appended to the main output (by {@link #appendSuffixToOutput})
+ */
+ private ArrayList<DalvInsn> suffix;
- /**
- * Constructs an instance.
- *
- * @param dexOptions {@code non-null;} options for dex output
- * @param initialCapacity {@code >= 0;} initial capacity of the output list
- * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
- * suffix
- * @param regCount {@code >= 0;} register count for the method
- */
- public OutputCollector(DexOptions dexOptions, int initialCapacity, int suffixInitialCapacity,
- int regCount) {
- this.finisher = new OutputFinisher(dexOptions, initialCapacity, regCount);
- this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity);
+ /**
+ * Constructs an instance.
+ *
+ * @param dexOptions {@code non-null;} options for dex output
+ * @param initialCapacity {@code >= 0;} initial capacity of the output list
+ * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
+ * suffix
+ * @param regCount {@code >= 0;} register count for the method
+ */
+ public OutputCollector(DexOptions dexOptions, int initialCapacity, int suffixInitialCapacity,
+ int regCount) {
+ this.finisher = new OutputFinisher(dexOptions, initialCapacity, regCount);
+ this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity);
+ }
+
+ /**
+ * Adds an instruction to the output.
+ *
+ * @param insn {@code non-null;} the instruction to add
+ */
+ public void add(DalvInsn insn) {
+ finisher.add(insn);
+ }
+
+ /**
+ * Reverses a branch which is buried a given number of instructions
+ * backward in the output. It is illegal to call this unless the
+ * indicated instruction really is a reversible branch.
+ *
+ * @param which how many instructions back to find the branch;
+ * {@code 0} is the most recently added instruction,
+ * {@code 1} is the instruction before that, etc.
+ * @param newTarget {@code non-null;} the new target for the reversed branch
+ */
+ public void reverseBranch(int which, CodeAddress newTarget) {
+ finisher.reverseBranch(which, newTarget);
+ }
+
+ /**
+ * Adds an instruction to the output suffix.
+ *
+ * @param insn {@code non-null;} the instruction to add
+ */
+ public void addSuffix(DalvInsn insn) {
+ suffix.add(insn);
+ }
+
+ /**
+ * Gets the results of all the calls on this instance, in the form of
+ * an {@link OutputFinisher}.
+ *
+ * @return {@code non-null;} the output finisher
+ * @throws UnsupportedOperationException if this method has
+ * already been called
+ */
+ public OutputFinisher getFinisher() {
+ if (suffix == null) {
+ throw new UnsupportedOperationException("already processed");
}
- /**
- * Adds an instruction to the output.
- *
- * @param insn {@code non-null;} the instruction to add
- */
- public void add(DalvInsn insn) {
- finisher.add(insn);
+ appendSuffixToOutput();
+ return finisher;
+ }
+
+ /**
+ * Helper for {@link #getFinisher}, which appends the suffix to
+ * the primary output.
+ */
+ private void appendSuffixToOutput() {
+ int size = suffix.size();
+
+ for (int i = 0; i < size; i++) {
+ finisher.add(suffix.get(i));
}
- /**
- * Reverses a branch which is buried a given number of instructions
- * backward in the output. It is illegal to call this unless the
- * indicated instruction really is a reversible branch.
- *
- * @param which how many instructions back to find the branch;
- * {@code 0} is the most recently added instruction,
- * {@code 1} is the instruction before that, etc.
- * @param newTarget {@code non-null;} the new target for the reversed branch
- */
- public void reverseBranch(int which, CodeAddress newTarget) {
- finisher.reverseBranch(which, newTarget);
- }
-
- /**
- * Adds an instruction to the output suffix.
- *
- * @param insn {@code non-null;} the instruction to add
- */
- public void addSuffix(DalvInsn insn) {
- suffix.add(insn);
- }
-
- /**
- * Gets the results of all the calls on this instance, in the form of
- * an {@link OutputFinisher}.
- *
- * @return {@code non-null;} the output finisher
- * @throws UnsupportedOperationException if this method has
- * already been called
- */
- public OutputFinisher getFinisher() {
- if (suffix == null) {
- throw new UnsupportedOperationException("already processed");
- }
-
- appendSuffixToOutput();
- return finisher;
- }
-
- /**
- * Helper for {@link #getFinisher}, which appends the suffix to
- * the primary output.
- */
- private void appendSuffixToOutput() {
- int size = suffix.size();
-
- for (int i = 0; i < size; i++) {
- finisher.add(suffix.get(i));
- }
-
- suffix = null;
- }
+ suffix = null;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/OutputFinisher.java b/dx/src/com/android/jack/dx/dex/code/OutputFinisher.java
index f004b02..ac3923d 100644
--- a/dx/src/com/android/jack/dx/dex/code/OutputFinisher.java
+++ b/dx/src/com/android/jack/dx/dex/code/OutputFinisher.java
@@ -41,744 +41,735 @@
* form of a {@link DalvInsnList} instance.
*/
public final class OutputFinisher {
- /** {@code non-null;} options for dex output */
- private final DexOptions dexOptions;
+ /** {@code non-null;} options for dex output */
+ private final DexOptions dexOptions;
- /**
- * {@code >= 0;} register count for the method, not including any extra
- * "reserved" registers needed to translate "difficult" instructions
- */
- private final int unreservedRegCount;
+ /**
+ * {@code >= 0;} register count for the method, not including any extra
+ * "reserved" registers needed to translate "difficult" instructions
+ */
+ private final int unreservedRegCount;
- /** {@code non-null;} the list of instructions, per se */
- private ArrayList<DalvInsn> insns;
+ /** {@code non-null;} the list of instructions, per se */
+ private ArrayList<DalvInsn> insns;
- /** whether any instruction has position info */
- private boolean hasAnyPositionInfo;
+ /** whether any instruction has position info */
+ private boolean hasAnyPositionInfo;
- /** whether any instruction has local variable info */
- private boolean hasAnyLocalInfo;
+ /** whether any instruction has local variable info */
+ private boolean hasAnyLocalInfo;
- /**
- * {@code >= 0;} the count of reserved registers (low-numbered
- * registers used when expanding instructions that can't be
- * represented simply); becomes valid after a call to {@link
- * #massageInstructions}
- */
- private int reservedCount;
+ /**
+ * {@code >= 0;} the count of reserved registers (low-numbered
+ * registers used when expanding instructions that can't be
+ * represented simply); becomes valid after a call to {@link
+ * #massageInstructions}
+ */
+ private int reservedCount;
- /**
- * Constructs an instance. It initially contains no instructions.
- *
- * @param dexOptions {@code non-null;} options for dex output
- * @param regCount {@code >= 0;} register count for the method
- * @param initialCapacity {@code >= 0;} initial capacity of the
- * instructions list
- */
- public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount) {
- this.dexOptions = dexOptions;
- this.unreservedRegCount = regCount;
- this.insns = new ArrayList<DalvInsn>(initialCapacity);
- this.reservedCount = -1;
- this.hasAnyPositionInfo = false;
- this.hasAnyLocalInfo = false;
- }
+ /**
+ * Constructs an instance. It initially contains no instructions.
+ *
+ * @param dexOptions {@code non-null;} options for dex output
+ * @param regCount {@code >= 0;} register count for the method
+ * @param initialCapacity {@code >= 0;} initial capacity of the
+ * instructions list
+ */
+ public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount) {
+ this.dexOptions = dexOptions;
+ this.unreservedRegCount = regCount;
+ this.insns = new ArrayList<DalvInsn>(initialCapacity);
+ this.reservedCount = -1;
+ this.hasAnyPositionInfo = false;
+ this.hasAnyLocalInfo = false;
+ }
- /**
- * Returns whether any of the instructions added to this instance
- * come with position info.
- *
- * @return whether any of the instructions added to this instance
- * come with position info
- */
- public boolean hasAnyPositionInfo() {
- return hasAnyPositionInfo;
- }
+ /**
+ * Returns whether any of the instructions added to this instance
+ * come with position info.
+ *
+ * @return whether any of the instructions added to this instance
+ * come with position info
+ */
+ public boolean hasAnyPositionInfo() {
+ return hasAnyPositionInfo;
+ }
- /**
- * Returns whether this instance has any local variable information.
- *
- * @return whether this instance has any local variable information
- */
- public boolean hasAnyLocalInfo() {
- return hasAnyLocalInfo;
- }
+ /**
+ * Returns whether this instance has any local variable information.
+ *
+ * @return whether this instance has any local variable information
+ */
+ public boolean hasAnyLocalInfo() {
+ return hasAnyLocalInfo;
+ }
- /**
- * Helper for {@link #add} which scrutinizes a single
- * instruction for local variable information.
- *
- * @param insn {@code non-null;} instruction to scrutinize
- * @return {@code true} iff the instruction refers to any
- * named locals
- */
- private static boolean hasLocalInfo(DalvInsn insn) {
- if (insn instanceof LocalSnapshot) {
- RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
- int size = specs.size();
- for (int i = 0; i < size; i++) {
- if (hasLocalInfo(specs.get(i))) {
- return true;
- }
- }
- } else if (insn instanceof LocalStart) {
- RegisterSpec spec = ((LocalStart) insn).getLocal();
- if (hasLocalInfo(spec)) {
- return true;
- }
+ /**
+ * Helper for {@link #add} which scrutinizes a single
+ * instruction for local variable information.
+ *
+ * @param insn {@code non-null;} instruction to scrutinize
+ * @return {@code true} iff the instruction refers to any
+ * named locals
+ */
+ private static boolean hasLocalInfo(DalvInsn insn) {
+ if (insn instanceof LocalSnapshot) {
+ RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+ int size = specs.size();
+ for (int i = 0; i < size; i++) {
+ if (hasLocalInfo(specs.get(i))) {
+ return true;
}
-
- return false;
+ }
+ } else if (insn instanceof LocalStart) {
+ RegisterSpec spec = ((LocalStart) insn).getLocal();
+ if (hasLocalInfo(spec)) {
+ return true;
+ }
}
- /**
- * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
- * register spec.
- *
- * @param spec {@code non-null;} spec to scrutinize
- * @return {@code true} iff the spec refers to any
- * named locals
- */
- private static boolean hasLocalInfo(RegisterSpec spec) {
- return (spec != null)
- && (spec.getLocalItem().getName() != null);
+ return false;
+ }
+
+ /**
+ * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
+ * register spec.
+ *
+ * @param spec {@code non-null;} spec to scrutinize
+ * @return {@code true} iff the spec refers to any
+ * named locals
+ */
+ private static boolean hasLocalInfo(RegisterSpec spec) {
+ return (spec != null) && (spec.getLocalItem().getName() != null);
+ }
+
+ /**
+ * Returns the set of all constants referred to by instructions added
+ * to this instance.
+ *
+ * @return {@code non-null;} the set of constants
+ */
+ public HashSet<Constant> getAllConstants() {
+ HashSet<Constant> result = new HashSet<Constant>(20);
+
+ for (DalvInsn insn : insns) {
+ addConstants(result, insn);
}
- /**
- * Returns the set of all constants referred to by instructions added
- * to this instance.
- *
- * @return {@code non-null;} the set of constants
- */
- public HashSet<Constant> getAllConstants() {
- HashSet<Constant> result = new HashSet<Constant>(20);
+ return result;
+ }
- for (DalvInsn insn : insns) {
- addConstants(result, insn);
- }
+ /**
+ * Helper for {@link #getAllConstants} which adds all the info for
+ * a single instruction.
+ *
+ * @param result {@code non-null;} result set to add to
+ * @param insn {@code non-null;} instruction to scrutinize
+ */
+ private static void addConstants(HashSet<Constant> result, DalvInsn insn) {
+ if (insn instanceof CstInsn) {
+ Constant cst = ((CstInsn) insn).getConstant();
+ result.add(cst);
+ } else if (insn instanceof LocalSnapshot) {
+ RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+ int size = specs.size();
+ for (int i = 0; i < size; i++) {
+ addConstants(result, specs.get(i));
+ }
+ } else if (insn instanceof LocalStart) {
+ RegisterSpec spec = ((LocalStart) insn).getLocal();
+ addConstants(result, spec);
+ }
+ }
- return result;
+ /**
+ * Helper for {@link #getAllConstants} which adds all the info for
+ * a single {@code RegisterSpec}.
+ *
+ * @param result {@code non-null;} result set to add to
+ * @param spec {@code null-ok;} register spec to add
+ */
+ private static void addConstants(HashSet<Constant> result, RegisterSpec spec) {
+ if (spec == null) {
+ return;
}
- /**
- * Helper for {@link #getAllConstants} which adds all the info for
- * a single instruction.
- *
- * @param result {@code non-null;} result set to add to
- * @param insn {@code non-null;} instruction to scrutinize
- */
- private static void addConstants(HashSet<Constant> result,
- DalvInsn insn) {
- if (insn instanceof CstInsn) {
- Constant cst = ((CstInsn) insn).getConstant();
- result.add(cst);
- } else if (insn instanceof LocalSnapshot) {
- RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
- int size = specs.size();
- for (int i = 0; i < size; i++) {
- addConstants(result, specs.get(i));
- }
- } else if (insn instanceof LocalStart) {
- RegisterSpec spec = ((LocalStart) insn).getLocal();
- addConstants(result, spec);
- }
+ LocalItem local = spec.getLocalItem();
+ CstString name = local.getName();
+ CstString signature = local.getSignature();
+ Type type = spec.getType();
+ CstType localType = local.getType();
+
+ if (type != Type.KNOWN_NULL) {
+ result.add(CstType.intern(type));
}
- /**
- * Helper for {@link #getAllConstants} which adds all the info for
- * a single {@code RegisterSpec}.
- *
- * @param result {@code non-null;} result set to add to
- * @param spec {@code null-ok;} register spec to add
- */
- private static void addConstants(HashSet<Constant> result,
- RegisterSpec spec) {
- if (spec == null) {
- return;
- }
-
- LocalItem local = spec.getLocalItem();
- CstString name = local.getName();
- CstString signature = local.getSignature();
- Type type = spec.getType();
- CstType localType = local.getType();
-
- if (type != Type.KNOWN_NULL) {
- result.add(CstType.intern(type));
- }
-
- if (localType != null) {
- result.add(localType);
- }
-
- if (name != null) {
- result.add(name);
- }
-
- if (signature != null) {
- result.add(signature);
- }
+ if (localType != null) {
+ result.add(localType);
}
- /**
- * Adds an instruction to the output.
- *
- * @param insn {@code non-null;} the instruction to add
- */
- public void add(DalvInsn insn) {
- insns.add(insn);
- updateInfo(insn);
+ if (name != null) {
+ result.add(name);
}
- /**
- * Inserts an instruction in the output at the given offset.
- *
- * @param at {@code >= 0;} what index to insert at
- * @param insn {@code non-null;} the instruction to insert
- */
- public void insert(int at, DalvInsn insn) {
- insns.add(at, insn);
- updateInfo(insn);
+ if (signature != null) {
+ result.add(signature);
+ }
+ }
+
+ /**
+ * Adds an instruction to the output.
+ *
+ * @param insn {@code non-null;} the instruction to add
+ */
+ public void add(DalvInsn insn) {
+ insns.add(insn);
+ updateInfo(insn);
+ }
+
+ /**
+ * Inserts an instruction in the output at the given offset.
+ *
+ * @param at {@code >= 0;} what index to insert at
+ * @param insn {@code non-null;} the instruction to insert
+ */
+ public void insert(int at, DalvInsn insn) {
+ insns.add(at, insn);
+ updateInfo(insn);
+ }
+
+ /**
+ * Helper for {@link #add} and {@link #insert},
+ * which updates the position and local info flags.
+ *
+ * @param insn {@code non-null;} an instruction that was just introduced
+ */
+ private void updateInfo(DalvInsn insn) {
+ if (!hasAnyPositionInfo) {
+ SourcePosition pos = insn.getPosition();
+ if (pos.getLine() >= 0) {
+ hasAnyPositionInfo = true;
+ }
}
- /**
- * Helper for {@link #add} and {@link #insert},
- * which updates the position and local info flags.
- *
- * @param insn {@code non-null;} an instruction that was just introduced
+ if (!hasAnyLocalInfo) {
+ if (hasLocalInfo(insn)) {
+ hasAnyLocalInfo = true;
+ }
+ }
+ }
+
+ /**
+ * Reverses a branch which is buried a given number of instructions
+ * backward in the output. It is illegal to call this unless the
+ * indicated instruction really is a reversible branch.
+ *
+ * @param which how many instructions back to find the branch;
+ * {@code 0} is the most recently added instruction,
+ * {@code 1} is the instruction before that, etc.
+ * @param newTarget {@code non-null;} the new target for the
+ * reversed branch
+ */
+ public void reverseBranch(int which, CodeAddress newTarget) {
+ int size = insns.size();
+ int index = size - which - 1;
+ TargetInsn targetInsn;
+
+ try {
+ targetInsn = (TargetInsn) insns.get(index);
+ } catch (IndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("too few instructions");
+ } catch (ClassCastException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("non-reversible instruction");
+ }
+
+ /*
+ * No need to call this.set(), since the format and other info
+ * are the same.
*/
- private void updateInfo(DalvInsn insn) {
- if (! hasAnyPositionInfo) {
- SourcePosition pos = insn.getPosition();
- if (pos.getLine() >= 0) {
- hasAnyPositionInfo = true;
- }
+ insns.set(index, targetInsn.withNewTargetAndReversed(newTarget));
+ }
+
+ /**
+ * Assigns indices in all instructions that need them, using the
+ * given callback to perform lookups. This should be called before
+ * calling {@link #finishProcessingAndGetList}.
+ *
+ * @param callback {@code non-null;} callback object
+ */
+ public void assignIndices(DalvCode.AssignIndicesCallback callback) {
+ for (DalvInsn insn : insns) {
+ if (insn instanceof CstInsn) {
+ assignIndices((CstInsn) insn, callback);
+ }
+ }
+ }
+
+ /**
+ * Helper for {@link #assignIndices} which does assignment for one
+ * instruction.
+ *
+ * @param insn {@code non-null;} the instruction
+ * @param callback {@code non-null;} the callback
+ */
+ private static void assignIndices(CstInsn insn, DalvCode.AssignIndicesCallback callback) {
+ Constant cst = insn.getConstant();
+ int index = callback.getIndex(cst);
+
+ if (index >= 0) {
+ insn.setIndex(index);
+ }
+
+ if (cst instanceof CstMemberRef) {
+ CstMemberRef member = (CstMemberRef) cst;
+ CstType definer = member.getDefiningClass();
+ index = callback.getIndex(definer);
+ if (index >= 0) {
+ insn.setClassIndex(index);
+ }
+ }
+ }
+
+ /**
+ * Does final processing on this instance and gets the output as
+ * a {@link DalvInsnList}. Final processing consists of:
+ *
+ * <ul>
+ * <li>optionally renumbering registers (to make room as needed for
+ * expanded instructions)</li>
+ * <li>picking a final opcode for each instruction</li>
+ * <li>rewriting instructions, because of register number,
+ * constant pool index, or branch target size issues</li>
+ * <li>assigning final addresses</li>
+ * </ul>
+ *
+ * <p><b>Note:</b> This method may only be called once per instance
+ * of this class.</p>
+ *
+ * @return {@code non-null;} the output list
+ * @throws UnsupportedOperationException if this method has
+ * already been called
+ */
+ public DalvInsnList finishProcessingAndGetList() {
+ if (reservedCount >= 0) {
+ throw new UnsupportedOperationException("already processed");
+ }
+
+ Dop[] opcodes = makeOpcodesArray();
+ reserveRegisters(opcodes);
+ massageInstructions(opcodes);
+ assignAddressesAndFixBranches();
+
+ return DalvInsnList.makeImmutable(insns, reservedCount + unreservedRegCount);
+ }
+
+ /**
+ * Helper for {@link #finishProcessingAndGetList}, which extracts
+ * the opcode out of each instruction into a separate array, to be
+ * further manipulated as things progress.
+ *
+ * @return {@code non-null;} the array of opcodes
+ */
+ private Dop[] makeOpcodesArray() {
+ int size = insns.size();
+ Dop[] result = new Dop[size];
+
+ for (int i = 0; i < size; i++) {
+ result[i] = insns.get(i).getOpcode();
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper for {@link #finishProcessingAndGetList}, which figures
+ * out how many reserved registers are required and then reserving
+ * them. It also updates the given {@code opcodes} array so
+ * as to avoid extra work when constructing the massaged
+ * instruction list.
+ *
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
+ */
+ private void reserveRegisters(Dop[] opcodes) {
+ int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
+
+ /*
+ * Call calculateReservedCount() and then perform register
+ * reservation, repeatedly until no new reservations happen.
+ */
+ for (;;) {
+ int newReservedCount = calculateReservedCount(opcodes);
+ if (oldReservedCount >= newReservedCount) {
+ break;
+ }
+
+ int reservedDifference = newReservedCount - oldReservedCount;
+ int size = insns.size();
+
+ for (int i = 0; i < size; i++) {
+ /*
+ * CodeAddress instance identity is used to link
+ * TargetInsns to their targets, so it is
+ * inappropriate to make replacements, and they don't
+ * have registers in any case. Hence, the instanceof
+ * test below.
+ */
+ DalvInsn insn = insns.get(i);
+ if (!(insn instanceof CodeAddress)) {
+ /*
+ * No need to call this.set() since the format and
+ * other info are the same.
+ */
+ insns.set(i, insn.withRegisterOffset(reservedDifference));
}
+ }
- if (! hasAnyLocalInfo) {
- if (hasLocalInfo(insn)) {
- hasAnyLocalInfo = true;
- }
- }
+ oldReservedCount = newReservedCount;
}
- /**
- * Reverses a branch which is buried a given number of instructions
- * backward in the output. It is illegal to call this unless the
- * indicated instruction really is a reversible branch.
- *
- * @param which how many instructions back to find the branch;
- * {@code 0} is the most recently added instruction,
- * {@code 1} is the instruction before that, etc.
- * @param newTarget {@code non-null;} the new target for the
- * reversed branch
- */
- public void reverseBranch(int which, CodeAddress newTarget) {
- int size = insns.size();
- int index = size - which - 1;
- TargetInsn targetInsn;
+ reservedCount = oldReservedCount;
+ }
+ /**
+ * Helper for {@link #reserveRegisters}, which does one
+ * pass over the instructions, calculating the number of
+ * registers that need to be reserved. It also updates the
+ * {@code opcodes} list to help avoid extra work in future
+ * register reservation passes.
+ *
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
+ * @return {@code >= 0;} the count of reserved registers
+ */
+ private int calculateReservedCount(Dop[] opcodes) {
+ int size = insns.size();
+
+ /*
+ * Potential new value of reservedCount, which gets updated in the
+ * following loop. It starts out with the existing reservedCount
+ * and gets increased if it turns out that additional registers
+ * need to be reserved.
+ */
+ int newReservedCount = reservedCount;
+
+ for (int i = 0; i < size; i++) {
+ DalvInsn insn = insns.get(i);
+ Dop originalOpcode = opcodes[i];
+ Dop newOpcode = findOpcodeForInsn(insn, originalOpcode);
+
+ if (newOpcode == null) {
+ /*
+ * The instruction will need to be expanded, so find the
+ * expanded opcode and reserve registers for it.
+ */
+ Dop expandedOp = findExpandedOpcodeForInsn(insn);
+ BitSet compatRegs = expandedOp.getFormat().compatibleRegs(insn);
+ int reserve = insn.getMinimumRegisterRequirement(compatRegs);
+ if (reserve > newReservedCount) {
+ newReservedCount = reserve;
+ }
+ } else if (originalOpcode == newOpcode) {
+ continue;
+ }
+
+ opcodes[i] = newOpcode;
+ }
+
+ return newReservedCount;
+ }
+
+ /**
+ * Attempts to fit the given instruction into a specific opcode,
+ * returning the opcode whose format that the instruction fits
+ * into or {@code null} to indicate that the instruction will need
+ * to be expanded. This fitting process starts with the given
+ * opcode as a first "best guess" and then pessimizes from there
+ * if necessary.
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @param guess {@code null-ok;} the current guess as to the best
+ * opcode; {@code null} means that no simple opcode fits
+ * @return {@code null-ok;} a possibly-different opcode; either a
+ * {@code non-null} good fit or {@code null} to indicate that no
+ * simple opcode fits
+ */
+ private Dop findOpcodeForInsn(DalvInsn insn, Dop guess) {
+ /*
+ * Note: The initial guess might be null, meaning that an
+ * earlier call to this method already determined that there
+ * was no possible simple opcode fit.
+ */
+
+while (guess != null) {
+ if (guess.getFormat().isCompatible(insn)) {
+ /*
+ * Don't break out for const_string to generate jumbo version
+ * when option is enabled.
+ */
+ if (!dexOptions.forceJumbo || guess.getOpcode() != Opcodes.CONST_STRING) {
+ break;
+ }
+ }
+
+ guess = Dops.getNextOrNull(guess, dexOptions);
+ }
+
+ return guess;
+ }
+
+ /**
+ * Finds the proper opcode for the given instruction, ignoring
+ * register constraints.
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @return {@code non-null;} the opcode that fits
+ */
+ private Dop findExpandedOpcodeForInsn(DalvInsn insn) {
+ Dop result = findOpcodeForInsn(insn.getLowRegVersion(), insn.getOpcode());
+ if (result == null) {
+ throw new DexException("No expanded opcode for " + insn);
+ }
+ return result;
+ }
+
+ /**
+ * Helper for {@link #finishProcessingAndGetList}, which goes
+ * through each instruction in the output, making sure its opcode
+ * can accomodate its arguments. In cases where the opcode is
+ * unable to do so, this replaces the instruction with a larger
+ * instruction with identical semantics that <i>will</i> work.
+ *
+ * <p>This method may also reserve a number of low-numbered
+ * registers, renumbering the instructions' original registers, in
+ * order to have register space available in which to move
+ * very-high registers when expanding instructions into
+ * multi-instruction sequences. This expansion is done when no
+ * simple instruction format can be found for a given instruction that
+ * is able to accomodate that instruction's registers.</p>
+ *
+ * <p>This method ignores issues of branch target size, since
+ * final addresses aren't known at the point that this method is
+ * called.</p>
+ *
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
+ */
+ private void massageInstructions(Dop[] opcodes) {
+ if (reservedCount == 0) {
+ /*
+ * The easy common case: No registers were reserved, so we
+ * merely need to replace any instructions whose format
+ * (and hence whose opcode) changed during the reservation
+ * pass, but all instructions will stay at their original
+ * indices, and the instruction list doesn't grow.
+ */
+ int size = insns.size();
+
+ for (int i = 0; i < size; i++) {
+ DalvInsn insn = insns.get(i);
+ Dop originalOpcode = insn.getOpcode();
+ Dop currentOpcode = opcodes[i];
+
+ if (originalOpcode != currentOpcode) {
+ insns.set(i, insn.withOpcode(currentOpcode));
+ }
+ }
+ } else {
+ /*
+ * The difficult uncommon case: Some instructions have to be
+ * expanded to deal with high registers.
+ */
+ insns = performExpansion(opcodes);
+ }
+ }
+
+ /**
+ * Helper for {@link #massageInstructions}, which constructs a
+ * replacement list, where each {link DalvInsn} instance that
+ * couldn't be represented simply (due to register representation
+ * problems) is expanded into a series of instances that together
+ * perform the proper function.
+ *
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
+ * @return {@code non-null;} the replacement list
+ */
+ private ArrayList<DalvInsn> performExpansion(Dop[] opcodes) {
+ int size = insns.size();
+ ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
+
+ ArrayList<CodeAddress> closelyBoundAddresses = new ArrayList<CodeAddress>();
+
+ for (int i = 0; i < size; i++) {
+ DalvInsn insn = insns.get(i);
+ Dop originalOpcode = insn.getOpcode();
+ Dop currentOpcode = opcodes[i];
+ DalvInsn prefix;
+ DalvInsn suffix;
+
+ if (currentOpcode != null) {
+ // No expansion is necessary.
+ prefix = null;
+ suffix = null;
+ } else {
+ // Expansion is required.
+ currentOpcode = findExpandedOpcodeForInsn(insn);
+ BitSet compatRegs = currentOpcode.getFormat().compatibleRegs(insn);
+ prefix = insn.expandedPrefix(compatRegs);
+ suffix = insn.expandedSuffix(compatRegs);
+
+ // Expand necessary registers to fit the new format
+ insn = insn.expandedVersion(compatRegs);
+ }
+
+ if (insn instanceof CodeAddress) {
+ // If we have a closely bound address, don't add it yet,
+ // because we need to add it after the prefix for the
+ // instruction it is bound to.
+ if (((CodeAddress) insn).getBindsClosely()) {
+ closelyBoundAddresses.add((CodeAddress) insn);
+ continue;
+ }
+ }
+
+ if (prefix != null) {
+ result.add(prefix);
+ }
+
+ // Add any pending closely bound addresses
+ if (!(insn instanceof ZeroSizeInsn) && closelyBoundAddresses.size() > 0) {
+ for (CodeAddress codeAddress : closelyBoundAddresses) {
+ result.add(codeAddress);
+ }
+ closelyBoundAddresses.clear();
+ }
+
+ if (currentOpcode != originalOpcode) {
+ insn = insn.withOpcode(currentOpcode);
+ }
+ result.add(insn);
+
+ if (suffix != null) {
+ result.add(suffix);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper for {@link #finishProcessingAndGetList}, which assigns
+ * addresses to each instruction, possibly rewriting branches to
+ * fix ones that wouldn't otherwise be able to reach their
+ * targets.
+ */
+ private void assignAddressesAndFixBranches() {
+ for (;;) {
+ assignAddresses();
+ if (!fixBranches()) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Helper for {@link #assignAddressesAndFixBranches}, which
+ * assigns an address to each instruction, in order.
+ */
+ private void assignAddresses() {
+ int address = 0;
+ int size = insns.size();
+
+ for (int i = 0; i < size; i++) {
+ DalvInsn insn = insns.get(i);
+ insn.setAddress(address);
+ address += insn.codeSize();
+ }
+ }
+
+ /**
+ * Helper for {@link #assignAddressesAndFixBranches}, which checks
+ * the branch target size requirement of each branch instruction
+ * to make sure it fits. For instructions that don't fit, this
+ * rewrites them to use a {@code goto} of some sort. In the
+ * case of a conditional branch that doesn't fit, the sense of the
+ * test is reversed in order to branch around a {@code goto}
+ * to the original target.
+ *
+ * @return whether any branches had to be fixed
+ */
+ private boolean fixBranches() {
+ int size = insns.size();
+ boolean anyFixed = false;
+
+ for (int i = 0; i < size; i++) {
+ DalvInsn insn = insns.get(i);
+ if (!(insn instanceof TargetInsn)) {
+ // This loop only needs to inspect TargetInsns.
+ continue;
+ }
+
+ Dop opcode = insn.getOpcode();
+ TargetInsn target = (TargetInsn) insn;
+
+ if (opcode.getFormat().branchFits(target)) {
+ continue;
+ }
+
+ if (opcode.getFamily() == Opcodes.GOTO) {
+ // It is a goto; widen it if possible.
+ opcode = findOpcodeForInsn(insn, opcode);
+ if (opcode == null) {
+ /*
+ * The branch is already maximally large. This should
+ * only be possible if a method somehow manages to have
+ * more than 2^31 code units.
+ */
+ throw new UnsupportedOperationException("method too long");
+ }
+ insns.set(i, insn.withOpcode(opcode));
+ } else {
+ /*
+ * It is a conditional: Reverse its sense, and arrange for
+ * it to branch around an absolute goto to the original
+ * branch target.
+ *
+ * Note: An invariant of the list being processed is
+ * that every TargetInsn is followed by a CodeAddress.
+ * Hence, it is always safe to get the next element
+ * after a TargetInsn and cast it to CodeAddress, as
+ * is happening a few lines down.
+ *
+ * Also note: Size gets incremented by one here, as we
+ * have -- in the net -- added one additional element
+ * to the list, so we increment i to match. The added
+ * and changed elements will be inspected by a repeat
+ * call to this method after this invocation returns.
+ */
+ CodeAddress newTarget;
try {
- targetInsn = (TargetInsn) insns.get(index);
+ newTarget = (CodeAddress) insns.get(i + 1);
} catch (IndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("too few instructions");
+ // The TargetInsn / CodeAddress invariant was violated.
+ throw new IllegalStateException("unpaired TargetInsn (dangling)");
} catch (ClassCastException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("non-reversible instruction");
+ // The TargetInsn / CodeAddress invariant was violated.
+ throw new IllegalStateException("unpaired TargetInsn");
}
+ TargetInsn gotoInsn = new TargetInsn(Dops.GOTO, target.getPosition(),
+ RegisterSpecList.EMPTY, target.getTarget());
+ insns.set(i, gotoInsn);
+ insns.add(i, target.withNewTargetAndReversed(newTarget));
+ size++;
+ i++;
+ }
- /*
- * No need to call this.set(), since the format and other info
- * are the same.
- */
- insns.set(index, targetInsn.withNewTargetAndReversed(newTarget));
+ anyFixed = true;
}
- /**
- * Assigns indices in all instructions that need them, using the
- * given callback to perform lookups. This should be called before
- * calling {@link #finishProcessingAndGetList}.
- *
- * @param callback {@code non-null;} callback object
- */
- public void assignIndices(DalvCode.AssignIndicesCallback callback) {
- for (DalvInsn insn : insns) {
- if (insn instanceof CstInsn) {
- assignIndices((CstInsn) insn, callback);
- }
- }
- }
-
- /**
- * Helper for {@link #assignIndices} which does assignment for one
- * instruction.
- *
- * @param insn {@code non-null;} the instruction
- * @param callback {@code non-null;} the callback
- */
- private static void assignIndices(CstInsn insn,
- DalvCode.AssignIndicesCallback callback) {
- Constant cst = insn.getConstant();
- int index = callback.getIndex(cst);
-
- if (index >= 0) {
- insn.setIndex(index);
- }
-
- if (cst instanceof CstMemberRef) {
- CstMemberRef member = (CstMemberRef) cst;
- CstType definer = member.getDefiningClass();
- index = callback.getIndex(definer);
- if (index >= 0) {
- insn.setClassIndex(index);
- }
- }
- }
-
- /**
- * Does final processing on this instance and gets the output as
- * a {@link DalvInsnList}. Final processing consists of:
- *
- * <ul>
- * <li>optionally renumbering registers (to make room as needed for
- * expanded instructions)</li>
- * <li>picking a final opcode for each instruction</li>
- * <li>rewriting instructions, because of register number,
- * constant pool index, or branch target size issues</li>
- * <li>assigning final addresses</li>
- * </ul>
- *
- * <p><b>Note:</b> This method may only be called once per instance
- * of this class.</p>
- *
- * @return {@code non-null;} the output list
- * @throws UnsupportedOperationException if this method has
- * already been called
- */
- public DalvInsnList finishProcessingAndGetList() {
- if (reservedCount >= 0) {
- throw new UnsupportedOperationException("already processed");
- }
-
- Dop[] opcodes = makeOpcodesArray();
- reserveRegisters(opcodes);
- massageInstructions(opcodes);
- assignAddressesAndFixBranches();
-
- return DalvInsnList.makeImmutable(insns,
- reservedCount + unreservedRegCount);
- }
-
- /**
- * Helper for {@link #finishProcessingAndGetList}, which extracts
- * the opcode out of each instruction into a separate array, to be
- * further manipulated as things progress.
- *
- * @return {@code non-null;} the array of opcodes
- */
- private Dop[] makeOpcodesArray() {
- int size = insns.size();
- Dop[] result = new Dop[size];
-
- for (int i = 0; i < size; i++) {
- result[i] = insns.get(i).getOpcode();
- }
-
- return result;
- }
-
- /**
- * Helper for {@link #finishProcessingAndGetList}, which figures
- * out how many reserved registers are required and then reserving
- * them. It also updates the given {@code opcodes} array so
- * as to avoid extra work when constructing the massaged
- * instruction list.
- *
- * @param opcodes {@code non-null;} array of per-instruction
- * opcode selections
- */
- private void reserveRegisters(Dop[] opcodes) {
- int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
-
- /*
- * Call calculateReservedCount() and then perform register
- * reservation, repeatedly until no new reservations happen.
- */
- for (;;) {
- int newReservedCount = calculateReservedCount(opcodes);
- if (oldReservedCount >= newReservedCount) {
- break;
- }
-
- int reservedDifference = newReservedCount - oldReservedCount;
- int size = insns.size();
-
- for (int i = 0; i < size; i++) {
- /*
- * CodeAddress instance identity is used to link
- * TargetInsns to their targets, so it is
- * inappropriate to make replacements, and they don't
- * have registers in any case. Hence, the instanceof
- * test below.
- */
- DalvInsn insn = insns.get(i);
- if (!(insn instanceof CodeAddress)) {
- /*
- * No need to call this.set() since the format and
- * other info are the same.
- */
- insns.set(i, insn.withRegisterOffset(reservedDifference));
- }
- }
-
- oldReservedCount = newReservedCount;
- }
-
- reservedCount = oldReservedCount;
- }
-
- /**
- * Helper for {@link #reserveRegisters}, which does one
- * pass over the instructions, calculating the number of
- * registers that need to be reserved. It also updates the
- * {@code opcodes} list to help avoid extra work in future
- * register reservation passes.
- *
- * @param opcodes {@code non-null;} array of per-instruction
- * opcode selections
- * @return {@code >= 0;} the count of reserved registers
- */
- private int calculateReservedCount(Dop[] opcodes) {
- int size = insns.size();
-
- /*
- * Potential new value of reservedCount, which gets updated in the
- * following loop. It starts out with the existing reservedCount
- * and gets increased if it turns out that additional registers
- * need to be reserved.
- */
- int newReservedCount = reservedCount;
-
- for (int i = 0; i < size; i++) {
- DalvInsn insn = insns.get(i);
- Dop originalOpcode = opcodes[i];
- Dop newOpcode = findOpcodeForInsn(insn, originalOpcode);
-
- if (newOpcode == null) {
- /*
- * The instruction will need to be expanded, so find the
- * expanded opcode and reserve registers for it.
- */
- Dop expandedOp = findExpandedOpcodeForInsn(insn);
- BitSet compatRegs = expandedOp.getFormat().compatibleRegs(insn);
- int reserve = insn.getMinimumRegisterRequirement(compatRegs);
- if (reserve > newReservedCount) {
- newReservedCount = reserve;
- }
- } else if (originalOpcode == newOpcode) {
- continue;
- }
-
- opcodes[i] = newOpcode;
- }
-
- return newReservedCount;
- }
-
- /**
- * Attempts to fit the given instruction into a specific opcode,
- * returning the opcode whose format that the instruction fits
- * into or {@code null} to indicate that the instruction will need
- * to be expanded. This fitting process starts with the given
- * opcode as a first "best guess" and then pessimizes from there
- * if necessary.
- *
- * @param insn {@code non-null;} the instruction in question
- * @param guess {@code null-ok;} the current guess as to the best
- * opcode; {@code null} means that no simple opcode fits
- * @return {@code null-ok;} a possibly-different opcode; either a
- * {@code non-null} good fit or {@code null} to indicate that no
- * simple opcode fits
- */
- private Dop findOpcodeForInsn(DalvInsn insn, Dop guess) {
- /*
- * Note: The initial guess might be null, meaning that an
- * earlier call to this method already determined that there
- * was no possible simple opcode fit.
- */
-
- while (guess != null) {
- if (guess.getFormat().isCompatible(insn)) {
- /*
- * Don't break out for const_string to generate jumbo version
- * when option is enabled.
- */
- if (!dexOptions.forceJumbo ||
- guess.getOpcode() != Opcodes.CONST_STRING) {
- break;
- }
- }
-
- guess = Dops.getNextOrNull(guess, dexOptions);
- }
-
- return guess;
- }
-
- /**
- * Finds the proper opcode for the given instruction, ignoring
- * register constraints.
- *
- * @param insn {@code non-null;} the instruction in question
- * @return {@code non-null;} the opcode that fits
- */
- private Dop findExpandedOpcodeForInsn(DalvInsn insn) {
- Dop result = findOpcodeForInsn(insn.getLowRegVersion(), insn.getOpcode());
- if (result == null) {
- throw new DexException("No expanded opcode for " + insn);
- }
- return result;
- }
-
- /**
- * Helper for {@link #finishProcessingAndGetList}, which goes
- * through each instruction in the output, making sure its opcode
- * can accomodate its arguments. In cases where the opcode is
- * unable to do so, this replaces the instruction with a larger
- * instruction with identical semantics that <i>will</i> work.
- *
- * <p>This method may also reserve a number of low-numbered
- * registers, renumbering the instructions' original registers, in
- * order to have register space available in which to move
- * very-high registers when expanding instructions into
- * multi-instruction sequences. This expansion is done when no
- * simple instruction format can be found for a given instruction that
- * is able to accomodate that instruction's registers.</p>
- *
- * <p>This method ignores issues of branch target size, since
- * final addresses aren't known at the point that this method is
- * called.</p>
- *
- * @param opcodes {@code non-null;} array of per-instruction
- * opcode selections
- */
- private void massageInstructions(Dop[] opcodes) {
- if (reservedCount == 0) {
- /*
- * The easy common case: No registers were reserved, so we
- * merely need to replace any instructions whose format
- * (and hence whose opcode) changed during the reservation
- * pass, but all instructions will stay at their original
- * indices, and the instruction list doesn't grow.
- */
- int size = insns.size();
-
- for (int i = 0; i < size; i++) {
- DalvInsn insn = insns.get(i);
- Dop originalOpcode = insn.getOpcode();
- Dop currentOpcode = opcodes[i];
-
- if (originalOpcode != currentOpcode) {
- insns.set(i, insn.withOpcode(currentOpcode));
- }
- }
- } else {
- /*
- * The difficult uncommon case: Some instructions have to be
- * expanded to deal with high registers.
- */
- insns = performExpansion(opcodes);
- }
- }
-
- /**
- * Helper for {@link #massageInstructions}, which constructs a
- * replacement list, where each {link DalvInsn} instance that
- * couldn't be represented simply (due to register representation
- * problems) is expanded into a series of instances that together
- * perform the proper function.
- *
- * @param opcodes {@code non-null;} array of per-instruction
- * opcode selections
- * @return {@code non-null;} the replacement list
- */
- private ArrayList<DalvInsn> performExpansion(Dop[] opcodes) {
- int size = insns.size();
- ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
-
- ArrayList<CodeAddress> closelyBoundAddresses = new ArrayList<CodeAddress>();
-
- for (int i = 0; i < size; i++) {
- DalvInsn insn = insns.get(i);
- Dop originalOpcode = insn.getOpcode();
- Dop currentOpcode = opcodes[i];
- DalvInsn prefix;
- DalvInsn suffix;
-
- if (currentOpcode != null) {
- // No expansion is necessary.
- prefix = null;
- suffix = null;
- } else {
- // Expansion is required.
- currentOpcode = findExpandedOpcodeForInsn(insn);
- BitSet compatRegs =
- currentOpcode.getFormat().compatibleRegs(insn);
- prefix = insn.expandedPrefix(compatRegs);
- suffix = insn.expandedSuffix(compatRegs);
-
- // Expand necessary registers to fit the new format
- insn = insn.expandedVersion(compatRegs);
- }
-
- if (insn instanceof CodeAddress) {
- // If we have a closely bound address, don't add it yet,
- // because we need to add it after the prefix for the
- // instruction it is bound to.
- if (((CodeAddress) insn).getBindsClosely()) {
- closelyBoundAddresses.add((CodeAddress)insn);
- continue;
- }
- }
-
- if (prefix != null) {
- result.add(prefix);
- }
-
- // Add any pending closely bound addresses
- if (!(insn instanceof ZeroSizeInsn) && closelyBoundAddresses.size() > 0) {
- for (CodeAddress codeAddress: closelyBoundAddresses) {
- result.add(codeAddress);
- }
- closelyBoundAddresses.clear();
- }
-
- if (currentOpcode != originalOpcode) {
- insn = insn.withOpcode(currentOpcode);
- }
- result.add(insn);
-
- if (suffix != null) {
- result.add(suffix);
- }
- }
-
- return result;
- }
-
- /**
- * Helper for {@link #finishProcessingAndGetList}, which assigns
- * addresses to each instruction, possibly rewriting branches to
- * fix ones that wouldn't otherwise be able to reach their
- * targets.
- */
- private void assignAddressesAndFixBranches() {
- for (;;) {
- assignAddresses();
- if (!fixBranches()) {
- break;
- }
- }
- }
-
- /**
- * Helper for {@link #assignAddressesAndFixBranches}, which
- * assigns an address to each instruction, in order.
- */
- private void assignAddresses() {
- int address = 0;
- int size = insns.size();
-
- for (int i = 0; i < size; i++) {
- DalvInsn insn = insns.get(i);
- insn.setAddress(address);
- address += insn.codeSize();
- }
- }
-
- /**
- * Helper for {@link #assignAddressesAndFixBranches}, which checks
- * the branch target size requirement of each branch instruction
- * to make sure it fits. For instructions that don't fit, this
- * rewrites them to use a {@code goto} of some sort. In the
- * case of a conditional branch that doesn't fit, the sense of the
- * test is reversed in order to branch around a {@code goto}
- * to the original target.
- *
- * @return whether any branches had to be fixed
- */
- private boolean fixBranches() {
- int size = insns.size();
- boolean anyFixed = false;
-
- for (int i = 0; i < size; i++) {
- DalvInsn insn = insns.get(i);
- if (!(insn instanceof TargetInsn)) {
- // This loop only needs to inspect TargetInsns.
- continue;
- }
-
- Dop opcode = insn.getOpcode();
- TargetInsn target = (TargetInsn) insn;
-
- if (opcode.getFormat().branchFits(target)) {
- continue;
- }
-
- if (opcode.getFamily() == Opcodes.GOTO) {
- // It is a goto; widen it if possible.
- opcode = findOpcodeForInsn(insn, opcode);
- if (opcode == null) {
- /*
- * The branch is already maximally large. This should
- * only be possible if a method somehow manages to have
- * more than 2^31 code units.
- */
- throw new UnsupportedOperationException("method too long");
- }
- insns.set(i, insn.withOpcode(opcode));
- } else {
- /*
- * It is a conditional: Reverse its sense, and arrange for
- * it to branch around an absolute goto to the original
- * branch target.
- *
- * Note: An invariant of the list being processed is
- * that every TargetInsn is followed by a CodeAddress.
- * Hence, it is always safe to get the next element
- * after a TargetInsn and cast it to CodeAddress, as
- * is happening a few lines down.
- *
- * Also note: Size gets incremented by one here, as we
- * have -- in the net -- added one additional element
- * to the list, so we increment i to match. The added
- * and changed elements will be inspected by a repeat
- * call to this method after this invocation returns.
- */
- CodeAddress newTarget;
- try {
- newTarget = (CodeAddress) insns.get(i + 1);
- } catch (IndexOutOfBoundsException ex) {
- // The TargetInsn / CodeAddress invariant was violated.
- throw new IllegalStateException(
- "unpaired TargetInsn (dangling)");
- } catch (ClassCastException ex) {
- // The TargetInsn / CodeAddress invariant was violated.
- throw new IllegalStateException("unpaired TargetInsn");
- }
- TargetInsn gotoInsn =
- new TargetInsn(Dops.GOTO, target.getPosition(),
- RegisterSpecList.EMPTY, target.getTarget());
- insns.set(i, gotoInsn);
- insns.add(i, target.withNewTargetAndReversed(newTarget));
- size++;
- i++;
- }
-
- anyFixed = true;
- }
-
- return anyFixed;
- }
+ return anyFixed;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/PositionList.java b/dx/src/com/android/jack/dx/dex/code/PositionList.java
index 75432d8..9b4eedb 100644
--- a/dx/src/com/android/jack/dx/dex/code/PositionList.java
+++ b/dx/src/com/android/jack/dx/dex/code/PositionList.java
@@ -24,169 +24,169 @@
* method to extract an instance out of a {@link DalvInsnList}.
*/
public final class PositionList extends FixedSizeList {
- /** {@code non-null;} empty instance */
- public static final PositionList EMPTY = new PositionList(0);
+ /** {@code non-null;} empty instance */
+ public static final PositionList EMPTY = new PositionList(0);
+
+ /**
+ * constant for {@link #make} to indicate that no actual position
+ * information should be returned
+ */
+ public static final int NONE = 1;
+
+ /**
+ * constant for {@link #make} to indicate that only line number
+ * transitions should be returned
+ */
+ public static final int LINES = 2;
+
+ /**
+ * constant for {@link #make} to indicate that only "important" position
+ * information should be returned. This includes block starts and
+ * instructions that might throw.
+ */
+ public static final int IMPORTANT = 3;
+
+ /**
+ * Extracts and returns the source position information out of an
+ * instruction list.
+ *
+ * @param insns {@code non-null;} instructions to convert
+ * @param howMuch how much information should be included; one of the
+ * static constants defined by this class
+ * @return {@code non-null;} the positions list
+ */
+ public static PositionList make(DalvInsnList insns, int howMuch) {
+ switch (howMuch) {
+ case NONE: {
+ return EMPTY;
+ }
+ case LINES:
+ case IMPORTANT: {
+ // Valid.
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("bogus howMuch");
+ }
+ }
+
+ SourcePosition noInfo = SourcePosition.NO_INFO;
+ SourcePosition cur = noInfo;
+ int sz = insns.size();
+ PositionList.Entry[] arr = new PositionList.Entry[sz];
+ boolean lastWasTarget = false;
+ int at = 0;
+
+ for (int i = 0; i < sz; i++) {
+ DalvInsn insn = insns.get(i);
+
+ if (insn instanceof CodeAddress) {
+ lastWasTarget = true;;
+ continue;
+ }
+
+ SourcePosition pos = insn.getPosition();
+
+ if (pos.equals(noInfo) || pos.sameLine(cur)) {
+ continue;
+ }
+
+ if ((howMuch == IMPORTANT) && !lastWasTarget) {
+ continue;
+ }
+
+ cur = pos;
+ arr[at] = new PositionList.Entry(insn.getAddress(), pos);
+ at++;
+
+ lastWasTarget = false;
+ }
+
+ PositionList result = new PositionList(at);
+ for (int i = 0; i < at; i++) {
+ result.set(i, arr[i]);
+ }
+
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size {@code >= 0;} the size of the list
+ */
+ public PositionList(int size) {
+ super(size);
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Entry get(int n) {
+ return (Entry) get0(n);
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
+ */
+ public void set(int n, Entry entry) {
+ set0(n, entry);
+ }
+
+ /**
+ * Entry in a position list.
+ */
+ public static class Entry {
+ /** {@code >= 0;} address of this entry */
+ private final int address;
+
+ /** {@code non-null;} corresponding source position information */
+ private final SourcePosition position;
/**
- * constant for {@link #make} to indicate that no actual position
- * information should be returned
- */
- public static final int NONE = 1;
-
- /**
- * constant for {@link #make} to indicate that only line number
- * transitions should be returned
- */
- public static final int LINES = 2;
-
- /**
- * constant for {@link #make} to indicate that only "important" position
- * information should be returned. This includes block starts and
- * instructions that might throw.
- */
- public static final int IMPORTANT = 3;
-
- /**
- * Extracts and returns the source position information out of an
- * instruction list.
+ * Constructs an instance.
*
- * @param insns {@code non-null;} instructions to convert
- * @param howMuch how much information should be included; one of the
- * static constants defined by this class
- * @return {@code non-null;} the positions list
+ * @param address {@code >= 0;} address of this entry
+ * @param position {@code non-null;} corresponding source position information
*/
- public static PositionList make(DalvInsnList insns, int howMuch) {
- switch (howMuch) {
- case NONE: {
- return EMPTY;
- }
- case LINES:
- case IMPORTANT: {
- // Valid.
- break;
- }
- default: {
- throw new IllegalArgumentException("bogus howMuch");
- }
- }
+ public Entry(int address, SourcePosition position) {
+ if (address < 0) {
+ throw new IllegalArgumentException("address < 0");
+ }
- SourcePosition noInfo = SourcePosition.NO_INFO;
- SourcePosition cur = noInfo;
- int sz = insns.size();
- PositionList.Entry[] arr = new PositionList.Entry[sz];
- boolean lastWasTarget = false;
- int at = 0;
+ if (position == null) {
+ throw new NullPointerException("position == null");
+ }
- for (int i = 0; i < sz; i++) {
- DalvInsn insn = insns.get(i);
-
- if (insn instanceof CodeAddress) {
- lastWasTarget = true;;
- continue;
- }
-
- SourcePosition pos = insn.getPosition();
-
- if (pos.equals(noInfo) || pos.sameLine(cur)) {
- continue;
- }
-
- if ((howMuch == IMPORTANT) && !lastWasTarget) {
- continue;
- }
-
- cur = pos;
- arr[at] = new PositionList.Entry(insn.getAddress(), pos);
- at++;
-
- lastWasTarget = false;
- }
-
- PositionList result = new PositionList(at);
- for (int i = 0; i < at; i++) {
- result.set(i, arr[i]);
- }
-
- result.setImmutable();
- return result;
+ this.address = address;
+ this.position = position;
}
/**
- * Constructs an instance. All indices initially contain {@code null}.
+ * Gets the address.
*
- * @param size {@code >= 0;} the size of the list
+ * @return {@code >= 0;} the address
*/
- public PositionList(int size) {
- super(size);
+ public int getAddress() {
+ return address;
}
/**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
+ * Gets the source position information.
*
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
+ * @return {@code non-null;} the position information
*/
- public Entry get(int n) {
- return (Entry) get0(n);
+ public SourcePosition getPosition() {
+ return position;
}
-
- /**
- * Sets the entry at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param entry {@code non-null;} the entry to set at {@code n}
- */
- public void set(int n, Entry entry) {
- set0(n, entry);
- }
-
- /**
- * Entry in a position list.
- */
- public static class Entry {
- /** {@code >= 0;} address of this entry */
- private final int address;
-
- /** {@code non-null;} corresponding source position information */
- private final SourcePosition position;
-
- /**
- * Constructs an instance.
- *
- * @param address {@code >= 0;} address of this entry
- * @param position {@code non-null;} corresponding source position information
- */
- public Entry (int address, SourcePosition position) {
- if (address < 0) {
- throw new IllegalArgumentException("address < 0");
- }
-
- if (position == null) {
- throw new NullPointerException("position == null");
- }
-
- this.address = address;
- this.position = position;
- }
-
- /**
- * Gets the address.
- *
- * @return {@code >= 0;} the address
- */
- public int getAddress() {
- return address;
- }
-
- /**
- * Gets the source position information.
- *
- * @return {@code non-null;} the position information
- */
- public SourcePosition getPosition() {
- return position;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/RopToDop.java b/dx/src/com/android/jack/dx/dex/code/RopToDop.java
index 6f64397..5ea7830 100644
--- a/dx/src/com/android/jack/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/jack/dx/dex/code/RopToDop.java
@@ -35,553 +35,578 @@
* {@link Dop} instances.
*/
public final class RopToDop {
- /** {@code non-null;} map from all the common rops to dalvik opcodes */
- private static final HashMap<Rop, Dop> MAP;
+ /** {@code non-null;} map from all the common rops to dalvik opcodes */
+ private static final HashMap<Rop, Dop> MAP;
- /**
- * This class is uninstantiable.
+ /**
+ * This class is uninstantiable.
+ */
+ private RopToDop() {
+ // This space intentionally left blank.
+ }
+
+ /*
+ * The following comment lists each opcode that should be considered
+ * the "head" of an opcode chain, in terms of the process of fitting
+ * an instruction's arguments to an actual opcode. This list is
+ * automatically generated and may be of use in double-checking the
+ * manually-generated static initialization code for this class.
+ *
+ * TODO(dx team): Make opcode-gen produce useful code in this case instead
+ * of just a comment.
+ */
+
+ // BEGIN(first-opcodes); GENERATED AUTOMATICALLY BY opcode-gen
+ // Opcodes.NOP
+ // Opcodes.MOVE
+ // Opcodes.MOVE_WIDE
+ // Opcodes.MOVE_OBJECT
+ // Opcodes.MOVE_RESULT
+ // Opcodes.MOVE_RESULT_WIDE
+ // Opcodes.MOVE_RESULT_OBJECT
+ // Opcodes.MOVE_EXCEPTION
+ // Opcodes.RETURN_VOID
+ // Opcodes.RETURN
+ // Opcodes.RETURN_WIDE
+ // Opcodes.RETURN_OBJECT
+ // Opcodes.CONST_4
+ // Opcodes.CONST_WIDE_16
+ // Opcodes.CONST_STRING
+ // Opcodes.CONST_CLASS
+ // Opcodes.MONITOR_ENTER
+ // Opcodes.MONITOR_EXIT
+ // Opcodes.CHECK_CAST
+ // Opcodes.INSTANCE_OF
+ // Opcodes.ARRAY_LENGTH
+ // Opcodes.NEW_INSTANCE
+ // Opcodes.NEW_ARRAY
+ // Opcodes.FILLED_NEW_ARRAY
+ // Opcodes.FILL_ARRAY_DATA
+ // Opcodes.THROW
+ // Opcodes.GOTO
+ // Opcodes.PACKED_SWITCH
+ // Opcodes.SPARSE_SWITCH
+ // Opcodes.CMPL_FLOAT
+ // Opcodes.CMPG_FLOAT
+ // Opcodes.CMPL_DOUBLE
+ // Opcodes.CMPG_DOUBLE
+ // Opcodes.CMP_LONG
+ // Opcodes.IF_EQ
+ // Opcodes.IF_NE
+ // Opcodes.IF_LT
+ // Opcodes.IF_GE
+ // Opcodes.IF_GT
+ // Opcodes.IF_LE
+ // Opcodes.IF_EQZ
+ // Opcodes.IF_NEZ
+ // Opcodes.IF_LTZ
+ // Opcodes.IF_GEZ
+ // Opcodes.IF_GTZ
+ // Opcodes.IF_LEZ
+ // Opcodes.AGET
+ // Opcodes.AGET_WIDE
+ // Opcodes.AGET_OBJECT
+ // Opcodes.AGET_BOOLEAN
+ // Opcodes.AGET_BYTE
+ // Opcodes.AGET_CHAR
+ // Opcodes.AGET_SHORT
+ // Opcodes.APUT
+ // Opcodes.APUT_WIDE
+ // Opcodes.APUT_OBJECT
+ // Opcodes.APUT_BOOLEAN
+ // Opcodes.APUT_BYTE
+ // Opcodes.APUT_CHAR
+ // Opcodes.APUT_SHORT
+ // Opcodes.IGET
+ // Opcodes.IGET_WIDE
+ // Opcodes.IGET_OBJECT
+ // Opcodes.IGET_BOOLEAN
+ // Opcodes.IGET_BYTE
+ // Opcodes.IGET_CHAR
+ // Opcodes.IGET_SHORT
+ // Opcodes.IPUT
+ // Opcodes.IPUT_WIDE
+ // Opcodes.IPUT_OBJECT
+ // Opcodes.IPUT_BOOLEAN
+ // Opcodes.IPUT_BYTE
+ // Opcodes.IPUT_CHAR
+ // Opcodes.IPUT_SHORT
+ // Opcodes.SGET
+ // Opcodes.SGET_WIDE
+ // Opcodes.SGET_OBJECT
+ // Opcodes.SGET_BOOLEAN
+ // Opcodes.SGET_BYTE
+ // Opcodes.SGET_CHAR
+ // Opcodes.SGET_SHORT
+ // Opcodes.SPUT
+ // Opcodes.SPUT_WIDE
+ // Opcodes.SPUT_OBJECT
+ // Opcodes.SPUT_BOOLEAN
+ // Opcodes.SPUT_BYTE
+ // Opcodes.SPUT_CHAR
+ // Opcodes.SPUT_SHORT
+ // Opcodes.INVOKE_VIRTUAL
+ // Opcodes.INVOKE_SUPER
+ // Opcodes.INVOKE_DIRECT
+ // Opcodes.INVOKE_STATIC
+ // Opcodes.INVOKE_INTERFACE
+ // Opcodes.NEG_INT
+ // Opcodes.NOT_INT
+ // Opcodes.NEG_LONG
+ // Opcodes.NOT_LONG
+ // Opcodes.NEG_FLOAT
+ // Opcodes.NEG_DOUBLE
+ // Opcodes.INT_TO_LONG
+ // Opcodes.INT_TO_FLOAT
+ // Opcodes.INT_TO_DOUBLE
+ // Opcodes.LONG_TO_INT
+ // Opcodes.LONG_TO_FLOAT
+ // Opcodes.LONG_TO_DOUBLE
+ // Opcodes.FLOAT_TO_INT
+ // Opcodes.FLOAT_TO_LONG
+ // Opcodes.FLOAT_TO_DOUBLE
+ // Opcodes.DOUBLE_TO_INT
+ // Opcodes.DOUBLE_TO_LONG
+ // Opcodes.DOUBLE_TO_FLOAT
+ // Opcodes.INT_TO_BYTE
+ // Opcodes.INT_TO_CHAR
+ // Opcodes.INT_TO_SHORT
+ // Opcodes.ADD_INT_2ADDR
+ // Opcodes.SUB_INT_2ADDR
+ // Opcodes.MUL_INT_2ADDR
+ // Opcodes.DIV_INT_2ADDR
+ // Opcodes.REM_INT_2ADDR
+ // Opcodes.AND_INT_2ADDR
+ // Opcodes.OR_INT_2ADDR
+ // Opcodes.XOR_INT_2ADDR
+ // Opcodes.SHL_INT_2ADDR
+ // Opcodes.SHR_INT_2ADDR
+ // Opcodes.USHR_INT_2ADDR
+ // Opcodes.ADD_LONG_2ADDR
+ // Opcodes.SUB_LONG_2ADDR
+ // Opcodes.MUL_LONG_2ADDR
+ // Opcodes.DIV_LONG_2ADDR
+ // Opcodes.REM_LONG_2ADDR
+ // Opcodes.AND_LONG_2ADDR
+ // Opcodes.OR_LONG_2ADDR
+ // Opcodes.XOR_LONG_2ADDR
+ // Opcodes.SHL_LONG_2ADDR
+ // Opcodes.SHR_LONG_2ADDR
+ // Opcodes.USHR_LONG_2ADDR
+ // Opcodes.ADD_FLOAT_2ADDR
+ // Opcodes.SUB_FLOAT_2ADDR
+ // Opcodes.MUL_FLOAT_2ADDR
+ // Opcodes.DIV_FLOAT_2ADDR
+ // Opcodes.REM_FLOAT_2ADDR
+ // Opcodes.ADD_DOUBLE_2ADDR
+ // Opcodes.SUB_DOUBLE_2ADDR
+ // Opcodes.MUL_DOUBLE_2ADDR
+ // Opcodes.DIV_DOUBLE_2ADDR
+ // Opcodes.REM_DOUBLE_2ADDR
+ // Opcodes.ADD_INT_LIT8
+ // Opcodes.RSUB_INT_LIT8
+ // Opcodes.MUL_INT_LIT8
+ // Opcodes.DIV_INT_LIT8
+ // Opcodes.REM_INT_LIT8
+ // Opcodes.AND_INT_LIT8
+ // Opcodes.OR_INT_LIT8
+ // Opcodes.XOR_INT_LIT8
+ // Opcodes.SHL_INT_LIT8
+ // Opcodes.SHR_INT_LIT8
+ // Opcodes.USHR_INT_LIT8
+ // END(first-opcodes)
+
+ static {
+ /*
+ * Note: The choices made here are to pick the optimistically
+ * smallest Dalvik opcode, and leave it to later processing to
+ * pessimize. See the automatically-generated comment above
+ * for reference.
*/
- private RopToDop() {
- // This space intentionally left blank.
+ MAP = new HashMap<Rop, Dop>(400);
+ MAP.put(Rops.NOP, Dops.NOP);
+ MAP.put(Rops.MOVE_INT, Dops.MOVE);
+ MAP.put(Rops.MOVE_LONG, Dops.MOVE_WIDE);
+ MAP.put(Rops.MOVE_FLOAT, Dops.MOVE);
+ MAP.put(Rops.MOVE_DOUBLE, Dops.MOVE_WIDE);
+ MAP.put(Rops.MOVE_OBJECT, Dops.MOVE_OBJECT);
+ MAP.put(Rops.MOVE_PARAM_INT, Dops.MOVE);
+ MAP.put(Rops.MOVE_PARAM_LONG, Dops.MOVE_WIDE);
+ MAP.put(Rops.MOVE_PARAM_FLOAT, Dops.MOVE);
+ MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
+ MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
+
+ /*
+ * Note: No entry for MOVE_EXCEPTION, since it varies by
+ * exception type. (That is, there is no unique instance to
+ * add to the map.)
+ */
+
+MAP.put(Rops.CONST_INT, Dops.CONST_4);
+ MAP.put(Rops.CONST_LONG, Dops.CONST_WIDE_16);
+ MAP.put(Rops.CONST_FLOAT, Dops.CONST_4);
+ MAP.put(Rops.CONST_DOUBLE, Dops.CONST_WIDE_16);
+
+ /*
+ * Note: No entry for CONST_OBJECT, since it needs to turn
+ * into either CONST_STRING or CONST_CLASS.
+ */
+
+/*
+ * TODO(dx team): I think the only case of this is for null, and
+ * const/4 should cover that.
+ */
+ MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
+
+ MAP.put(Rops.GOTO, Dops.GOTO);
+ MAP.put(Rops.IF_EQZ_INT, Dops.IF_EQZ);
+ MAP.put(Rops.IF_NEZ_INT, Dops.IF_NEZ);
+ MAP.put(Rops.IF_LTZ_INT, Dops.IF_LTZ);
+ MAP.put(Rops.IF_GEZ_INT, Dops.IF_GEZ);
+ MAP.put(Rops.IF_LEZ_INT, Dops.IF_LEZ);
+ MAP.put(Rops.IF_GTZ_INT, Dops.IF_GTZ);
+ MAP.put(Rops.IF_EQZ_OBJECT, Dops.IF_EQZ);
+ MAP.put(Rops.IF_NEZ_OBJECT, Dops.IF_NEZ);
+ MAP.put(Rops.IF_EQ_INT, Dops.IF_EQ);
+ MAP.put(Rops.IF_NE_INT, Dops.IF_NE);
+ MAP.put(Rops.IF_LT_INT, Dops.IF_LT);
+ MAP.put(Rops.IF_GE_INT, Dops.IF_GE);
+ MAP.put(Rops.IF_LE_INT, Dops.IF_LE);
+ MAP.put(Rops.IF_GT_INT, Dops.IF_GT);
+ MAP.put(Rops.IF_EQ_OBJECT, Dops.IF_EQ);
+ MAP.put(Rops.IF_NE_OBJECT, Dops.IF_NE);
+ MAP.put(Rops.SWITCH, Dops.SPARSE_SWITCH);
+ MAP.put(Rops.ADD_INT, Dops.ADD_INT_2ADDR);
+ MAP.put(Rops.ADD_LONG, Dops.ADD_LONG_2ADDR);
+ MAP.put(Rops.ADD_FLOAT, Dops.ADD_FLOAT_2ADDR);
+ MAP.put(Rops.ADD_DOUBLE, Dops.ADD_DOUBLE_2ADDR);
+ MAP.put(Rops.SUB_INT, Dops.SUB_INT_2ADDR);
+ MAP.put(Rops.SUB_LONG, Dops.SUB_LONG_2ADDR);
+ MAP.put(Rops.SUB_FLOAT, Dops.SUB_FLOAT_2ADDR);
+ MAP.put(Rops.SUB_DOUBLE, Dops.SUB_DOUBLE_2ADDR);
+ MAP.put(Rops.MUL_INT, Dops.MUL_INT_2ADDR);
+ MAP.put(Rops.MUL_LONG, Dops.MUL_LONG_2ADDR);
+ MAP.put(Rops.MUL_FLOAT, Dops.MUL_FLOAT_2ADDR);
+ MAP.put(Rops.MUL_DOUBLE, Dops.MUL_DOUBLE_2ADDR);
+ MAP.put(Rops.DIV_INT, Dops.DIV_INT_2ADDR);
+ MAP.put(Rops.DIV_LONG, Dops.DIV_LONG_2ADDR);
+ MAP.put(Rops.DIV_FLOAT, Dops.DIV_FLOAT_2ADDR);
+ MAP.put(Rops.DIV_DOUBLE, Dops.DIV_DOUBLE_2ADDR);
+ MAP.put(Rops.REM_INT, Dops.REM_INT_2ADDR);
+ MAP.put(Rops.REM_LONG, Dops.REM_LONG_2ADDR);
+ MAP.put(Rops.REM_FLOAT, Dops.REM_FLOAT_2ADDR);
+ MAP.put(Rops.REM_DOUBLE, Dops.REM_DOUBLE_2ADDR);
+ MAP.put(Rops.NEG_INT, Dops.NEG_INT);
+ MAP.put(Rops.NEG_LONG, Dops.NEG_LONG);
+ MAP.put(Rops.NEG_FLOAT, Dops.NEG_FLOAT);
+ MAP.put(Rops.NEG_DOUBLE, Dops.NEG_DOUBLE);
+ MAP.put(Rops.AND_INT, Dops.AND_INT_2ADDR);
+ MAP.put(Rops.AND_LONG, Dops.AND_LONG_2ADDR);
+ MAP.put(Rops.OR_INT, Dops.OR_INT_2ADDR);
+ MAP.put(Rops.OR_LONG, Dops.OR_LONG_2ADDR);
+ MAP.put(Rops.XOR_INT, Dops.XOR_INT_2ADDR);
+ MAP.put(Rops.XOR_LONG, Dops.XOR_LONG_2ADDR);
+ MAP.put(Rops.SHL_INT, Dops.SHL_INT_2ADDR);
+ MAP.put(Rops.SHL_LONG, Dops.SHL_LONG_2ADDR);
+ MAP.put(Rops.SHR_INT, Dops.SHR_INT_2ADDR);
+ MAP.put(Rops.SHR_LONG, Dops.SHR_LONG_2ADDR);
+ MAP.put(Rops.USHR_INT, Dops.USHR_INT_2ADDR);
+ MAP.put(Rops.USHR_LONG, Dops.USHR_LONG_2ADDR);
+ MAP.put(Rops.NOT_INT, Dops.NOT_INT);
+ MAP.put(Rops.NOT_LONG, Dops.NOT_LONG);
+
+ MAP.put(Rops.ADD_CONST_INT, Dops.ADD_INT_LIT8);
+ // Note: No dalvik ops for other types of add_const.
+
+ MAP.put(Rops.SUB_CONST_INT, Dops.RSUB_INT_LIT8);
+ /*
+ * Note: No dalvik ops for any type of sub_const; instead
+ * there's a *reverse* sub (constant - reg) for ints only.
+ */
+
+MAP.put(Rops.MUL_CONST_INT, Dops.MUL_INT_LIT8);
+ // Note: No dalvik ops for other types of mul_const.
+
+ MAP.put(Rops.DIV_CONST_INT, Dops.DIV_INT_LIT8);
+ // Note: No dalvik ops for other types of div_const.
+
+ MAP.put(Rops.REM_CONST_INT, Dops.REM_INT_LIT8);
+ // Note: No dalvik ops for other types of rem_const.
+
+ MAP.put(Rops.AND_CONST_INT, Dops.AND_INT_LIT8);
+ // Note: No dalvik op for and_const_long.
+
+ MAP.put(Rops.OR_CONST_INT, Dops.OR_INT_LIT8);
+ // Note: No dalvik op for or_const_long.
+
+ MAP.put(Rops.XOR_CONST_INT, Dops.XOR_INT_LIT8);
+ // Note: No dalvik op for xor_const_long.
+
+ MAP.put(Rops.SHL_CONST_INT, Dops.SHL_INT_LIT8);
+ // Note: No dalvik op for shl_const_long.
+
+ MAP.put(Rops.SHR_CONST_INT, Dops.SHR_INT_LIT8);
+ // Note: No dalvik op for shr_const_long.
+
+ MAP.put(Rops.USHR_CONST_INT, Dops.USHR_INT_LIT8);
+ // Note: No dalvik op for shr_const_long.
+
+ MAP.put(Rops.CMPL_LONG, Dops.CMP_LONG);
+ MAP.put(Rops.CMPL_FLOAT, Dops.CMPL_FLOAT);
+ MAP.put(Rops.CMPL_DOUBLE, Dops.CMPL_DOUBLE);
+ MAP.put(Rops.CMPG_FLOAT, Dops.CMPG_FLOAT);
+ MAP.put(Rops.CMPG_DOUBLE, Dops.CMPG_DOUBLE);
+ MAP.put(Rops.CONV_L2I, Dops.LONG_TO_INT);
+ MAP.put(Rops.CONV_F2I, Dops.FLOAT_TO_INT);
+ MAP.put(Rops.CONV_D2I, Dops.DOUBLE_TO_INT);
+ MAP.put(Rops.CONV_I2L, Dops.INT_TO_LONG);
+ MAP.put(Rops.CONV_F2L, Dops.FLOAT_TO_LONG);
+ MAP.put(Rops.CONV_D2L, Dops.DOUBLE_TO_LONG);
+ MAP.put(Rops.CONV_I2F, Dops.INT_TO_FLOAT);
+ MAP.put(Rops.CONV_L2F, Dops.LONG_TO_FLOAT);
+ MAP.put(Rops.CONV_D2F, Dops.DOUBLE_TO_FLOAT);
+ MAP.put(Rops.CONV_I2D, Dops.INT_TO_DOUBLE);
+ MAP.put(Rops.CONV_L2D, Dops.LONG_TO_DOUBLE);
+ MAP.put(Rops.CONV_F2D, Dops.FLOAT_TO_DOUBLE);
+ MAP.put(Rops.TO_BYTE, Dops.INT_TO_BYTE);
+ MAP.put(Rops.TO_CHAR, Dops.INT_TO_CHAR);
+ MAP.put(Rops.TO_SHORT, Dops.INT_TO_SHORT);
+ MAP.put(Rops.RETURN_VOID, Dops.RETURN_VOID);
+ MAP.put(Rops.RETURN_INT, Dops.RETURN);
+ MAP.put(Rops.RETURN_LONG, Dops.RETURN_WIDE);
+ MAP.put(Rops.RETURN_FLOAT, Dops.RETURN);
+ MAP.put(Rops.RETURN_DOUBLE, Dops.RETURN_WIDE);
+ MAP.put(Rops.RETURN_OBJECT, Dops.RETURN_OBJECT);
+ MAP.put(Rops.ARRAY_LENGTH, Dops.ARRAY_LENGTH);
+ MAP.put(Rops.THROW, Dops.THROW);
+ MAP.put(Rops.MONITOR_ENTER, Dops.MONITOR_ENTER);
+ MAP.put(Rops.MONITOR_EXIT, Dops.MONITOR_EXIT);
+ MAP.put(Rops.AGET_INT, Dops.AGET);
+ MAP.put(Rops.AGET_LONG, Dops.AGET_WIDE);
+ MAP.put(Rops.AGET_FLOAT, Dops.AGET);
+ MAP.put(Rops.AGET_DOUBLE, Dops.AGET_WIDE);
+ MAP.put(Rops.AGET_OBJECT, Dops.AGET_OBJECT);
+ MAP.put(Rops.AGET_BOOLEAN, Dops.AGET_BOOLEAN);
+ MAP.put(Rops.AGET_BYTE, Dops.AGET_BYTE);
+ MAP.put(Rops.AGET_CHAR, Dops.AGET_CHAR);
+ MAP.put(Rops.AGET_SHORT, Dops.AGET_SHORT);
+ MAP.put(Rops.APUT_INT, Dops.APUT);
+ MAP.put(Rops.APUT_LONG, Dops.APUT_WIDE);
+ MAP.put(Rops.APUT_FLOAT, Dops.APUT);
+ MAP.put(Rops.APUT_DOUBLE, Dops.APUT_WIDE);
+ MAP.put(Rops.APUT_OBJECT, Dops.APUT_OBJECT);
+ MAP.put(Rops.APUT_BOOLEAN, Dops.APUT_BOOLEAN);
+ MAP.put(Rops.APUT_BYTE, Dops.APUT_BYTE);
+ MAP.put(Rops.APUT_CHAR, Dops.APUT_CHAR);
+ MAP.put(Rops.APUT_SHORT, Dops.APUT_SHORT);
+ MAP.put(Rops.NEW_INSTANCE, Dops.NEW_INSTANCE);
+ MAP.put(Rops.CHECK_CAST, Dops.CHECK_CAST);
+ MAP.put(Rops.INSTANCE_OF, Dops.INSTANCE_OF);
+
+ MAP.put(Rops.GET_FIELD_LONG, Dops.IGET_WIDE);
+ MAP.put(Rops.GET_FIELD_FLOAT, Dops.IGET);
+ MAP.put(Rops.GET_FIELD_DOUBLE, Dops.IGET_WIDE);
+ MAP.put(Rops.GET_FIELD_OBJECT, Dops.IGET_OBJECT);
+ /*
+ * Note: No map entries for get_field_* for non-long integral types,
+ * since they need to be handled specially (see dopFor() below).
+ */
+
+MAP.put(Rops.GET_STATIC_LONG, Dops.SGET_WIDE);
+ MAP.put(Rops.GET_STATIC_FLOAT, Dops.SGET);
+ MAP.put(Rops.GET_STATIC_DOUBLE, Dops.SGET_WIDE);
+ MAP.put(Rops.GET_STATIC_OBJECT, Dops.SGET_OBJECT);
+ /*
+ * Note: No map entries for get_static* for non-long integral types,
+ * since they need to be handled specially (see dopFor() below).
+ */
+
+MAP.put(Rops.PUT_FIELD_LONG, Dops.IPUT_WIDE);
+ MAP.put(Rops.PUT_FIELD_FLOAT, Dops.IPUT);
+ MAP.put(Rops.PUT_FIELD_DOUBLE, Dops.IPUT_WIDE);
+ MAP.put(Rops.PUT_FIELD_OBJECT, Dops.IPUT_OBJECT);
+ /*
+ * Note: No map entries for put_field_* for non-long integral types,
+ * since they need to be handled specially (see dopFor() below).
+ */
+
+MAP.put(Rops.PUT_STATIC_LONG, Dops.SPUT_WIDE);
+ MAP.put(Rops.PUT_STATIC_FLOAT, Dops.SPUT);
+ MAP.put(Rops.PUT_STATIC_DOUBLE, Dops.SPUT_WIDE);
+ MAP.put(Rops.PUT_STATIC_OBJECT, Dops.SPUT_OBJECT);
+ /*
+ * Note: No map entries for put_static* for non-long integral types,
+ * since they need to be handled specially (see dopFor() below).
+ */
+
+ /*
+ * Note: No map entries for invoke*, new_array, and
+ * filled_new_array, since they need to be handled specially
+ * (see dopFor() below).
+ */
+ }
+
+ /**
+ * Returns the dalvik opcode appropriate for the given register-based
+ * instruction.
+ *
+ * @param insn {@code non-null;} the original instruction
+ * @return the corresponding dalvik opcode; one of the constants in
+ * {@link Dops}
+ */
+ public static Dop dopFor(Insn insn) {
+ Rop rop = insn.getOpcode();
+
+ /*
+ * First, just try looking up the rop in the MAP of easy
+ * cases.
+ */
+ Dop result = MAP.get(rop);
+ if (result != null) {
+ return result;
}
/*
- * The following comment lists each opcode that should be considered
- * the "head" of an opcode chain, in terms of the process of fitting
- * an instruction's arguments to an actual opcode. This list is
- * automatically generated and may be of use in double-checking the
- * manually-generated static initialization code for this class.
+ * There was no easy case for the rop, so look up the opcode, and
+ * do something special for each:
*
- * TODO: Make opcode-gen produce useful code in this case instead
- * of just a comment.
+ * The move_exception, new_array, filled_new_array, and
+ * invoke* opcodes won't be found in MAP, since they'll each
+ * have different source and/or result register types / lists.
+ *
+ * The get* and put* opcodes for (non-long) integral types
+ * aren't in the map, since the type signatures aren't
+ * sufficient to distinguish between the types (the salient
+ * source or result will always be just "int").
+ *
+ * And const instruction need to distinguish between strings and
+ * classes.
*/
- // BEGIN(first-opcodes); GENERATED AUTOMATICALLY BY opcode-gen
- // Opcodes.NOP
- // Opcodes.MOVE
- // Opcodes.MOVE_WIDE
- // Opcodes.MOVE_OBJECT
- // Opcodes.MOVE_RESULT
- // Opcodes.MOVE_RESULT_WIDE
- // Opcodes.MOVE_RESULT_OBJECT
- // Opcodes.MOVE_EXCEPTION
- // Opcodes.RETURN_VOID
- // Opcodes.RETURN
- // Opcodes.RETURN_WIDE
- // Opcodes.RETURN_OBJECT
- // Opcodes.CONST_4
- // Opcodes.CONST_WIDE_16
- // Opcodes.CONST_STRING
- // Opcodes.CONST_CLASS
- // Opcodes.MONITOR_ENTER
- // Opcodes.MONITOR_EXIT
- // Opcodes.CHECK_CAST
- // Opcodes.INSTANCE_OF
- // Opcodes.ARRAY_LENGTH
- // Opcodes.NEW_INSTANCE
- // Opcodes.NEW_ARRAY
- // Opcodes.FILLED_NEW_ARRAY
- // Opcodes.FILL_ARRAY_DATA
- // Opcodes.THROW
- // Opcodes.GOTO
- // Opcodes.PACKED_SWITCH
- // Opcodes.SPARSE_SWITCH
- // Opcodes.CMPL_FLOAT
- // Opcodes.CMPG_FLOAT
- // Opcodes.CMPL_DOUBLE
- // Opcodes.CMPG_DOUBLE
- // Opcodes.CMP_LONG
- // Opcodes.IF_EQ
- // Opcodes.IF_NE
- // Opcodes.IF_LT
- // Opcodes.IF_GE
- // Opcodes.IF_GT
- // Opcodes.IF_LE
- // Opcodes.IF_EQZ
- // Opcodes.IF_NEZ
- // Opcodes.IF_LTZ
- // Opcodes.IF_GEZ
- // Opcodes.IF_GTZ
- // Opcodes.IF_LEZ
- // Opcodes.AGET
- // Opcodes.AGET_WIDE
- // Opcodes.AGET_OBJECT
- // Opcodes.AGET_BOOLEAN
- // Opcodes.AGET_BYTE
- // Opcodes.AGET_CHAR
- // Opcodes.AGET_SHORT
- // Opcodes.APUT
- // Opcodes.APUT_WIDE
- // Opcodes.APUT_OBJECT
- // Opcodes.APUT_BOOLEAN
- // Opcodes.APUT_BYTE
- // Opcodes.APUT_CHAR
- // Opcodes.APUT_SHORT
- // Opcodes.IGET
- // Opcodes.IGET_WIDE
- // Opcodes.IGET_OBJECT
- // Opcodes.IGET_BOOLEAN
- // Opcodes.IGET_BYTE
- // Opcodes.IGET_CHAR
- // Opcodes.IGET_SHORT
- // Opcodes.IPUT
- // Opcodes.IPUT_WIDE
- // Opcodes.IPUT_OBJECT
- // Opcodes.IPUT_BOOLEAN
- // Opcodes.IPUT_BYTE
- // Opcodes.IPUT_CHAR
- // Opcodes.IPUT_SHORT
- // Opcodes.SGET
- // Opcodes.SGET_WIDE
- // Opcodes.SGET_OBJECT
- // Opcodes.SGET_BOOLEAN
- // Opcodes.SGET_BYTE
- // Opcodes.SGET_CHAR
- // Opcodes.SGET_SHORT
- // Opcodes.SPUT
- // Opcodes.SPUT_WIDE
- // Opcodes.SPUT_OBJECT
- // Opcodes.SPUT_BOOLEAN
- // Opcodes.SPUT_BYTE
- // Opcodes.SPUT_CHAR
- // Opcodes.SPUT_SHORT
- // Opcodes.INVOKE_VIRTUAL
- // Opcodes.INVOKE_SUPER
- // Opcodes.INVOKE_DIRECT
- // Opcodes.INVOKE_STATIC
- // Opcodes.INVOKE_INTERFACE
- // Opcodes.NEG_INT
- // Opcodes.NOT_INT
- // Opcodes.NEG_LONG
- // Opcodes.NOT_LONG
- // Opcodes.NEG_FLOAT
- // Opcodes.NEG_DOUBLE
- // Opcodes.INT_TO_LONG
- // Opcodes.INT_TO_FLOAT
- // Opcodes.INT_TO_DOUBLE
- // Opcodes.LONG_TO_INT
- // Opcodes.LONG_TO_FLOAT
- // Opcodes.LONG_TO_DOUBLE
- // Opcodes.FLOAT_TO_INT
- // Opcodes.FLOAT_TO_LONG
- // Opcodes.FLOAT_TO_DOUBLE
- // Opcodes.DOUBLE_TO_INT
- // Opcodes.DOUBLE_TO_LONG
- // Opcodes.DOUBLE_TO_FLOAT
- // Opcodes.INT_TO_BYTE
- // Opcodes.INT_TO_CHAR
- // Opcodes.INT_TO_SHORT
- // Opcodes.ADD_INT_2ADDR
- // Opcodes.SUB_INT_2ADDR
- // Opcodes.MUL_INT_2ADDR
- // Opcodes.DIV_INT_2ADDR
- // Opcodes.REM_INT_2ADDR
- // Opcodes.AND_INT_2ADDR
- // Opcodes.OR_INT_2ADDR
- // Opcodes.XOR_INT_2ADDR
- // Opcodes.SHL_INT_2ADDR
- // Opcodes.SHR_INT_2ADDR
- // Opcodes.USHR_INT_2ADDR
- // Opcodes.ADD_LONG_2ADDR
- // Opcodes.SUB_LONG_2ADDR
- // Opcodes.MUL_LONG_2ADDR
- // Opcodes.DIV_LONG_2ADDR
- // Opcodes.REM_LONG_2ADDR
- // Opcodes.AND_LONG_2ADDR
- // Opcodes.OR_LONG_2ADDR
- // Opcodes.XOR_LONG_2ADDR
- // Opcodes.SHL_LONG_2ADDR
- // Opcodes.SHR_LONG_2ADDR
- // Opcodes.USHR_LONG_2ADDR
- // Opcodes.ADD_FLOAT_2ADDR
- // Opcodes.SUB_FLOAT_2ADDR
- // Opcodes.MUL_FLOAT_2ADDR
- // Opcodes.DIV_FLOAT_2ADDR
- // Opcodes.REM_FLOAT_2ADDR
- // Opcodes.ADD_DOUBLE_2ADDR
- // Opcodes.SUB_DOUBLE_2ADDR
- // Opcodes.MUL_DOUBLE_2ADDR
- // Opcodes.DIV_DOUBLE_2ADDR
- // Opcodes.REM_DOUBLE_2ADDR
- // Opcodes.ADD_INT_LIT8
- // Opcodes.RSUB_INT_LIT8
- // Opcodes.MUL_INT_LIT8
- // Opcodes.DIV_INT_LIT8
- // Opcodes.REM_INT_LIT8
- // Opcodes.AND_INT_LIT8
- // Opcodes.OR_INT_LIT8
- // Opcodes.XOR_INT_LIT8
- // Opcodes.SHL_INT_LIT8
- // Opcodes.SHR_INT_LIT8
- // Opcodes.USHR_INT_LIT8
- // END(first-opcodes)
+switch (rop.getOpcode()) {
+ case RegOps.MOVE_EXCEPTION:
+ return Dops.MOVE_EXCEPTION;
+ case RegOps.INVOKE_STATIC:
+ return Dops.INVOKE_STATIC;
+ case RegOps.INVOKE_VIRTUAL:
+ return Dops.INVOKE_VIRTUAL;
+ case RegOps.INVOKE_SUPER:
+ return Dops.INVOKE_SUPER;
+ case RegOps.INVOKE_DIRECT:
+ return Dops.INVOKE_DIRECT;
+ case RegOps.INVOKE_INTERFACE:
+ return Dops.INVOKE_INTERFACE;
+ case RegOps.NEW_ARRAY:
+ return Dops.NEW_ARRAY;
+ case RegOps.FILLED_NEW_ARRAY:
+ return Dops.FILLED_NEW_ARRAY;
+ case RegOps.FILL_ARRAY_DATA:
+ return Dops.FILL_ARRAY_DATA;
+ case RegOps.MOVE_RESULT: {
+ RegisterSpec resultReg = insn.getResult();
- static {
- /*
- * Note: The choices made here are to pick the optimistically
- * smallest Dalvik opcode, and leave it to later processing to
- * pessimize. See the automatically-generated comment above
- * for reference.
- */
- MAP = new HashMap<Rop, Dop>(400);
- MAP.put(Rops.NOP, Dops.NOP);
- MAP.put(Rops.MOVE_INT, Dops.MOVE);
- MAP.put(Rops.MOVE_LONG, Dops.MOVE_WIDE);
- MAP.put(Rops.MOVE_FLOAT, Dops.MOVE);
- MAP.put(Rops.MOVE_DOUBLE, Dops.MOVE_WIDE);
- MAP.put(Rops.MOVE_OBJECT, Dops.MOVE_OBJECT);
- MAP.put(Rops.MOVE_PARAM_INT, Dops.MOVE);
- MAP.put(Rops.MOVE_PARAM_LONG, Dops.MOVE_WIDE);
- MAP.put(Rops.MOVE_PARAM_FLOAT, Dops.MOVE);
- MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
- MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
+ if (resultReg == null) {
+ return Dops.NOP;
+ } else {
+ switch (resultReg.getBasicType()) {
+ case Type.BT_INT:
+ case Type.BT_FLOAT:
+ case Type.BT_BOOLEAN:
+ case Type.BT_BYTE:
+ case Type.BT_CHAR:
+ case Type.BT_SHORT:
+ return Dops.MOVE_RESULT;
+ case Type.BT_LONG:
+ case Type.BT_DOUBLE:
+ return Dops.MOVE_RESULT_WIDE;
+ case Type.BT_OBJECT:
+ return Dops.MOVE_RESULT_OBJECT;
+ default: {
+ throw new RuntimeException("Unexpected basic type");
+ }
+ }
+ }
+ }
- /*
- * Note: No entry for MOVE_EXCEPTION, since it varies by
- * exception type. (That is, there is no unique instance to
- * add to the map.)
- */
-
- MAP.put(Rops.CONST_INT, Dops.CONST_4);
- MAP.put(Rops.CONST_LONG, Dops.CONST_WIDE_16);
- MAP.put(Rops.CONST_FLOAT, Dops.CONST_4);
- MAP.put(Rops.CONST_DOUBLE, Dops.CONST_WIDE_16);
-
- /*
- * Note: No entry for CONST_OBJECT, since it needs to turn
- * into either CONST_STRING or CONST_CLASS.
- */
-
- /*
- * TODO: I think the only case of this is for null, and
- * const/4 should cover that.
- */
- MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
-
- MAP.put(Rops.GOTO, Dops.GOTO);
- MAP.put(Rops.IF_EQZ_INT, Dops.IF_EQZ);
- MAP.put(Rops.IF_NEZ_INT, Dops.IF_NEZ);
- MAP.put(Rops.IF_LTZ_INT, Dops.IF_LTZ);
- MAP.put(Rops.IF_GEZ_INT, Dops.IF_GEZ);
- MAP.put(Rops.IF_LEZ_INT, Dops.IF_LEZ);
- MAP.put(Rops.IF_GTZ_INT, Dops.IF_GTZ);
- MAP.put(Rops.IF_EQZ_OBJECT, Dops.IF_EQZ);
- MAP.put(Rops.IF_NEZ_OBJECT, Dops.IF_NEZ);
- MAP.put(Rops.IF_EQ_INT, Dops.IF_EQ);
- MAP.put(Rops.IF_NE_INT, Dops.IF_NE);
- MAP.put(Rops.IF_LT_INT, Dops.IF_LT);
- MAP.put(Rops.IF_GE_INT, Dops.IF_GE);
- MAP.put(Rops.IF_LE_INT, Dops.IF_LE);
- MAP.put(Rops.IF_GT_INT, Dops.IF_GT);
- MAP.put(Rops.IF_EQ_OBJECT, Dops.IF_EQ);
- MAP.put(Rops.IF_NE_OBJECT, Dops.IF_NE);
- MAP.put(Rops.SWITCH, Dops.SPARSE_SWITCH);
- MAP.put(Rops.ADD_INT, Dops.ADD_INT_2ADDR);
- MAP.put(Rops.ADD_LONG, Dops.ADD_LONG_2ADDR);
- MAP.put(Rops.ADD_FLOAT, Dops.ADD_FLOAT_2ADDR);
- MAP.put(Rops.ADD_DOUBLE, Dops.ADD_DOUBLE_2ADDR);
- MAP.put(Rops.SUB_INT, Dops.SUB_INT_2ADDR);
- MAP.put(Rops.SUB_LONG, Dops.SUB_LONG_2ADDR);
- MAP.put(Rops.SUB_FLOAT, Dops.SUB_FLOAT_2ADDR);
- MAP.put(Rops.SUB_DOUBLE, Dops.SUB_DOUBLE_2ADDR);
- MAP.put(Rops.MUL_INT, Dops.MUL_INT_2ADDR);
- MAP.put(Rops.MUL_LONG, Dops.MUL_LONG_2ADDR);
- MAP.put(Rops.MUL_FLOAT, Dops.MUL_FLOAT_2ADDR);
- MAP.put(Rops.MUL_DOUBLE, Dops.MUL_DOUBLE_2ADDR);
- MAP.put(Rops.DIV_INT, Dops.DIV_INT_2ADDR);
- MAP.put(Rops.DIV_LONG, Dops.DIV_LONG_2ADDR);
- MAP.put(Rops.DIV_FLOAT, Dops.DIV_FLOAT_2ADDR);
- MAP.put(Rops.DIV_DOUBLE, Dops.DIV_DOUBLE_2ADDR);
- MAP.put(Rops.REM_INT, Dops.REM_INT_2ADDR);
- MAP.put(Rops.REM_LONG, Dops.REM_LONG_2ADDR);
- MAP.put(Rops.REM_FLOAT, Dops.REM_FLOAT_2ADDR);
- MAP.put(Rops.REM_DOUBLE, Dops.REM_DOUBLE_2ADDR);
- MAP.put(Rops.NEG_INT, Dops.NEG_INT);
- MAP.put(Rops.NEG_LONG, Dops.NEG_LONG);
- MAP.put(Rops.NEG_FLOAT, Dops.NEG_FLOAT);
- MAP.put(Rops.NEG_DOUBLE, Dops.NEG_DOUBLE);
- MAP.put(Rops.AND_INT, Dops.AND_INT_2ADDR);
- MAP.put(Rops.AND_LONG, Dops.AND_LONG_2ADDR);
- MAP.put(Rops.OR_INT, Dops.OR_INT_2ADDR);
- MAP.put(Rops.OR_LONG, Dops.OR_LONG_2ADDR);
- MAP.put(Rops.XOR_INT, Dops.XOR_INT_2ADDR);
- MAP.put(Rops.XOR_LONG, Dops.XOR_LONG_2ADDR);
- MAP.put(Rops.SHL_INT, Dops.SHL_INT_2ADDR);
- MAP.put(Rops.SHL_LONG, Dops.SHL_LONG_2ADDR);
- MAP.put(Rops.SHR_INT, Dops.SHR_INT_2ADDR);
- MAP.put(Rops.SHR_LONG, Dops.SHR_LONG_2ADDR);
- MAP.put(Rops.USHR_INT, Dops.USHR_INT_2ADDR);
- MAP.put(Rops.USHR_LONG, Dops.USHR_LONG_2ADDR);
- MAP.put(Rops.NOT_INT, Dops.NOT_INT);
- MAP.put(Rops.NOT_LONG, Dops.NOT_LONG);
-
- MAP.put(Rops.ADD_CONST_INT, Dops.ADD_INT_LIT8);
- // Note: No dalvik ops for other types of add_const.
-
- MAP.put(Rops.SUB_CONST_INT, Dops.RSUB_INT_LIT8);
- /*
- * Note: No dalvik ops for any type of sub_const; instead
- * there's a *reverse* sub (constant - reg) for ints only.
- */
-
- MAP.put(Rops.MUL_CONST_INT, Dops.MUL_INT_LIT8);
- // Note: No dalvik ops for other types of mul_const.
-
- MAP.put(Rops.DIV_CONST_INT, Dops.DIV_INT_LIT8);
- // Note: No dalvik ops for other types of div_const.
-
- MAP.put(Rops.REM_CONST_INT, Dops.REM_INT_LIT8);
- // Note: No dalvik ops for other types of rem_const.
-
- MAP.put(Rops.AND_CONST_INT, Dops.AND_INT_LIT8);
- // Note: No dalvik op for and_const_long.
-
- MAP.put(Rops.OR_CONST_INT, Dops.OR_INT_LIT8);
- // Note: No dalvik op for or_const_long.
-
- MAP.put(Rops.XOR_CONST_INT, Dops.XOR_INT_LIT8);
- // Note: No dalvik op for xor_const_long.
-
- MAP.put(Rops.SHL_CONST_INT, Dops.SHL_INT_LIT8);
- // Note: No dalvik op for shl_const_long.
-
- MAP.put(Rops.SHR_CONST_INT, Dops.SHR_INT_LIT8);
- // Note: No dalvik op for shr_const_long.
-
- MAP.put(Rops.USHR_CONST_INT, Dops.USHR_INT_LIT8);
- // Note: No dalvik op for shr_const_long.
-
- MAP.put(Rops.CMPL_LONG, Dops.CMP_LONG);
- MAP.put(Rops.CMPL_FLOAT, Dops.CMPL_FLOAT);
- MAP.put(Rops.CMPL_DOUBLE, Dops.CMPL_DOUBLE);
- MAP.put(Rops.CMPG_FLOAT, Dops.CMPG_FLOAT);
- MAP.put(Rops.CMPG_DOUBLE, Dops.CMPG_DOUBLE);
- MAP.put(Rops.CONV_L2I, Dops.LONG_TO_INT);
- MAP.put(Rops.CONV_F2I, Dops.FLOAT_TO_INT);
- MAP.put(Rops.CONV_D2I, Dops.DOUBLE_TO_INT);
- MAP.put(Rops.CONV_I2L, Dops.INT_TO_LONG);
- MAP.put(Rops.CONV_F2L, Dops.FLOAT_TO_LONG);
- MAP.put(Rops.CONV_D2L, Dops.DOUBLE_TO_LONG);
- MAP.put(Rops.CONV_I2F, Dops.INT_TO_FLOAT);
- MAP.put(Rops.CONV_L2F, Dops.LONG_TO_FLOAT);
- MAP.put(Rops.CONV_D2F, Dops.DOUBLE_TO_FLOAT);
- MAP.put(Rops.CONV_I2D, Dops.INT_TO_DOUBLE);
- MAP.put(Rops.CONV_L2D, Dops.LONG_TO_DOUBLE);
- MAP.put(Rops.CONV_F2D, Dops.FLOAT_TO_DOUBLE);
- MAP.put(Rops.TO_BYTE, Dops.INT_TO_BYTE);
- MAP.put(Rops.TO_CHAR, Dops.INT_TO_CHAR);
- MAP.put(Rops.TO_SHORT, Dops.INT_TO_SHORT);
- MAP.put(Rops.RETURN_VOID, Dops.RETURN_VOID);
- MAP.put(Rops.RETURN_INT, Dops.RETURN);
- MAP.put(Rops.RETURN_LONG, Dops.RETURN_WIDE);
- MAP.put(Rops.RETURN_FLOAT, Dops.RETURN);
- MAP.put(Rops.RETURN_DOUBLE, Dops.RETURN_WIDE);
- MAP.put(Rops.RETURN_OBJECT, Dops.RETURN_OBJECT);
- MAP.put(Rops.ARRAY_LENGTH, Dops.ARRAY_LENGTH);
- MAP.put(Rops.THROW, Dops.THROW);
- MAP.put(Rops.MONITOR_ENTER, Dops.MONITOR_ENTER);
- MAP.put(Rops.MONITOR_EXIT, Dops.MONITOR_EXIT);
- MAP.put(Rops.AGET_INT, Dops.AGET);
- MAP.put(Rops.AGET_LONG, Dops.AGET_WIDE);
- MAP.put(Rops.AGET_FLOAT, Dops.AGET);
- MAP.put(Rops.AGET_DOUBLE, Dops.AGET_WIDE);
- MAP.put(Rops.AGET_OBJECT, Dops.AGET_OBJECT);
- MAP.put(Rops.AGET_BOOLEAN, Dops.AGET_BOOLEAN);
- MAP.put(Rops.AGET_BYTE, Dops.AGET_BYTE);
- MAP.put(Rops.AGET_CHAR, Dops.AGET_CHAR);
- MAP.put(Rops.AGET_SHORT, Dops.AGET_SHORT);
- MAP.put(Rops.APUT_INT, Dops.APUT);
- MAP.put(Rops.APUT_LONG, Dops.APUT_WIDE);
- MAP.put(Rops.APUT_FLOAT, Dops.APUT);
- MAP.put(Rops.APUT_DOUBLE, Dops.APUT_WIDE);
- MAP.put(Rops.APUT_OBJECT, Dops.APUT_OBJECT);
- MAP.put(Rops.APUT_BOOLEAN, Dops.APUT_BOOLEAN);
- MAP.put(Rops.APUT_BYTE, Dops.APUT_BYTE);
- MAP.put(Rops.APUT_CHAR, Dops.APUT_CHAR);
- MAP.put(Rops.APUT_SHORT, Dops.APUT_SHORT);
- MAP.put(Rops.NEW_INSTANCE, Dops.NEW_INSTANCE);
- MAP.put(Rops.CHECK_CAST, Dops.CHECK_CAST);
- MAP.put(Rops.INSTANCE_OF, Dops.INSTANCE_OF);
-
- MAP.put(Rops.GET_FIELD_LONG, Dops.IGET_WIDE);
- MAP.put(Rops.GET_FIELD_FLOAT, Dops.IGET);
- MAP.put(Rops.GET_FIELD_DOUBLE, Dops.IGET_WIDE);
- MAP.put(Rops.GET_FIELD_OBJECT, Dops.IGET_OBJECT);
- /*
- * Note: No map entries for get_field_* for non-long integral types,
- * since they need to be handled specially (see dopFor() below).
- */
-
- MAP.put(Rops.GET_STATIC_LONG, Dops.SGET_WIDE);
- MAP.put(Rops.GET_STATIC_FLOAT, Dops.SGET);
- MAP.put(Rops.GET_STATIC_DOUBLE, Dops.SGET_WIDE);
- MAP.put(Rops.GET_STATIC_OBJECT, Dops.SGET_OBJECT);
- /*
- * Note: No map entries for get_static* for non-long integral types,
- * since they need to be handled specially (see dopFor() below).
- */
-
- MAP.put(Rops.PUT_FIELD_LONG, Dops.IPUT_WIDE);
- MAP.put(Rops.PUT_FIELD_FLOAT, Dops.IPUT);
- MAP.put(Rops.PUT_FIELD_DOUBLE, Dops.IPUT_WIDE);
- MAP.put(Rops.PUT_FIELD_OBJECT, Dops.IPUT_OBJECT);
- /*
- * Note: No map entries for put_field_* for non-long integral types,
- * since they need to be handled specially (see dopFor() below).
- */
-
- MAP.put(Rops.PUT_STATIC_LONG, Dops.SPUT_WIDE);
- MAP.put(Rops.PUT_STATIC_FLOAT, Dops.SPUT);
- MAP.put(Rops.PUT_STATIC_DOUBLE, Dops.SPUT_WIDE);
- MAP.put(Rops.PUT_STATIC_OBJECT, Dops.SPUT_OBJECT);
- /*
- * Note: No map entries for put_static* for non-long integral types,
- * since they need to be handled specially (see dopFor() below).
- */
-
- /*
- * Note: No map entries for invoke*, new_array, and
- * filled_new_array, since they need to be handled specially
- * (see dopFor() below).
- */
+ case RegOps.GET_FIELD: {
+ CstFieldRef ref = (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+ int basicType = ref.getBasicType();
+ switch (basicType) {
+ case Type.BT_BOOLEAN:
+ return Dops.IGET_BOOLEAN;
+ case Type.BT_BYTE:
+ return Dops.IGET_BYTE;
+ case Type.BT_CHAR:
+ return Dops.IGET_CHAR;
+ case Type.BT_SHORT:
+ return Dops.IGET_SHORT;
+ case Type.BT_INT:
+ return Dops.IGET;
+ }
+ break;
+ }
+ case RegOps.PUT_FIELD: {
+ CstFieldRef ref = (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+ int basicType = ref.getBasicType();
+ switch (basicType) {
+ case Type.BT_BOOLEAN:
+ return Dops.IPUT_BOOLEAN;
+ case Type.BT_BYTE:
+ return Dops.IPUT_BYTE;
+ case Type.BT_CHAR:
+ return Dops.IPUT_CHAR;
+ case Type.BT_SHORT:
+ return Dops.IPUT_SHORT;
+ case Type.BT_INT:
+ return Dops.IPUT;
+ }
+ break;
+ }
+ case RegOps.GET_STATIC: {
+ CstFieldRef ref = (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+ int basicType = ref.getBasicType();
+ switch (basicType) {
+ case Type.BT_BOOLEAN:
+ return Dops.SGET_BOOLEAN;
+ case Type.BT_BYTE:
+ return Dops.SGET_BYTE;
+ case Type.BT_CHAR:
+ return Dops.SGET_CHAR;
+ case Type.BT_SHORT:
+ return Dops.SGET_SHORT;
+ case Type.BT_INT:
+ return Dops.SGET;
+ }
+ break;
+ }
+ case RegOps.PUT_STATIC: {
+ CstFieldRef ref = (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+ int basicType = ref.getBasicType();
+ switch (basicType) {
+ case Type.BT_BOOLEAN:
+ return Dops.SPUT_BOOLEAN;
+ case Type.BT_BYTE:
+ return Dops.SPUT_BYTE;
+ case Type.BT_CHAR:
+ return Dops.SPUT_CHAR;
+ case Type.BT_SHORT:
+ return Dops.SPUT_SHORT;
+ case Type.BT_INT:
+ return Dops.SPUT;
+ }
+ break;
+ }
+ case RegOps.CONST: {
+ Constant cst = ((ThrowingCstInsn) insn).getConstant();
+ if (cst instanceof CstType) {
+ return Dops.CONST_CLASS;
+ } else if (cst instanceof CstString) {
+ return Dops.CONST_STRING;
+ }
+ break;
+ }
}
- /**
- * Returns the dalvik opcode appropriate for the given register-based
- * instruction.
- *
- * @param insn {@code non-null;} the original instruction
- * @return the corresponding dalvik opcode; one of the constants in
- * {@link Dops}
- */
- public static Dop dopFor(Insn insn) {
- Rop rop = insn.getOpcode();
-
- /*
- * First, just try looking up the rop in the MAP of easy
- * cases.
- */
- Dop result = MAP.get(rop);
- if (result != null) {
- return result;
- }
-
- /*
- * There was no easy case for the rop, so look up the opcode, and
- * do something special for each:
- *
- * The move_exception, new_array, filled_new_array, and
- * invoke* opcodes won't be found in MAP, since they'll each
- * have different source and/or result register types / lists.
- *
- * The get* and put* opcodes for (non-long) integral types
- * aren't in the map, since the type signatures aren't
- * sufficient to distinguish between the types (the salient
- * source or result will always be just "int").
- *
- * And const instruction need to distinguish between strings and
- * classes.
- */
-
- switch (rop.getOpcode()) {
- case RegOps.MOVE_EXCEPTION: return Dops.MOVE_EXCEPTION;
- case RegOps.INVOKE_STATIC: return Dops.INVOKE_STATIC;
- case RegOps.INVOKE_VIRTUAL: return Dops.INVOKE_VIRTUAL;
- case RegOps.INVOKE_SUPER: return Dops.INVOKE_SUPER;
- case RegOps.INVOKE_DIRECT: return Dops.INVOKE_DIRECT;
- case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
- case RegOps.NEW_ARRAY: return Dops.NEW_ARRAY;
- case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
- case RegOps.FILL_ARRAY_DATA: return Dops.FILL_ARRAY_DATA;
- case RegOps.MOVE_RESULT: {
- RegisterSpec resultReg = insn.getResult();
-
- if (resultReg == null) {
- return Dops.NOP;
- } else {
- switch (resultReg.getBasicType()) {
- case Type.BT_INT:
- case Type.BT_FLOAT:
- case Type.BT_BOOLEAN:
- case Type.BT_BYTE:
- case Type.BT_CHAR:
- case Type.BT_SHORT:
- return Dops.MOVE_RESULT;
- case Type.BT_LONG:
- case Type.BT_DOUBLE:
- return Dops.MOVE_RESULT_WIDE;
- case Type.BT_OBJECT:
- return Dops.MOVE_RESULT_OBJECT;
- default: {
- throw new RuntimeException("Unexpected basic type");
- }
- }
- }
- }
-
- case RegOps.GET_FIELD: {
- CstFieldRef ref =
- (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
- int basicType = ref.getBasicType();
- switch (basicType) {
- case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
- case Type.BT_BYTE: return Dops.IGET_BYTE;
- case Type.BT_CHAR: return Dops.IGET_CHAR;
- case Type.BT_SHORT: return Dops.IGET_SHORT;
- case Type.BT_INT: return Dops.IGET;
- }
- break;
- }
- case RegOps.PUT_FIELD: {
- CstFieldRef ref =
- (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
- int basicType = ref.getBasicType();
- switch (basicType) {
- case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
- case Type.BT_BYTE: return Dops.IPUT_BYTE;
- case Type.BT_CHAR: return Dops.IPUT_CHAR;
- case Type.BT_SHORT: return Dops.IPUT_SHORT;
- case Type.BT_INT: return Dops.IPUT;
- }
- break;
- }
- case RegOps.GET_STATIC: {
- CstFieldRef ref =
- (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
- int basicType = ref.getBasicType();
- switch (basicType) {
- case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
- case Type.BT_BYTE: return Dops.SGET_BYTE;
- case Type.BT_CHAR: return Dops.SGET_CHAR;
- case Type.BT_SHORT: return Dops.SGET_SHORT;
- case Type.BT_INT: return Dops.SGET;
- }
- break;
- }
- case RegOps.PUT_STATIC: {
- CstFieldRef ref =
- (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
- int basicType = ref.getBasicType();
- switch (basicType) {
- case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
- case Type.BT_BYTE: return Dops.SPUT_BYTE;
- case Type.BT_CHAR: return Dops.SPUT_CHAR;
- case Type.BT_SHORT: return Dops.SPUT_SHORT;
- case Type.BT_INT: return Dops.SPUT;
- }
- break;
- }
- case RegOps.CONST: {
- Constant cst = ((ThrowingCstInsn) insn).getConstant();
- if (cst instanceof CstType) {
- return Dops.CONST_CLASS;
- } else if (cst instanceof CstString) {
- return Dops.CONST_STRING;
- }
- break;
- }
- }
-
- throw new RuntimeException("unknown rop: " + rop);
- }
+ throw new RuntimeException("unknown rop: " + rop);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/RopTranslator.java b/dx/src/com/android/jack/dx/dex/code/RopTranslator.java
index 29b7400..ef0b7f6 100644
--- a/dx/src/com/android/jack/dx/dex/code/RopTranslator.java
+++ b/dx/src/com/android/jack/dx/dex/code/RopTranslator.java
@@ -47,836 +47,802 @@
* #translate} method is the thing to call on this class.
*/
public final class RopTranslator {
- /** {@code non-null;} options for dex output */
- private final DexOptions dexOptions;
- /** {@code non-null;} method to translate */
- private final RopMethod method;
+ /** {@code non-null;} method to translate */
+ private final RopMethod method;
- /**
- * how much position info to preserve; one of the static
- * constants in {@link PositionList}
+ /**
+ * how much position info to preserve; one of the static
+ * constants in {@link PositionList}
+ */
+ private final int positionInfo;
+
+ /** {@code null-ok;} local variable info to use */
+ private final LocalVariableInfo locals;
+
+ /** {@code non-null;} container for all the address objects for the method */
+ private final BlockAddresses addresses;
+
+ /** {@code non-null;} list of output instructions in-progress */
+ private final OutputCollector output;
+
+ /** {@code non-null;} visitor to use during translation */
+ private final TranslationVisitor translationVisitor;
+
+ /** {@code >= 0;} register count for the method */
+ private final int regCount;
+
+ /** {@code null-ok;} block output order; becomes non-null in {@link #pickOrder} */
+ private int[] order;
+
+ /** size, in register units, of all the parameters to this method */
+ private final int paramSize;
+
+ /**
+ * true if the parameters to this method happen to be in proper order
+ * at the end of the frame (as the optimizer emits them)
+ */
+ private boolean paramsAreInOrder;
+
+ /**
+ * Translates a {@link RopMethod}. This may modify the given
+ * input.
+ *
+ * @param method {@code non-null;} the original method
+ * @param positionInfo how much position info to preserve; one of the
+ * static constants in {@link PositionList}
+ * @param locals {@code null-ok;} local variable information to use
+ * @param paramSize size, in register units, of all the parameters to
+ * this method
+ * @param dexOptions {@code non-null;} options for dex output
+ * @return {@code non-null;} the translated version
+ */
+ public static DalvCode translate(RopMethod method, int positionInfo, LocalVariableInfo locals,
+ int paramSize, DexOptions dexOptions) {
+ RopTranslator translator =
+ new RopTranslator(method, positionInfo, locals, paramSize, dexOptions);
+ return translator.translateAndGetResult();
+ }
+
+ /**
+ * Constructs an instance. This method is private. Use {@link #translate}.
+ *
+ * @param method {@code non-null;} the original method
+ * @param positionInfo how much position info to preserve; one of the
+ * static constants in {@link PositionList}
+ * @param locals {@code null-ok;} local variable information to use
+ * @param paramSize size, in register units, of all the parameters to
+ * this method
+ * @param dexOptions {@code non-null;} options for dex output
+ */
+ private RopTranslator(RopMethod method, int positionInfo, LocalVariableInfo locals, int paramSize,
+ DexOptions dexOptions) {
+ this.method = method;
+ this.positionInfo = positionInfo;
+ this.locals = locals;
+ this.addresses = new BlockAddresses(method);
+ this.paramSize = paramSize;
+ this.order = null;
+ this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
+
+ BasicBlockList blocks = method.getBlocks();
+ int bsz = blocks.size();
+
+ /*
+ * Max possible instructions includes three code address
+ * objects per basic block (to the first and last instruction,
+ * and just past the end of the block), and the possibility of
+ * an extra goto at the end of each basic block.
*/
- private final int positionInfo;
+ int maxInsns = (bsz * 3) + blocks.getInstructionCount();
- /** {@code null-ok;} local variable info to use */
- private final LocalVariableInfo locals;
+ if (locals != null) {
+ /*
+ * If we're tracking locals, then there's could be another
+ * extra instruction per block (for the locals state at the
+ * start of the block) as well as one for each interblock
+ * local introduction.
+ */
+ maxInsns += bsz + locals.getAssignmentCount();
+ }
- /** {@code non-null;} container for all the address objects for the method */
- private final BlockAddresses addresses;
+ /*
+ * If params are not in order, we will need register space
+ * for them before this is all over...
+ */
+ this.regCount = blocks.getRegCount() + (paramsAreInOrder ? 0 : this.paramSize);
+ this.output = new OutputCollector(dexOptions, maxInsns, bsz * 3, regCount);
+
+ if (locals != null) {
+ this.translationVisitor = new LocalVariableAwareTranslationVisitor(output, locals);
+ } else {
+ this.translationVisitor = new TranslationVisitor(output);
+ }
+ }
+
+ /**
+ * Checks to see if the move-param instructions that occur in this
+ * method happen to slot the params in an order at the top of the
+ * stack frame that matches dalvik's calling conventions. This will
+ * alway result in "true" for methods that have run through the
+ * SSA optimizer.
+ *
+ * @param paramSize size, in register units, of all the parameters
+ * to this method
+ */
+ private static boolean calculateParamsAreInOrder(RopMethod method, final int paramSize) {
+ final boolean[] paramsAreInOrder = {true};
+ final int initialRegCount = method.getBlocks().getRegCount();
+
+ /*
+ * We almost could just check the first block here, but the
+ * {@code cf} layer will put in a second move-param in a
+ * subsequent block in the case of synchronized methods.
+ */
+ method.getBlocks().forEachInsn(new Insn.BaseVisitor() {
+ @Override
+ public void visitPlainCstInsn(PlainCstInsn insn) {
+ if (insn.getOpcode().getOpcode() == RegOps.MOVE_PARAM) {
+ int param = ((CstInteger) insn.getConstant()).getValue();
+
+ paramsAreInOrder[0] = paramsAreInOrder[0]
+ && ((initialRegCount - paramSize + param) == insn.getResult().getReg());
+ }
+ }
+ });
+
+ return paramsAreInOrder[0];
+ }
+
+ /**
+ * Does the translation and returns the result.
+ *
+ * @return {@code non-null;} the result
+ */
+ private DalvCode translateAndGetResult() {
+ pickOrder();
+ outputInstructions();
+
+ StdCatchBuilder catches = new StdCatchBuilder(method, order, addresses);
+
+ return new DalvCode(positionInfo, output.getFinisher(), catches);
+ }
+
+ /**
+ * Performs initial creation of output instructions based on the
+ * original blocks.
+ */
+ private void outputInstructions() {
+ BasicBlockList blocks = method.getBlocks();
+ int[] order = this.order;
+ int len = order.length;
+
+ // Process the blocks in output order.
+ for (int i = 0; i < len; i++) {
+ int nextI = i + 1;
+ int nextLabel = (nextI == order.length) ? -1 : order[nextI];
+ outputBlock(blocks.labelToBlock(order[i]), nextLabel);
+ }
+ }
+
+ /**
+ * Helper for {@link #outputInstructions}, which does the processing
+ * and output of one block.
+ *
+ * @param block {@code non-null;} the block to process and output
+ * @param nextLabel {@code >= -1;} the next block that will be processed, or
+ * {@code -1} if there is no next block
+ */
+ private void outputBlock(BasicBlock block, int nextLabel) {
+ // Append the code address for this block.
+ CodeAddress startAddress = addresses.getStart(block);
+ output.add(startAddress);
+
+ // Append the local variable state for the block.
+ if (locals != null) {
+ RegisterSpecSet starts = locals.getStarts(block);
+ output.add(new LocalSnapshot(startAddress.getPosition(), starts));
+ }
+
+ /*
+ * Choose and append an output instruction for each original
+ * instruction.
+ */
+ translationVisitor.setBlock(block, addresses.getLast(block));
+ block.getInsns().forEach(translationVisitor);
+
+ // Insert the block end code address.
+ output.add(addresses.getEnd(block));
+
+ // Set up for end-of-block activities.
+
+ int succ = block.getPrimarySuccessor();
+ Insn lastInsn = block.getLastInsn();
+
+ /*
+ * Check for (and possibly correct for) a non-optimal choice of
+ * which block will get output next.
+ */
+
+if ((succ >= 0) && (succ != nextLabel)) {
+ /*
+ * The block has a "primary successor" and that primary
+ * successor isn't the next block to be output.
+ */
+ Rop lastRop = lastInsn.getOpcode();
+ if ((lastRop.getBranchingness() == Rop.BRANCH_IF)
+ && (block.getSecondarySuccessor() == nextLabel)) {
+ /*
+ * The block ends with an "if" of some sort, and its
+ * secondary successor (the "then") is in fact the
+ * next block to output. So, reverse the sense of
+ * the test, so that we can just emit the next block
+ * without an interstitial goto.
+ */
+ output.reverseBranch(1, addresses.getStart(succ));
+ } else {
+ /*
+ * Our only recourse is to add a goto here to get the
+ * flow to be correct.
+ */
+ TargetInsn insn = new TargetInsn(Dops.GOTO, lastInsn.getPosition(), RegisterSpecList.EMPTY,
+ addresses.getStart(succ));
+ output.add(insn);
+ }
+ }
+ }
+
+ /**
+ * Picks an order for the blocks by doing "trace" analysis.
+ */
+ private void pickOrder() {
+ BasicBlockList blocks = method.getBlocks();
+ int sz = blocks.size();
+ int maxLabel = blocks.getMaxLabel();
+ int[] workSet = Bits.makeBitSet(maxLabel);
+ int[] tracebackSet = Bits.makeBitSet(maxLabel);
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = blocks.get(i);
+ Bits.set(workSet, one.getLabel());
+ }
+
+ int[] order = new int[sz];
+ int at = 0;
+
+ /*
+ * Starting with the designated "first label" (that is, the
+ * first block of the method), add that label to the order,
+ * and then pick its first as-yet unordered successor to
+ * immediately follow it, giving top priority to the primary
+ * (aka default) successor (if any). Keep following successors
+ * until the trace runs out of possibilities. Then, continue
+ * by finding an unordered chain containing the first as-yet
+ * unordered block, and adding it to the order, and so on.
+ */
+ for (int label = method.getFirstLabel(); label != -1; label = Bits.findFirst(workSet, 0)) {
+
+ /*
+ * Attempt to trace backward from the chosen block to an
+ * as-yet unordered predecessor which lists the chosen
+ * block as its primary successor, and so on, until we
+ * fail to find such an unordered predecessor. Start the
+ * trace with that block. Note that the first block in the
+ * method has no predecessors, so in that case this loop
+ * will simply terminate with zero iterations and without
+ * picking a new starter block.
+ */
+ traceBack: for (;;) {
+ IntList preds = method.labelToPredecessors(label);
+ int psz = preds.size();
+
+ for (int i = 0; i < psz; i++) {
+ int predLabel = preds.get(i);
+
+ if (Bits.get(tracebackSet, predLabel)) {
+ /*
+ * We found a predecessor loop; stop tracing back
+ * from here.
+ */
+ break;
+ }
+
+ if (!Bits.get(workSet, predLabel)) {
+ // This one's already ordered.
+ continue;
+ }
+
+ BasicBlock pred = blocks.labelToBlock(predLabel);
+ if (pred.getPrimarySuccessor() == label) {
+ // Found one!
+ label = predLabel;
+ Bits.set(tracebackSet, label);
+ continue traceBack;
+ }
+ }
+
+ // Failed to find a better block to start the trace.
+ break;
+ }
+
+ /*
+ * Trace a path from the chosen block to one of its
+ * unordered successors (hopefully the primary), and so
+ * on, until we run out of unordered successors.
+ */
+ while (label != -1) {
+ Bits.clear(workSet, label);
+ Bits.clear(tracebackSet, label);
+ order[at] = label;
+ at++;
+
+ BasicBlock one = blocks.labelToBlock(label);
+ BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
+
+ if (preferredBlock == null) {
+ break;
+ }
+
+ int preferred = preferredBlock.getLabel();
+ int primary = one.getPrimarySuccessor();
+
+ if (Bits.get(workSet, preferred)) {
+ /*
+ * Order the current block's preferred successor
+ * next, as it has yet to be scheduled.
+ */
+ label = preferred;
+ } else if ((primary != preferred) && (primary >= 0) && Bits.get(workSet, primary)) {
+ /*
+ * The primary is available, so use that.
+ */
+ label = primary;
+ } else {
+ /*
+ * There's no obvious candidate, so pick the first
+ * one that's available, if any.
+ */
+ IntList successors = one.getSuccessors();
+ int ssz = successors.size();
+ label = -1;
+ for (int i = 0; i < ssz; i++) {
+ int candidate = successors.get(i);
+ if (Bits.get(workSet, candidate)) {
+ label = candidate;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (at != sz) {
+ // There was a duplicate block label.
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ this.order = order;
+ }
+
+ /**
+ * Gets the complete register list (result and sources) out of a
+ * given rop instruction. For insns that are commutative, have
+ * two register sources, and have a source equal to the result,
+ * place that source first.
+ *
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code non-null;} the instruction's complete register list
+ */
+ private static RegisterSpecList getRegs(Insn insn) {
+ return getRegs(insn, insn.getResult());
+ }
+
+ /**
+ * Gets the complete register list (result and sources) out of a
+ * given rop instruction. For insns that are commutative, have
+ * two register sources, and have a source equal to the result,
+ * place that source first.
+ *
+ * @param insn {@code non-null;} instruction in question
+ * @param resultReg {@code null-ok;} the real result to use (ignore the insn's)
+ * @return {@code non-null;} the instruction's complete register list
+ */
+ private static RegisterSpecList getRegs(Insn insn, RegisterSpec resultReg) {
+ RegisterSpecList regs = insn.getSources();
+
+ if (insn.getOpcode().isCommutative() && (regs.size() == 2)
+ && (resultReg.getReg() == regs.get(1).getReg())) {
+
+ /*
+ * For commutative ops which have two register sources,
+ * if the second source is the same register as the result,
+ * swap the sources so that an opcode of form 12x can be selected
+ * instead of one of form 23x
+ */
+
+regs = RegisterSpecList.make(regs.get(1), regs.get(0));
+ }
+
+ if (resultReg == null) {
+ return regs;
+ }
+
+ return regs.withFirst(resultReg);
+ }
+
+ /**
+ * Instruction visitor class for doing the instruction translation per se.
+ */
+ private class TranslationVisitor implements Insn.Visitor {
/** {@code non-null;} list of output instructions in-progress */
private final OutputCollector output;
- /** {@code non-null;} visitor to use during translation */
- private final TranslationVisitor translationVisitor;
-
- /** {@code >= 0;} register count for the method */
- private final int regCount;
-
- /** {@code null-ok;} block output order; becomes non-null in {@link #pickOrder} */
- private int[] order;
-
- /** size, in register units, of all the parameters to this method */
- private final int paramSize;
+ /** {@code non-null;} basic block being worked on */
+ private BasicBlock block;
/**
- * true if the parameters to this method happen to be in proper order
- * at the end of the frame (as the optimizer emits them)
+ * {@code null-ok;} code address for the salient last instruction of the
+ * block (used before switches and throwing instructions)
*/
- private boolean paramsAreInOrder;
+ private CodeAddress lastAddress;
/**
- * Translates a {@link RopMethod}. This may modify the given
- * input.
+ * Constructs an instance.
*
- * @param method {@code non-null;} the original method
- * @param positionInfo how much position info to preserve; one of the
- * static constants in {@link PositionList}
- * @param locals {@code null-ok;} local variable information to use
- * @param paramSize size, in register units, of all the parameters to
- * this method
- * @param dexOptions {@code non-null;} options for dex output
- * @return {@code non-null;} the translated version
+ * @param output {@code non-null;} destination for instruction output
*/
- public static DalvCode translate(RopMethod method, int positionInfo,
- LocalVariableInfo locals, int paramSize, DexOptions dexOptions) {
- RopTranslator translator =
- new RopTranslator(method, positionInfo, locals, paramSize, dexOptions);
- return translator.translateAndGetResult();
+ public TranslationVisitor(OutputCollector output) {
+ this.output = output;
}
/**
- * Constructs an instance. This method is private. Use {@link #translate}.
+ * Sets the block currently being worked on.
*
- * @param method {@code non-null;} the original method
- * @param positionInfo how much position info to preserve; one of the
- * static constants in {@link PositionList}
- * @param locals {@code null-ok;} local variable information to use
- * @param paramSize size, in register units, of all the parameters to
- * this method
- * @param dexOptions {@code non-null;} options for dex output
+ * @param block {@code non-null;} the block
+ * @param lastAddress {@code non-null;} code address for the salient
+ * last instruction of the block
*/
- private RopTranslator(RopMethod method, int positionInfo, LocalVariableInfo locals,
- int paramSize, DexOptions dexOptions) {
- this.dexOptions = dexOptions;
- this.method = method;
- this.positionInfo = positionInfo;
- this.locals = locals;
- this.addresses = new BlockAddresses(method);
- this.paramSize = paramSize;
- this.order = null;
- this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
+ public void setBlock(BasicBlock block, CodeAddress lastAddress) {
+ this.block = block;
+ this.lastAddress = lastAddress;
+ }
- BasicBlockList blocks = method.getBlocks();
- int bsz = blocks.size();
-
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainInsn(PlainInsn insn) {
+ Rop rop = insn.getOpcode();
+ if (rop.getOpcode() == RegOps.MARK_LOCAL) {
/*
- * Max possible instructions includes three code address
- * objects per basic block (to the first and last instruction,
- * and just past the end of the block), and the possibility of
- * an extra goto at the end of each basic block.
+ * Ignore these. They're dealt with by
+ * the LocalVariableAwareTranslationVisitor
*/
- int maxInsns = (bsz * 3) + blocks.getInstructionCount();
+ return;
+ }
+ if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+ // These get skipped
+ return;
+ }
- if (locals != null) {
- /*
- * If we're tracking locals, then there's could be another
- * extra instruction per block (for the locals state at the
- * start of the block) as well as one for each interblock
- * local introduction.
- */
- maxInsns += bsz + locals.getAssignmentCount();
+ SourcePosition pos = insn.getPosition();
+ Dop opcode = RopToDop.dopFor(insn);
+ DalvInsn di;
+
+ switch (rop.getBranchingness()) {
+ case Rop.BRANCH_NONE:
+ case Rop.BRANCH_RETURN:
+ case Rop.BRANCH_THROW: {
+ di = new SimpleInsn(opcode, pos, getRegs(insn));
+ break;
}
-
- /*
- * If params are not in order, we will need register space
- * for them before this is all over...
- */
- this.regCount = blocks.getRegCount()
- + (paramsAreInOrder ? 0 : this.paramSize);
-
- this.output = new OutputCollector(dexOptions, maxInsns, bsz * 3, regCount);
-
- if (locals != null) {
- this.translationVisitor =
- new LocalVariableAwareTranslationVisitor(output, locals);
- } else {
- this.translationVisitor = new TranslationVisitor(output);
+ case Rop.BRANCH_GOTO: {
+ /*
+ * Code in the main translation loop will emit a
+ * goto if necessary (if the branch isn't to the
+ * immediately subsequent block).
+ */
+ return;
}
+ case Rop.BRANCH_IF: {
+ int target = block.getSuccessors().get(1);
+ di = new TargetInsn(opcode, pos, getRegs(insn), addresses.getStart(target));
+ break;
+ }
+ default: {
+ throw new RuntimeException("shouldn't happen");
+ }
+ }
+
+ addOutput(di);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainCstInsn(PlainCstInsn insn) {
+ SourcePosition pos = insn.getPosition();
+ Dop opcode = RopToDop.dopFor(insn);
+ Rop rop = insn.getOpcode();
+ int ropOpcode = rop.getOpcode();
+ DalvInsn di;
+
+ if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ if (ropOpcode == RegOps.MOVE_PARAM) {
+ if (!paramsAreInOrder) {
+ /*
+ * Parameters are not in order at the top of the reg space.
+ * We need to add moves.
+ */
+
+RegisterSpec dest = insn.getResult();
+ int param = ((CstInteger) insn.getConstant()).getValue();
+ RegisterSpec source = RegisterSpec.make(regCount - paramSize + param, dest.getType());
+ di = new SimpleInsn(opcode, pos, RegisterSpecList.make(dest, source));
+ addOutput(di);
+ }
+ } else {
+ // No moves required for the parameters
+ RegisterSpecList regs = getRegs(insn);
+ di = new CstInsn(opcode, pos, regs, insn.getConstant());
+ addOutput(di);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitSwitchInsn(SwitchInsn insn) {
+ SourcePosition pos = insn.getPosition();
+ IntList cases = insn.getCases();
+ IntList successors = block.getSuccessors();
+ int casesSz = cases.size();
+ int succSz = successors.size();
+ int primarySuccessor = block.getPrimarySuccessor();
+
+ /*
+ * Check the assumptions that the number of cases is one
+ * less than the number of successors and that the last
+ * successor in the list is the primary (in this case, the
+ * default). This test is here to guard against forgetting
+ * to change this code if the way switch instructions are
+ * constructed also gets changed.
+ */
+ if ((casesSz != (succSz - 1)) || (primarySuccessor != successors.get(casesSz))) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ CodeAddress[] switchTargets = new CodeAddress[casesSz];
+
+ for (int i = 0; i < casesSz; i++) {
+ int label = successors.get(i);
+ switchTargets[i] = addresses.getStart(label);
+ }
+
+ CodeAddress dataAddress = new CodeAddress(pos);
+ // make a new address that binds closely to the switch instruction
+ CodeAddress switchAddress = new CodeAddress(lastAddress.getPosition(), true);
+ SwitchData dataInsn = new SwitchData(pos, switchAddress, cases, switchTargets);
+ Dop opcode = dataInsn.isPacked() ? Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
+ TargetInsn switchInsn = new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
+
+ addOutput(switchAddress);
+ addOutput(switchInsn);
+
+ addOutputSuffix(new OddSpacer(pos));
+ addOutputSuffix(dataAddress);
+ addOutputSuffix(dataInsn);
}
/**
- * Checks to see if the move-param instructions that occur in this
- * method happen to slot the params in an order at the top of the
- * stack frame that matches dalvik's calling conventions. This will
- * alway result in "true" for methods that have run through the
- * SSA optimizer.
+ * Looks forward to the current block's primary successor, returning
+ * the RegisterSpec of the result of the move-result-pseudo at the
+ * top of that block or null if none.
*
- * @param paramSize size, in register units, of all the parameters
- * to this method
+ * @return {@code null-ok;} result of move-result-pseudo at the beginning of
+ * primary successor
*/
- private static boolean calculateParamsAreInOrder(RopMethod method,
- final int paramSize) {
- final boolean[] paramsAreInOrder = { true };
- final int initialRegCount = method.getBlocks().getRegCount();
+ private RegisterSpec getNextMoveResultPseudo() {
+ int label = block.getPrimarySuccessor();
- /*
- * We almost could just check the first block here, but the
- * {@code cf} layer will put in a second move-param in a
- * subsequent block in the case of synchronized methods.
- */
- method.getBlocks().forEachInsn(new Insn.BaseVisitor() {
- @Override
- public void visitPlainCstInsn(PlainCstInsn insn) {
- if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) {
- int param =
- ((CstInteger) insn.getConstant()).getValue();
+ if (label < 0) {
+ return null;
+ }
- paramsAreInOrder[0] = paramsAreInOrder[0]
- && ((initialRegCount - paramSize + param)
- == insn.getResult().getReg());
- }
- }
- });
+ Insn insn = method.getBlocks().labelToBlock(label).getInsns().get(0);
- return paramsAreInOrder[0];
+ if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
+ return null;
+ } else {
+ return insn.getResult();
+ }
}
- /**
- * Does the translation and returns the result.
- *
- * @return {@code non-null;} the result
- */
- private DalvCode translateAndGetResult() {
- pickOrder();
- outputInstructions();
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+ SourcePosition pos = insn.getPosition();
+ Dop opcode = RopToDop.dopFor(insn);
+ Rop rop = insn.getOpcode();
+ Constant cst = insn.getConstant();
- StdCatchBuilder catches =
- new StdCatchBuilder(method, order, addresses);
+ if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+ throw new RuntimeException("shouldn't happen");
+ }
- return new DalvCode(positionInfo, output.getFinisher(), catches);
- }
+ addOutput(lastAddress);
- /**
- * Performs initial creation of output instructions based on the
- * original blocks.
- */
- private void outputInstructions() {
- BasicBlockList blocks = method.getBlocks();
- int[] order = this.order;
- int len = order.length;
-
- // Process the blocks in output order.
- for (int i = 0; i < len; i++) {
- int nextI = i + 1;
- int nextLabel = (nextI == order.length) ? -1 : order[nextI];
- outputBlock(blocks.labelToBlock(order[i]), nextLabel);
- }
- }
-
- /**
- * Helper for {@link #outputInstructions}, which does the processing
- * and output of one block.
- *
- * @param block {@code non-null;} the block to process and output
- * @param nextLabel {@code >= -1;} the next block that will be processed, or
- * {@code -1} if there is no next block
- */
- private void outputBlock(BasicBlock block, int nextLabel) {
- // Append the code address for this block.
- CodeAddress startAddress = addresses.getStart(block);
- output.add(startAddress);
-
- // Append the local variable state for the block.
- if (locals != null) {
- RegisterSpecSet starts = locals.getStarts(block);
- output.add(new LocalSnapshot(startAddress.getPosition(),
- starts));
- }
-
- /*
- * Choose and append an output instruction for each original
- * instruction.
- */
- translationVisitor.setBlock(block, addresses.getLast(block));
- block.getInsns().forEach(translationVisitor);
-
- // Insert the block end code address.
- output.add(addresses.getEnd(block));
-
- // Set up for end-of-block activities.
-
- int succ = block.getPrimarySuccessor();
- Insn lastInsn = block.getLastInsn();
-
- /*
- * Check for (and possibly correct for) a non-optimal choice of
- * which block will get output next.
- */
-
- if ((succ >= 0) && (succ != nextLabel)) {
- /*
- * The block has a "primary successor" and that primary
- * successor isn't the next block to be output.
- */
- Rop lastRop = lastInsn.getOpcode();
- if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
- (block.getSecondarySuccessor() == nextLabel)) {
- /*
- * The block ends with an "if" of some sort, and its
- * secondary successor (the "then") is in fact the
- * next block to output. So, reverse the sense of
- * the test, so that we can just emit the next block
- * without an interstitial goto.
- */
- output.reverseBranch(1, addresses.getStart(succ));
- } else {
- /*
- * Our only recourse is to add a goto here to get the
- * flow to be correct.
- */
- TargetInsn insn =
- new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
- RegisterSpecList.EMPTY,
- addresses.getStart(succ));
- output.add(insn);
- }
- }
- }
-
- /**
- * Picks an order for the blocks by doing "trace" analysis.
- */
- private void pickOrder() {
- BasicBlockList blocks = method.getBlocks();
- int sz = blocks.size();
- int maxLabel = blocks.getMaxLabel();
- int[] workSet = Bits.makeBitSet(maxLabel);
- int[] tracebackSet = Bits.makeBitSet(maxLabel);
-
- for (int i = 0; i < sz; i++) {
- BasicBlock one = blocks.get(i);
- Bits.set(workSet, one.getLabel());
- }
-
- int[] order = new int[sz];
- int at = 0;
-
- /*
- * Starting with the designated "first label" (that is, the
- * first block of the method), add that label to the order,
- * and then pick its first as-yet unordered successor to
- * immediately follow it, giving top priority to the primary
- * (aka default) successor (if any). Keep following successors
- * until the trace runs out of possibilities. Then, continue
- * by finding an unordered chain containing the first as-yet
- * unordered block, and adding it to the order, and so on.
- */
- for (int label = method.getFirstLabel();
- label != -1;
- label = Bits.findFirst(workSet, 0)) {
-
- /*
- * Attempt to trace backward from the chosen block to an
- * as-yet unordered predecessor which lists the chosen
- * block as its primary successor, and so on, until we
- * fail to find such an unordered predecessor. Start the
- * trace with that block. Note that the first block in the
- * method has no predecessors, so in that case this loop
- * will simply terminate with zero iterations and without
- * picking a new starter block.
- */
- traceBack:
- for (;;) {
- IntList preds = method.labelToPredecessors(label);
- int psz = preds.size();
-
- for (int i = 0; i < psz; i++) {
- int predLabel = preds.get(i);
-
- if (Bits.get(tracebackSet, predLabel)) {
- /*
- * We found a predecessor loop; stop tracing back
- * from here.
- */
- break;
- }
-
- if (!Bits.get(workSet, predLabel)) {
- // This one's already ordered.
- continue;
- }
-
- BasicBlock pred = blocks.labelToBlock(predLabel);
- if (pred.getPrimarySuccessor() == label) {
- // Found one!
- label = predLabel;
- Bits.set(tracebackSet, label);
- continue traceBack;
- }
- }
-
- // Failed to find a better block to start the trace.
- break;
- }
-
- /*
- * Trace a path from the chosen block to one of its
- * unordered successors (hopefully the primary), and so
- * on, until we run out of unordered successors.
- */
- while (label != -1) {
- Bits.clear(workSet, label);
- Bits.clear(tracebackSet, label);
- order[at] = label;
- at++;
-
- BasicBlock one = blocks.labelToBlock(label);
- BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
-
- if (preferredBlock == null) {
- break;
- }
-
- int preferred = preferredBlock.getLabel();
- int primary = one.getPrimarySuccessor();
-
- if (Bits.get(workSet, preferred)) {
- /*
- * Order the current block's preferred successor
- * next, as it has yet to be scheduled.
- */
- label = preferred;
- } else if ((primary != preferred) && (primary >= 0)
- && Bits.get(workSet, primary)) {
- /*
- * The primary is available, so use that.
- */
- label = primary;
- } else {
- /*
- * There's no obvious candidate, so pick the first
- * one that's available, if any.
- */
- IntList successors = one.getSuccessors();
- int ssz = successors.size();
- label = -1;
- for (int i = 0; i < ssz; i++) {
- int candidate = successors.get(i);
- if (Bits.get(workSet, candidate)) {
- label = candidate;
- break;
- }
- }
- }
- }
- }
-
- if (at != sz) {
- // There was a duplicate block label.
- throw new RuntimeException("shouldn't happen");
- }
-
- this.order = order;
- }
-
- /**
- * Gets the complete register list (result and sources) out of a
- * given rop instruction. For insns that are commutative, have
- * two register sources, and have a source equal to the result,
- * place that source first.
- *
- * @param insn {@code non-null;} instruction in question
- * @return {@code non-null;} the instruction's complete register list
- */
- private static RegisterSpecList getRegs(Insn insn) {
- return getRegs(insn, insn.getResult());
- }
-
- /**
- * Gets the complete register list (result and sources) out of a
- * given rop instruction. For insns that are commutative, have
- * two register sources, and have a source equal to the result,
- * place that source first.
- *
- * @param insn {@code non-null;} instruction in question
- * @param resultReg {@code null-ok;} the real result to use (ignore the insn's)
- * @return {@code non-null;} the instruction's complete register list
- */
- private static RegisterSpecList getRegs(Insn insn,
- RegisterSpec resultReg) {
+ if (rop.isCallLike()) {
RegisterSpecList regs = insn.getSources();
+ DalvInsn di = new CstInsn(opcode, pos, regs, cst);
- if (insn.getOpcode().isCommutative()
- && (regs.size() == 2)
- && (resultReg.getReg() == regs.get(1).getReg())) {
+ addOutput(di);
+ } else {
+ RegisterSpec realResult = getNextMoveResultPseudo();
- /*
- * For commutative ops which have two register sources,
- * if the second source is the same register as the result,
- * swap the sources so that an opcode of form 12x can be selected
- * instead of one of form 23x
- */
+ RegisterSpecList regs = getRegs(insn, realResult);
+ DalvInsn di;
- regs = RegisterSpecList.make(regs.get(1), regs.get(0));
+ boolean hasResult = opcode.hasResult() || (rop.getOpcode() == RegOps.CHECK_CAST);
+
+ if (hasResult != (realResult != null)) {
+ throw new RuntimeException("Insn with result/move-result-pseudo mismatch " + insn);
}
- if (resultReg == null) {
- return regs;
+ if ((rop.getOpcode() == RegOps.NEW_ARRAY) && (opcode.getOpcode() != Opcodes.NEW_ARRAY)) {
+ /*
+ * It's a type-specific new-array-<primitive>, and
+ * so it should be turned into a SimpleInsn (no
+ * constant ref as it's implicit).
+ */
+ di = new SimpleInsn(opcode, pos, regs);
+ } else {
+ /*
+ * This is the general case for constant-bearing
+ * instructions.
+ */
+ di = new CstInsn(opcode, pos, regs, cst);
}
- return regs.withFirst(resultReg);
+ addOutput(di);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingInsn(ThrowingInsn insn) {
+ SourcePosition pos = insn.getPosition();
+ Dop opcode = RopToDop.dopFor(insn);
+ Rop rop = insn.getOpcode();
+ RegisterSpec realResult;
+
+ if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ realResult = getNextMoveResultPseudo();
+
+ if (opcode.hasResult() != (realResult != null)) {
+ throw new RuntimeException("Insn with result/move-result-pseudo mismatch" + insn);
+ }
+
+ addOutput(lastAddress);
+
+ DalvInsn di = new SimpleInsn(opcode, pos, getRegs(insn, realResult));
+
+ addOutput(di);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+ SourcePosition pos = insn.getPosition();
+ Constant cst = insn.getConstant();
+ ArrayList<Constant> values = insn.getInitValues();
+ Rop rop = insn.getOpcode();
+
+ if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+ throw new RuntimeException("shouldn't happen");
+ }
+ CodeAddress dataAddress = new CodeAddress(pos);
+ ArrayData dataInsn = new ArrayData(pos, lastAddress, values, cst);
+
+ TargetInsn fillArrayDataInsn =
+ new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn), dataAddress);
+
+ addOutput(lastAddress);
+ addOutput(fillArrayDataInsn);
+
+ addOutputSuffix(new OddSpacer(pos));
+ addOutputSuffix(dataAddress);
+ addOutputSuffix(dataInsn);
}
/**
- * Instruction visitor class for doing the instruction translation per se.
+ * Adds to the output.
+ *
+ * @param insn {@code non-null;} instruction to add
*/
- private class TranslationVisitor implements Insn.Visitor {
- /** {@code non-null;} list of output instructions in-progress */
- private final OutputCollector output;
-
- /** {@code non-null;} basic block being worked on */
- private BasicBlock block;
-
- /**
- * {@code null-ok;} code address for the salient last instruction of the
- * block (used before switches and throwing instructions)
- */
- private CodeAddress lastAddress;
-
- /**
- * Constructs an instance.
- *
- * @param output {@code non-null;} destination for instruction output
- */
- public TranslationVisitor(OutputCollector output) {
- this.output = output;
- }
-
- /**
- * Sets the block currently being worked on.
- *
- * @param block {@code non-null;} the block
- * @param lastAddress {@code non-null;} code address for the salient
- * last instruction of the block
- */
- public void setBlock(BasicBlock block, CodeAddress lastAddress) {
- this.block = block;
- this.lastAddress = lastAddress;
- }
-
- /** {@inheritDoc} */
- public void visitPlainInsn(PlainInsn insn) {
- Rop rop = insn.getOpcode();
- if (rop.getOpcode() == RegOps.MARK_LOCAL) {
- /*
- * Ignore these. They're dealt with by
- * the LocalVariableAwareTranslationVisitor
- */
- return;
- }
- if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
- // These get skipped
- return;
- }
-
- SourcePosition pos = insn.getPosition();
- Dop opcode = RopToDop.dopFor(insn);
- DalvInsn di;
-
- switch (rop.getBranchingness()) {
- case Rop.BRANCH_NONE:
- case Rop.BRANCH_RETURN:
- case Rop.BRANCH_THROW: {
- di = new SimpleInsn(opcode, pos, getRegs(insn));
- break;
- }
- case Rop.BRANCH_GOTO: {
- /*
- * Code in the main translation loop will emit a
- * goto if necessary (if the branch isn't to the
- * immediately subsequent block).
- */
- return;
- }
- case Rop.BRANCH_IF: {
- int target = block.getSuccessors().get(1);
- di = new TargetInsn(opcode, pos, getRegs(insn),
- addresses.getStart(target));
- break;
- }
- default: {
- throw new RuntimeException("shouldn't happen");
- }
- }
-
- addOutput(di);
- }
-
- /** {@inheritDoc} */
- public void visitPlainCstInsn(PlainCstInsn insn) {
- SourcePosition pos = insn.getPosition();
- Dop opcode = RopToDop.dopFor(insn);
- Rop rop = insn.getOpcode();
- int ropOpcode = rop.getOpcode();
- DalvInsn di;
-
- if (rop.getBranchingness() != Rop.BRANCH_NONE) {
- throw new RuntimeException("shouldn't happen");
- }
-
- if (ropOpcode == RegOps.MOVE_PARAM) {
- if (!paramsAreInOrder) {
- /*
- * Parameters are not in order at the top of the reg space.
- * We need to add moves.
- */
-
- RegisterSpec dest = insn.getResult();
- int param =
- ((CstInteger) insn.getConstant()).getValue();
- RegisterSpec source =
- RegisterSpec.make(regCount - paramSize + param,
- dest.getType());
- di = new SimpleInsn(opcode, pos,
- RegisterSpecList.make(dest, source));
- addOutput(di);
- }
- } else {
- // No moves required for the parameters
- RegisterSpecList regs = getRegs(insn);
- di = new CstInsn(opcode, pos, regs, insn.getConstant());
- addOutput(di);
- }
- }
-
- /** {@inheritDoc} */
- public void visitSwitchInsn(SwitchInsn insn) {
- SourcePosition pos = insn.getPosition();
- IntList cases = insn.getCases();
- IntList successors = block.getSuccessors();
- int casesSz = cases.size();
- int succSz = successors.size();
- int primarySuccessor = block.getPrimarySuccessor();
-
- /*
- * Check the assumptions that the number of cases is one
- * less than the number of successors and that the last
- * successor in the list is the primary (in this case, the
- * default). This test is here to guard against forgetting
- * to change this code if the way switch instructions are
- * constructed also gets changed.
- */
- if ((casesSz != (succSz - 1)) ||
- (primarySuccessor != successors.get(casesSz))) {
- throw new RuntimeException("shouldn't happen");
- }
-
- CodeAddress[] switchTargets = new CodeAddress[casesSz];
-
- for (int i = 0; i < casesSz; i++) {
- int label = successors.get(i);
- switchTargets[i] = addresses.getStart(label);
- }
-
- CodeAddress dataAddress = new CodeAddress(pos);
- // make a new address that binds closely to the switch instruction
- CodeAddress switchAddress =
- new CodeAddress(lastAddress.getPosition(), true);
- SwitchData dataInsn =
- new SwitchData(pos, switchAddress, cases, switchTargets);
- Dop opcode = dataInsn.isPacked() ?
- Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
- TargetInsn switchInsn =
- new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
-
- addOutput(switchAddress);
- addOutput(switchInsn);
-
- addOutputSuffix(new OddSpacer(pos));
- addOutputSuffix(dataAddress);
- addOutputSuffix(dataInsn);
- }
-
- /**
- * Looks forward to the current block's primary successor, returning
- * the RegisterSpec of the result of the move-result-pseudo at the
- * top of that block or null if none.
- *
- * @return {@code null-ok;} result of move-result-pseudo at the beginning of
- * primary successor
- */
- private RegisterSpec getNextMoveResultPseudo()
- {
- int label = block.getPrimarySuccessor();
-
- if (label < 0) {
- return null;
- }
-
- Insn insn
- = method.getBlocks().labelToBlock(label).getInsns().get(0);
-
- if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
- return null;
- } else {
- return insn.getResult();
- }
- }
-
- /** {@inheritDoc} */
- public void visitThrowingCstInsn(ThrowingCstInsn insn) {
- SourcePosition pos = insn.getPosition();
- Dop opcode = RopToDop.dopFor(insn);
- Rop rop = insn.getOpcode();
- Constant cst = insn.getConstant();
-
- if (rop.getBranchingness() != Rop.BRANCH_THROW) {
- throw new RuntimeException("shouldn't happen");
- }
-
- addOutput(lastAddress);
-
- if (rop.isCallLike()) {
- RegisterSpecList regs = insn.getSources();
- DalvInsn di = new CstInsn(opcode, pos, regs, cst);
-
- addOutput(di);
- } else {
- RegisterSpec realResult = getNextMoveResultPseudo();
-
- RegisterSpecList regs = getRegs(insn, realResult);
- DalvInsn di;
-
- boolean hasResult = opcode.hasResult()
- || (rop.getOpcode() == RegOps.CHECK_CAST);
-
- if (hasResult != (realResult != null)) {
- throw new RuntimeException(
- "Insn with result/move-result-pseudo mismatch " +
- insn);
- }
-
- if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
- (opcode.getOpcode() != Opcodes.NEW_ARRAY)) {
- /*
- * It's a type-specific new-array-<primitive>, and
- * so it should be turned into a SimpleInsn (no
- * constant ref as it's implicit).
- */
- di = new SimpleInsn(opcode, pos, regs);
- } else {
- /*
- * This is the general case for constant-bearing
- * instructions.
- */
- di = new CstInsn(opcode, pos, regs, cst);
- }
-
- addOutput(di);
- }
- }
-
- /** {@inheritDoc} */
- public void visitThrowingInsn(ThrowingInsn insn) {
- SourcePosition pos = insn.getPosition();
- Dop opcode = RopToDop.dopFor(insn);
- Rop rop = insn.getOpcode();
- RegisterSpec realResult;
-
- if (rop.getBranchingness() != Rop.BRANCH_THROW) {
- throw new RuntimeException("shouldn't happen");
- }
-
- realResult = getNextMoveResultPseudo();
-
- if (opcode.hasResult() != (realResult != null)) {
- throw new RuntimeException(
- "Insn with result/move-result-pseudo mismatch" + insn);
- }
-
- addOutput(lastAddress);
-
- DalvInsn di = new SimpleInsn(opcode, pos,
- getRegs(insn, realResult));
-
- addOutput(di);
- }
-
- /** {@inheritDoc} */
- public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
- SourcePosition pos = insn.getPosition();
- Constant cst = insn.getConstant();
- ArrayList<Constant> values = insn.getInitValues();
- Rop rop = insn.getOpcode();
-
- if (rop.getBranchingness() != Rop.BRANCH_NONE) {
- throw new RuntimeException("shouldn't happen");
- }
- CodeAddress dataAddress = new CodeAddress(pos);
- ArrayData dataInsn =
- new ArrayData(pos, lastAddress, values, cst);
-
- TargetInsn fillArrayDataInsn =
- new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
- dataAddress);
-
- addOutput(lastAddress);
- addOutput(fillArrayDataInsn);
-
- addOutputSuffix(new OddSpacer(pos));
- addOutputSuffix(dataAddress);
- addOutputSuffix(dataInsn);
- }
-
- /**
- * Adds to the output.
- *
- * @param insn {@code non-null;} instruction to add
- */
- protected void addOutput(DalvInsn insn) {
- output.add(insn);
- }
-
- /**
- * Adds to the output suffix.
- *
- * @param insn {@code non-null;} instruction to add
- */
- protected void addOutputSuffix(DalvInsn insn) {
- output.addSuffix(insn);
- }
+ protected void addOutput(DalvInsn insn) {
+ output.add(insn);
}
/**
- * Instruction visitor class for doing instruction translation with
- * local variable tracking
+ * Adds to the output suffix.
+ *
+ * @param insn {@code non-null;} instruction to add
*/
- private class LocalVariableAwareTranslationVisitor
- extends TranslationVisitor {
- /** {@code non-null;} local variable info */
- private LocalVariableInfo locals;
-
- /**
- * Constructs an instance.
- *
- * @param output {@code non-null;} destination for instruction output
- * @param locals {@code non-null;} the local variable info
- */
- public LocalVariableAwareTranslationVisitor(OutputCollector output,
- LocalVariableInfo locals) {
- super(output);
- this.locals = locals;
- }
-
- /** {@inheritDoc} */
- @Override
- public void visitPlainInsn(PlainInsn insn) {
- super.visitPlainInsn(insn);
- addIntroductionIfNecessary(insn);
- }
-
- /** {@inheritDoc} */
- @Override
- public void visitPlainCstInsn(PlainCstInsn insn) {
- super.visitPlainCstInsn(insn);
- addIntroductionIfNecessary(insn);
- }
-
- /** {@inheritDoc} */
- @Override
- public void visitSwitchInsn(SwitchInsn insn) {
- super.visitSwitchInsn(insn);
- addIntroductionIfNecessary(insn);
- }
-
- /** {@inheritDoc} */
- @Override
- public void visitThrowingCstInsn(ThrowingCstInsn insn) {
- super.visitThrowingCstInsn(insn);
- addIntroductionIfNecessary(insn);
- }
-
- /** {@inheritDoc} */
- @Override
- public void visitThrowingInsn(ThrowingInsn insn) {
- super.visitThrowingInsn(insn);
- addIntroductionIfNecessary(insn);
- }
-
- /**
- * Adds a {@link LocalStart} to the output if the given
- * instruction in fact introduces a local variable.
- *
- * @param insn {@code non-null;} instruction in question
- */
- public void addIntroductionIfNecessary(Insn insn) {
- RegisterSpec spec = locals.getAssignment(insn);
-
- if (spec != null) {
- addOutput(new LocalStart(insn.getPosition(), spec));
- }
- }
+ protected void addOutputSuffix(DalvInsn insn) {
+ output.addSuffix(insn);
}
+ }
+
+ /**
+ * Instruction visitor class for doing instruction translation with
+ * local variable tracking
+ */
+ private class LocalVariableAwareTranslationVisitor extends TranslationVisitor {
+ /** {@code non-null;} local variable info */
+ private LocalVariableInfo locals;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param output {@code non-null;} destination for instruction output
+ * @param locals {@code non-null;} the local variable info
+ */
+ public LocalVariableAwareTranslationVisitor(OutputCollector output, LocalVariableInfo locals) {
+ super(output);
+ this.locals = locals;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainInsn(PlainInsn insn) {
+ super.visitPlainInsn(insn);
+ addIntroductionIfNecessary(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainCstInsn(PlainCstInsn insn) {
+ super.visitPlainCstInsn(insn);
+ addIntroductionIfNecessary(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitSwitchInsn(SwitchInsn insn) {
+ super.visitSwitchInsn(insn);
+ addIntroductionIfNecessary(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+ super.visitThrowingCstInsn(insn);
+ addIntroductionIfNecessary(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingInsn(ThrowingInsn insn) {
+ super.visitThrowingInsn(insn);
+ addIntroductionIfNecessary(insn);
+ }
+
+ /**
+ * Adds a {@link LocalStart} to the output if the given
+ * instruction in fact introduces a local variable.
+ *
+ * @param insn {@code non-null;} instruction in question
+ */
+ public void addIntroductionIfNecessary(Insn insn) {
+ RegisterSpec spec = locals.getAssignment(insn);
+
+ if (spec != null) {
+ addOutput(new LocalStart(insn.getPosition(), spec));
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/SimpleInsn.java b/dx/src/com/android/jack/dx/dex/code/SimpleInsn.java
index ca233e4..351c218 100644
--- a/dx/src/com/android/jack/dx/dex/code/SimpleInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/SimpleInsn.java
@@ -24,36 +24,35 @@
* the base class.
*/
public final class SimpleInsn extends FixedSizeInsn {
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param opcode the opcode; one of the constants from {@link Dops}
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} register list, including a
- * result register if appropriate (that is, registers may be either
- * ins or outs)
- */
- public SimpleInsn(Dop opcode, SourcePosition position,
- RegisterSpecList registers) {
- super(opcode, position, registers);
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param opcode the opcode; one of the constants from {@link Dops}
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
+ * result register if appropriate (that is, registers may be either
+ * ins or outs)
+ */
+ public SimpleInsn(Dop opcode, SourcePosition position, RegisterSpecList registers) {
+ super(opcode, position, registers);
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withOpcode(Dop opcode) {
- return new SimpleInsn(opcode, getPosition(), getRegisters());
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withOpcode(Dop opcode) {
+ return new SimpleInsn(opcode, getPosition(), getRegisters());
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new SimpleInsn(getOpcode(), getPosition(), registers);
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new SimpleInsn(getOpcode(), getPosition(), registers);
+ }
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- return null;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ return null;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/StdCatchBuilder.java b/dx/src/com/android/jack/dx/dex/code/StdCatchBuilder.java
index e7f75eb..04c6e0b 100644
--- a/dx/src/com/android/jack/dx/dex/code/StdCatchBuilder.java
+++ b/dx/src/com/android/jack/dx/dex/code/StdCatchBuilder.java
@@ -32,285 +32,275 @@
* and associated data.
*/
public final class StdCatchBuilder implements CatchBuilder {
- /** the maximum range of a single catch handler, in code units */
- private static final int MAX_CATCH_RANGE = 65535;
+ /** the maximum range of a single catch handler, in code units */
+ private static final int MAX_CATCH_RANGE = 65535;
- /** {@code non-null;} method to build the list for */
- private final RopMethod method;
+ /** {@code non-null;} method to build the list for */
+ private final RopMethod method;
- /** {@code non-null;} block output order */
- private final int[] order;
+ /** {@code non-null;} block output order */
+ private final int[] order;
- /** {@code non-null;} address objects for each block */
- private final BlockAddresses addresses;
+ /** {@code non-null;} address objects for each block */
+ private final BlockAddresses addresses;
- /**
- * Constructs an instance. It merely holds onto its parameters for
- * a subsequent call to {@link #build}.
- *
- * @param method {@code non-null;} method to build the list for
- * @param order {@code non-null;} block output order
- * @param addresses {@code non-null;} address objects for each block
- */
- public StdCatchBuilder(RopMethod method, int[] order,
- BlockAddresses addresses) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- if (order == null) {
- throw new NullPointerException("order == null");
- }
-
- if (addresses == null) {
- throw new NullPointerException("addresses == null");
- }
-
- this.method = method;
- this.order = order;
- this.addresses = addresses;
+ /**
+ * Constructs an instance. It merely holds onto its parameters for
+ * a subsequent call to {@link #build}.
+ *
+ * @param method {@code non-null;} method to build the list for
+ * @param order {@code non-null;} block output order
+ * @param addresses {@code non-null;} address objects for each block
+ */
+ public StdCatchBuilder(RopMethod method, int[] order, BlockAddresses addresses) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /** {@inheritDoc} */
- public CatchTable build() {
- return build(method, order, addresses);
+ if (order == null) {
+ throw new NullPointerException("order == null");
}
- /** {@inheritDoc} */
- public boolean hasAnyCatches() {
- BasicBlockList blocks = method.getBlocks();
- int size = blocks.size();
-
- for (int i = 0; i < size; i++) {
- BasicBlock block = blocks.get(i);
- TypeList catches = block.getLastInsn().getCatches();
- if (catches.size() != 0) {
- return true;
- }
- }
-
- return false;
+ if (addresses == null) {
+ throw new NullPointerException("addresses == null");
}
- /** {@inheritDoc} */
- public HashSet<Type> getCatchTypes() {
- HashSet<Type> result = new HashSet<Type>(20);
- BasicBlockList blocks = method.getBlocks();
- int size = blocks.size();
+ this.method = method;
+ this.order = order;
+ this.addresses = addresses;
+ }
- for (int i = 0; i < size; i++) {
- BasicBlock block = blocks.get(i);
- TypeList catches = block.getLastInsn().getCatches();
- int catchSize = catches.size();
+ /** {@inheritDoc} */
+ @Override
+ public CatchTable build() {
+ return build(method, order, addresses);
+ }
- for (int j = 0; j < catchSize; j++) {
- result.add(catches.getType(j));
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasAnyCatches() {
+ BasicBlockList blocks = method.getBlocks();
+ int size = blocks.size();
- return result;
+ for (int i = 0; i < size; i++) {
+ BasicBlock block = blocks.get(i);
+ TypeList catches = block.getLastInsn().getCatches();
+ if (catches.size() != 0) {
+ return true;
+ }
}
- /**
- * Builds and returns the catch table for a given method.
- *
- * @param method {@code non-null;} method to build the list for
- * @param order {@code non-null;} block output order
- * @param addresses {@code non-null;} address objects for each block
- * @return {@code non-null;} the constructed table
- */
- public static CatchTable build(RopMethod method, int[] order,
- BlockAddresses addresses) {
- int len = order.length;
- BasicBlockList blocks = method.getBlocks();
- ArrayList<CatchTable.Entry> resultList =
- new ArrayList<CatchTable.Entry>(len);
- CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
- BasicBlock currentStartBlock = null;
- BasicBlock currentEndBlock = null;
+ return false;
+ }
- for (int i = 0; i < len; i++) {
- BasicBlock block = blocks.labelToBlock(order[i]);
+ /** {@inheritDoc} */
+ @Override
+ public HashSet<Type> getCatchTypes() {
+ HashSet<Type> result = new HashSet<Type>(20);
+ BasicBlockList blocks = method.getBlocks();
+ int size = blocks.size();
- if (!block.canThrow()) {
- /*
- * There is no need to concern ourselves with the
- * placement of blocks that can't throw with respect
- * to the blocks that *can* throw.
- */
- continue;
- }
+ for (int i = 0; i < size; i++) {
+ BasicBlock block = blocks.get(i);
+ TypeList catches = block.getLastInsn().getCatches();
+ int catchSize = catches.size();
- CatchHandlerList handlers = handlersFor(block, addresses);
-
- if (currentHandlers.size() == 0) {
- // This is the start of a new catch range.
- currentStartBlock = block;
- currentEndBlock = block;
- currentHandlers = handlers;
- continue;
- }
-
- if (currentHandlers.equals(handlers)
- && rangeIsValid(currentStartBlock, block, addresses)) {
- /*
- * The block we are looking at now has the same handlers
- * as the block that started the currently open catch
- * range, and adding it to the currently open range won't
- * cause it to be too long.
- */
- currentEndBlock = block;
- continue;
- }
-
- /*
- * The block we are looking at now has incompatible handlers,
- * so we need to finish off the last entry and start a new
- * one. Note: We only emit an entry if it has associated handlers.
- */
- if (currentHandlers.size() != 0) {
- CatchTable.Entry entry =
- makeEntry(currentStartBlock, currentEndBlock,
- currentHandlers, addresses);
- resultList.add(entry);
- }
-
- currentStartBlock = block;
- currentEndBlock = block;
- currentHandlers = handlers;
- }
-
- if (currentHandlers.size() != 0) {
- // Emit an entry for the range that was left hanging.
- CatchTable.Entry entry =
- makeEntry(currentStartBlock, currentEndBlock,
- currentHandlers, addresses);
- resultList.add(entry);
- }
-
- // Construct the final result.
-
- int resultSz = resultList.size();
-
- if (resultSz == 0) {
- return CatchTable.EMPTY;
- }
-
- CatchTable result = new CatchTable(resultSz);
-
- for (int i = 0; i < resultSz; i++) {
- result.set(i, resultList.get(i));
- }
-
- result.setImmutable();
- return result;
+ for (int j = 0; j < catchSize; j++) {
+ result.add(catches.getType(j));
+ }
}
- /**
- * Makes the {@link CatchHandlerList} for the given basic block.
- *
- * @param block {@code non-null;} block to get entries for
- * @param addresses {@code non-null;} address objects for each block
- * @return {@code non-null;} array of entries
- */
- private static CatchHandlerList handlersFor(BasicBlock block,
- BlockAddresses addresses) {
- IntList successors = block.getSuccessors();
- int succSize = successors.size();
- int primary = block.getPrimarySuccessor();
- TypeList catches = block.getLastInsn().getCatches();
- int catchSize = catches.size();
+ return result;
+ }
- if (catchSize == 0) {
- return CatchHandlerList.EMPTY;
- }
+ /**
+ * Builds and returns the catch table for a given method.
+ *
+ * @param method {@code non-null;} method to build the list for
+ * @param order {@code non-null;} block output order
+ * @param addresses {@code non-null;} address objects for each block
+ * @return {@code non-null;} the constructed table
+ */
+ public static CatchTable build(RopMethod method, int[] order, BlockAddresses addresses) {
+ int len = order.length;
+ BasicBlockList blocks = method.getBlocks();
+ ArrayList<CatchTable.Entry> resultList = new ArrayList<CatchTable.Entry>(len);
+ CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
+ BasicBlock currentStartBlock = null;
+ BasicBlock currentEndBlock = null;
- if (((primary == -1) && (succSize != catchSize))
- || ((primary != -1) &&
- ((succSize != (catchSize + 1))
- || (primary != successors.get(catchSize))))) {
- /*
- * Blocks that throw are supposed to list their primary
- * successor -- if any -- last in the successors list, but
- * that constraint appears to be violated here.
- */
- throw new RuntimeException(
- "shouldn't happen: weird successors list");
- }
+ for (int i = 0; i < len; i++) {
+ BasicBlock block = blocks.labelToBlock(order[i]);
+ if (!block.canThrow()) {
/*
- * Reduce the effective catchSize if we spot a catch-all that
- * isn't at the end.
+ * There is no need to concern ourselves with the
+ * placement of blocks that can't throw with respect
+ * to the blocks that *can* throw.
*/
- for (int i = 0; i < catchSize; i++) {
- Type type = catches.getType(i);
- if (type.equals(Type.OBJECT)) {
- catchSize = i + 1;
- break;
- }
- }
+ continue;
+ }
- CatchHandlerList result = new CatchHandlerList(catchSize);
+ CatchHandlerList handlers = handlersFor(block, addresses);
- for (int i = 0; i < catchSize; i++) {
- CstType oneType = new CstType(catches.getType(i));
- CodeAddress oneHandler = addresses.getStart(successors.get(i));
- result.set(i, oneType, oneHandler.getAddress());
- }
+ if (currentHandlers.size() == 0) {
+ // This is the start of a new catch range.
+ currentStartBlock = block;
+ currentEndBlock = block;
+ currentHandlers = handlers;
+ continue;
+ }
- result.setImmutable();
- return result;
- }
-
- /**
- * Makes a {@link CatchTable#Entry} for the given block range and
- * handlers.
- *
- * @param start {@code non-null;} the start block for the range (inclusive)
- * @param end {@code non-null;} the start block for the range (also inclusive)
- * @param handlers {@code non-null;} the handlers for the range
- * @param addresses {@code non-null;} address objects for each block
- */
- private static CatchTable.Entry makeEntry(BasicBlock start,
- BasicBlock end, CatchHandlerList handlers,
- BlockAddresses addresses) {
+ if (currentHandlers.equals(handlers) && rangeIsValid(currentStartBlock, block, addresses)) {
/*
- * We start at the *last* instruction of the start block, since
- * that's the instruction that can throw...
+ * The block we are looking at now has the same handlers
+ * as the block that started the currently open catch
+ * range, and adding it to the currently open range won't
+ * cause it to be too long.
*/
- CodeAddress startAddress = addresses.getLast(start);
+ currentEndBlock = block;
+ continue;
+ }
- // ...And we end *after* the last instruction of the end block.
- CodeAddress endAddress = addresses.getEnd(end);
+ /*
+ * The block we are looking at now has incompatible handlers,
+ * so we need to finish off the last entry and start a new
+ * one. Note: We only emit an entry if it has associated handlers.
+ */
+ if (currentHandlers.size() != 0) {
+ CatchTable.Entry entry =
+ makeEntry(currentStartBlock, currentEndBlock, currentHandlers, addresses);
+ resultList.add(entry);
+ }
- return new CatchTable.Entry(startAddress.getAddress(),
- endAddress.getAddress(), handlers);
+ currentStartBlock = block;
+ currentEndBlock = block;
+ currentHandlers = handlers;
}
- /**
- * Gets whether the address range for the given two blocks is valid
- * for a catch handler. This is true as long as the covered range is
- * under 65536 code units.
- *
- * @param start {@code non-null;} the start block for the range (inclusive)
- * @param end {@code non-null;} the start block for the range (also inclusive)
- * @param addresses {@code non-null;} address objects for each block
- * @return {@code true} if the range is valid as a catch range
+ if (currentHandlers.size() != 0) {
+ // Emit an entry for the range that was left hanging.
+ CatchTable.Entry entry =
+ makeEntry(currentStartBlock, currentEndBlock, currentHandlers, addresses);
+ resultList.add(entry);
+ }
+
+ // Construct the final result.
+
+ int resultSz = resultList.size();
+
+ if (resultSz == 0) {
+ return CatchTable.EMPTY;
+ }
+
+ CatchTable result = new CatchTable(resultSz);
+
+ for (int i = 0; i < resultSz; i++) {
+ result.set(i, resultList.get(i));
+ }
+
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Makes the {@link CatchHandlerList} for the given basic block.
+ *
+ * @param block {@code non-null;} block to get entries for
+ * @param addresses {@code non-null;} address objects for each block
+ * @return {@code non-null;} array of entries
+ */
+ private static CatchHandlerList handlersFor(BasicBlock block, BlockAddresses addresses) {
+ IntList successors = block.getSuccessors();
+ int succSize = successors.size();
+ int primary = block.getPrimarySuccessor();
+ TypeList catches = block.getLastInsn().getCatches();
+ int catchSize = catches.size();
+
+ if (catchSize == 0) {
+ return CatchHandlerList.EMPTY;
+ }
+
+ if (((primary == -1) && (succSize != catchSize)) || ((primary != -1)
+ && ((succSize != (catchSize + 1)) || (primary != successors.get(catchSize))))) {
+ /*
+ * Blocks that throw are supposed to list their primary
+ * successor -- if any -- last in the successors list, but
+ * that constraint appears to be violated here.
+ */
+ throw new RuntimeException("shouldn't happen: weird successors list");
+ }
+
+ /*
+ * Reduce the effective catchSize if we spot a catch-all that
+ * isn't at the end.
*/
- private static boolean rangeIsValid(BasicBlock start, BasicBlock end,
- BlockAddresses addresses) {
- if (start == null) {
- throw new NullPointerException("start == null");
- }
-
- if (end == null) {
- throw new NullPointerException("end == null");
- }
-
- // See above about selection of instructions.
- int startAddress = addresses.getLast(start).getAddress();
- int endAddress = addresses.getEnd(end).getAddress();
-
- return (endAddress - startAddress) <= MAX_CATCH_RANGE;
+ for (int i = 0; i < catchSize; i++) {
+ Type type = catches.getType(i);
+ if (type.equals(Type.OBJECT)) {
+ catchSize = i + 1;
+ break;
+ }
}
+
+ CatchHandlerList result = new CatchHandlerList(catchSize);
+
+ for (int i = 0; i < catchSize; i++) {
+ CstType oneType = new CstType(catches.getType(i));
+ CodeAddress oneHandler = addresses.getStart(successors.get(i));
+ result.set(i, oneType, oneHandler.getAddress());
+ }
+
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Makes a {@link CatchTable#Entry} for the given block range and
+ * handlers.
+ *
+ * @param start {@code non-null;} the start block for the range (inclusive)
+ * @param end {@code non-null;} the start block for the range (also inclusive)
+ * @param handlers {@code non-null;} the handlers for the range
+ * @param addresses {@code non-null;} address objects for each block
+ */
+ private static CatchTable.Entry makeEntry(BasicBlock start, BasicBlock end,
+ CatchHandlerList handlers, BlockAddresses addresses) {
+ /*
+ * We start at the *last* instruction of the start block, since
+ * that's the instruction that can throw...
+ */
+ CodeAddress startAddress = addresses.getLast(start);
+
+ // ...And we end *after* the last instruction of the end block.
+ CodeAddress endAddress = addresses.getEnd(end);
+
+ return new CatchTable.Entry(startAddress.getAddress(), endAddress.getAddress(), handlers);
+ }
+
+ /**
+ * Gets whether the address range for the given two blocks is valid
+ * for a catch handler. This is true as long as the covered range is
+ * under 65536 code units.
+ *
+ * @param start {@code non-null;} the start block for the range (inclusive)
+ * @param end {@code non-null;} the start block for the range (also inclusive)
+ * @param addresses {@code non-null;} address objects for each block
+ * @return {@code true} if the range is valid as a catch range
+ */
+ private static boolean rangeIsValid(BasicBlock start, BasicBlock end, BlockAddresses addresses) {
+ if (start == null) {
+ throw new NullPointerException("start == null");
+ }
+
+ if (end == null) {
+ throw new NullPointerException("end == null");
+ }
+
+ // See above about selection of instructions.
+ int startAddress = addresses.getLast(start).getAddress();
+ int endAddress = addresses.getEnd(end).getAddress();
+
+ return (endAddress - startAddress) <= MAX_CATCH_RANGE;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/SwitchData.java b/dx/src/com/android/jack/dx/dex/code/SwitchData.java
index 0785fba..2e6c268 100644
--- a/dx/src/com/android/jack/dx/dex/code/SwitchData.java
+++ b/dx/src/com/android/jack/dx/dex/code/SwitchData.java
@@ -29,230 +29,229 @@
* in either a "packed" or "sparse" form.
*/
public final class SwitchData extends VariableSizeInsn {
- /**
- * {@code non-null;} address representing the instruction that uses this
- * instance
- */
- private final CodeAddress user;
+ /**
+ * {@code non-null;} address representing the instruction that uses this
+ * instance
+ */
+ private final CodeAddress user;
- /** {@code non-null;} sorted list of switch cases (keys) */
- private final IntList cases;
+ /** {@code non-null;} sorted list of switch cases (keys) */
+ private final IntList cases;
- /**
- * {@code non-null;} corresponding list of code addresses; the branch
- * target for each case
- */
- private final CodeAddress[] targets;
+ /**
+ * {@code non-null;} corresponding list of code addresses; the branch
+ * target for each case
+ */
+ private final CodeAddress[] targets;
- /** whether the output table will be packed (vs. sparse) */
- private final boolean packed;
+ /** whether the output table will be packed (vs. sparse) */
+ private final boolean packed;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param user {@code non-null;} address representing the instruction that
- * uses this instance
- * @param cases {@code non-null;} sorted list of switch cases (keys)
- * @param targets {@code non-null;} corresponding list of code addresses; the
- * branch target for each case
- */
- public SwitchData(SourcePosition position, CodeAddress user,
- IntList cases, CodeAddress[] targets) {
- super(position, RegisterSpecList.EMPTY);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param user {@code non-null;} address representing the instruction that
+ * uses this instance
+ * @param cases {@code non-null;} sorted list of switch cases (keys)
+ * @param targets {@code non-null;} corresponding list of code addresses; the
+ * branch target for each case
+ */
+ public SwitchData(SourcePosition position, CodeAddress user, IntList cases,
+ CodeAddress[] targets) {
+ super(position, RegisterSpecList.EMPTY);
- if (user == null) {
- throw new NullPointerException("user == null");
- }
-
- if (cases == null) {
- throw new NullPointerException("cases == null");
- }
-
- if (targets == null) {
- throw new NullPointerException("targets == null");
- }
-
- int sz = cases.size();
-
- if (sz != targets.length) {
- throw new IllegalArgumentException("cases / targets mismatch");
- }
-
- if (sz > 65535) {
- throw new IllegalArgumentException("too many cases");
- }
-
- this.user = user;
- this.cases = cases;
- this.targets = targets;
- this.packed = shouldPack(cases);
+ if (user == null) {
+ throw new NullPointerException("user == null");
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return packed ? (int) packedCodeSize(cases) :
- (int) sparseCodeSize(cases);
+ if (cases == null) {
+ throw new NullPointerException("cases == null");
}
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out) {
- int baseAddress = user.getAddress();
- int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize();
- int sz = targets.length;
+ if (targets == null) {
+ throw new NullPointerException("targets == null");
+ }
- if (packed) {
- int firstCase = (sz == 0) ? 0 : cases.get(0);
- int lastCase = (sz == 0) ? 0 : cases.get(sz - 1);
- int outSz = lastCase - firstCase + 1;
+ int sz = cases.size();
- out.writeShort(Opcodes.PACKED_SWITCH_PAYLOAD);
- out.writeShort(outSz);
- out.writeInt(firstCase);
+ if (sz != targets.length) {
+ throw new IllegalArgumentException("cases / targets mismatch");
+ }
- int caseAt = 0;
- for (int i = 0; i < outSz; i++) {
- int outCase = firstCase + i;
- int oneCase = cases.get(caseAt);
- int relTarget;
+ if (sz > 65535) {
+ throw new IllegalArgumentException("too many cases");
+ }
- if (oneCase > outCase) {
- relTarget = defaultTarget;
- } else {
- relTarget = targets[caseAt].getAddress() - baseAddress;
- caseAt++;
- }
+ this.user = user;
+ this.cases = cases;
+ this.targets = targets;
+ this.packed = shouldPack(cases);
+ }
- out.writeInt(relTarget);
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return packed ? (int) packedCodeSize(cases) : (int) sparseCodeSize(cases);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out) {
+ int baseAddress = user.getAddress();
+ int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize();
+ int sz = targets.length;
+
+ if (packed) {
+ int firstCase = (sz == 0) ? 0 : cases.get(0);
+ int lastCase = (sz == 0) ? 0 : cases.get(sz - 1);
+ int outSz = lastCase - firstCase + 1;
+
+ out.writeShort(Opcodes.PACKED_SWITCH_PAYLOAD);
+ out.writeShort(outSz);
+ out.writeInt(firstCase);
+
+ int caseAt = 0;
+ for (int i = 0; i < outSz; i++) {
+ int outCase = firstCase + i;
+ int oneCase = cases.get(caseAt);
+ int relTarget;
+
+ if (oneCase > outCase) {
+ relTarget = defaultTarget;
} else {
- out.writeShort(Opcodes.SPARSE_SWITCH_PAYLOAD);
- out.writeShort(sz);
-
- for (int i = 0; i < sz; i++) {
- out.writeInt(cases.get(i));
- }
-
- for (int i = 0; i < sz; i++) {
- int relTarget = targets[i].getAddress() - baseAddress;
- out.writeInt(relTarget);
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new SwitchData(getPosition(), user, cases, targets);
- }
-
- /**
- * Returns whether or not this instance's data will be output as packed.
- *
- * @return {@code true} iff the data is to be packed
- */
- public boolean isPacked() {
- return packed;
- }
-
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- StringBuffer sb = new StringBuffer(100);
-
- int sz = targets.length;
- for (int i = 0; i < sz; i++) {
- sb.append("\n ");
- sb.append(cases.get(i));
- sb.append(": ");
- sb.append(targets[i]);
+ relTarget = targets[caseAt].getAddress() - baseAddress;
+ caseAt++;
}
- return sb.toString();
+ out.writeInt(relTarget);
+ }
+ } else {
+ out.writeShort(Opcodes.SPARSE_SWITCH_PAYLOAD);
+ out.writeShort(sz);
+
+ for (int i = 0; i < sz; i++) {
+ out.writeInt(cases.get(i));
+ }
+
+ for (int i = 0; i < sz; i++) {
+ int relTarget = targets[i].getAddress() - baseAddress;
+ out.writeInt(relTarget);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new SwitchData(getPosition(), user, cases, targets);
+ }
+
+ /**
+ * Returns whether or not this instance's data will be output as packed.
+ *
+ * @return {@code true} iff the data is to be packed
+ */
+ public boolean isPacked() {
+ return packed;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ int sz = targets.length;
+ for (int i = 0; i < sz; i++) {
+ sb.append("\n ");
+ sb.append(cases.get(i));
+ sb.append(": ");
+ sb.append(targets[i]);
}
- /** {@inheritDoc} */
- @Override
- protected String listingString0(boolean noteIndices) {
- int baseAddress = user.getAddress();
- StringBuffer sb = new StringBuffer(100);
- int sz = targets.length;
+ return sb.toString();
+ }
- sb.append(packed ? "packed" : "sparse");
- sb.append("-switch-payload // for switch @ ");
- sb.append(Hex.u2(baseAddress));
+ /** {@inheritDoc} */
+ @Override
+ protected String listingString0(boolean noteIndices) {
+ int baseAddress = user.getAddress();
+ StringBuffer sb = new StringBuffer(100);
+ int sz = targets.length;
- for (int i = 0; i < sz; i++) {
- int absTarget = targets[i].getAddress();
- int relTarget = absTarget - baseAddress;
- sb.append("\n ");
- sb.append(cases.get(i));
- sb.append(": ");
- sb.append(Hex.u4(absTarget));
- sb.append(" // ");
- sb.append(Hex.s4(relTarget));
- }
+ sb.append(packed ? "packed" : "sparse");
+ sb.append("-switch-payload // for switch @ ");
+ sb.append(Hex.u2(baseAddress));
- return sb.toString();
+ for (int i = 0; i < sz; i++) {
+ int absTarget = targets[i].getAddress();
+ int relTarget = absTarget - baseAddress;
+ sb.append("\n ");
+ sb.append(cases.get(i));
+ sb.append(": ");
+ sb.append(Hex.u4(absTarget));
+ sb.append(" // ");
+ sb.append(Hex.s4(relTarget));
}
- /**
- * Gets the size of a packed table for the given cases, in 16-bit code
- * units.
- *
- * @param cases {@code non-null;} sorted list of cases
- * @return {@code >= -1;} the packed table size or {@code -1} if the
- * cases couldn't possibly be represented as a packed table
+ return sb.toString();
+ }
+
+ /**
+ * Gets the size of a packed table for the given cases, in 16-bit code
+ * units.
+ *
+ * @param cases {@code non-null;} sorted list of cases
+ * @return {@code >= -1;} the packed table size or {@code -1} if the
+ * cases couldn't possibly be represented as a packed table
+ */
+ private static long packedCodeSize(IntList cases) {
+ int sz = cases.size();
+ long low = cases.get(0);
+ long high = cases.get(sz - 1);
+ long result = ((high - low + 1)) * 2 + 4;
+
+ return (result <= 0x7fffffff) ? result : -1;
+ }
+
+ /**
+ * Gets the size of a sparse table for the given cases, in 16-bit code
+ * units.
+ *
+ * @param cases {@code non-null;} sorted list of cases
+ * @return {@code > 0;} the sparse table size
+ */
+ private static long sparseCodeSize(IntList cases) {
+ int sz = cases.size();
+
+ return (sz * 4L) + 2;
+ }
+
+ /**
+ * Determines whether the given list of cases warrant being packed.
+ *
+ * @param cases {@code non-null;} sorted list of cases
+ * @return {@code true} iff the table encoding the cases
+ * should be packed
+ */
+ private static boolean shouldPack(IntList cases) {
+ int sz = cases.size();
+
+ if (sz < 2) {
+ return true;
+ }
+
+ long packedSize = packedCodeSize(cases);
+ long sparseSize = sparseCodeSize(cases);
+
+ /*
+ * We pick the packed representation if it is possible and
+ * would be as small or smaller than 5/4 of the sparse
+ * representation. That is, we accept some size overhead on
+ * the packed representation, since that format is faster to
+ * execute at runtime.
*/
- private static long packedCodeSize(IntList cases) {
- int sz = cases.size();
- long low = cases.get(0);
- long high = cases.get(sz - 1);
- long result = ((high - low + 1)) * 2 + 4;
-
- return (result <= 0x7fffffff) ? result : -1;
- }
-
- /**
- * Gets the size of a sparse table for the given cases, in 16-bit code
- * units.
- *
- * @param cases {@code non-null;} sorted list of cases
- * @return {@code > 0;} the sparse table size
- */
- private static long sparseCodeSize(IntList cases) {
- int sz = cases.size();
-
- return (sz * 4L) + 2;
- }
-
- /**
- * Determines whether the given list of cases warrant being packed.
- *
- * @param cases {@code non-null;} sorted list of cases
- * @return {@code true} iff the table encoding the cases
- * should be packed
- */
- private static boolean shouldPack(IntList cases) {
- int sz = cases.size();
-
- if (sz < 2) {
- return true;
- }
-
- long packedSize = packedCodeSize(cases);
- long sparseSize = sparseCodeSize(cases);
-
- /*
- * We pick the packed representation if it is possible and
- * would be as small or smaller than 5/4 of the sparse
- * representation. That is, we accept some size overhead on
- * the packed representation, since that format is faster to
- * execute at runtime.
- */
- return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4));
- }
+ return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/TargetInsn.java b/dx/src/com/android/jack/dx/dex/code/TargetInsn.java
index c957867..b97025d 100644
--- a/dx/src/com/android/jack/dx/dex/code/TargetInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/TargetInsn.java
@@ -23,110 +23,110 @@
* Instruction which has a single branch target.
*/
public final class TargetInsn extends FixedSizeInsn {
- /** {@code non-null;} the branch target */
- private CodeAddress target;
+ /** {@code non-null;} the branch target */
+ private CodeAddress target;
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}), and the target is initially
- * {@code null}.
- *
- * @param opcode the opcode; one of the constants from {@link Dops}
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} register list, including a
- * result register if appropriate (that is, registers may be either
- * ins or outs)
- * @param target {@code non-null;} the branch target
- */
- public TargetInsn(Dop opcode, SourcePosition position,
- RegisterSpecList registers, CodeAddress target) {
- super(opcode, position, registers);
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}), and the target is initially
+ * {@code null}.
+ *
+ * @param opcode the opcode; one of the constants from {@link Dops}
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
+ * result register if appropriate (that is, registers may be either
+ * ins or outs)
+ * @param target {@code non-null;} the branch target
+ */
+ public TargetInsn(Dop opcode, SourcePosition position, RegisterSpecList registers,
+ CodeAddress target) {
+ super(opcode, position, registers);
- if (target == null) {
- throw new NullPointerException("target == null");
- }
-
- this.target = target;
+ if (target == null) {
+ throw new NullPointerException("target == null");
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withOpcode(Dop opcode) {
- return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+ this.target = target;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withOpcode(Dop opcode) {
+ return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisters(RegisterSpecList registers) {
+ return new TargetInsn(getOpcode(), getPosition(), registers, target);
+ }
+
+ /**
+ * Returns an instance that is just like this one, except that its
+ * opcode has the opposite sense (as a test; e.g. a
+ * {@code lt} test becomes a {@code ge}), and its branch
+ * target is replaced by the one given, and all set-once values
+ * associated with the class (such as its address) are reset.
+ *
+ * @param target {@code non-null;} the new branch target
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public TargetInsn withNewTargetAndReversed(CodeAddress target) {
+ Dop opcode = getOpcode().getOppositeTest();
+
+ return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+ }
+
+ /**
+ * Gets the unique branch target of this instruction.
+ *
+ * @return {@code non-null;} the branch target
+ */
+ public CodeAddress getTarget() {
+ return target;
+ }
+
+ /**
+ * Gets the target address of this instruction. This is only valid
+ * to call if the target instruction has been assigned an address,
+ * and it is merely a convenient shorthand for
+ * {@code getTarget().getAddress()}.
+ *
+ * @return {@code >= 0;} the target address
+ */
+ public int getTargetAddress() {
+ return target.getAddress();
+ }
+
+ /**
+ * Gets the branch offset of this instruction. This is only valid to
+ * call if both this and the target instruction each has been assigned
+ * an address, and it is merely a convenient shorthand for
+ * {@code getTargetAddress() - getAddress()}.
+ *
+ * @return the branch offset
+ */
+ public int getTargetOffset() {
+ return target.getAddress() - getAddress();
+ }
+
+ /**
+ * Returns whether the target offset is known.
+ *
+ * @return {@code true} if the target offset is known or
+ * {@code false} if not
+ */
+ public boolean hasTargetOffset() {
+ return hasAddress() && target.hasAddress();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String argString() {
+ if (target == null) {
+ return "????";
}
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisters(RegisterSpecList registers) {
- return new TargetInsn(getOpcode(), getPosition(), registers, target);
- }
-
- /**
- * Returns an instance that is just like this one, except that its
- * opcode has the opposite sense (as a test; e.g. a
- * {@code lt} test becomes a {@code ge}), and its branch
- * target is replaced by the one given, and all set-once values
- * associated with the class (such as its address) are reset.
- *
- * @param target {@code non-null;} the new branch target
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public TargetInsn withNewTargetAndReversed(CodeAddress target) {
- Dop opcode = getOpcode().getOppositeTest();
-
- return new TargetInsn(opcode, getPosition(), getRegisters(), target);
- }
-
- /**
- * Gets the unique branch target of this instruction.
- *
- * @return {@code non-null;} the branch target
- */
- public CodeAddress getTarget() {
- return target;
- }
-
- /**
- * Gets the target address of this instruction. This is only valid
- * to call if the target instruction has been assigned an address,
- * and it is merely a convenient shorthand for
- * {@code getTarget().getAddress()}.
- *
- * @return {@code >= 0;} the target address
- */
- public int getTargetAddress() {
- return target.getAddress();
- }
-
- /**
- * Gets the branch offset of this instruction. This is only valid to
- * call if both this and the target instruction each has been assigned
- * an address, and it is merely a convenient shorthand for
- * {@code getTargetAddress() - getAddress()}.
- *
- * @return the branch offset
- */
- public int getTargetOffset() {
- return target.getAddress() - getAddress();
- }
-
- /**
- * Returns whether the target offset is known.
- *
- * @return {@code true} if the target offset is known or
- * {@code false} if not
- */
- public boolean hasTargetOffset() {
- return hasAddress() && target.hasAddress();
- }
-
- /** {@inheritDoc} */
- @Override
- protected String argString() {
- if (target == null) {
- return "????";
- }
-
- return target.identifierString();
- }
+ return target.identifierString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/VariableSizeInsn.java b/dx/src/com/android/jack/dx/dex/code/VariableSizeInsn.java
index 3110629..d3e5ba5 100644
--- a/dx/src/com/android/jack/dx/dex/code/VariableSizeInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/VariableSizeInsn.java
@@ -23,27 +23,26 @@
* Pseudo-instruction base class for variable-sized instructions.
*/
public abstract class VariableSizeInsn extends DalvInsn {
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- * @param registers {@code non-null;} source registers
- */
- public VariableSizeInsn(SourcePosition position,
- RegisterSpecList registers) {
- super(Dops.SPECIAL_FORMAT, position, registers);
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} source registers
+ */
+ public VariableSizeInsn(SourcePosition position, RegisterSpecList registers) {
+ super(Dops.SPECIAL_FORMAT, position, registers);
+ }
- /** {@inheritDoc} */
- @Override
- public final DalvInsn withOpcode(Dop opcode) {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public final DalvInsn withOpcode(Dop opcode) {
+ throw new RuntimeException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public final DalvInsn withRegisterOffset(int delta) {
- return withRegisters(getRegisters().withOffset(delta));
- }
+ /** {@inheritDoc} */
+ @Override
+ public final DalvInsn withRegisterOffset(int delta) {
+ return withRegisters(getRegisters().withOffset(delta));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/ZeroSizeInsn.java b/dx/src/com/android/jack/dx/dex/code/ZeroSizeInsn.java
index d9a7f1b..4e1de10 100644
--- a/dx/src/com/android/jack/dx/dex/code/ZeroSizeInsn.java
+++ b/dx/src/com/android/jack/dx/dex/code/ZeroSizeInsn.java
@@ -26,37 +26,37 @@
* about the code they are adjacent to.
*/
public abstract class ZeroSizeInsn extends DalvInsn {
- /**
- * Constructs an instance. The output address of this instance is initially
- * unknown ({@code -1}).
- *
- * @param position {@code non-null;} source position
- */
- public ZeroSizeInsn(SourcePosition position) {
- super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY);
- }
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ */
+ public ZeroSizeInsn(SourcePosition position) {
+ super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY);
+ }
- /** {@inheritDoc} */
- @Override
- public final int codeSize() {
- return 0;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final int codeSize() {
+ return 0;
+ }
- /** {@inheritDoc} */
- @Override
- public final void writeTo(AnnotatedOutput out) {
- // Nothing to do here, for this class.
- }
+ /** {@inheritDoc} */
+ @Override
+ public final void writeTo(AnnotatedOutput out) {
+ // Nothing to do here, for this class.
+ }
- /** {@inheritDoc} */
- @Override
- public final DalvInsn withOpcode(Dop opcode) {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public final DalvInsn withOpcode(Dop opcode) {
+ throw new RuntimeException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public DalvInsn withRegisterOffset(int delta) {
- return withRegisters(getRegisters().withOffset(delta));
- }
+ /** {@inheritDoc} */
+ @Override
+ public DalvInsn withRegisterOffset(int delta) {
+ return withRegisters(getRegisters().withOffset(delta));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form10t.java b/dx/src/com/android/jack/dx/dex/code/form/Form10t.java
index 6f27986..cc484ba 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form10t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form10t.java
@@ -26,61 +26,60 @@
* for details.
*/
public final class Form10t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form10t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form10t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form10t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form10t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ return branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!((insn instanceof TargetInsn) && (insn.getRegisters().size() == 0))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- return branchString(insn);
- }
+ TargetInsn ti = (TargetInsn) insn;
+ return ti.hasTargetOffset() ? branchFits(ti) : true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ int offset = insn.getTargetOffset();
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 1;
- }
+ // Note: A zero offset would fit, but it is prohibited by the spec.
+ return (offset != 0) && signedFitsInByte(offset);
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!((insn instanceof TargetInsn) &&
- (insn.getRegisters().size() == 0))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ int offset = ((TargetInsn) insn).getTargetOffset();
- TargetInsn ti = (TargetInsn) insn;
- return ti.hasTargetOffset() ? branchFits(ti) : true;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- int offset = insn.getTargetOffset();
-
- // Note: A zero offset would fit, but it is prohibited by the spec.
- return (offset != 0) && signedFitsInByte(offset);
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out, opcodeUnit(insn, (offset & 0xff)));
- }
+ write(out, opcodeUnit(insn, (offset & 0xff)));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form10x.java b/dx/src/com/android/jack/dx/dex/code/form/Form10x.java
index 785f0fa..30dbd74 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form10x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form10x.java
@@ -26,47 +26,46 @@
* for details.
*/
public final class Form10x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form10x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form10x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form10x() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form10x() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- // This format has no arguments.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ // This format has no arguments.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 1;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- return (insn instanceof SimpleInsn) &&
- (insn.getRegisters().size() == 0);
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ return (insn instanceof SimpleInsn) && (insn.getRegisters().size() == 0);
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- write(out, opcodeUnit(insn, 0));
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ write(out, opcodeUnit(insn, 0));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form11n.java b/dx/src/com/android/jack/dx/dex/code/form/Form11n.java
index c30357e..7c4cf49 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form11n.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form11n.java
@@ -31,80 +31,77 @@
* for details.
*/
public final class Form11n extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form11n();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form11n();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form11n() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form11n() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 4);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+
+ if (!((insn instanceof CstInsn) && (regs.size() == 1)
+ && unsignedFitsInNibble(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 4);
- }
+ CstLiteralBits cb = (CstLiteralBits) cst;
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 1;
- }
+ return cb.fitsInInt() && signedFitsInNibble(cb.getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInNibble(regs.get(0).getReg()))) {
- return false;
- }
+ bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+ return bits;
+ }
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int value = ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
-
- CstLiteralBits cb = (CstLiteralBits) cst;
-
- return cb.fitsInInt() && signedFitsInNibble(cb.getIntBits());
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int value =
- ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
-
- write(out,
- opcodeUnit(insn, makeByte(regs.get(0).getReg(), value & 0xf)));
- }
+ write(out, opcodeUnit(insn, makeByte(regs.get(0).getReg(), value & 0xf)));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form11x.java b/dx/src/com/android/jack/dx/dex/code/form/Form11x.java
index a000202..24f35fa 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form11x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form11x.java
@@ -29,60 +29,59 @@
* for details.
*/
public final class Form11x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form11x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form11x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form11x() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form11x() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString();
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString();
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 1;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return (insn instanceof SimpleInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg());
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return (insn instanceof SimpleInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg());
+ }
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- write(out, opcodeUnit(insn, regs.get(0).getReg()));
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ write(out, opcodeUnit(insn, regs.get(0).getReg()));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form12x.java b/dx/src/com/android/jack/dx/dex/code/form/Form12x.java
index 4c93d27..e0aabe4 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form12x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form12x.java
@@ -30,133 +30,129 @@
* for details.
*/
public final class Form12x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form12x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form12x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form12x() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int sz = regs.size();
+
+ /*
+ * The (sz - 2) and (sz - 1) below makes this code work for
+ * both the two- and three-register ops. (See "case 3" in
+ * isCompatible(), below.)
*/
- private Form12x() {
- // This space intentionally left blank.
+
+return regs.get(sz - 2).regString() + ", " + regs.get(sz - 1).regString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!(insn instanceof SimpleInsn)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int sz = regs.size();
+ RegisterSpecList regs = insn.getRegisters();
+ RegisterSpec rs1;
+ RegisterSpec rs2;
+ switch (regs.size()) {
+ case 2: {
+ rs1 = regs.get(0);
+ rs2 = regs.get(1);
+ break;
+ }
+ case 3: {
/*
- * The (sz - 2) and (sz - 1) below makes this code work for
- * both the two- and three-register ops. (See "case 3" in
- * isCompatible(), below.)
+ * This format is allowed for ops that are effectively
+ * 3-arg but where the first two args are identical.
*/
-
- return regs.get(sz - 2).regString() + ", " +
- regs.get(sz - 1).regString();
+ rs1 = regs.get(1);
+ rs2 = regs.get(2);
+ if (rs1.getReg() != regs.get(0).getReg()) {
+ return false;
+ }
+ break;
+ }
+ default: {
+ return false;
+ }
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ return unsignedFitsInNibble(rs1.getReg()) && unsignedFitsInNibble(rs2.getReg());
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
+ int r0 = regs.get(0).getReg();
+ int r1 = regs.get(1).getReg();
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!(insn instanceof SimpleInsn)) {
- return false;
+ switch (regs.size()) {
+ case 2: {
+ bits.set(0, unsignedFitsInNibble(r0));
+ bits.set(1, unsignedFitsInNibble(r1));
+ break;
+ }
+ case 3: {
+ if (r0 != r1) {
+ bits.set(0, false);
+ bits.set(1, false);
+ } else {
+ boolean dstRegComp = unsignedFitsInNibble(r1);
+ bits.set(0, dstRegComp);
+ bits.set(1, dstRegComp);
}
- RegisterSpecList regs = insn.getRegisters();
- RegisterSpec rs1;
- RegisterSpec rs2;
-
- switch (regs.size()) {
- case 2: {
- rs1 = regs.get(0);
- rs2 = regs.get(1);
- break;
- }
- case 3: {
- /*
- * This format is allowed for ops that are effectively
- * 3-arg but where the first two args are identical.
- */
- rs1 = regs.get(1);
- rs2 = regs.get(2);
- if (rs1.getReg() != regs.get(0).getReg()) {
- return false;
- }
- break;
- }
- default: {
- return false;
- }
- }
-
- return unsignedFitsInNibble(rs1.getReg()) &&
- unsignedFitsInNibble(rs2.getReg());
+ bits.set(2, unsignedFitsInNibble(regs.get(2).getReg()));
+ break;
+ }
+ default: {
+ throw new AssertionError();
+ }
}
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
- int r0 = regs.get(0).getReg();
- int r1 = regs.get(1).getReg();
+ return bits;
+ }
- switch (regs.size()) {
- case 2: {
- bits.set(0, unsignedFitsInNibble(r0));
- bits.set(1, unsignedFitsInNibble(r1));
- break;
- }
- case 3: {
- if (r0 != r1) {
- bits.set(0, false);
- bits.set(1, false);
- } else {
- boolean dstRegComp = unsignedFitsInNibble(r1);
- bits.set(0, dstRegComp);
- bits.set(1, dstRegComp);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int sz = regs.size();
- bits.set(2, unsignedFitsInNibble(regs.get(2).getReg()));
- break;
- }
- default: {
- throw new AssertionError();
- }
- }
+ /*
+ * The (sz - 2) and (sz - 1) below makes this code work for
+ * both the two- and three-register ops. (See "case 3" in
+ * isCompatible(), above.)
+ */
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int sz = regs.size();
-
- /*
- * The (sz - 2) and (sz - 1) below makes this code work for
- * both the two- and three-register ops. (See "case 3" in
- * isCompatible(), above.)
- */
-
- write(out, opcodeUnit(insn,
- makeByte(regs.get(sz - 2).getReg(),
- regs.get(sz - 1).getReg())));
- }
+write(out, opcodeUnit(insn, makeByte(regs.get(sz - 2).getReg(), regs.get(sz - 1).getReg())));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form20t.java b/dx/src/com/android/jack/dx/dex/code/form/Form20t.java
index e05042a..8044c02 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form20t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form20t.java
@@ -26,61 +26,60 @@
* for details.
*/
public final class Form20t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form20t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form20t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form20t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form20t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ return branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!((insn instanceof TargetInsn) && (insn.getRegisters().size() == 0))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- return branchString(insn);
- }
+ TargetInsn ti = (TargetInsn) insn;
+ return ti.hasTargetOffset() ? branchFits(ti) : true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ int offset = insn.getTargetOffset();
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ // Note: A zero offset would fit, but it is prohibited by the spec.
+ return (offset != 0) && signedFitsInShort(offset);
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!((insn instanceof TargetInsn) &&
- (insn.getRegisters().size() == 0))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ int offset = ((TargetInsn) insn).getTargetOffset();
- TargetInsn ti = (TargetInsn) insn;
- return ti.hasTargetOffset() ? branchFits(ti) : true;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- int offset = insn.getTargetOffset();
-
- // Note: A zero offset would fit, but it is prohibited by the spec.
- return (offset != 0) && signedFitsInShort(offset);
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out, opcodeUnit(insn, 0), (short) offset);
- }
+ write(out, opcodeUnit(insn, 0), (short) offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form21c.java b/dx/src/com/android/jack/dx/dex/code/form/Form21c.java
index 90415f1..fa77e8f 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form21c.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form21c.java
@@ -34,116 +34,112 @@
* for details.
*/
public final class Form21c extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form21c();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form21c();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form21c() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form21c() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + cstString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ if (noteIndices) {
+ return cstComment(insn);
+ } else {
+ return "";
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!(insn instanceof CstInsn)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + cstString(insn);
- }
+ RegisterSpecList regs = insn.getRegisters();
+ RegisterSpec reg;
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- if (noteIndices) {
- return cstComment(insn);
- } else {
- return "";
+ switch (regs.size()) {
+ case 1: {
+ reg = regs.get(0);
+ break;
+ }
+ case 2: {
+ /*
+ * This format is allowed for ops that are effectively
+ * 2-arg but where the two args are identical.
+ */
+ reg = regs.get(0);
+ if (reg.getReg() != regs.get(1).getReg()) {
+ return false;
}
+ break;
+ }
+ default: {
+ return false;
+ }
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
+ if (!unsignedFitsInByte(reg.getReg())) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!(insn instanceof CstInsn)) {
- return false;
- }
+ CstInsn ci = (CstInsn) insn;
+ int cpi = ci.getIndex();
+ Constant cst = ci.getConstant();
- RegisterSpecList regs = insn.getRegisters();
- RegisterSpec reg;
-
- switch (regs.size()) {
- case 1: {
- reg = regs.get(0);
- break;
- }
- case 2: {
- /*
- * This format is allowed for ops that are effectively
- * 2-arg but where the two args are identical.
- */
- reg = regs.get(0);
- if (reg.getReg() != regs.get(1).getReg()) {
- return false;
- }
- break;
- }
- default: {
- return false;
- }
- }
-
- if (!unsignedFitsInByte(reg.getReg())) {
- return false;
- }
-
- CstInsn ci = (CstInsn) insn;
- int cpi = ci.getIndex();
- Constant cst = ci.getConstant();
-
- if (! unsignedFitsInShort(cpi)) {
- return false;
- }
-
- return (cst instanceof CstType) ||
- (cst instanceof CstFieldRef) ||
- (cst instanceof CstString);
+ if (!unsignedFitsInShort(cpi)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int sz = regs.size();
- BitSet bits = new BitSet(sz);
- boolean compat = unsignedFitsInByte(regs.get(0).getReg());
+ return (cst instanceof CstType) || (cst instanceof CstFieldRef) || (cst instanceof CstString);
+ }
- if (sz == 1) {
- bits.set(0, compat);
- } else {
- if (regs.get(0).getReg() == regs.get(1).getReg()) {
- bits.set(0, compat);
- bits.set(1, compat);
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int sz = regs.size();
+ BitSet bits = new BitSet(sz);
+ boolean compat = unsignedFitsInByte(regs.get(0).getReg());
- return bits;
+ if (sz == 1) {
+ bits.set(0, compat);
+ } else {
+ if (regs.get(0).getReg() == regs.get(1).getReg()) {
+ bits.set(0, compat);
+ bits.set(1, compat);
+ }
}
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int cpi = ((CstInsn) insn).getIndex();
+ return bits;
+ }
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- (short) cpi);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int cpi = ((CstInsn) insn).getIndex();
+
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), (short) cpi);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form21h.java b/dx/src/com/android/jack/dx/dex/code/form/Form21h.java
index 4a57f0a..585fa53 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form21h.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form21h.java
@@ -31,96 +31,93 @@
* for details.
*/
public final class Form21h extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form21h();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form21h();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form21h() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form21h() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return literalBitsComment(value, (regs.get(0).getCategory() == 1) ? 32 : 64);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstLiteralBits cb = (CstLiteralBits) cst;
- return
- literalBitsComment(value,
- (regs.get(0).getCategory() == 1) ? 32 : 64);
+ // Where the high bits are depends on the category of the target.
+ if (regs.get(0).getCategory() == 1) {
+ int bits = cb.getIntBits();
+ return ((bits & 0xffff) == 0);
+ } else {
+ long bits = cb.getLongBits();
+ return ((bits & 0xffffffffffffL) == 0);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
+
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits cb = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ short bits;
+
+ // Where the high bits are depends on the category of the target.
+ if (regs.get(0).getCategory() == 1) {
+ bits = (short) (cb.getIntBits() >>> 16);
+ } else {
+ bits = (short) (cb.getLongBits() >>> 48);
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
-
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
-
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
-
- CstLiteralBits cb = (CstLiteralBits) cst;
-
- // Where the high bits are depends on the category of the target.
- if (regs.get(0).getCategory() == 1) {
- int bits = cb.getIntBits();
- return ((bits & 0xffff) == 0);
- } else {
- long bits = cb.getLongBits();
- return ((bits & 0xffffffffffffL) == 0);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits cb = (CstLiteralBits) ((CstInsn) insn).getConstant();
- short bits;
-
- // Where the high bits are depends on the category of the target.
- if (regs.get(0).getCategory() == 1) {
- bits = (short) (cb.getIntBits() >>> 16);
- } else {
- bits = (short) (cb.getLongBits() >>> 48);
- }
-
- write(out, opcodeUnit(insn, regs.get(0).getReg()), bits);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), bits);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form21s.java b/dx/src/com/android/jack/dx/dex/code/form/Form21s.java
index 57dd12a..0852541 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form21s.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form21s.java
@@ -31,80 +31,76 @@
* for details.
*/
public final class Form21s extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form21s();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form21s();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form21s() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form21s() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 16);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 16);
- }
+ CstLiteralBits cb = (CstLiteralBits) cst;
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int value = ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
- CstLiteralBits cb = (CstLiteralBits) cst;
-
- return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int value =
- ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
-
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- (short) value);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), (short) value);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form21t.java b/dx/src/com/android/jack/dx/dex/code/form/Form21t.java
index 5836a5e..955eced 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form21t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form21t.java
@@ -29,78 +29,75 @@
* for details.
*/
public final class Form21t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form21t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form21t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form21t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form21t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+
+ if (!((insn instanceof TargetInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + branchString(insn);
- }
+ TargetInsn ti = (TargetInsn) insn;
+ return ti.hasTargetOffset() ? branchFits(ti) : true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ int offset = insn.getTargetOffset();
- if (!((insn instanceof TargetInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
+ // Note: A zero offset would fit, but it is prohibited by the spec.
+ return (offset != 0) && signedFitsInShort(offset);
+ }
- TargetInsn ti = (TargetInsn) insn;
- return ti.hasTargetOffset() ? branchFits(ti) : true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int offset = ((TargetInsn) insn).getTargetOffset();
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- int offset = insn.getTargetOffset();
-
- // Note: A zero offset would fit, but it is prohibited by the spec.
- return (offset != 0) && signedFitsInShort(offset);
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- (short) offset);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), (short) offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form22b.java b/dx/src/com/android/jack/dx/dex/code/form/Form22b.java
index a09b6c6..fcae319 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form22b.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form22b.java
@@ -31,83 +31,79 @@
* for details.
*/
public final class Form22b extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form22b();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form22b();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form22b() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form22b() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + regs.get(1).regString() + ", "
+ + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 8);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 2)
+ && unsignedFitsInByte(regs.get(0).getReg()) && unsignedFitsInByte(regs.get(1).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + regs.get(1).regString() +
- ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 8);
- }
+ CstLiteralBits cb = (CstLiteralBits) cst;
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ return cb.fitsInInt() && signedFitsInByte(cb.getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInByte(regs.get(0).getReg()) &&
- unsignedFitsInByte(regs.get(1).getReg()))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+ return bits;
+ }
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int value = ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
- CstLiteralBits cb = (CstLiteralBits) cst;
-
- return cb.fitsInInt() && signedFitsInByte(cb.getIntBits());
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int value =
- ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
-
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- codeUnit(regs.get(1).getReg(), value & 0xff));
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()),
+ codeUnit(regs.get(1).getReg(), value & 0xff));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form22c.java b/dx/src/com/android/jack/dx/dex/code/form/Form22c.java
index d170e06..fdf51c4 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form22c.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form22c.java
@@ -32,84 +32,78 @@
* for details.
*/
public final class Form22c extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form22c();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form22c();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form22c() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form22c() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + regs.get(1).regString() + ", " + cstString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ if (noteIndices) {
+ return cstComment(insn);
+ } else {
+ return "";
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 2)
+ && unsignedFitsInNibble(regs.get(0).getReg())
+ && unsignedFitsInNibble(regs.get(1).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + regs.get(1).regString() +
- ", " + cstString(insn);
+ CstInsn ci = (CstInsn) insn;
+ int cpi = ci.getIndex();
+
+ if (!unsignedFitsInShort(cpi)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- if (noteIndices) {
- return cstComment(insn);
- } else {
- return "";
- }
- }
+ Constant cst = ci.getConstant();
+ return (cst instanceof CstType) || (cst instanceof CstFieldRef);
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInNibble(regs.get(0).getReg()) &&
- unsignedFitsInNibble(regs.get(1).getReg()))) {
- return false;
- }
+ bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+ return bits;
+ }
- CstInsn ci = (CstInsn) insn;
- int cpi = ci.getIndex();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int cpi = ((CstInsn) insn).getIndex();
- if (! unsignedFitsInShort(cpi)) {
- return false;
- }
-
- Constant cst = ci.getConstant();
- return (cst instanceof CstType) ||
- (cst instanceof CstFieldRef);
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
-
- bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int cpi = ((CstInsn) insn).getIndex();
-
- write(out,
- opcodeUnit(insn,
- makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
- (short) cpi);
- }
+ write(out, opcodeUnit(insn, makeByte(regs.get(0).getReg(), regs.get(1).getReg())), (short) cpi);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form22s.java b/dx/src/com/android/jack/dx/dex/code/form/Form22s.java
index bbd66a3..1fcbd7601 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form22s.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form22s.java
@@ -31,84 +31,80 @@
* for details.
*/
public final class Form22s extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form22s();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form22s();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form22s() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form22s() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + regs.get(1).regString() + ", "
+ + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 16);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 2)
+ && unsignedFitsInNibble(regs.get(0).getReg())
+ && unsignedFitsInNibble(regs.get(1).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + regs.get(1).regString()
- + ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 16);
- }
+ CstLiteralBits cb = (CstLiteralBits) cst;
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInNibble(regs.get(0).getReg()) &&
- unsignedFitsInNibble(regs.get(1).getReg()))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+ return bits;
+ }
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int value = ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
- CstLiteralBits cb = (CstLiteralBits) cst;
-
- return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
-
- bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int value =
- ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
-
- write(out,
- opcodeUnit(insn,
- makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
- (short) value);
- }
+ write(out, opcodeUnit(insn, makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+ (short) value);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form22t.java b/dx/src/com/android/jack/dx/dex/code/form/Form22t.java
index 3e9cfdb..66dbde8 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form22t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form22t.java
@@ -29,82 +29,78 @@
* for details.
*/
public final class Form22t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form22t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form22t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form22t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form22t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + regs.get(1).regString() + ", " + branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+
+ if (!((insn instanceof TargetInsn) && (regs.size() == 2)
+ && unsignedFitsInNibble(regs.get(0).getReg())
+ && unsignedFitsInNibble(regs.get(1).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + regs.get(1).regString() +
- ", " + branchString(insn);
- }
+ TargetInsn ti = (TargetInsn) insn;
+ return ti.hasTargetOffset() ? branchFits(ti) : true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ int offset = insn.getTargetOffset();
- if (!((insn instanceof TargetInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInNibble(regs.get(0).getReg()) &&
- unsignedFitsInNibble(regs.get(1).getReg()))) {
- return false;
- }
+ // Note: A zero offset would fit, but it is prohibited by the spec.
+ return (offset != 0) && signedFitsInShort(offset);
+ }
- TargetInsn ti = (TargetInsn) insn;
- return ti.hasTargetOffset() ? branchFits(ti) : true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int offset = ((TargetInsn) insn).getTargetOffset();
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
-
- bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- int offset = insn.getTargetOffset();
-
- // Note: A zero offset would fit, but it is prohibited by the spec.
- return (offset != 0) && signedFitsInShort(offset);
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out,
- opcodeUnit(insn,
- makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
- (short) offset);
- }
+ write(out, opcodeUnit(insn, makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+ (short) offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form22x.java b/dx/src/com/android/jack/dx/dex/code/form/Form22x.java
index f9e4d9c..e505566 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form22x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form22x.java
@@ -29,65 +29,61 @@
* for details.
*/
public final class Form22x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form22x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form22x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form22x() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form22x() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + regs.get(1).regString();
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + regs.get(1).regString();
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
- return (insn instanceof SimpleInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInByte(regs.get(0).getReg()) &&
- unsignedFitsInShort(regs.get(1).getReg());
- }
+ return (insn instanceof SimpleInsn) && (regs.size() == 2)
+ && unsignedFitsInByte(regs.get(0).getReg()) && unsignedFitsInShort(regs.get(1).getReg());
+ }
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
- return bits;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- (short) regs.get(1).getReg());
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), (short) regs.get(1).getReg());
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form23x.java b/dx/src/com/android/jack/dx/dex/code/form/Form23x.java
index 3261788..40dc9c0 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form23x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form23x.java
@@ -29,68 +29,65 @@
* for details.
*/
public final class Form23x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form23x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form23x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form23x() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form23x() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + regs.get(1).regString() +
- ", " + regs.get(2).regString();
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + regs.get(1).regString() + ", "
+ + regs.get(2).regString();
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 2;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 2;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
- return (insn instanceof SimpleInsn) &&
- (regs.size() == 3) &&
- unsignedFitsInByte(regs.get(0).getReg()) &&
- unsignedFitsInByte(regs.get(1).getReg()) &&
- unsignedFitsInByte(regs.get(2).getReg());
- }
+ return (insn instanceof SimpleInsn) && (regs.size() == 3)
+ && unsignedFitsInByte(regs.get(0).getReg()) && unsignedFitsInByte(regs.get(1).getReg())
+ && unsignedFitsInByte(regs.get(2).getReg());
+ }
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(3);
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(3);
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
- bits.set(2, unsignedFitsInByte(regs.get(2).getReg()));
- return bits;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+ bits.set(2, unsignedFitsInByte(regs.get(2).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- write(out,
- opcodeUnit(insn, regs.get(0).getReg()),
- codeUnit(regs.get(1).getReg(), regs.get(2).getReg()));
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ write(out, opcodeUnit(insn, regs.get(0).getReg()),
+ codeUnit(regs.get(1).getReg(), regs.get(2).getReg()));
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form30t.java b/dx/src/com/android/jack/dx/dex/code/form/Form30t.java
index 743f806..579253f 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form30t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form30t.java
@@ -26,57 +26,56 @@
* for details.
*/
public final class Form30t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form30t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form30t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form30t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form30t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ return branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!((insn instanceof TargetInsn) && (insn.getRegisters().size() == 0))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- return branchString(insn);
- }
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ int offset = ((TargetInsn) insn).getTargetOffset();
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!((insn instanceof TargetInsn) &&
- (insn.getRegisters().size() == 0))) {
- return false;
- }
-
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out, opcodeUnit(insn, 0), offset);
- }
+ write(out, opcodeUnit(insn, 0), offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form31c.java b/dx/src/com/android/jack/dx/dex/code/form/Form31c.java
index 12e5f14..cd4877a 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form31c.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form31c.java
@@ -34,109 +34,107 @@
* for details.
*/
public final class Form31c extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form31c();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form31c();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form31c() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form31c() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + cstString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ if (noteIndices) {
+ return cstComment(insn);
+ } else {
+ return "";
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!(insn instanceof CstInsn)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + cstString(insn);
- }
+ RegisterSpecList regs = insn.getRegisters();
+ RegisterSpec reg;
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- if (noteIndices) {
- return cstComment(insn);
- } else {
- return "";
+ switch (regs.size()) {
+ case 1: {
+ reg = regs.get(0);
+ break;
+ }
+ case 2: {
+ /*
+ * This format is allowed for ops that are effectively
+ * 2-arg but where the two args are identical.
+ */
+ reg = regs.get(0);
+ if (reg.getReg() != regs.get(1).getReg()) {
+ return false;
}
+ break;
+ }
+ default: {
+ return false;
+ }
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
+ if (!unsignedFitsInByte(reg.getReg())) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!(insn instanceof CstInsn)) {
- return false;
- }
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- RegisterSpecList regs = insn.getRegisters();
- RegisterSpec reg;
+ return (cst instanceof CstType) || (cst instanceof CstFieldRef) || (cst instanceof CstString);
+ }
- switch (regs.size()) {
- case 1: {
- reg = regs.get(0);
- break;
- }
- case 2: {
- /*
- * This format is allowed for ops that are effectively
- * 2-arg but where the two args are identical.
- */
- reg = regs.get(0);
- if (reg.getReg() != regs.get(1).getReg()) {
- return false;
- }
- break;
- }
- default: {
- return false;
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int sz = regs.size();
+ BitSet bits = new BitSet(sz);
+ boolean compat = unsignedFitsInByte(regs.get(0).getReg());
- if (!unsignedFitsInByte(reg.getReg())) {
- return false;
- }
-
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
-
- return (cst instanceof CstType) ||
- (cst instanceof CstFieldRef) ||
- (cst instanceof CstString);
+ if (sz == 1) {
+ bits.set(0, compat);
+ } else {
+ if (regs.get(0).getReg() == regs.get(1).getReg()) {
+ bits.set(0, compat);
+ bits.set(1, compat);
+ }
}
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int sz = regs.size();
- BitSet bits = new BitSet(sz);
- boolean compat = unsignedFitsInByte(regs.get(0).getReg());
+ return bits;
+ }
- if (sz == 1) {
- bits.set(0, compat);
- } else {
- if (regs.get(0).getReg() == regs.get(1).getReg()) {
- bits.set(0, compat);
- bits.set(1, compat);
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int cpi = ((CstInsn) insn).getIndex();
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int cpi = ((CstInsn) insn).getIndex();
-
- write(out, opcodeUnit(insn, regs.get(0).getReg()), cpi);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), cpi);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form31i.java b/dx/src/com/android/jack/dx/dex/code/form/Form31i.java
index 8e45f18..4a10162 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form31i.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form31i.java
@@ -31,76 +31,74 @@
* for details.
*/
public final class Form31i extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form31i();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form31i();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form31i() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form31i() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 32);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + literalBitsString(value);
+ if (!(cst instanceof CstLiteralBits)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 32);
- }
+ return ((CstLiteralBits) cst).fitsInInt();
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int value = ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
- if (!(cst instanceof CstLiteralBits)) {
- return false;
- }
-
- return ((CstLiteralBits) cst).fitsInInt();
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int value =
- ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
-
- write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form31t.java b/dx/src/com/android/jack/dx/dex/code/form/Form31t.java
index 8573615..603fd18 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form31t.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form31t.java
@@ -29,72 +29,71 @@
* for details.
*/
public final class Form31t extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form31t();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form31t();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form31t() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form31t() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + branchString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ return branchComment(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+
+ if (!((insn instanceof TargetInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + branchString(insn);
- }
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- return branchComment(insn);
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public boolean branchFits(TargetInsn insn) {
+ return true;
+ }
- if (!((insn instanceof TargetInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int offset = ((TargetInsn) insn).getTargetOffset();
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean branchFits(TargetInsn insn) {
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int offset = ((TargetInsn) insn).getTargetOffset();
-
- write(out, opcodeUnit(insn, regs.get(0).getReg()), offset);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form32x.java b/dx/src/com/android/jack/dx/dex/code/form/Form32x.java
index 2f856ce..07d18a2 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form32x.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form32x.java
@@ -29,66 +29,61 @@
* for details.
*/
public final class Form32x extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form32x();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form32x();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form32x() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form32x() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return regs.get(0).regString() + ", " + regs.get(1).regString();
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return regs.get(0).regString() + ", " + regs.get(1).regString();
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- // This format has no comment.
- return "";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ // This format has no comment.
+ return "";
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- return (insn instanceof SimpleInsn) &&
- (regs.size() == 2) &&
- unsignedFitsInShort(regs.get(0).getReg()) &&
- unsignedFitsInShort(regs.get(1).getReg());
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ return (insn instanceof SimpleInsn) && (regs.size() == 2)
+ && unsignedFitsInShort(regs.get(0).getReg()) && unsignedFitsInShort(regs.get(1).getReg());
+ }
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(2);
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(2);
- bits.set(0, unsignedFitsInShort(regs.get(0).getReg()));
- bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
- return bits;
- }
+ bits.set(0, unsignedFitsInShort(regs.get(0).getReg()));
+ bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
- write(out,
- opcodeUnit(insn, 0),
- (short) regs.get(0).getReg(),
- (short) regs.get(1).getReg());
- }
+ write(out, opcodeUnit(insn, 0), (short) regs.get(0).getReg(), (short) regs.get(1).getReg());
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form35c.java b/dx/src/com/android/jack/dx/dex/code/form/Form35c.java
index df277ef..9fd6a03 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form35c.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form35c.java
@@ -34,178 +34,172 @@
* for details.
*/
public final class Form35c extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form35c();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form35c();
- /** Maximal number of operands */
- private static final int MAX_NUM_OPS = 5;
+ /** Maximal number of operands */
+ private static final int MAX_NUM_OPS = 5;
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form35c() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form35c() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = explicitize(insn.getRegisters());
+ return regListString(regs) + ", " + cstString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ if (noteIndices) {
+ return cstComment(insn);
+ } else {
+ return "";
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!(insn instanceof CstInsn)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = explicitize(insn.getRegisters());
- return regListString(regs) + ", " + cstString(insn);
+ CstInsn ci = (CstInsn) insn;
+ int cpi = ci.getIndex();
+
+ if (!unsignedFitsInShort(cpi)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- if (noteIndices) {
- return cstComment(insn);
- } else {
- return "";
- }
+ Constant cst = ci.getConstant();
+ if (!((cst instanceof CstMethodRef) || (cst instanceof CstType))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
+ RegisterSpecList regs = ci.getRegisters();
+ return (wordCount(regs) >= 0);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int sz = regs.size();
+ BitSet bits = new BitSet(sz);
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec reg = regs.get(i);
+ /*
+ * The check below adds (category - 1) to the register, to
+ * account for the fact that the second half of a
+ * category-2 register has to be represented explicitly in
+ * the result.
+ */
+ bits.set(i, unsignedFitsInNibble(reg.getReg() + reg.getCategory() - 1));
}
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!(insn instanceof CstInsn)) {
- return false;
- }
+ return bits;
+ }
- CstInsn ci = (CstInsn) insn;
- int cpi = ci.getIndex();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ int cpi = ((CstInsn) insn).getIndex();
+ RegisterSpecList regs = explicitize(insn.getRegisters());
+ int sz = regs.size();
+ int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
+ int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
+ int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
+ int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
+ int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
- if (! unsignedFitsInShort(cpi)) {
- return false;
- }
+ write(out, opcodeUnit(insn, makeByte(r4, sz)), // encode the fifth operand here
+ (short) cpi, codeUnit(r0, r1, r2, r3));
+ }
- Constant cst = ci.getConstant();
- if (!((cst instanceof CstMethodRef) ||
- (cst instanceof CstType))) {
- return false;
- }
+ /**
+ * Gets the number of words required for the given register list, where
+ * category-2 values count as two words. Return {@code -1} if the
+ * list requires more than five words or contains registers that need
+ * more than a nibble to identify them.
+ *
+ * @param regs {@code non-null;} the register list in question
+ * @return {@code >= -1;} the number of words required, or {@code -1}
+ * if the list couldn't possibly fit in this format
+ */
+ private static int wordCount(RegisterSpecList regs) {
+ int sz = regs.size();
- RegisterSpecList regs = ci.getRegisters();
- return (wordCount(regs) >= 0);
+ if (sz > MAX_NUM_OPS) {
+ // It can't possibly fit.
+ return -1;
}
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int sz = regs.size();
- BitSet bits = new BitSet(sz);
+ int result = 0;
- for (int i = 0; i < sz; i++) {
- RegisterSpec reg = regs.get(i);
- /*
- * The check below adds (category - 1) to the register, to
- * account for the fact that the second half of a
- * category-2 register has to be represented explicitly in
- * the result.
- */
- bits.set(i, unsignedFitsInNibble(reg.getReg() +
- reg.getCategory() - 1));
- }
-
- return bits;
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec one = regs.get(i);
+ result += one.getCategory();
+ /*
+ * The check below adds (category - 1) to the register, to
+ * account for the fact that the second half of a
+ * category-2 register has to be represented explicitly in
+ * the result.
+ */
+ if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
+ return -1;
+ }
}
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- int cpi = ((CstInsn) insn).getIndex();
- RegisterSpecList regs = explicitize(insn.getRegisters());
- int sz = regs.size();
- int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
- int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
- int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
- int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
- int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
+ return (result <= MAX_NUM_OPS) ? result : -1;
+ }
- write(out,
- opcodeUnit(insn,
- makeByte(r4, sz)), // encode the fifth operand here
- (short) cpi,
- codeUnit(r0, r1, r2, r3));
+ /**
+ * Returns a register list which is equivalent to the given one,
+ * except that it splits category-2 registers into two explicit
+ * entries. This returns the original list if no modification is
+ * required
+ *
+ * @param orig {@code non-null;} the original list
+ * @return {@code non-null;} the list with the described transformation
+ */
+ private static RegisterSpecList explicitize(RegisterSpecList orig) {
+ int wordCount = wordCount(orig);
+ int sz = orig.size();
+
+ if (wordCount == sz) {
+ return orig;
}
- /**
- * Gets the number of words required for the given register list, where
- * category-2 values count as two words. Return {@code -1} if the
- * list requires more than five words or contains registers that need
- * more than a nibble to identify them.
- *
- * @param regs {@code non-null;} the register list in question
- * @return {@code >= -1;} the number of words required, or {@code -1}
- * if the list couldn't possibly fit in this format
- */
- private static int wordCount(RegisterSpecList regs) {
- int sz = regs.size();
+ RegisterSpecList result = new RegisterSpecList(wordCount);
+ int wordAt = 0;
- if (sz > MAX_NUM_OPS) {
- // It can't possibly fit.
- return -1;
- }
-
- int result = 0;
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec one = regs.get(i);
- result += one.getCategory();
- /*
- * The check below adds (category - 1) to the register, to
- * account for the fact that the second half of a
- * category-2 register has to be represented explicitly in
- * the result.
- */
- if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
- return -1;
- }
- }
-
- return (result <= MAX_NUM_OPS) ? result : -1;
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec one = orig.get(i);
+ result.set(wordAt, one);
+ if (one.getCategory() == 2) {
+ result.set(wordAt + 1, RegisterSpec.make(one.getReg() + 1, Type.VOID));
+ wordAt += 2;
+ } else {
+ wordAt++;
+ }
}
- /**
- * Returns a register list which is equivalent to the given one,
- * except that it splits category-2 registers into two explicit
- * entries. This returns the original list if no modification is
- * required
- *
- * @param orig {@code non-null;} the original list
- * @return {@code non-null;} the list with the described transformation
- */
- private static RegisterSpecList explicitize(RegisterSpecList orig) {
- int wordCount = wordCount(orig);
- int sz = orig.size();
-
- if (wordCount == sz) {
- return orig;
- }
-
- RegisterSpecList result = new RegisterSpecList(wordCount);
- int wordAt = 0;
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec one = orig.get(i);
- result.set(wordAt, one);
- if (one.getCategory() == 2) {
- result.set(wordAt + 1,
- RegisterSpec.make(one.getReg() + 1, Type.VOID));
- wordAt += 2;
- } else {
- wordAt++;
- }
- }
-
- result.setImmutable();
- return result;
- }
+ result.setImmutable();
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form3rc.java b/dx/src/com/android/jack/dx/dex/code/form/Form3rc.java
index 35adc7a..ec0ca88 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form3rc.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form3rc.java
@@ -30,77 +30,72 @@
* for details.
*/
public final class Form3rc extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form3rc();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form3rc();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form3rc() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form3rc() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ return regRangeString(insn.getRegisters()) + ", " + cstString(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ if (noteIndices) {
+ return cstComment(insn);
+ } else {
+ return "";
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 3;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ if (!(insn instanceof CstInsn)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- return regRangeString(insn.getRegisters()) + ", " +
- cstString(insn);
+ CstInsn ci = (CstInsn) insn;
+ int cpi = ci.getIndex();
+ Constant cst = ci.getConstant();
+
+ if (!unsignedFitsInShort(cpi)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- if (noteIndices) {
- return cstComment(insn);
- } else {
- return "";
- }
+ if (!((cst instanceof CstMethodRef) || (cst instanceof CstType))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 3;
- }
+ RegisterSpecList regs = ci.getRegisters();
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- if (!(insn instanceof CstInsn)) {
- return false;
- }
+ return (regs.size() == 0) || (isRegListSequential(regs)
+ && unsignedFitsInShort(regs.get(0).getReg()) && unsignedFitsInByte(regs.getWordCount()));
+ }
- CstInsn ci = (CstInsn) insn;
- int cpi = ci.getIndex();
- Constant cst = ci.getConstant();
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ int cpi = ((CstInsn) insn).getIndex();
+ int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
+ int count = regs.getWordCount();
- if (! unsignedFitsInShort(cpi)) {
- return false;
- }
-
- if (!((cst instanceof CstMethodRef) ||
- (cst instanceof CstType))) {
- return false;
- }
-
- RegisterSpecList regs = ci.getRegisters();
- int sz = regs.size();
-
- return (regs.size() == 0) ||
- (isRegListSequential(regs) &&
- unsignedFitsInShort(regs.get(0).getReg()) &&
- unsignedFitsInByte(regs.getWordCount()));
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- int cpi = ((CstInsn) insn).getIndex();
- int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
- int count = regs.getWordCount();
-
- write(out, opcodeUnit(insn, count), (short) cpi, (short) firstReg);
- }
+ write(out, opcodeUnit(insn, count), (short) cpi, (short) firstReg);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/Form51l.java b/dx/src/com/android/jack/dx/dex/code/form/Form51l.java
index 9dd086f..5555149 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/Form51l.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/Form51l.java
@@ -32,72 +32,70 @@
* for details.
*/
public final class Form51l extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new Form51l();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new Form51l();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private Form51l() {
- // This space intentionally left blank.
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private Form51l() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+ return regs.get(0).regString() + ", " + literalBitsString(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ return literalBitsComment(value, 64);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ return 5;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ if (!((insn instanceof CstInsn) && (regs.size() == 1)
+ && unsignedFitsInByte(regs.get(0).getReg()))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+ CstInsn ci = (CstInsn) insn;
+ Constant cst = ci.getConstant();
- return regs.get(0).regString() + ", " + literalBitsString(value);
- }
+ return (cst instanceof CstLiteral64);
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
- return literalBitsComment(value, 64);
- }
+ /** {@inheritDoc} */
+ @Override
+ public BitSet compatibleRegs(DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ BitSet bits = new BitSet(1);
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- return 5;
- }
+ bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+ return bits;
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- if (!((insn instanceof CstInsn) &&
- (regs.size() == 1) &&
- unsignedFitsInByte(regs.get(0).getReg()))) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ RegisterSpecList regs = insn.getRegisters();
+ long value = ((CstLiteral64) ((CstInsn) insn).getConstant()).getLongBits();
- CstInsn ci = (CstInsn) insn;
- Constant cst = ci.getConstant();
-
- return (cst instanceof CstLiteral64);
- }
-
- /** {@inheritDoc} */
- @Override
- public BitSet compatibleRegs(DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- BitSet bits = new BitSet(1);
-
- bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- RegisterSpecList regs = insn.getRegisters();
- long value =
- ((CstLiteral64) ((CstInsn) insn).getConstant()).getLongBits();
-
- write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
- }
+ write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/code/form/SpecialFormat.java b/dx/src/com/android/jack/dx/dex/code/form/SpecialFormat.java
index bce8a67..b0cf53a 100644
--- a/dx/src/com/android/jack/dx/dex/code/form/SpecialFormat.java
+++ b/dx/src/com/android/jack/dx/dex/code/form/SpecialFormat.java
@@ -29,44 +29,44 @@
* always returns {@code true}.
*/
public final class SpecialFormat extends InsnFormat {
- /** {@code non-null;} unique instance of this class */
- public static final InsnFormat THE_ONE = new SpecialFormat();
+ /** {@code non-null;} unique instance of this class */
+ public static final InsnFormat THE_ONE = new SpecialFormat();
- /**
- * Constructs an instance. This class is not publicly
- * instantiable. Use {@link #THE_ONE}.
- */
- private SpecialFormat() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly
+ * instantiable. Use {@link #THE_ONE}.
+ */
+ private SpecialFormat() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public String insnArgString(DalvInsn insn) {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnArgString(DalvInsn insn) {
+ throw new RuntimeException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public String insnCommentString(DalvInsn insn, boolean noteIndices) {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+ throw new RuntimeException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public int codeSize() {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public int codeSize() {
+ throw new RuntimeException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCompatible(DalvInsn insn) {
- return true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCompatible(DalvInsn insn) {
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(AnnotatedOutput out, DalvInsn insn) {
- throw new RuntimeException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+ throw new RuntimeException("unsupported");
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/AnnotationItem.java b/dx/src/com/android/jack/dx/dex/file/AnnotationItem.java
index c48c3d8..c7394c9 100644
--- a/dx/src/com/android/jack/dx/dex/file/AnnotationItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/AnnotationItem.java
@@ -32,187 +32,193 @@
* element pairs.
*/
public final class AnnotationItem extends OffsettedItem {
- /** annotation visibility constant: visible at build time only */
- private static final int VISIBILITY_BUILD = 0;
+ /** annotation visibility constant: visible at build time only */
+ private static final int VISIBILITY_BUILD = 0;
- /** annotation visibility constant: visible at runtime */
- private static final int VISIBILITY_RUNTIME = 1;
+ /** annotation visibility constant: visible at runtime */
+ private static final int VISIBILITY_RUNTIME = 1;
- /** annotation visibility constant: visible at runtime only to system */
- private static final int VISIBILITY_SYSTEM = 2;
+ /** annotation visibility constant: visible at runtime only to system */
+ private static final int VISIBILITY_SYSTEM = 2;
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 1;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 1;
- /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
- private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
+ /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
+ private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
- /** {@code non-null;} the annotation to represent */
- private final Annotation annotation;
+ /** {@code non-null;} the annotation to represent */
+ private final Annotation annotation;
- /**
- * {@code null-ok;} type reference for the annotation type; set during
- * {@link #addContents}
- */
- private TypeIdItem type;
+ /**
+ * {@code null-ok;} type reference for the annotation type; set during
+ * {@link #addContents}
+ */
+ private TypeIdItem type;
- /**
- * {@code null-ok;} encoded form, ready for writing to a file; set during
- * {@link #place0}
- */
- private byte[] encodedForm;
+ /**
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
+ * {@link #place0}
+ */
+ private byte[] encodedForm;
- /**
- * Comparator that sorts (outer) instances by type id index.
- */
- private static class TypeIdSorter implements Comparator<AnnotationItem> {
- /** {@inheritDoc} */
- public int compare(AnnotationItem item1, AnnotationItem item2) {
- int index1 = item1.type.getIndex();
- int index2 = item2.type.getIndex();
-
- if (index1 < index2) {
- return -1;
- } else if (index1 > index2) {
- return 1;
- }
-
- return 0;
- }
- }
-
- /**
- * Sorts an array of instances, in place, by type id index,
- * ignoring all other aspects of the elements. This is only valid
- * to use after type id indices are known.
- *
- * @param array {@code non-null;} array to sort
- */
- public static void sortByTypeIdIndex(AnnotationItem[] array) {
- Arrays.sort(array, TYPE_ID_SORTER);
- }
-
- /**
- * Constructs an instance.
- *
- * @param annotation {@code non-null;} annotation to represent
- */
- public AnnotationItem(Annotation annotation) {
- /*
- * The write size isn't known up-front because (the variable-lengthed)
- * leb128 type is used to represent some things.
- */
- super(ALIGNMENT, -1);
-
- if (annotation == null) {
- throw new NullPointerException("annotation == null");
- }
-
- this.annotation = annotation;
- this.type = null;
- this.encodedForm = null;
- }
-
+ /**
+ * Comparator that sorts (outer) instances by type id index.
+ */
+ private static class TypeIdSorter implements Comparator<AnnotationItem> {
/** {@inheritDoc} */
@Override
- public ItemType itemType() {
- return ItemType.TYPE_ANNOTATION_ITEM;
+ public int compare(AnnotationItem item1, AnnotationItem item2) {
+ int index1 = item1.type.getIndex();
+ int index2 = item2.type.getIndex();
+
+ if (index1 < index2) {
+ return -1;
+ } else if (index1 > index2) {
+ return 1;
+ }
+
+ return 0;
}
+ }
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return annotation.hashCode();
- }
+ /**
+ * Sorts an array of instances, in place, by type id index,
+ * ignoring all other aspects of the elements. This is only valid
+ * to use after type id indices are known.
+ *
+ * @param array {@code non-null;} array to sort
+ */
+ public static void sortByTypeIdIndex(AnnotationItem[] array) {
+ Arrays.sort(array, TYPE_ID_SORTER);
+ }
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(OffsettedItem other) {
- AnnotationItem otherAnnotation = (AnnotationItem) other;
-
- return annotation.compareTo(otherAnnotation.annotation);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return annotation.toHuman();
- }
-
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- type = file.getTypeIds().intern(annotation.getType());
- ValueEncoder.addContents(file, annotation);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // Encode the data and note the size.
-
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
- ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
-
- encoder.writeAnnotation(annotation, false);
- encodedForm = out.toByteArray();
-
- // Add one for the visibility byte in front of the encoded annotation.
- setWriteSize(encodedForm.length + 1);
- }
-
- /**
- * Write a (listing file) annotation for this instance to the given
- * output, that consumes no bytes of output. This is for annotating
- * a reference to this instance at the point of the reference.
- *
- * @param out {@code non-null;} where to output to
- * @param prefix {@code non-null;} prefix for each line of output
+ /**
+ * Constructs an instance.
+ *
+ * @param annotation {@code non-null;} annotation to represent
+ */
+ public AnnotationItem(Annotation annotation) {
+ /*
+ * The write size isn't known up-front because (the variable-lengthed)
+ * leb128 type is used to represent some things.
*/
- public void annotateTo(AnnotatedOutput out, String prefix) {
- out.annotate(0, prefix + "visibility: " +
- annotation.getVisibility().toHuman());
- out.annotate(0, prefix + "type: " + annotation.getType().toHuman());
+ super(ALIGNMENT, -1);
- for (NameValuePair pair : annotation.getNameValuePairs()) {
- CstString name = pair.getName();
- Constant value = pair.getValue();
-
- out.annotate(0, prefix + name.toHuman() + ": " +
- ValueEncoder.constantToHuman(value));
- }
+ if (annotation == null) {
+ throw new NullPointerException("annotation == null");
}
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
- AnnotationVisibility visibility = annotation.getVisibility();
+ this.annotation = annotation;
+ this.type = null;
+ this.encodedForm = null;
+ }
- if (annotates) {
- out.annotate(0, offsetString() + " annotation");
- out.annotate(1, " visibility: VISBILITY_" + visibility);
- }
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_ANNOTATION_ITEM;
+ }
- switch (visibility) {
- case BUILD: out.writeByte(VISIBILITY_BUILD); break;
- case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break;
- case SYSTEM: out.writeByte(VISIBILITY_SYSTEM); break;
- default: {
- // EMBEDDED shouldn't appear at the top level.
- throw new RuntimeException("shouldn't happen");
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return annotation.hashCode();
+ }
- if (annotates) {
- /*
- * The output is to be annotated, so redo the work previously
- * done by place0(), except this time annotations will actually
- * get emitted.
- */
- ValueEncoder encoder = new ValueEncoder(file, out);
- encoder.writeAnnotation(annotation, true);
- } else {
- out.write(encodedForm);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(OffsettedItem other) {
+ AnnotationItem otherAnnotation = (AnnotationItem) other;
+
+ return annotation.compareTo(otherAnnotation.annotation);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return annotation.toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ type = file.getTypeIds().intern(annotation.getType());
+ ValueEncoder.addContents(file, annotation);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // Encode the data and note the size.
+
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+ ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+ encoder.writeAnnotation(annotation, false);
+ encodedForm = out.toByteArray();
+
+ // Add one for the visibility byte in front of the encoded annotation.
+ setWriteSize(encodedForm.length + 1);
+ }
+
+ /**
+ * Write a (listing file) annotation for this instance to the given
+ * output, that consumes no bytes of output. This is for annotating
+ * a reference to this instance at the point of the reference.
+ *
+ * @param out {@code non-null;} where to output to
+ * @param prefix {@code non-null;} prefix for each line of output
+ */
+ public void annotateTo(AnnotatedOutput out, String prefix) {
+ out.annotate(0, prefix + "visibility: " + annotation.getVisibility().toHuman());
+ out.annotate(0, prefix + "type: " + annotation.getType().toHuman());
+
+ for (NameValuePair pair : annotation.getNameValuePairs()) {
+ CstString name = pair.getName();
+ Constant value = pair.getValue();
+
+ out.annotate(0, prefix + name.toHuman() + ": " + ValueEncoder.constantToHuman(value));
}
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ AnnotationVisibility visibility = annotation.getVisibility();
+
+ if (annotates) {
+ out.annotate(0, offsetString() + " annotation");
+ out.annotate(1, " visibility: VISBILITY_" + visibility);
+ }
+
+ switch (visibility) {
+ case BUILD:
+ out.writeByte(VISIBILITY_BUILD);
+ break;
+ case RUNTIME:
+ out.writeByte(VISIBILITY_RUNTIME);
+ break;
+ case SYSTEM:
+ out.writeByte(VISIBILITY_SYSTEM);
+ break;
+ default: {
+ // EMBEDDED shouldn't appear at the top level.
+ throw new RuntimeException("shouldn't happen");
+ }
+ }
+
+ if (annotates) {
+ /*
+ * The output is to be annotated, so redo the work previously
+ * done by place0(), except this time annotations will actually
+ * get emitted.
+ */
+ ValueEncoder encoder = new ValueEncoder(file, out);
+ encoder.writeAnnotation(annotation, true);
+ } else {
+ out.write(encodedForm);
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/jack/dx/dex/file/AnnotationSetItem.java
index 9672023..eea7fa6 100644
--- a/dx/src/com/android/jack/dx/dex/file/AnnotationSetItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/AnnotationSetItem.java
@@ -25,133 +25,133 @@
* Set of annotations, where no annotation type appears more than once.
*/
public final class AnnotationSetItem extends OffsettedItem {
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 4;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 4;
- /** the size of an entry int the set: one {@code uint} */
- private static final int ENTRY_WRITE_SIZE = 4;
+ /** the size of an entry int the set: one {@code uint} */
+ private static final int ENTRY_WRITE_SIZE = 4;
- /** {@code non-null;} the set of annotations */
- private final Annotations annotations;
+ /** {@code non-null;} the set of annotations */
+ private final Annotations annotations;
- /**
- * {@code non-null;} set of annotations as individual items in an array.
- * <b>Note:</b> The contents have to get sorted by type id before
- * writing.
- */
- private final AnnotationItem[] items;
+ /**
+ * {@code non-null;} set of annotations as individual items in an array.
+ * <b>Note:</b> The contents have to get sorted by type id before
+ * writing.
+ */
+ private final AnnotationItem[] items;
- /**
- * Constructs an instance.
- *
- * @param annotations {@code non-null;} set of annotations
- */
- public AnnotationSetItem(Annotations annotations) {
- super(ALIGNMENT, writeSize(annotations));
+ /**
+ * Constructs an instance.
+ *
+ * @param annotations {@code non-null;} set of annotations
+ */
+ public AnnotationSetItem(Annotations annotations) {
+ super(ALIGNMENT, writeSize(annotations));
- this.annotations = annotations;
- this.items = new AnnotationItem[annotations.size()];
+ this.annotations = annotations;
+ this.items = new AnnotationItem[annotations.size()];
- int at = 0;
- for (Annotation a : annotations.getAnnotations()) {
- items[at] = new AnnotationItem(a);
- at++;
- }
+ int at = 0;
+ for (Annotation a : annotations.getAnnotations()) {
+ items[at] = new AnnotationItem(a);
+ at++;
+ }
+ }
+
+ /**
+ * Gets the write size for the given set.
+ *
+ * @param annotations {@code non-null;} the set
+ * @return {@code > 0;} the write size
+ */
+ private static int writeSize(Annotations annotations) {
+ // This includes an int size at the start of the list.
+
+ try {
+ return (annotations.size() * ENTRY_WRITE_SIZE) + 4;
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("list == null");
+ }
+ }
+
+ /**
+ * Gets the underlying annotations of this instance
+ *
+ * @return {@code non-null;} the annotations
+ */
+ public Annotations getAnnotations() {
+ return annotations;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return annotations.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(OffsettedItem other) {
+ AnnotationSetItem otherSet = (AnnotationSetItem) other;
+
+ return annotations.compareTo(otherSet.annotations);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_ANNOTATION_SET_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return annotations.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ MixedItemSection byteData = file.getByteData();
+ int size = items.length;
+
+ for (int i = 0; i < size; i++) {
+ items[i] = byteData.intern(items[i]);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // Sort the array to be in type id index order.
+ AnnotationItem.sortByTypeIdIndex(items);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ int size = items.length;
+
+ if (annotates) {
+ out.annotate(0, offsetString() + " annotation set");
+ out.annotate(4, " size: " + Hex.u4(size));
}
- /**
- * Gets the write size for the given set.
- *
- * @param annotations {@code non-null;} the set
- * @return {@code > 0;} the write size
- */
- private static int writeSize(Annotations annotations) {
- // This includes an int size at the start of the list.
+ out.writeInt(size);
- try {
- return (annotations.size() * ENTRY_WRITE_SIZE) + 4;
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("list == null");
- }
+ for (int i = 0; i < size; i++) {
+ AnnotationItem item = items[i];
+ int offset = item.getAbsoluteOffset();
+
+ if (annotates) {
+ out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " + Hex.u4(offset));
+ items[i].annotateTo(out, " ");
+ }
+
+ out.writeInt(offset);
}
-
- /**
- * Gets the underlying annotations of this instance
- *
- * @return {@code non-null;} the annotations
- */
- public Annotations getAnnotations() {
- return annotations;
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return annotations.hashCode();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(OffsettedItem other) {
- AnnotationSetItem otherSet = (AnnotationSetItem) other;
-
- return annotations.compareTo(otherSet.annotations);
- }
-
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_ANNOTATION_SET_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return annotations.toString();
- }
-
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- MixedItemSection byteData = file.getByteData();
- int size = items.length;
-
- for (int i = 0; i < size; i++) {
- items[i] = byteData.intern(items[i]);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // Sort the array to be in type id index order.
- AnnotationItem.sortByTypeIdIndex(items);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
- int size = items.length;
-
- if (annotates) {
- out.annotate(0, offsetString() + " annotation set");
- out.annotate(4, " size: " + Hex.u4(size));
- }
-
- out.writeInt(size);
-
- for (int i = 0; i < size; i++) {
- AnnotationItem item = items[i];
- int offset = item.getAbsoluteOffset();
-
- if (annotates) {
- out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " +
- Hex.u4(offset));
- items[i].annotateTo(out, " ");
- }
-
- out.writeInt(offset);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/jack/dx/dex/file/AnnotationSetRefItem.java
index a78dafc..2759ebd 100644
--- a/dx/src/com/android/jack/dx/dex/file/AnnotationSetRefItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/AnnotationSetRefItem.java
@@ -23,58 +23,59 @@
* Indirect reference to an {@link AnnotationSetItem}.
*/
public final class AnnotationSetRefItem extends OffsettedItem {
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 4;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 4;
- /** write size of this class, in bytes */
- private static final int WRITE_SIZE = 4;
+ /** write size of this class, in bytes */
+ private static final int WRITE_SIZE = 4;
- /** {@code non-null;} the annotation set to refer to */
- private AnnotationSetItem annotations;
+ /** {@code non-null;} the annotation set to refer to */
+ private AnnotationSetItem annotations;
- /**
- * Constructs an instance.
- *
- * @param annotations {@code non-null;} the annotation set to refer to
- */
- public AnnotationSetRefItem(AnnotationSetItem annotations) {
- super(ALIGNMENT, WRITE_SIZE);
+ /**
+ * Constructs an instance.
+ *
+ * @param annotations {@code non-null;} the annotation set to refer to
+ */
+ public AnnotationSetRefItem(AnnotationSetItem annotations) {
+ super(ALIGNMENT, WRITE_SIZE);
- if (annotations == null) {
- throw new NullPointerException("annotations == null");
- }
-
- this.annotations = annotations;
+ if (annotations == null) {
+ throw new NullPointerException("annotations == null");
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_ANNOTATION_SET_REF_ITEM;
+ this.annotations = annotations;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_ANNOTATION_SET_REF_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ MixedItemSection wordData = file.getWordData();
+
+ annotations = wordData.intern(annotations);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return annotations.toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ int annotationsOff = annotations.getAbsoluteOffset();
+
+ if (out.annotates()) {
+ out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff));
}
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- MixedItemSection wordData = file.getWordData();
-
- annotations = wordData.intern(annotations);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return annotations.toHuman();
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- int annotationsOff = annotations.getAbsoluteOffset();
-
- if (out.annotates()) {
- out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff));
- }
-
- out.writeInt(annotationsOff);
- }
+ out.writeInt(annotationsOff);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/jack/dx/dex/file/AnnotationUtils.java
index 868f82b..99bd2b9 100644
--- a/dx/src/com/android/jack/dx/dex/file/AnnotationUtils.java
+++ b/dx/src/com/android/jack/dx/dex/file/AnnotationUtils.java
@@ -16,6 +16,8 @@
package com.android.jack.dx.dex.file;
+import static com.android.jack.dx.rop.annotation.AnnotationVisibility.SYSTEM;
+
import com.android.jack.dx.rop.annotation.Annotation;
import com.android.jack.dx.rop.annotation.NameValuePair;
import com.android.jack.dx.rop.cst.Constant;
@@ -31,222 +33,219 @@
import java.util.ArrayList;
-import static com.android.jack.dx.rop.annotation.AnnotationVisibility.*;
-
/**
* Utility class for dealing with annotations.
*/
public final class AnnotationUtils {
- /** {@code non-null;} type for {@code AnnotationDefault} annotations */
- private static final CstType ANNOTATION_DEFAULT_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
+ /** {@code non-null;} type for {@code AnnotationDefault} annotations */
+ private static final CstType ANNOTATION_DEFAULT_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
- /** {@code non-null;} type for {@code EnclosingClass} annotations */
- private static final CstType ENCLOSING_CLASS_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
+ /** {@code non-null;} type for {@code EnclosingClass} annotations */
+ private static final CstType ENCLOSING_CLASS_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
- /** {@code non-null;} type for {@code EnclosingMethod} annotations */
- private static final CstType ENCLOSING_METHOD_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
+ /** {@code non-null;} type for {@code EnclosingMethod} annotations */
+ private static final CstType ENCLOSING_METHOD_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
- /** {@code non-null;} type for {@code InnerClass} annotations */
- private static final CstType INNER_CLASS_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
+ /** {@code non-null;} type for {@code InnerClass} annotations */
+ private static final CstType INNER_CLASS_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
- /** {@code non-null;} type for {@code MemberClasses} annotations */
- private static final CstType MEMBER_CLASSES_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
+ /** {@code non-null;} type for {@code MemberClasses} annotations */
+ private static final CstType MEMBER_CLASSES_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
- /** {@code non-null;} type for {@code Signature} annotations */
- private static final CstType SIGNATURE_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
+ /** {@code non-null;} type for {@code Signature} annotations */
+ private static final CstType SIGNATURE_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
- /** {@code non-null;} type for {@code Throws} annotations */
- private static final CstType THROWS_TYPE =
- CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
+ /** {@code non-null;} type for {@code Throws} annotations */
+ private static final CstType THROWS_TYPE =
+ CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
- /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
- private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags");
+ /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
+ private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags");
- /** {@code non-null;} the UTF-8 constant {@code "name"} */
- private static final CstString NAME_STRING = new CstString("name");
+ /** {@code non-null;} the UTF-8 constant {@code "name"} */
+ private static final CstString NAME_STRING = new CstString("name");
- /** {@code non-null;} the UTF-8 constant {@code "value"} */
- private static final CstString VALUE_STRING = new CstString("value");
+ /** {@code non-null;} the UTF-8 constant {@code "value"} */
+ private static final CstString VALUE_STRING = new CstString("value");
- /**
- * This class is uninstantiable.
+ /**
+ * This class is uninstantiable.
+ */
+ private AnnotationUtils() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Constructs a standard {@code AnnotationDefault} annotation.
+ *
+ * @param defaults {@code non-null;} the defaults, itself as an annotation
+ * @return {@code non-null;} the constructed annotation
+ */
+ public static Annotation makeAnnotationDefault(Annotation defaults) {
+ Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM);
+
+ result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults)));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs a standard {@code EnclosingClass} annotation.
+ *
+ * @param clazz {@code non-null;} the enclosing class
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeEnclosingClass(CstType clazz) {
+ Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM);
+
+ result.put(new NameValuePair(VALUE_STRING, clazz));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs a standard {@code EnclosingMethod} annotation.
+ *
+ * @param method {@code non-null;} the enclosing method
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeEnclosingMethod(CstMethodRef method) {
+ Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM);
+
+ result.put(new NameValuePair(VALUE_STRING, method));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs a standard {@code InnerClass} annotation.
+ *
+ * @param name {@code null-ok;} the original name of the class, or
+ * {@code null} to represent an anonymous class
+ * @param accessFlags the original access flags
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeInnerClass(CstString name, int accessFlags) {
+ Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
+ Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE;
+
+ result.put(new NameValuePair(NAME_STRING, nameCst));
+ result.put(new NameValuePair(ACCESS_FLAGS_STRING, CstInteger.make(accessFlags)));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs a standard {@code MemberClasses} annotation.
+ *
+ * @param types {@code non-null;} the list of (the types of) the member classes
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeMemberClasses(TypeList types) {
+ CstArray array = makeCstArray(types);
+ Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
+ result.put(new NameValuePair(VALUE_STRING, array));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Constructs a standard {@code Signature} annotation.
+ *
+ * @param signature {@code non-null;} the signature string
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeSignature(CstString signature) {
+ Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
+
+ /*
+ * Split the string into pieces that are likely to be common
+ * across many signatures and the rest of the file.
*/
- private AnnotationUtils() {
- // This space intentionally left blank.
- }
- /**
- * Constructs a standard {@code AnnotationDefault} annotation.
- *
- * @param defaults {@code non-null;} the defaults, itself as an annotation
- * @return {@code non-null;} the constructed annotation
- */
- public static Annotation makeAnnotationDefault(Annotation defaults) {
- Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM);
+String raw = signature.getString();
+ int rawLength = raw.length();
+ ArrayList<String> pieces = new ArrayList<String>(20);
- result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults)));
- result.setImmutable();
- return result;
- }
-
- /**
- * Constructs a standard {@code EnclosingClass} annotation.
- *
- * @param clazz {@code non-null;} the enclosing class
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeEnclosingClass(CstType clazz) {
- Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM);
-
- result.put(new NameValuePair(VALUE_STRING, clazz));
- result.setImmutable();
- return result;
- }
-
- /**
- * Constructs a standard {@code EnclosingMethod} annotation.
- *
- * @param method {@code non-null;} the enclosing method
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeEnclosingMethod(CstMethodRef method) {
- Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM);
-
- result.put(new NameValuePair(VALUE_STRING, method));
- result.setImmutable();
- return result;
- }
-
- /**
- * Constructs a standard {@code InnerClass} annotation.
- *
- * @param name {@code null-ok;} the original name of the class, or
- * {@code null} to represent an anonymous class
- * @param accessFlags the original access flags
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeInnerClass(CstString name, int accessFlags) {
- Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
- Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE;
-
- result.put(new NameValuePair(NAME_STRING, nameCst));
- result.put(new NameValuePair(ACCESS_FLAGS_STRING,
- CstInteger.make(accessFlags)));
- result.setImmutable();
- return result;
- }
-
- /**
- * Constructs a standard {@code MemberClasses} annotation.
- *
- * @param types {@code non-null;} the list of (the types of) the member classes
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeMemberClasses(TypeList types) {
- CstArray array = makeCstArray(types);
- Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
- result.put(new NameValuePair(VALUE_STRING, array));
- result.setImmutable();
- return result;
- }
-
- /**
- * Constructs a standard {@code Signature} annotation.
- *
- * @param signature {@code non-null;} the signature string
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeSignature(CstString signature) {
- Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
-
- /*
- * Split the string into pieces that are likely to be common
- * across many signatures and the rest of the file.
- */
-
- String raw = signature.getString();
- int rawLength = raw.length();
- ArrayList<String> pieces = new ArrayList<String>(20);
-
- for (int at = 0; at < rawLength; /*at*/) {
- char c = raw.charAt(at);
- int endAt = at + 1;
- if (c == 'L') {
- // Scan to ';' or '<'. Consume ';' but not '<'.
- while (endAt < rawLength) {
- c = raw.charAt(endAt);
- if (c == ';') {
- endAt++;
- break;
- } else if (c == '<') {
- break;
- }
- endAt++;
- }
- } else {
- // Scan to 'L' without consuming it.
- while (endAt < rawLength) {
- c = raw.charAt(endAt);
- if (c == 'L') {
- break;
- }
- endAt++;
- }
- }
-
- pieces.add(raw.substring(at, endAt));
- at = endAt;
+ for (int at = 0; at < rawLength; /*at*/) {
+ char c = raw.charAt(at);
+ int endAt = at + 1;
+ if (c == 'L') {
+ // Scan to ';' or '<'. Consume ';' but not '<'.
+ while (endAt < rawLength) {
+ c = raw.charAt(endAt);
+ if (c == ';') {
+ endAt++;
+ break;
+ } else if (c == '<') {
+ break;
+ }
+ endAt++;
}
-
- int size = pieces.size();
- CstArray.List list = new CstArray.List(size);
-
- for (int i = 0; i < size; i++) {
- list.set(i, new CstString(pieces.get(i)));
+ } else {
+ // Scan to 'L' without consuming it.
+ while (endAt < rawLength) {
+ c = raw.charAt(endAt);
+ if (c == 'L') {
+ break;
+ }
+ endAt++;
}
+ }
- list.setImmutable();
-
- result.put(new NameValuePair(VALUE_STRING, new CstArray(list)));
- result.setImmutable();
- return result;
+ pieces.add(raw.substring(at, endAt));
+ at = endAt;
}
- /**
- * Constructs a standard {@code Throws} annotation.
- *
- * @param types {@code non-null;} the list of thrown types
- * @return {@code non-null;} the annotation
- */
- public static Annotation makeThrows(TypeList types) {
- CstArray array = makeCstArray(types);
- Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
- result.put(new NameValuePair(VALUE_STRING, array));
- result.setImmutable();
- return result;
+ int size = pieces.size();
+ CstArray.List list = new CstArray.List(size);
+
+ for (int i = 0; i < size; i++) {
+ list.set(i, new CstString(pieces.get(i)));
}
- /**
- * Converts a {@link TypeList} to a {@link CstArray}.
- *
- * @param types {@code non-null;} the type list
- * @return {@code non-null;} the corresponding array constant
- */
- private static CstArray makeCstArray(TypeList types) {
- int size = types.size();
- CstArray.List list = new CstArray.List(size);
+ list.setImmutable();
- for (int i = 0; i < size; i++) {
- list.set(i, CstType.intern(types.getType(i)));
- }
+ result.put(new NameValuePair(VALUE_STRING, new CstArray(list)));
+ result.setImmutable();
+ return result;
+ }
- list.setImmutable();
- return new CstArray(list);
+ /**
+ * Constructs a standard {@code Throws} annotation.
+ *
+ * @param types {@code non-null;} the list of thrown types
+ * @return {@code non-null;} the annotation
+ */
+ public static Annotation makeThrows(TypeList types) {
+ CstArray array = makeCstArray(types);
+ Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
+ result.put(new NameValuePair(VALUE_STRING, array));
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Converts a {@link TypeList} to a {@link CstArray}.
+ *
+ * @param types {@code non-null;} the type list
+ * @return {@code non-null;} the corresponding array constant
+ */
+ private static CstArray makeCstArray(TypeList types) {
+ int size = types.size();
+ CstArray.List list = new CstArray.List(size);
+
+ for (int i = 0; i < size; i++) {
+ list.set(i, CstType.intern(types.getType(i)));
}
+
+ list.setImmutable();
+ return new CstArray(list);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/jack/dx/dex/file/AnnotationsDirectoryItem.java
index acde7fa..13f727a 100644
--- a/dx/src/com/android/jack/dx/dex/file/AnnotationsDirectoryItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/AnnotationsDirectoryItem.java
@@ -31,355 +31,342 @@
* Per-class directory of annotations.
*/
public final class AnnotationsDirectoryItem extends OffsettedItem {
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 4;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 4;
- /** write size of this class's header, in bytes */
- private static final int HEADER_SIZE = 16;
+ /** write size of this class's header, in bytes */
+ private static final int HEADER_SIZE = 16;
- /** write size of a list element, in bytes */
- private static final int ELEMENT_SIZE = 8;
+ /** write size of a list element, in bytes */
+ private static final int ELEMENT_SIZE = 8;
- /** {@code null-ok;} the class-level annotations, if any */
- private AnnotationSetItem classAnnotations;
+ /** {@code null-ok;} the class-level annotations, if any */
+ private AnnotationSetItem classAnnotations;
- /** {@code null-ok;} the annotated fields, if any */
- private ArrayList<FieldAnnotationStruct> fieldAnnotations;
+ /** {@code null-ok;} the annotated fields, if any */
+ private ArrayList<FieldAnnotationStruct> fieldAnnotations;
- /** {@code null-ok;} the annotated methods, if any */
- private ArrayList<MethodAnnotationStruct> methodAnnotations;
+ /** {@code null-ok;} the annotated methods, if any */
+ private ArrayList<MethodAnnotationStruct> methodAnnotations;
- /** {@code null-ok;} the annotated parameters, if any */
- private ArrayList<ParameterAnnotationStruct> parameterAnnotations;
+ /** {@code null-ok;} the annotated parameters, if any */
+ private ArrayList<ParameterAnnotationStruct> parameterAnnotations;
- /**
- * Constructs an empty instance.
- */
- public AnnotationsDirectoryItem() {
- super(ALIGNMENT, -1);
+ /**
+ * Constructs an empty instance.
+ */
+ public AnnotationsDirectoryItem() {
+ super(ALIGNMENT, -1);
- classAnnotations = null;
- fieldAnnotations = null;
- methodAnnotations = null;
- parameterAnnotations = null;
+ classAnnotations = null;
+ fieldAnnotations = null;
+ methodAnnotations = null;
+ parameterAnnotations = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
+ }
+
+ /**
+ * Returns whether this item is empty (has no contents).
+ *
+ * @return {@code true} if this item is empty, or {@code false}
+ * if not
+ */
+ public boolean isEmpty() {
+ return (classAnnotations == null) && (fieldAnnotations == null) && (methodAnnotations == null)
+ && (parameterAnnotations == null);
+ }
+
+ /**
+ * Returns whether this item is a candidate for interning. The only
+ * interning candidates are ones that <i>only</i> have a non-null
+ * set of class annotations, with no other lists.
+ *
+ * @return {@code true} if this is an interning candidate, or
+ * {@code false} if not
+ */
+ public boolean isInternable() {
+ return (classAnnotations != null) && (fieldAnnotations == null) && (methodAnnotations == null)
+ && (parameterAnnotations == null);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ if (classAnnotations == null) {
+ return 0;
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
+ return classAnnotations.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b>: This throws an exception if this item is not
+ * internable.</p>
+ *
+ * @see #isInternable
+ */
+ @Override
+ public int compareTo0(OffsettedItem other) {
+ if (!isInternable()) {
+ throw new UnsupportedOperationException("uninternable instance");
}
- /**
- * Returns whether this item is empty (has no contents).
- *
- * @return {@code true} if this item is empty, or {@code false}
- * if not
- */
- public boolean isEmpty() {
- return (classAnnotations == null) &&
- (fieldAnnotations == null) &&
- (methodAnnotations == null) &&
- (parameterAnnotations == null);
+ AnnotationsDirectoryItem otherDirectory = (AnnotationsDirectoryItem) other;
+ return classAnnotations.compareTo(otherDirectory.classAnnotations);
+ }
+
+ /**
+ * Sets the direct annotations on this instance. These are annotations
+ * made on the class, per se, as opposed to on one of its members.
+ * It is only valid to call this method at most once per instance.
+ *
+ * @param annotations {@code non-null;} annotations to set for this class
+ */
+ public void setClassAnnotations(Annotations annotations) {
+ if (annotations == null) {
+ throw new NullPointerException("annotations == null");
}
- /**
- * Returns whether this item is a candidate for interning. The only
- * interning candidates are ones that <i>only</i> have a non-null
- * set of class annotations, with no other lists.
- *
- * @return {@code true} if this is an interning candidate, or
- * {@code false} if not
- */
- public boolean isInternable() {
- return (classAnnotations != null) &&
- (fieldAnnotations == null) &&
- (methodAnnotations == null) &&
- (parameterAnnotations == null);
+ if (classAnnotations != null) {
+ throw new UnsupportedOperationException("class annotations already set");
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- if (classAnnotations == null) {
- return 0;
- }
+ classAnnotations = new AnnotationSetItem(annotations);
+ }
- return classAnnotations.hashCode();
+ /**
+ * Adds a field annotations item to this instance.
+ *
+ * @param field {@code non-null;} field in question
+ * @param annotations {@code non-null;} associated annotations to add
+ */
+ public void addFieldAnnotations(CstFieldRef field, Annotations annotations) {
+ if (fieldAnnotations == null) {
+ fieldAnnotations = new ArrayList<FieldAnnotationStruct>();
}
- /**
- * {@inheritDoc}
- *
- * <p><b>Note:</b>: This throws an exception if this item is not
- * internable.</p>
- *
- * @see #isInternable
- */
- @Override
- public int compareTo0(OffsettedItem other) {
- if (! isInternable()) {
- throw new UnsupportedOperationException("uninternable instance");
- }
+ fieldAnnotations.add(new FieldAnnotationStruct(field, new AnnotationSetItem(annotations)));
+ }
- AnnotationsDirectoryItem otherDirectory =
- (AnnotationsDirectoryItem) other;
- return classAnnotations.compareTo(otherDirectory.classAnnotations);
+ /**
+ * Adds a method annotations item to this instance.
+ *
+ * @param method {@code non-null;} method in question
+ * @param annotations {@code non-null;} associated annotations to add
+ */
+ public void addMethodAnnotations(CstMethodRef method, Annotations annotations) {
+ if (methodAnnotations == null) {
+ methodAnnotations = new ArrayList<MethodAnnotationStruct>();
}
- /**
- * Sets the direct annotations on this instance. These are annotations
- * made on the class, per se, as opposed to on one of its members.
- * It is only valid to call this method at most once per instance.
- *
- * @param annotations {@code non-null;} annotations to set for this class
- */
- public void setClassAnnotations(Annotations annotations) {
- if (annotations == null) {
- throw new NullPointerException("annotations == null");
- }
+ methodAnnotations.add(new MethodAnnotationStruct(method, new AnnotationSetItem(annotations)));
+ }
- if (classAnnotations != null) {
- throw new UnsupportedOperationException(
- "class annotations already set");
- }
-
- classAnnotations = new AnnotationSetItem(annotations);
+ /**
+ * Adds a parameter annotations item to this instance.
+ *
+ * @param method {@code non-null;} method in question
+ * @param list {@code non-null;} associated list of annotation sets to add
+ */
+ public void addParameterAnnotations(CstMethodRef method, AnnotationsList list) {
+ if (parameterAnnotations == null) {
+ parameterAnnotations = new ArrayList<ParameterAnnotationStruct>();
}
- /**
- * Adds a field annotations item to this instance.
- *
- * @param field {@code non-null;} field in question
- * @param annotations {@code non-null;} associated annotations to add
- */
- public void addFieldAnnotations(CstFieldRef field,
- Annotations annotations) {
- if (fieldAnnotations == null) {
- fieldAnnotations = new ArrayList<FieldAnnotationStruct>();
- }
+ parameterAnnotations.add(new ParameterAnnotationStruct(method, list));
+ }
- fieldAnnotations.add(new FieldAnnotationStruct(field,
- new AnnotationSetItem(annotations)));
+ /**
+ * Gets the method annotations for a given method, if any. This is
+ * meant for use by debugging / dumping code.
+ *
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the method annotations, if any
+ */
+ public Annotations getMethodAnnotations(CstMethodRef method) {
+ if (methodAnnotations == null) {
+ return null;
}
- /**
- * Adds a method annotations item to this instance.
- *
- * @param method {@code non-null;} method in question
- * @param annotations {@code non-null;} associated annotations to add
- */
- public void addMethodAnnotations(CstMethodRef method,
- Annotations annotations) {
- if (methodAnnotations == null) {
- methodAnnotations = new ArrayList<MethodAnnotationStruct>();
- }
-
- methodAnnotations.add(new MethodAnnotationStruct(method,
- new AnnotationSetItem(annotations)));
+ for (MethodAnnotationStruct item : methodAnnotations) {
+ if (item.getMethod().equals(method)) {
+ return item.getAnnotations();
+ }
}
- /**
- * Adds a parameter annotations item to this instance.
- *
- * @param method {@code non-null;} method in question
- * @param list {@code non-null;} associated list of annotation sets to add
- */
- public void addParameterAnnotations(CstMethodRef method,
- AnnotationsList list) {
- if (parameterAnnotations == null) {
- parameterAnnotations = new ArrayList<ParameterAnnotationStruct>();
- }
+ return null;
+ }
- parameterAnnotations.add(new ParameterAnnotationStruct(method, list));
+ /**
+ * Gets the parameter annotations for a given method, if any. This is
+ * meant for use by debugging / dumping code.
+ *
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the parameter annotations, if any
+ */
+ public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+ if (parameterAnnotations == null) {
+ return null;
}
- /**
- * Gets the method annotations for a given method, if any. This is
- * meant for use by debugging / dumping code.
- *
- * @param method {@code non-null;} the method
- * @return {@code null-ok;} the method annotations, if any
- */
- public Annotations getMethodAnnotations(CstMethodRef method) {
- if (methodAnnotations == null) {
- return null;
- }
-
- for (MethodAnnotationStruct item : methodAnnotations) {
- if (item.getMethod().equals(method)) {
- return item.getAnnotations();
- }
- }
-
- return null;
+ for (ParameterAnnotationStruct item : parameterAnnotations) {
+ if (item.getMethod().equals(method)) {
+ return item.getAnnotationsList();
+ }
}
- /**
- * Gets the parameter annotations for a given method, if any. This is
- * meant for use by debugging / dumping code.
- *
- * @param method {@code non-null;} the method
- * @return {@code null-ok;} the parameter annotations, if any
- */
- public AnnotationsList getParameterAnnotations(CstMethodRef method) {
- if (parameterAnnotations == null) {
- return null;
- }
+ return null;
+ }
- for (ParameterAnnotationStruct item : parameterAnnotations) {
- if (item.getMethod().equals(method)) {
- return item.getAnnotationsList();
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ MixedItemSection wordData = file.getWordData();
- return null;
+ if (classAnnotations != null) {
+ classAnnotations = wordData.intern(classAnnotations);
}
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- MixedItemSection wordData = file.getWordData();
-
- if (classAnnotations != null) {
- classAnnotations = wordData.intern(classAnnotations);
- }
-
- if (fieldAnnotations != null) {
- for (FieldAnnotationStruct item : fieldAnnotations) {
- item.addContents(file);
- }
- }
-
- if (methodAnnotations != null) {
- for (MethodAnnotationStruct item : methodAnnotations) {
- item.addContents(file);
- }
- }
-
- if (parameterAnnotations != null) {
- for (ParameterAnnotationStruct item : parameterAnnotations) {
- item.addContents(file);
- }
- }
+ if (fieldAnnotations != null) {
+ for (FieldAnnotationStruct item : fieldAnnotations) {
+ item.addContents(file);
+ }
}
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- throw new RuntimeException("unsupported");
+ if (methodAnnotations != null) {
+ for (MethodAnnotationStruct item : methodAnnotations) {
+ item.addContents(file);
+ }
}
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // We just need to set the write size here.
+ if (parameterAnnotations != null) {
+ for (ParameterAnnotationStruct item : parameterAnnotations) {
+ item.addContents(file);
+ }
+ }
+ }
- int elementCount = listSize(fieldAnnotations)
- + listSize(methodAnnotations) + listSize(parameterAnnotations);
- setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE));
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ throw new RuntimeException("unsupported");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // We just need to set the write size here.
+
+ int elementCount =
+ listSize(fieldAnnotations) + listSize(methodAnnotations) + listSize(parameterAnnotations);
+ setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations);
+ int fieldsSize = listSize(fieldAnnotations);
+ int methodsSize = listSize(methodAnnotations);
+ int parametersSize = listSize(parameterAnnotations);
+
+ if (annotates) {
+ out.annotate(0, offsetString() + " annotations directory");
+ out.annotate(4, " class_annotations_off: " + Hex.u4(classOff));
+ out.annotate(4, " fields_size: " + Hex.u4(fieldsSize));
+ out.annotate(4, " methods_size: " + Hex.u4(methodsSize));
+ out.annotate(4, " parameters_size: " + Hex.u4(parametersSize));
}
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
- int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations);
- int fieldsSize = listSize(fieldAnnotations);
- int methodsSize = listSize(methodAnnotations);
- int parametersSize = listSize(parameterAnnotations);
+ out.writeInt(classOff);
+ out.writeInt(fieldsSize);
+ out.writeInt(methodsSize);
+ out.writeInt(parametersSize);
- if (annotates) {
- out.annotate(0, offsetString() + " annotations directory");
- out.annotate(4, " class_annotations_off: " + Hex.u4(classOff));
- out.annotate(4, " fields_size: " +
- Hex.u4(fieldsSize));
- out.annotate(4, " methods_size: " +
- Hex.u4(methodsSize));
- out.annotate(4, " parameters_size: " +
- Hex.u4(parametersSize));
- }
-
- out.writeInt(classOff);
- out.writeInt(fieldsSize);
- out.writeInt(methodsSize);
- out.writeInt(parametersSize);
-
- if (fieldsSize != 0) {
- Collections.sort(fieldAnnotations);
- if (annotates) {
- out.annotate(0, " fields:");
- }
- for (FieldAnnotationStruct item : fieldAnnotations) {
- item.writeTo(file, out);
- }
- }
-
- if (methodsSize != 0) {
- Collections.sort(methodAnnotations);
- if (annotates) {
- out.annotate(0, " methods:");
- }
- for (MethodAnnotationStruct item : methodAnnotations) {
- item.writeTo(file, out);
- }
- }
-
- if (parametersSize != 0) {
- Collections.sort(parameterAnnotations);
- if (annotates) {
- out.annotate(0, " parameters:");
- }
- for (ParameterAnnotationStruct item : parameterAnnotations) {
- item.writeTo(file, out);
- }
- }
+ if (fieldsSize != 0) {
+ Collections.sort(fieldAnnotations);
+ if (annotates) {
+ out.annotate(0, " fields:");
+ }
+ for (FieldAnnotationStruct item : fieldAnnotations) {
+ item.writeTo(file, out);
+ }
}
- /**
- * Gets the list size of the given list, or {@code 0} if given
- * {@code null}.
- *
- * @param list {@code null-ok;} the list in question
- * @return {@code >= 0;} its size
- */
- private static int listSize(ArrayList<?> list) {
- if (list == null) {
- return 0;
- }
-
- return list.size();
+ if (methodsSize != 0) {
+ Collections.sort(methodAnnotations);
+ if (annotates) {
+ out.annotate(0, " methods:");
+ }
+ for (MethodAnnotationStruct item : methodAnnotations) {
+ item.writeTo(file, out);
+ }
}
- /**
- * Prints out the contents of this instance, in a debugging-friendly
- * way. This is meant to be called from {@link ClassDefItem#debugPrint}.
- *
- * @param out {@code non-null;} where to output to
- */
- /*package*/ void debugPrint(PrintWriter out) {
- if (classAnnotations != null) {
- out.println(" class annotations: " + classAnnotations);
- }
-
- if (fieldAnnotations != null) {
- out.println(" field annotations:");
- for (FieldAnnotationStruct item : fieldAnnotations) {
- out.println(" " + item.toHuman());
- }
- }
-
- if (methodAnnotations != null) {
- out.println(" method annotations:");
- for (MethodAnnotationStruct item : methodAnnotations) {
- out.println(" " + item.toHuman());
- }
- }
-
- if (parameterAnnotations != null) {
- out.println(" parameter annotations:");
- for (ParameterAnnotationStruct item : parameterAnnotations) {
- out.println(" " + item.toHuman());
- }
- }
+ if (parametersSize != 0) {
+ Collections.sort(parameterAnnotations);
+ if (annotates) {
+ out.annotate(0, " parameters:");
+ }
+ for (ParameterAnnotationStruct item : parameterAnnotations) {
+ item.writeTo(file, out);
+ }
}
+ }
+
+ /**
+ * Gets the list size of the given list, or {@code 0} if given
+ * {@code null}.
+ *
+ * @param list {@code null-ok;} the list in question
+ * @return {@code >= 0;} its size
+ */
+ private static int listSize(ArrayList<?> list) {
+ if (list == null) {
+ return 0;
+ }
+
+ return list.size();
+ }
+
+ /**
+ * Prints out the contents of this instance, in a debugging-friendly
+ * way. This is meant to be called from {@link ClassDefItem#debugPrint}.
+ *
+ * @param out {@code non-null;} where to output to
+ */
+ /*package*/void debugPrint(PrintWriter out) {
+ if (classAnnotations != null) {
+ out.println(" class annotations: " + classAnnotations);
+ }
+
+ if (fieldAnnotations != null) {
+ out.println(" field annotations:");
+ for (FieldAnnotationStruct item : fieldAnnotations) {
+ out.println(" " + item.toHuman());
+ }
+ }
+
+ if (methodAnnotations != null) {
+ out.println(" method annotations:");
+ for (MethodAnnotationStruct item : methodAnnotations) {
+ out.println(" " + item.toHuman());
+ }
+ }
+
+ if (parameterAnnotations != null) {
+ out.println(" parameter annotations:");
+ for (ParameterAnnotationStruct item : parameterAnnotations) {
+ out.println(" " + item.toHuman());
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/CatchStructs.java b/dx/src/com/android/jack/dx/dex/file/CatchStructs.java
index 686ef82..3426fac 100644
--- a/dx/src/com/android/jack/dx/dex/file/CatchStructs.java
+++ b/dx/src/com/android/jack/dx/dex/file/CatchStructs.java
@@ -34,282 +34,284 @@
* {@code catch_handler_item[]}.
*/
public final class CatchStructs {
- /**
- * the size of a {@code try_item}: a {@code uint}
- * and two {@code ushort}s
- */
- public static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
+ /**
+ * the size of a {@code try_item}: a {@code uint}
+ * and two {@code ushort}s
+ */
+ public static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
- /** {@code non-null;} code that contains the catches */
- private final DalvCode code;
+ /** {@code non-null;} code that contains the catches */
+ private final DalvCode code;
- /**
- * {@code null-ok;} the underlying table; set in
- * {@link #finishProcessingIfNecessary}
- */
- private CatchTable table;
+ /**
+ * {@code null-ok;} the underlying table; set in
+ * {@link #finishProcessingIfNecessary}
+ */
+ private CatchTable table;
- /**
- * {@code null-ok;} the encoded handler list, if calculated; set in
- * {@link #encode}
- */
- private byte[] encodedHandlers;
+ /**
+ * {@code null-ok;} the encoded handler list, if calculated; set in
+ * {@link #encode}
+ */
+ private byte[] encodedHandlers;
- /**
- * length of the handlers header (encoded size), if known; used for
- * annotation
- */
- private int encodedHandlerHeaderSize;
+ /**
+ * length of the handlers header (encoded size), if known; used for
+ * annotation
+ */
+ private int encodedHandlerHeaderSize;
- /**
- * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
- * {@link #encode}
- */
- private TreeMap<CatchHandlerList, Integer> handlerOffsets;
+ /**
+ * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
+ * {@link #encode}
+ */
+ private TreeMap<CatchHandlerList, Integer> handlerOffsets;
- /**
- * Constructs an instance.
- *
- * @param code {@code non-null;} code that contains the catches
+ /**
+ * Constructs an instance.
+ *
+ * @param code {@code non-null;} code that contains the catches
+ */
+ public CatchStructs(DalvCode code) {
+ this.code = code;
+ this.table = null;
+ this.encodedHandlers = null;
+ this.encodedHandlerHeaderSize = 0;
+ this.handlerOffsets = null;
+ }
+
+ /**
+ * Finish processing the catches, if necessary.
+ */
+ private void finishProcessingIfNecessary() {
+ if (table == null) {
+ table = code.getCatches();
+ }
+ }
+
+ /**
+ * Gets the size of the tries list, in entries.
+ *
+ * @return {@code >= 0;} the tries list size
+ */
+ public int triesSize() {
+ finishProcessingIfNecessary();
+ return table.size();
+ }
+
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
+ */
+ public void debugPrint(PrintWriter out, String prefix) {
+ annotateEntries(prefix, out, null);
+ }
+
+ /**
+ * Encodes the handler lists.
+ *
+ * @param file {@code non-null;} file this instance is part of
+ */
+ public void encode(DexFile file) {
+ finishProcessingIfNecessary();
+
+ TypeIdsSection typeIds = file.getTypeIds();
+ int size = table.size();
+
+ handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
+
+ /*
+ * First add a map entry for each unique list. The tree structure
+ * will ensure they are sorted when we reiterate later.
*/
- public CatchStructs(DalvCode code) {
- this.code = code;
- this.table = null;
- this.encodedHandlers = null;
- this.encodedHandlerHeaderSize = 0;
- this.handlerOffsets = null;
+ for (int i = 0; i < size; i++) {
+ handlerOffsets.put(table.get(i).getHandlers(), null);
}
- /**
- * Finish processing the catches, if necessary.
- */
- private void finishProcessingIfNecessary() {
- if (table == null) {
- table = code.getCatches();
- }
+ if (handlerOffsets.size() > 65535) {
+ throw new UnsupportedOperationException("too many catch handlers");
}
- /**
- * Gets the size of the tries list, in entries.
- *
- * @return {@code >= 0;} the tries list size
- */
- public int triesSize() {
- finishProcessingIfNecessary();
- return table.size();
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+ // Write out the handlers "header" consisting of its size in entries.
+ encodedHandlerHeaderSize = out.writeUleb128(handlerOffsets.size());
+
+ // Now write the lists out in order, noting the offset of each.
+ for (Map.Entry<CatchHandlerList, Integer> mapping : handlerOffsets.entrySet()) {
+ CatchHandlerList list = mapping.getKey();
+ int listSize = list.size();
+ boolean catchesAll = list.catchesAll();
+
+ // Set the offset before we do any writing.
+ mapping.setValue(out.getCursor());
+
+ if (catchesAll) {
+ // A size <= 0 means that the list ends with a catch-all.
+ out.writeSleb128(-(listSize - 1));
+ listSize--;
+ } else {
+ out.writeSleb128(listSize);
+ }
+
+ for (int i = 0; i < listSize; i++) {
+ CatchHandlerList.Entry entry = list.get(i);
+ out.writeUleb128(typeIds.indexOf(entry.getExceptionType()));
+ out.writeUleb128(entry.getHandler());
+ }
+
+ if (catchesAll) {
+ out.writeUleb128(list.get(listSize).getHandler());
+ }
}
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} prefix to attach to each line of output
- */
- public void debugPrint(PrintWriter out, String prefix) {
- annotateEntries(prefix, out, null);
+ encodedHandlers = out.toByteArray();
+ }
+
+ /**
+ * Gets the write size of this instance, in bytes.
+ *
+ * @return {@code >= 0;} the write size
+ */
+ public int writeSize() {
+ return (triesSize() * TRY_ITEM_WRITE_SIZE) + encodedHandlers.length;
+ }
+
+ /**
+ * Writes this instance to the given stream.
+ *
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
+ */
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ finishProcessingIfNecessary();
+
+ if (out.annotates()) {
+ annotateEntries(" ", null, out);
}
- /**
- * Encodes the handler lists.
- *
- * @param file {@code non-null;} file this instance is part of
- */
- public void encode(DexFile file) {
- finishProcessingIfNecessary();
+ int tableSize = table.size();
+ for (int i = 0; i < tableSize; i++) {
+ CatchTable.Entry one = table.get(i);
+ int start = one.getStart();
+ int end = one.getEnd();
+ int insnCount = end - start;
- TypeIdsSection typeIds = file.getTypeIds();
- int size = table.size();
+ if (insnCount >= 65536) {
+ throw new UnsupportedOperationException(
+ "bogus exception range: " + Hex.u4(start) + ".." + Hex.u4(end));
+ }
- handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
-
- /*
- * First add a map entry for each unique list. The tree structure
- * will ensure they are sorted when we reiterate later.
- */
- for (int i = 0; i < size; i++) {
- handlerOffsets.put(table.get(i).getHandlers(), null);
- }
-
- if (handlerOffsets.size() > 65535) {
- throw new UnsupportedOperationException(
- "too many catch handlers");
- }
-
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
-
- // Write out the handlers "header" consisting of its size in entries.
- encodedHandlerHeaderSize =
- out.writeUleb128(handlerOffsets.size());
-
- // Now write the lists out in order, noting the offset of each.
- for (Map.Entry<CatchHandlerList, Integer> mapping :
- handlerOffsets.entrySet()) {
- CatchHandlerList list = mapping.getKey();
- int listSize = list.size();
- boolean catchesAll = list.catchesAll();
-
- // Set the offset before we do any writing.
- mapping.setValue(out.getCursor());
-
- if (catchesAll) {
- // A size <= 0 means that the list ends with a catch-all.
- out.writeSleb128(-(listSize - 1));
- listSize--;
- } else {
- out.writeSleb128(listSize);
- }
-
- for (int i = 0; i < listSize; i++) {
- CatchHandlerList.Entry entry = list.get(i);
- out.writeUleb128(
- typeIds.indexOf(entry.getExceptionType()));
- out.writeUleb128(entry.getHandler());
- }
-
- if (catchesAll) {
- out.writeUleb128(list.get(listSize).getHandler());
- }
- }
-
- encodedHandlers = out.toByteArray();
+ out.writeInt(start);
+ out.writeShort(insnCount);
+ out.writeShort(handlerOffsets.get(one.getHandlers()));
}
- /**
- * Gets the write size of this instance, in bytes.
- *
- * @return {@code >= 0;} the write size
- */
- public int writeSize() {
- return (triesSize() * TRY_ITEM_WRITE_SIZE) +
- + encodedHandlers.length;
+ out.write(encodedHandlers);
+ }
+
+ /**
+ * Helper method to annotate or simply print the exception handlers.
+ * Only one of {@code printTo} or {@code annotateTo} should
+ * be non-null.
+ *
+ * @param prefix {@code non-null;} prefix for each line
+ * @param printTo {@code null-ok;} where to print to
+ * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
+ */
+ private void annotateEntries(String prefix, PrintWriter printTo, AnnotatedOutput annotateTo) {
+ finishProcessingIfNecessary();
+
+ boolean consume = (annotateTo != null);
+ int amt1 = consume ? 6 : 0;
+ int amt2 = consume ? 2 : 0;
+ int size = table.size();
+ String subPrefix = prefix + " ";
+
+ if (consume) {
+ annotateTo.annotate(0, prefix + "tries:");
+ } else {
+ printTo.println(prefix + "tries:");
}
- /**
- * Writes this instance to the given stream.
- *
- * @param file {@code non-null;} file this instance is part of
- * @param out {@code non-null;} where to write to
- */
- public void writeTo(DexFile file, AnnotatedOutput out) {
- finishProcessingIfNecessary();
+ for (int i = 0; i < size; i++) {
+ CatchTable.Entry entry = table.get(i);
+ CatchHandlerList handlers = entry.getHandlers();
+ String s1 =
+ subPrefix + "try " + Hex.u2or4(entry.getStart()) + ".." + Hex.u2or4(entry.getEnd());
+ String s2 = handlers.toHuman(subPrefix, "");
- if (out.annotates()) {
- annotateEntries(" ", null, out);
- }
-
- int tableSize = table.size();
- for (int i = 0; i < tableSize; i++) {
- CatchTable.Entry one = table.get(i);
- int start = one.getStart();
- int end = one.getEnd();
- int insnCount = end - start;
-
- if (insnCount >= 65536) {
- throw new UnsupportedOperationException(
- "bogus exception range: " + Hex.u4(start) + ".." +
- Hex.u4(end));
- }
-
- out.writeInt(start);
- out.writeShort(insnCount);
- out.writeShort(handlerOffsets.get(one.getHandlers()));
- }
-
- out.write(encodedHandlers);
+ if (consume) {
+ annotateTo.annotate(amt1, s1);
+ annotateTo.annotate(amt2, s2);
+ } else {
+ printTo.println(s1);
+ printTo.println(s2);
+ }
}
- /**
- * Helper method to annotate or simply print the exception handlers.
- * Only one of {@code printTo} or {@code annotateTo} should
- * be non-null.
- *
- * @param prefix {@code non-null;} prefix for each line
- * @param printTo {@code null-ok;} where to print to
- * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
- */
- private void annotateEntries(String prefix, PrintWriter printTo,
- AnnotatedOutput annotateTo) {
- finishProcessingIfNecessary();
-
- boolean consume = (annotateTo != null);
- int amt1 = consume ? 6 : 0;
- int amt2 = consume ? 2 : 0;
- int size = table.size();
- String subPrefix = prefix + " ";
-
- if (consume) {
- annotateTo.annotate(0, prefix + "tries:");
- } else {
- printTo.println(prefix + "tries:");
- }
-
- for (int i = 0; i < size; i++) {
- CatchTable.Entry entry = table.get(i);
- CatchHandlerList handlers = entry.getHandlers();
- String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart())
- + ".." + Hex.u2or4(entry.getEnd());
- String s2 = handlers.toHuman(subPrefix, "");
-
- if (consume) {
- annotateTo.annotate(amt1, s1);
- annotateTo.annotate(amt2, s2);
- } else {
- printTo.println(s1);
- printTo.println(s2);
- }
- }
-
- if (! consume) {
- // Only emit the handler lists if we are consuming bytes.
- return;
- }
-
- annotateTo.annotate(0, prefix + "handlers:");
- annotateTo.annotate(encodedHandlerHeaderSize,
- subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
-
- int lastOffset = 0;
- CatchHandlerList lastList = null;
-
- for (Map.Entry<CatchHandlerList, Integer> mapping :
- handlerOffsets.entrySet()) {
- CatchHandlerList list = mapping.getKey();
- int offset = mapping.getValue();
-
- if (lastList != null) {
- annotateAndConsumeHandlers(lastList, lastOffset,
- offset - lastOffset, subPrefix, printTo, annotateTo);
- }
-
- lastList = list;
- lastOffset = offset;
- }
-
- annotateAndConsumeHandlers(lastList, lastOffset,
- encodedHandlers.length - lastOffset,
- subPrefix, printTo, annotateTo);
+ if (!consume) {
+ // Only emit the handler lists if we are consuming bytes.
+ return;
}
- /**
- * Helper for {@link #annotateEntries} to annotate a catch handler list
- * while consuming it.
- *
- * @param handlers {@code non-null;} handlers to annotate
- * @param offset {@code >= 0;} the offset of this handler
- * @param size {@code >= 1;} the number of bytes the handlers consume
- * @param prefix {@code non-null;} prefix for each line
- * @param printTo {@code null-ok;} where to print to
- * @param annotateTo {@code non-null;} where to annotate to
- */
- private static void annotateAndConsumeHandlers(CatchHandlerList handlers,
- int offset, int size, String prefix, PrintWriter printTo,
- AnnotatedOutput annotateTo) {
- String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
+ annotateTo.annotate(0, prefix + "handlers:");
+ annotateTo.annotate(encodedHandlerHeaderSize,
+ subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
- if (printTo != null) {
- printTo.println(s);
- }
+ int lastOffset = 0;
+ CatchHandlerList lastList = null;
- annotateTo.annotate(size, s);
+ for (Map.Entry<CatchHandlerList, Integer> mapping : handlerOffsets.entrySet()) {
+ CatchHandlerList list = mapping.getKey();
+ int offset = mapping.getValue();
+
+ if (lastList != null) {
+ annotateAndConsumeHandlers(lastList,
+ lastOffset,
+ offset - lastOffset,
+ subPrefix,
+ printTo,
+ annotateTo);
+ }
+
+ lastList = list;
+ lastOffset = offset;
}
+
+ annotateAndConsumeHandlers(lastList,
+ lastOffset,
+ encodedHandlers.length - lastOffset,
+ subPrefix,
+ printTo,
+ annotateTo);
+ }
+
+ /**
+ * Helper for {@link #annotateEntries} to annotate a catch handler list
+ * while consuming it.
+ *
+ * @param handlers {@code non-null;} handlers to annotate
+ * @param offset {@code >= 0;} the offset of this handler
+ * @param size {@code >= 1;} the number of bytes the handlers consume
+ * @param prefix {@code non-null;} prefix for each line
+ * @param printTo {@code null-ok;} where to print to
+ * @param annotateTo {@code non-null;} where to annotate to
+ */
+ private static void annotateAndConsumeHandlers(CatchHandlerList handlers,
+ int offset,
+ int size,
+ String prefix,
+ PrintWriter printTo,
+ AnnotatedOutput annotateTo) {
+ String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
+
+ if (printTo != null) {
+ printTo.println(s);
+ }
+
+ annotateTo.annotate(size, s);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ClassDataItem.java b/dx/src/com/android/jack/dx/dex/file/ClassDataItem.java
index 8ca353c..7e9ccce 100644
--- a/dx/src/com/android/jack/dx/dex/file/ClassDataItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/ClassDataItem.java
@@ -38,389 +38,385 @@
* {@code dex} file, as opposed to a random-access form.
*/
public final class ClassDataItem extends OffsettedItem {
- /** {@code non-null;} what class this data is for, just for listing generation */
- private final CstType thisClass;
+ /** {@code non-null;} what class this data is for, just for listing generation */
+ private final CstType thisClass;
- /** {@code non-null;} list of static fields */
- private final ArrayList<EncodedField> staticFields;
+ /** {@code non-null;} list of static fields */
+ private final ArrayList<EncodedField> staticFields;
- /** {@code non-null;} list of initial values for static fields */
- private final HashMap<EncodedField, Constant> staticValues;
+ /** {@code non-null;} list of initial values for static fields */
+ private final HashMap<EncodedField, Constant> staticValues;
- /** {@code non-null;} list of instance fields */
- private final ArrayList<EncodedField> instanceFields;
+ /** {@code non-null;} list of instance fields */
+ private final ArrayList<EncodedField> instanceFields;
- /** {@code non-null;} list of direct methods */
- private final ArrayList<EncodedMethod> directMethods;
+ /** {@code non-null;} list of direct methods */
+ private final ArrayList<EncodedMethod> directMethods;
- /** {@code non-null;} list of virtual methods */
- private final ArrayList<EncodedMethod> virtualMethods;
+ /** {@code non-null;} list of virtual methods */
+ private final ArrayList<EncodedMethod> virtualMethods;
- /** {@code null-ok;} static initializer list; set in {@link #addContents} */
- private CstArray staticValuesConstant;
+ /** {@code null-ok;} static initializer list; set in {@link #addContents} */
+ private CstArray staticValuesConstant;
- /**
- * {@code null-ok;} encoded form, ready for writing to a file; set during
- * {@link #place0}
+ /**
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
+ * {@link #place0}
+ */
+ private byte[] encodedForm;
+
+ /**
+ * Constructs an instance. Its sets of members are initially
+ * empty.
+ *
+ * @param thisClass {@code non-null;} what class this data is for, just
+ * for listing generation
+ */
+ public ClassDataItem(CstType thisClass) {
+ super(1, -1);
+
+ if (thisClass == null) {
+ throw new NullPointerException("thisClass == null");
+ }
+
+ this.thisClass = thisClass;
+ this.staticFields = new ArrayList<EncodedField>(20);
+ this.staticValues = new HashMap<EncodedField, Constant>(40);
+ this.instanceFields = new ArrayList<EncodedField>(20);
+ this.directMethods = new ArrayList<EncodedMethod>(20);
+ this.virtualMethods = new ArrayList<EncodedMethod>(20);
+ this.staticValuesConstant = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_CLASS_DATA_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return toString();
+ }
+
+ /**
+ * Returns whether this instance is empty.
+ *
+ * @return {@code true} if this instance is empty or
+ * {@code false} if at least one element has been added to it
+ */
+ public boolean isEmpty() {
+ return staticFields.isEmpty() && instanceFields.isEmpty() && directMethods.isEmpty()
+ && virtualMethods.isEmpty();
+ }
+
+ /**
+ * Adds a static field.
+ *
+ * @param field {@code non-null;} the field to add
+ * @param value {@code null-ok;} initial value for the field, if any
+ */
+ public void addStaticField(EncodedField field, Constant value) {
+ if (field == null) {
+ throw new NullPointerException("field == null");
+ }
+
+ if (staticValuesConstant != null) {
+ throw new UnsupportedOperationException("static fields already sorted");
+ }
+
+ staticFields.add(field);
+ staticValues.put(field, value);
+ }
+
+ /**
+ * Adds an instance field.
+ *
+ * @param field {@code non-null;} the field to add
+ */
+ public void addInstanceField(EncodedField field) {
+ if (field == null) {
+ throw new NullPointerException("field == null");
+ }
+
+ instanceFields.add(field);
+ }
+
+ /**
+ * Adds a direct ({@code static} and/or {@code private}) method.
+ *
+ * @param method {@code non-null;} the method to add
+ */
+ public void addDirectMethod(EncodedMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
+ }
+
+ directMethods.add(method);
+ }
+
+ /**
+ * Adds a virtual method.
+ *
+ * @param method {@code non-null;} the method to add
+ */
+ public void addVirtualMethod(EncodedMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
+ }
+
+ virtualMethods.add(method);
+ }
+
+ /**
+ * Gets all the methods in this class. The returned list is not linked
+ * in any way to the underlying lists contained in this instance, but
+ * the objects contained in the list are shared.
+ *
+ * @return {@code non-null;} list of all methods
+ */
+ public ArrayList<EncodedMethod> getMethods() {
+ int sz = directMethods.size() + virtualMethods.size();
+ ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz);
+
+ result.addAll(directMethods);
+ result.addAll(virtualMethods);
+
+ return result;
+ }
+
+
+ /**
+ * Prints out the contents of this instance, in a debugging-friendly
+ * way.
+ *
+ * @param out {@code non-null;} where to output to
+ * @param verbose whether to be verbose with the output
+ */
+ public void debugPrint(Writer out, boolean verbose) {
+ PrintWriter pw = Writers.printWriterFor(out);
+
+ int sz = staticFields.size();
+ for (int i = 0; i < sz; i++) {
+ pw.println(" sfields[" + i + "]: " + staticFields.get(i));
+ }
+
+ sz = instanceFields.size();
+ for (int i = 0; i < sz; i++) {
+ pw.println(" ifields[" + i + "]: " + instanceFields.get(i));
+ }
+
+ sz = directMethods.size();
+ for (int i = 0; i < sz; i++) {
+ pw.println(" dmeths[" + i + "]:");
+ directMethods.get(i).debugPrint(pw, verbose);
+ }
+
+ sz = virtualMethods.size();
+ for (int i = 0; i < sz; i++) {
+ pw.println(" vmeths[" + i + "]:");
+ virtualMethods.get(i).debugPrint(pw, verbose);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ if (!staticFields.isEmpty()) {
+ getStaticValuesConstant(); // Force the fields to be sorted.
+ for (EncodedField field : staticFields) {
+ field.addContents(file);
+ }
+ }
+
+ if (!instanceFields.isEmpty()) {
+ Collections.sort(instanceFields);
+ for (EncodedField field : instanceFields) {
+ field.addContents(file);
+ }
+ }
+
+ if (!directMethods.isEmpty()) {
+ Collections.sort(directMethods);
+ for (EncodedMethod method : directMethods) {
+ method.addContents(file);
+ }
+ }
+
+ if (!virtualMethods.isEmpty()) {
+ Collections.sort(virtualMethods);
+ for (EncodedMethod method : virtualMethods) {
+ method.addContents(file);
+ }
+ }
+ }
+
+ /**
+ * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+ * it contains any non-zero non-{@code null} values.
+ *
+ * @return {@code null-ok;} the corresponding constant or {@code null} if
+ * there are no values to encode
+ */
+ public CstArray getStaticValuesConstant() {
+ if ((staticValuesConstant == null) && (staticFields.size() != 0)) {
+ staticValuesConstant = makeStaticValuesConstant();
+ }
+
+ return staticValuesConstant;
+ }
+
+ /**
+ * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+ * it contains any non-zero non-{@code null} values.
+ *
+ * @return {@code null-ok;} the corresponding constant or {@code null} if
+ * there are no values to encode
+ */
+ private CstArray makeStaticValuesConstant() {
+ // First sort the statics into their final order.
+ Collections.sort(staticFields);
+
+ /*
+ * Get the size of staticValues minus any trailing zeros/nulls (both
+ * nulls per se as well as instances of CstKnownNull).
*/
- private byte[] encodedForm;
- /**
- * Constructs an instance. Its sets of members are initially
- * empty.
- *
- * @param thisClass {@code non-null;} what class this data is for, just
- * for listing generation
- */
- public ClassDataItem(CstType thisClass) {
- super(1, -1);
-
- if (thisClass == null) {
- throw new NullPointerException("thisClass == null");
+int size = staticFields.size();
+ while (size > 0) {
+ EncodedField field = staticFields.get(size - 1);
+ Constant cst = staticValues.get(field);
+ if (cst instanceof CstLiteralBits) {
+ // Note: CstKnownNull extends CstLiteralBits.
+ if (((CstLiteralBits) cst).getLongBits() != 0) {
+ break;
}
-
- this.thisClass = thisClass;
- this.staticFields = new ArrayList<EncodedField>(20);
- this.staticValues = new HashMap<EncodedField, Constant>(40);
- this.instanceFields = new ArrayList<EncodedField>(20);
- this.directMethods = new ArrayList<EncodedMethod>(20);
- this.virtualMethods = new ArrayList<EncodedMethod>(20);
- this.staticValuesConstant = null;
+ } else if (cst != null) {
+ break;
+ }
+ size--;
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_CLASS_DATA_ITEM;
+ if (size == 0) {
+ return null;
}
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return toString();
+ // There is something worth encoding, so build up a result.
+
+ CstArray.List list = new CstArray.List(size);
+ for (int i = 0; i < size; i++) {
+ EncodedField field = staticFields.get(i);
+ Constant cst = staticValues.get(field);
+ if (cst == null) {
+ cst = Zeroes.zeroFor(field.getRef().getType());
+ }
+ list.set(i, cst);
+ }
+ list.setImmutable();
+
+ return new CstArray(list);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // Encode the data and note the size.
+
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+ encodeOutput(addedTo.getFile(), out);
+ encodedForm = out.toByteArray();
+ setWriteSize(encodedForm.length);
+ }
+
+ /**
+ * Writes out the encoded form of this instance.
+ *
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
+ */
+ private void encodeOutput(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+
+ if (annotates) {
+ out.annotate(0, offsetString() + " class data for " + thisClass.toHuman());
}
- /**
- * Returns whether this instance is empty.
- *
- * @return {@code true} if this instance is empty or
- * {@code false} if at least one element has been added to it
- */
- public boolean isEmpty() {
- return staticFields.isEmpty() && instanceFields.isEmpty()
- && directMethods.isEmpty() && virtualMethods.isEmpty();
+ encodeSize(file, out, "static_fields", staticFields.size());
+ encodeSize(file, out, "instance_fields", instanceFields.size());
+ encodeSize(file, out, "direct_methods", directMethods.size());
+ encodeSize(file, out, "virtual_methods", virtualMethods.size());
+
+ encodeList(file, out, "static_fields", staticFields);
+ encodeList(file, out, "instance_fields", instanceFields);
+ encodeList(file, out, "direct_methods", directMethods);
+ encodeList(file, out, "virtual_methods", virtualMethods);
+
+ if (annotates) {
+ out.endAnnotation();
+ }
+ }
+
+ /**
+ * Helper for {@link #encodeOutput}, which writes out the given
+ * size value, annotating it as well (if annotations are enabled).
+ *
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
+ * @param label {@code non-null;} the label for the purposes of annotation
+ * @param size {@code >= 0;} the size to write
+ */
+ private static void encodeSize(DexFile file, AnnotatedOutput out, String label, int size) {
+ if (out.annotates()) {
+ out.annotate(String.format(" %-21s %08x", label + "_size:", size));
}
- /**
- * Adds a static field.
- *
- * @param field {@code non-null;} the field to add
- * @param value {@code null-ok;} initial value for the field, if any
- */
- public void addStaticField(EncodedField field, Constant value) {
- if (field == null) {
- throw new NullPointerException("field == null");
- }
+ out.writeUleb128(size);
+ }
- if (staticValuesConstant != null) {
- throw new UnsupportedOperationException(
- "static fields already sorted");
- }
+ /**
+ * Helper for {@link #encodeOutput}, which writes out the given
+ * list. It also annotates the items (if any and if annotations
+ * are enabled).
+ *
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
+ * @param label {@code non-null;} the label for the purposes of annotation
+ * @param list {@code non-null;} the list in question
+ */
+ private static void encodeList(DexFile file, AnnotatedOutput out, String label,
+ ArrayList<? extends EncodedMember> list) {
+ int size = list.size();
+ int lastIndex = 0;
- staticFields.add(field);
- staticValues.put(field, value);
+ if (size == 0) {
+ return;
}
- /**
- * Adds an instance field.
- *
- * @param field {@code non-null;} the field to add
- */
- public void addInstanceField(EncodedField field) {
- if (field == null) {
- throw new NullPointerException("field == null");
- }
-
- instanceFields.add(field);
+ if (out.annotates()) {
+ out.annotate(0, " " + label + ":");
}
- /**
- * Adds a direct ({@code static} and/or {@code private}) method.
- *
- * @param method {@code non-null;} the method to add
- */
- public void addDirectMethod(EncodedMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- directMethods.add(method);
+ for (int i = 0; i < size; i++) {
+ lastIndex = list.get(i).encode(file, out, lastIndex, i);
}
+ }
- /**
- * Adds a virtual method.
- *
- * @param method {@code non-null;} the method to add
- */
- public void addVirtualMethod(EncodedMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
- virtualMethods.add(method);
+ if (annotates) {
+ /*
+ * The output is to be annotated, so redo the work previously
+ * done by place0(), except this time annotations will actually
+ * get emitted.
+ */
+ encodeOutput(file, out);
+ } else {
+ out.write(encodedForm);
}
-
- /**
- * Gets all the methods in this class. The returned list is not linked
- * in any way to the underlying lists contained in this instance, but
- * the objects contained in the list are shared.
- *
- * @return {@code non-null;} list of all methods
- */
- public ArrayList<EncodedMethod> getMethods() {
- int sz = directMethods.size() + virtualMethods.size();
- ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz);
-
- result.addAll(directMethods);
- result.addAll(virtualMethods);
-
- return result;
- }
-
-
- /**
- * Prints out the contents of this instance, in a debugging-friendly
- * way.
- *
- * @param out {@code non-null;} where to output to
- * @param verbose whether to be verbose with the output
- */
- public void debugPrint(Writer out, boolean verbose) {
- PrintWriter pw = Writers.printWriterFor(out);
-
- int sz = staticFields.size();
- for (int i = 0; i < sz; i++) {
- pw.println(" sfields[" + i + "]: " + staticFields.get(i));
- }
-
- sz = instanceFields.size();
- for (int i = 0; i < sz; i++) {
- pw.println(" ifields[" + i + "]: " + instanceFields.get(i));
- }
-
- sz = directMethods.size();
- for (int i = 0; i < sz; i++) {
- pw.println(" dmeths[" + i + "]:");
- directMethods.get(i).debugPrint(pw, verbose);
- }
-
- sz = virtualMethods.size();
- for (int i = 0; i < sz; i++) {
- pw.println(" vmeths[" + i + "]:");
- virtualMethods.get(i).debugPrint(pw, verbose);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- if (!staticFields.isEmpty()) {
- getStaticValuesConstant(); // Force the fields to be sorted.
- for (EncodedField field : staticFields) {
- field.addContents(file);
- }
- }
-
- if (!instanceFields.isEmpty()) {
- Collections.sort(instanceFields);
- for (EncodedField field : instanceFields) {
- field.addContents(file);
- }
- }
-
- if (!directMethods.isEmpty()) {
- Collections.sort(directMethods);
- for (EncodedMethod method : directMethods) {
- method.addContents(file);
- }
- }
-
- if (!virtualMethods.isEmpty()) {
- Collections.sort(virtualMethods);
- for (EncodedMethod method : virtualMethods) {
- method.addContents(file);
- }
- }
- }
-
- /**
- * Gets a {@link CstArray} corresponding to {@link #staticValues} if
- * it contains any non-zero non-{@code null} values.
- *
- * @return {@code null-ok;} the corresponding constant or {@code null} if
- * there are no values to encode
- */
- public CstArray getStaticValuesConstant() {
- if ((staticValuesConstant == null) && (staticFields.size() != 0)) {
- staticValuesConstant = makeStaticValuesConstant();
- }
-
- return staticValuesConstant;
- }
-
- /**
- * Gets a {@link CstArray} corresponding to {@link #staticValues} if
- * it contains any non-zero non-{@code null} values.
- *
- * @return {@code null-ok;} the corresponding constant or {@code null} if
- * there are no values to encode
- */
- private CstArray makeStaticValuesConstant() {
- // First sort the statics into their final order.
- Collections.sort(staticFields);
-
- /*
- * Get the size of staticValues minus any trailing zeros/nulls (both
- * nulls per se as well as instances of CstKnownNull).
- */
-
- int size = staticFields.size();
- while (size > 0) {
- EncodedField field = staticFields.get(size - 1);
- Constant cst = staticValues.get(field);
- if (cst instanceof CstLiteralBits) {
- // Note: CstKnownNull extends CstLiteralBits.
- if (((CstLiteralBits) cst).getLongBits() != 0) {
- break;
- }
- } else if (cst != null) {
- break;
- }
- size--;
- }
-
- if (size == 0) {
- return null;
- }
-
- // There is something worth encoding, so build up a result.
-
- CstArray.List list = new CstArray.List(size);
- for (int i = 0; i < size; i++) {
- EncodedField field = staticFields.get(i);
- Constant cst = staticValues.get(field);
- if (cst == null) {
- cst = Zeroes.zeroFor(field.getRef().getType());
- }
- list.set(i, cst);
- }
- list.setImmutable();
-
- return new CstArray(list);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // Encode the data and note the size.
-
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
-
- encodeOutput(addedTo.getFile(), out);
- encodedForm = out.toByteArray();
- setWriteSize(encodedForm.length);
- }
-
- /**
- * Writes out the encoded form of this instance.
- *
- * @param file {@code non-null;} file this instance is part of
- * @param out {@code non-null;} where to write to
- */
- private void encodeOutput(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
-
- if (annotates) {
- out.annotate(0, offsetString() + " class data for " +
- thisClass.toHuman());
- }
-
- encodeSize(file, out, "static_fields", staticFields.size());
- encodeSize(file, out, "instance_fields", instanceFields.size());
- encodeSize(file, out, "direct_methods", directMethods.size());
- encodeSize(file, out, "virtual_methods", virtualMethods.size());
-
- encodeList(file, out, "static_fields", staticFields);
- encodeList(file, out, "instance_fields", instanceFields);
- encodeList(file, out, "direct_methods", directMethods);
- encodeList(file, out, "virtual_methods", virtualMethods);
-
- if (annotates) {
- out.endAnnotation();
- }
- }
-
- /**
- * Helper for {@link #encodeOutput}, which writes out the given
- * size value, annotating it as well (if annotations are enabled).
- *
- * @param file {@code non-null;} file this instance is part of
- * @param out {@code non-null;} where to write to
- * @param label {@code non-null;} the label for the purposes of annotation
- * @param size {@code >= 0;} the size to write
- */
- private static void encodeSize(DexFile file, AnnotatedOutput out,
- String label, int size) {
- if (out.annotates()) {
- out.annotate(String.format(" %-21s %08x", label + "_size:",
- size));
- }
-
- out.writeUleb128(size);
- }
-
- /**
- * Helper for {@link #encodeOutput}, which writes out the given
- * list. It also annotates the items (if any and if annotations
- * are enabled).
- *
- * @param file {@code non-null;} file this instance is part of
- * @param out {@code non-null;} where to write to
- * @param label {@code non-null;} the label for the purposes of annotation
- * @param list {@code non-null;} the list in question
- */
- private static void encodeList(DexFile file, AnnotatedOutput out,
- String label, ArrayList<? extends EncodedMember> list) {
- int size = list.size();
- int lastIndex = 0;
-
- if (size == 0) {
- return;
- }
-
- if (out.annotates()) {
- out.annotate(0, " " + label + ":");
- }
-
- for (int i = 0; i < size; i++) {
- lastIndex = list.get(i).encode(file, out, lastIndex, i);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
-
- if (annotates) {
- /*
- * The output is to be annotated, so redo the work previously
- * done by place0(), except this time annotations will actually
- * get emitted.
- */
- encodeOutput(file, out);
- } else {
- out.write(encodedForm);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ClassDefItem.java b/dx/src/com/android/jack/dx/dex/file/ClassDefItem.java
index 7f485a6..e845fab 100644
--- a/dx/src/com/android/jack/dx/dex/file/ClassDefItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/ClassDefItem.java
@@ -43,366 +43,351 @@
*/
public final class ClassDefItem extends IndexedItem {
- /** {@code non-null;} type constant for this class */
- private final CstType thisClass;
+ /** {@code non-null;} type constant for this class */
+ private final CstType thisClass;
- /** access flags */
- private final int accessFlags;
+ /** access flags */
+ private final int accessFlags;
- /**
- * {@code null-ok;} superclass or {@code null} if this class is a/the
- * root class
+ /**
+ * {@code null-ok;} superclass or {@code null} if this class is a/the
+ * root class
+ */
+ private final CstType superclass;
+
+ /** {@code null-ok;} list of implemented interfaces */
+ private TypeListItem interfaces;
+
+ /** {@code null-ok;} source file name or {@code null} if unknown */
+ private final CstString sourceFile;
+
+ /** {@code non-null;} associated class data object */
+ private final ClassDataItem classData;
+
+ /**
+ * {@code null-ok;} item wrapper for the static values, initialized
+ * in {@link #addContents}
+ */
+ private EncodedArrayItem staticValuesItem;
+
+ /** {@code non-null;} annotations directory */
+ private AnnotationsDirectoryItem annotationsDirectory;
+
+ /**
+ * Constructs an instance. Its sets of members and annotations are
+ * initially empty.
+ *
+ * @param thisClass {@code non-null;} type constant for this class
+ * @param accessFlags access flags
+ * @param superclass {@code null-ok;} superclass or {@code null} if
+ * this class is a/the root class
+ * @param interfaces {@code non-null;} list of implemented interfaces
+ * @param sourceFile {@code null-ok;} source file name or
+ * {@code null} if unknown
+ */
+ public ClassDefItem(CstType thisClass, int accessFlags, CstType superclass, TypeList interfaces,
+ CstString sourceFile) {
+ if (thisClass == null) {
+ throw new NullPointerException("thisClass == null");
+ }
+
+ /*
+ * TODO(dx team): Maybe check accessFlags and superclass, at
+ * least for easily-checked stuff?
*/
- private final CstType superclass;
- /** {@code null-ok;} list of implemented interfaces */
- private TypeListItem interfaces;
+if (interfaces == null) {
+ throw new NullPointerException("interfaces == null");
+ }
- /** {@code null-ok;} source file name or {@code null} if unknown */
- private final CstString sourceFile;
+ this.thisClass = thisClass;
+ this.accessFlags = accessFlags;
+ this.superclass = superclass;
+ this.interfaces = (interfaces.size() == 0) ? null : new TypeListItem(interfaces);
+ this.sourceFile = sourceFile;
+ this.classData = new ClassDataItem(thisClass);
+ this.staticValuesItem = null;
+ this.annotationsDirectory = new AnnotationsDirectoryItem();
+ }
- /** {@code non-null;} associated class data object */
- private final ClassDataItem classData;
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_CLASS_DEF_ITEM;
+ }
- /**
- * {@code null-ok;} item wrapper for the static values, initialized
- * in {@link #addContents}
- */
- private EncodedArrayItem staticValuesItem;
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.CLASS_DEF_ITEM;
+ }
- /** {@code non-null;} annotations directory */
- private AnnotationsDirectoryItem annotationsDirectory;
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ MixedItemSection byteData = file.getByteData();
+ MixedItemSection wordData = file.getWordData();
+ MixedItemSection typeLists = file.getTypeLists();
+ StringIdsSection stringIds = file.getStringIds();
- /**
- * Constructs an instance. Its sets of members and annotations are
- * initially empty.
- *
- * @param thisClass {@code non-null;} type constant for this class
- * @param accessFlags access flags
- * @param superclass {@code null-ok;} superclass or {@code null} if
- * this class is a/the root class
- * @param interfaces {@code non-null;} list of implemented interfaces
- * @param sourceFile {@code null-ok;} source file name or
- * {@code null} if unknown
- */
- public ClassDefItem(CstType thisClass, int accessFlags,
- CstType superclass, TypeList interfaces, CstString sourceFile) {
- if (thisClass == null) {
- throw new NullPointerException("thisClass == null");
+ typeIds.intern(thisClass);
+
+ if (!classData.isEmpty()) {
+ MixedItemSection classDataSection = file.getClassData();
+ classDataSection.add(classData);
+
+ CstArray staticValues = classData.getStaticValuesConstant();
+ if (staticValues != null) {
+ staticValuesItem = byteData.intern(new EncodedArrayItem(staticValues));
+ }
+ }
+
+ if (superclass != null) {
+ typeIds.intern(superclass);
+ }
+
+ if (interfaces != null) {
+ interfaces = typeLists.intern(interfaces);
+ }
+
+ if (sourceFile != null) {
+ stringIds.intern(sourceFile);
+ }
+
+ if (!annotationsDirectory.isEmpty()) {
+ if (annotationsDirectory.isInternable()) {
+ annotationsDirectory = wordData.intern(annotationsDirectory);
+ } else {
+ wordData.add(annotationsDirectory);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ TypeIdsSection typeIds = file.getTypeIds();
+ int classIdx = typeIds.indexOf(thisClass);
+ int superIdx = (superclass == null) ? -1 : typeIds.indexOf(superclass);
+ int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces);
+ int annoOff = annotationsDirectory.isEmpty() ? 0 : annotationsDirectory.getAbsoluteOffset();
+ int sourceFileIdx = (sourceFile == null) ? -1 : file.getStringIds().indexOf(sourceFile);
+ int dataOff = classData.isEmpty() ? 0 : classData.getAbsoluteOffset();
+ int staticValuesOff = OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem);
+
+ if (annotates) {
+ out.annotate(0, indexString() + ' ' + thisClass.toHuman());
+ out.annotate(4, " class_idx: " + Hex.u4(classIdx));
+ out.annotate(4, " access_flags: " + AccessFlags.classString(accessFlags));
+ out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) + " // "
+ + ((superclass == null) ? "<none>" : superclass.toHuman()));
+ out.annotate(4, " interfaces_off: " + Hex.u4(interOff));
+ if (interOff != 0) {
+ TypeList list = interfaces.getList();
+ int sz = list.size();
+ for (int i = 0; i < sz; i++) {
+ out.annotate(0, " " + list.getType(i).toHuman());
}
-
- /*
- * TODO: Maybe check accessFlags and superclass, at
- * least for easily-checked stuff?
- */
-
- if (interfaces == null) {
- throw new NullPointerException("interfaces == null");
- }
-
- this.thisClass = thisClass;
- this.accessFlags = accessFlags;
- this.superclass = superclass;
- this.interfaces =
- (interfaces.size() == 0) ? null : new TypeListItem(interfaces);
- this.sourceFile = sourceFile;
- this.classData = new ClassDataItem(thisClass);
- this.staticValuesItem = null;
- this.annotationsDirectory = new AnnotationsDirectoryItem();
+ }
+ out.annotate(4, " source_file_idx: " + Hex.u4(sourceFileIdx) + " // "
+ + ((sourceFile == null) ? "<none>" : sourceFile.toHuman()));
+ out.annotate(4, " annotations_off: " + Hex.u4(annoOff));
+ out.annotate(4, " class_data_off: " + Hex.u4(dataOff));
+ out.annotate(4, " static_values_off: " + Hex.u4(staticValuesOff));
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_CLASS_DEF_ITEM;
+ out.writeInt(classIdx);
+ out.writeInt(accessFlags);
+ out.writeInt(superIdx);
+ out.writeInt(interOff);
+ out.writeInt(sourceFileIdx);
+ out.writeInt(annoOff);
+ out.writeInt(dataOff);
+ out.writeInt(staticValuesOff);
+ }
+
+ /**
+ * Gets the constant corresponding to this class.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public CstType getThisClass() {
+ return thisClass;
+ }
+
+ /**
+ * Gets the access flags.
+ *
+ * @return the access flags
+ */
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ /**
+ * Gets the superclass.
+ *
+ * @return {@code null-ok;} the superclass or {@code null} if
+ * this class is a/the root class
+ */
+ public CstType getSuperclass() {
+ return superclass;
+ }
+
+ /**
+ * Gets the list of interfaces implemented.
+ *
+ * @return {@code non-null;} the interfaces list
+ */
+ public TypeList getInterfaces() {
+ if (interfaces == null) {
+ return StdTypeList.EMPTY;
}
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.CLASS_DEF_ITEM;
- }
+ return interfaces.getList();
+ }
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- TypeIdsSection typeIds = file.getTypeIds();
- MixedItemSection byteData = file.getByteData();
- MixedItemSection wordData = file.getWordData();
- MixedItemSection typeLists = file.getTypeLists();
- StringIdsSection stringIds = file.getStringIds();
+ /**
+ * Gets the source file name.
+ *
+ * @return {@code null-ok;} the source file name or {@code null} if unknown
+ */
+ public CstString getSourceFile() {
+ return sourceFile;
+ }
- typeIds.intern(thisClass);
+ /**
+ * Adds a static field.
+ *
+ * @param field {@code non-null;} the field to add
+ * @param value {@code null-ok;} initial value for the field, if any
+ */
+ public void addStaticField(EncodedField field, Constant value) {
+ classData.addStaticField(field, value);
+ }
- if (!classData.isEmpty()) {
- MixedItemSection classDataSection = file.getClassData();
- classDataSection.add(classData);
+ /**
+ * Adds an instance field.
+ *
+ * @param field {@code non-null;} the field to add
+ */
+ public void addInstanceField(EncodedField field) {
+ classData.addInstanceField(field);
+ }
- CstArray staticValues = classData.getStaticValuesConstant();
- if (staticValues != null) {
- staticValuesItem =
- byteData.intern(new EncodedArrayItem(staticValues));
- }
- }
+ /**
+ * Adds a direct ({@code static} and/or {@code private}) method.
+ *
+ * @param method {@code non-null;} the method to add
+ */
+ public void addDirectMethod(EncodedMethod method) {
+ classData.addDirectMethod(method);
+ }
- if (superclass != null) {
- typeIds.intern(superclass);
- }
+ /**
+ * Adds a virtual method.
+ *
+ * @param method {@code non-null;} the method to add
+ */
+ public void addVirtualMethod(EncodedMethod method) {
+ classData.addVirtualMethod(method);
+ }
- if (interfaces != null) {
- interfaces = typeLists.intern(interfaces);
- }
+ /**
+ * Gets all the methods in this class. The returned list is not linked
+ * in any way to the underlying lists contained in this instance, but
+ * the objects contained in the list are shared.
+ *
+ * @return {@code non-null;} list of all methods
+ */
+ public ArrayList<EncodedMethod> getMethods() {
+ return classData.getMethods();
+ }
- if (sourceFile != null) {
- stringIds.intern(sourceFile);
- }
+ /**
+ * Sets the direct annotations on this class. These are annotations
+ * made on the class, per se, as opposed to on one of its members.
+ * It is only valid to call this method at most once per instance.
+ *
+ * @param annotations {@code non-null;} annotations to set for this class
+ */
+ public void setClassAnnotations(Annotations annotations) {
+ annotationsDirectory.setClassAnnotations(annotations);
+ }
- if (! annotationsDirectory.isEmpty()) {
- if (annotationsDirectory.isInternable()) {
- annotationsDirectory = wordData.intern(annotationsDirectory);
- } else {
- wordData.add(annotationsDirectory);
- }
- }
- }
+ /**
+ * Adds a field annotations item to this class.
+ *
+ * @param field {@code non-null;} field in question
+ * @param annotations {@code non-null;} associated annotations to add
+ */
+ public void addFieldAnnotations(CstFieldRef field, Annotations annotations) {
+ annotationsDirectory.addFieldAnnotations(field, annotations);
+ }
- /** {@inheritDoc} */
- @Override
- public void writeTo(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
- TypeIdsSection typeIds = file.getTypeIds();
- int classIdx = typeIds.indexOf(thisClass);
- int superIdx = (superclass == null) ? -1 :
- typeIds.indexOf(superclass);
- int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces);
- int annoOff = annotationsDirectory.isEmpty() ? 0 :
- annotationsDirectory.getAbsoluteOffset();
- int sourceFileIdx = (sourceFile == null) ? -1 :
- file.getStringIds().indexOf(sourceFile);
- int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset();
- int staticValuesOff =
- OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem);
+ /**
+ * Adds a method annotations item to this class.
+ *
+ * @param method {@code non-null;} method in question
+ * @param annotations {@code non-null;} associated annotations to add
+ */
+ public void addMethodAnnotations(CstMethodRef method, Annotations annotations) {
+ annotationsDirectory.addMethodAnnotations(method, annotations);
+ }
- if (annotates) {
- out.annotate(0, indexString() + ' ' + thisClass.toHuman());
- out.annotate(4, " class_idx: " + Hex.u4(classIdx));
- out.annotate(4, " access_flags: " +
- AccessFlags.classString(accessFlags));
- out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) +
- " // " + ((superclass == null) ? "<none>" :
- superclass.toHuman()));
- out.annotate(4, " interfaces_off: " + Hex.u4(interOff));
- if (interOff != 0) {
- TypeList list = interfaces.getList();
- int sz = list.size();
- for (int i = 0; i < sz; i++) {
- out.annotate(0, " " + list.getType(i).toHuman());
- }
- }
- out.annotate(4, " source_file_idx: " + Hex.u4(sourceFileIdx) +
- " // " + ((sourceFile == null) ? "<none>" :
- sourceFile.toHuman()));
- out.annotate(4, " annotations_off: " + Hex.u4(annoOff));
- out.annotate(4, " class_data_off: " + Hex.u4(dataOff));
- out.annotate(4, " static_values_off: " +
- Hex.u4(staticValuesOff));
- }
+ /**
+ * Adds a parameter annotations item to this class.
+ *
+ * @param method {@code non-null;} method in question
+ * @param list {@code non-null;} associated list of annotation sets to add
+ */
+ public void addParameterAnnotations(CstMethodRef method, AnnotationsList list) {
+ annotationsDirectory.addParameterAnnotations(method, list);
+ }
- out.writeInt(classIdx);
- out.writeInt(accessFlags);
- out.writeInt(superIdx);
- out.writeInt(interOff);
- out.writeInt(sourceFileIdx);
- out.writeInt(annoOff);
- out.writeInt(dataOff);
- out.writeInt(staticValuesOff);
- }
+ /**
+ * Gets the method annotations for a given method, if any. This is
+ * meant for use by debugging / dumping code.
+ *
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the method annotations, if any
+ */
+ public Annotations getMethodAnnotations(CstMethodRef method) {
+ return annotationsDirectory.getMethodAnnotations(method);
+ }
- /**
- * Gets the constant corresponding to this class.
- *
- * @return {@code non-null;} the constant
- */
- public CstType getThisClass() {
- return thisClass;
- }
+ /**
+ * Gets the parameter annotations for a given method, if any. This is
+ * meant for use by debugging / dumping code.
+ *
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the parameter annotations, if any
+ */
+ public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+ return annotationsDirectory.getParameterAnnotations(method);
+ }
- /**
- * Gets the access flags.
- *
- * @return the access flags
- */
- public int getAccessFlags() {
- return accessFlags;
- }
+ /**
+ * Prints out the contents of this instance, in a debugging-friendly
+ * way.
+ *
+ * @param out {@code non-null;} where to output to
+ * @param verbose whether to be verbose with the output
+ */
+ public void debugPrint(Writer out, boolean verbose) {
+ PrintWriter pw = Writers.printWriterFor(out);
- /**
- * Gets the superclass.
- *
- * @return {@code null-ok;} the superclass or {@code null} if
- * this class is a/the root class
- */
- public CstType getSuperclass() {
- return superclass;
- }
+ pw.println(getClass().getName() + " {");
+ pw.println(" accessFlags: " + Hex.u2(accessFlags));
+ pw.println(" superclass: " + superclass);
+ pw.println(" interfaces: " + ((interfaces == null) ? "<none>" : interfaces));
+ pw.println(" sourceFile: " + ((sourceFile == null) ? "<none>" : sourceFile.toQuoted()));
- /**
- * Gets the list of interfaces implemented.
- *
- * @return {@code non-null;} the interfaces list
- */
- public TypeList getInterfaces() {
- if (interfaces == null) {
- return StdTypeList.EMPTY;
- }
+ classData.debugPrint(out, verbose);
+ annotationsDirectory.debugPrint(pw);
- return interfaces.getList();
- }
-
- /**
- * Gets the source file name.
- *
- * @return {@code null-ok;} the source file name or {@code null} if unknown
- */
- public CstString getSourceFile() {
- return sourceFile;
- }
-
- /**
- * Adds a static field.
- *
- * @param field {@code non-null;} the field to add
- * @param value {@code null-ok;} initial value for the field, if any
- */
- public void addStaticField(EncodedField field, Constant value) {
- classData.addStaticField(field, value);
- }
-
- /**
- * Adds an instance field.
- *
- * @param field {@code non-null;} the field to add
- */
- public void addInstanceField(EncodedField field) {
- classData.addInstanceField(field);
- }
-
- /**
- * Adds a direct ({@code static} and/or {@code private}) method.
- *
- * @param method {@code non-null;} the method to add
- */
- public void addDirectMethod(EncodedMethod method) {
- classData.addDirectMethod(method);
- }
-
- /**
- * Adds a virtual method.
- *
- * @param method {@code non-null;} the method to add
- */
- public void addVirtualMethod(EncodedMethod method) {
- classData.addVirtualMethod(method);
- }
-
- /**
- * Gets all the methods in this class. The returned list is not linked
- * in any way to the underlying lists contained in this instance, but
- * the objects contained in the list are shared.
- *
- * @return {@code non-null;} list of all methods
- */
- public ArrayList<EncodedMethod> getMethods() {
- return classData.getMethods();
- }
-
- /**
- * Sets the direct annotations on this class. These are annotations
- * made on the class, per se, as opposed to on one of its members.
- * It is only valid to call this method at most once per instance.
- *
- * @param annotations {@code non-null;} annotations to set for this class
- */
- public void setClassAnnotations(Annotations annotations) {
- annotationsDirectory.setClassAnnotations(annotations);
- }
-
- /**
- * Adds a field annotations item to this class.
- *
- * @param field {@code non-null;} field in question
- * @param annotations {@code non-null;} associated annotations to add
- */
- public void addFieldAnnotations(CstFieldRef field,
- Annotations annotations) {
- annotationsDirectory.addFieldAnnotations(field, annotations);
- }
-
- /**
- * Adds a method annotations item to this class.
- *
- * @param method {@code non-null;} method in question
- * @param annotations {@code non-null;} associated annotations to add
- */
- public void addMethodAnnotations(CstMethodRef method,
- Annotations annotations) {
- annotationsDirectory.addMethodAnnotations(method, annotations);
- }
-
- /**
- * Adds a parameter annotations item to this class.
- *
- * @param method {@code non-null;} method in question
- * @param list {@code non-null;} associated list of annotation sets to add
- */
- public void addParameterAnnotations(CstMethodRef method,
- AnnotationsList list) {
- annotationsDirectory.addParameterAnnotations(method, list);
- }
-
- /**
- * Gets the method annotations for a given method, if any. This is
- * meant for use by debugging / dumping code.
- *
- * @param method {@code non-null;} the method
- * @return {@code null-ok;} the method annotations, if any
- */
- public Annotations getMethodAnnotations(CstMethodRef method) {
- return annotationsDirectory.getMethodAnnotations(method);
- }
-
- /**
- * Gets the parameter annotations for a given method, if any. This is
- * meant for use by debugging / dumping code.
- *
- * @param method {@code non-null;} the method
- * @return {@code null-ok;} the parameter annotations, if any
- */
- public AnnotationsList getParameterAnnotations(CstMethodRef method) {
- return annotationsDirectory.getParameterAnnotations(method);
- }
-
- /**
- * Prints out the contents of this instance, in a debugging-friendly
- * way.
- *
- * @param out {@code non-null;} where to output to
- * @param verbose whether to be verbose with the output
- */
- public void debugPrint(Writer out, boolean verbose) {
- PrintWriter pw = Writers.printWriterFor(out);
-
- pw.println(getClass().getName() + " {");
- pw.println(" accessFlags: " + Hex.u2(accessFlags));
- pw.println(" superclass: " + superclass);
- pw.println(" interfaces: " +
- ((interfaces == null) ? "<none>" : interfaces));
- pw.println(" sourceFile: " +
- ((sourceFile == null) ? "<none>" : sourceFile.toQuoted()));
-
- classData.debugPrint(out, verbose);
- annotationsDirectory.debugPrint(pw);
-
- pw.println("}");
- }
+ pw.println("}");
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/jack/dx/dex/file/ClassDefsSection.java
index 512ffc1..0c66c50 100644
--- a/dx/src/com/android/jack/dx/dex/file/ClassDefsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/ClassDefsSection.java
@@ -31,157 +31,157 @@
* Class definitions list section of a {@code .dex} file.
*/
public final class ClassDefsSection extends UniformItemSection {
- /**
- * {@code non-null;} map from type constants for classes to {@link
- * ClassDefItem} instances that define those classes
+ /**
+ * {@code non-null;} map from type constants for classes to {@link
+ * ClassDefItem} instances that define those classes
+ */
+ private final TreeMap<Type, ClassDefItem> classDefs;
+
+ /** {@code null-ok;} ordered list of classes; set in {@link #orderItems} */
+ private ArrayList<ClassDefItem> orderedDefs;
+
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public ClassDefsSection(DexFile file) {
+ super("class_defs", file, 4);
+
+ classDefs = new TreeMap<Type, ClassDefItem>();
+ orderedDefs = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ if (orderedDefs != null) {
+ return orderedDefs;
+ }
+
+ return classDefs.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
+ }
+
+ throwIfNotPrepared();
+
+ Type type = ((CstType) cst).getClassType();
+ IndexedItem result = classDefs.get(type);
+
+ if (result == null) {
+ throw new IllegalArgumentException("not found");
+ }
+
+ return result;
+ }
+
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
+
+ int sz = classDefs.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
+
+ if (out.annotates()) {
+ out.annotate(4, "class_defs_size: " + Hex.u4(sz));
+ out.annotate(4, "class_defs_off: " + Hex.u4(offset));
+ }
+
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
+
+ /**
+ * Adds an element to this instance. It is illegal to attempt to add more
+ * than one class with the same name.
+ *
+ * @param clazz {@code non-null;} the class def to add
+ */
+ public void add(ClassDefItem clazz) {
+ Type type;
+
+ try {
+ type = clazz.getThisClass().getClassType();
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("clazz == null");
+ }
+
+ throwIfPrepared();
+
+ if (classDefs.get(type) != null) {
+ throw new IllegalArgumentException("already added: " + type);
+ }
+
+ classDefs.put(type, clazz);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ int sz = classDefs.size();
+ int idx = 0;
+
+ orderedDefs = new ArrayList<ClassDefItem>(sz);
+
+ /*
+ * Iterate over all the classes, recursively assigning an
+ * index to each, implicitly skipping the ones that have
+ * already been assigned by the time this (top-level)
+ * iteration reaches them.
*/
- private final TreeMap<Type, ClassDefItem> classDefs;
+ for (Type type : classDefs.keySet()) {
+ idx = orderItems0(type, idx, sz - idx);
+ }
+ }
- /** {@code null-ok;} ordered list of classes; set in {@link #orderItems} */
- private ArrayList<ClassDefItem> orderedDefs;
+ /**
+ * Helper for {@link #orderItems}, which recursively assigns indices
+ * to classes.
+ *
+ * @param type {@code null-ok;} type ref to assign, if any
+ * @param idx {@code >= 0;} the next index to assign
+ * @param maxDepth maximum recursion depth; if negative, this will
+ * throw an exception indicating class definition circularity
+ * @return {@code >= 0;} the next index to assign
+ */
+ private int orderItems0(Type type, int idx, int maxDepth) {
+ ClassDefItem c = classDefs.get(type);
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public ClassDefsSection(DexFile file) {
- super("class_defs", file, 4);
-
- classDefs = new TreeMap<Type, ClassDefItem>();
- orderedDefs = null;
+ if ((c == null) || (c.hasIndex())) {
+ return idx;
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- if (orderedDefs != null) {
- return orderedDefs;
- }
-
- return classDefs.values();
+ if (maxDepth < 0) {
+ throw new RuntimeException("class circularity with " + type);
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
+ maxDepth--;
- throwIfNotPrepared();
-
- Type type = ((CstType) cst).getClassType();
- IndexedItem result = classDefs.get(type);
-
- if (result == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return result;
+ CstType superclassCst = c.getSuperclass();
+ if (superclassCst != null) {
+ Type superclass = superclassCst.getClassType();
+ idx = orderItems0(superclass, idx, maxDepth);
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
-
- int sz = classDefs.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
-
- if (out.annotates()) {
- out.annotate(4, "class_defs_size: " + Hex.u4(sz));
- out.annotate(4, "class_defs_off: " + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ TypeList interfaces = c.getInterfaces();
+ int sz = interfaces.size();
+ for (int i = 0; i < sz; i++) {
+ idx = orderItems0(interfaces.getType(i), idx, maxDepth);
}
- /**
- * Adds an element to this instance. It is illegal to attempt to add more
- * than one class with the same name.
- *
- * @param clazz {@code non-null;} the class def to add
- */
- public void add(ClassDefItem clazz) {
- Type type;
-
- try {
- type = clazz.getThisClass().getClassType();
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("clazz == null");
- }
-
- throwIfPrepared();
-
- if (classDefs.get(type) != null) {
- throw new IllegalArgumentException("already added: " + type);
- }
-
- classDefs.put(type, clazz);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- int sz = classDefs.size();
- int idx = 0;
-
- orderedDefs = new ArrayList<ClassDefItem>(sz);
-
- /*
- * Iterate over all the classes, recursively assigning an
- * index to each, implicitly skipping the ones that have
- * already been assigned by the time this (top-level)
- * iteration reaches them.
- */
- for (Type type : classDefs.keySet()) {
- idx = orderItems0(type, idx, sz - idx);
- }
- }
-
- /**
- * Helper for {@link #orderItems}, which recursively assigns indices
- * to classes.
- *
- * @param type {@code null-ok;} type ref to assign, if any
- * @param idx {@code >= 0;} the next index to assign
- * @param maxDepth maximum recursion depth; if negative, this will
- * throw an exception indicating class definition circularity
- * @return {@code >= 0;} the next index to assign
- */
- private int orderItems0(Type type, int idx, int maxDepth) {
- ClassDefItem c = classDefs.get(type);
-
- if ((c == null) || (c.hasIndex())) {
- return idx;
- }
-
- if (maxDepth < 0) {
- throw new RuntimeException("class circularity with " + type);
- }
-
- maxDepth--;
-
- CstType superclassCst = c.getSuperclass();
- if (superclassCst != null) {
- Type superclass = superclassCst.getClassType();
- idx = orderItems0(superclass, idx, maxDepth);
- }
-
- TypeList interfaces = c.getInterfaces();
- int sz = interfaces.size();
- for (int i = 0; i < sz; i++) {
- idx = orderItems0(interfaces.getType(i), idx, maxDepth);
- }
-
- c.setIndex(idx);
- orderedDefs.add(c);
- return idx + 1;
- }
+ c.setIndex(idx);
+ orderedDefs.add(c);
+ return idx + 1;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/CodeItem.java b/dx/src/com/android/jack/dx/dex/file/CodeItem.java
index 15cb5a8..2dbaed9 100644
--- a/dx/src/com/android/jack/dx/dex/file/CodeItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/CodeItem.java
@@ -35,290 +35,288 @@
*/
public final class CodeItem extends OffsettedItem implements Code {
- /** {@code non-null;} method that this code implements */
- private final CstMethodRef ref;
+ /** {@code non-null;} method that this code implements */
+ private final CstMethodRef ref;
- /** {@code non-null;} the bytecode instructions and associated data */
- private final DalvCode code;
+ /** {@code non-null;} the bytecode instructions and associated data */
+ private final DalvCode code;
- /** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
- private CatchStructs catches;
+ /** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
+ private CatchStructs catches;
- /** whether this instance is for a {@code static} method */
- private final boolean isStatic;
+ /** whether this instance is for a {@code static} method */
+ private final boolean isStatic;
- /**
- * {@code non-null;} list of possibly-thrown exceptions; just used in
- * generating debugging output (listings)
+ /**
+ * {@code non-null;} list of possibly-thrown exceptions; just used in
+ * generating debugging output (listings)
+ */
+ private final TypeList throwsList;
+
+ /**
+ * {@code null-ok;} the debug info or {@code null} if there is none;
+ * set in {@link #addContents}
+ */
+ private DebugInfoItem debugInfo;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param ref {@code non-null;} method that this code implements
+ * @param code {@code non-null;} the underlying code
+ * @param isStatic whether this instance is for a {@code static}
+ * method
+ * @param throwsList {@code non-null;} list of possibly-thrown exceptions,
+ * just used in generating debugging output (listings)
+ */
+ public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic, TypeList throwsList) {
+ super(ALIGNMENT, -1);
+
+ if (ref == null) {
+ throw new NullPointerException("ref == null");
+ }
+
+ if (code == null) {
+ throw new NullPointerException("code == null");
+ }
+
+ if (throwsList == null) {
+ throw new NullPointerException("throwsList == null");
+ }
+
+ this.ref = ref;
+ this.code = code;
+ this.isStatic = isStatic;
+ this.throwsList = throwsList;
+ this.catches = null;
+ this.debugInfo = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_CODE_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ MixedItemSection byteData = file.getByteData();
+ TypeIdsSection typeIds = file.getTypeIds();
+
+ if (code.hasPositions() || code.hasLocals()) {
+ debugInfo = new DebugInfoItem(code, isStatic, ref);
+ byteData.add(debugInfo);
+ }
+
+ if (code.hasAnyCatches()) {
+ for (Type type : code.getCatchTypes()) {
+ typeIds.intern(type);
+ }
+ catches = new CatchStructs(code);
+ }
+
+ for (Constant c : code.getInsnConstants()) {
+ file.internIfAppropriate(c);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "CodeItem{" + toHuman() + "}";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return ref.toHuman();
+ }
+
+ /**
+ * Gets the reference to the method this instance implements.
+ *
+ * @return {@code non-null;} the method reference
+ */
+ public CstMethodRef getRef() {
+ return ref;
+ }
+
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} per-line prefix to use
+ * @param verbose whether to be verbose with the output
+ */
+ @Override
+ public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
+ out.println(ref.toHuman() + ":");
+
+ DalvInsnList insns = code.getInsns();
+ out.println("regs: " + Hex.u2(getRegistersSize()) + "; ins: " + Hex.u2(getInsSize())
+ + "; outs: " + Hex.u2(getOutsSize()));
+
+ insns.debugPrint(out, prefix, verbose);
+
+ String prefix2 = prefix + " ";
+
+ if (catches != null) {
+ out.print(prefix);
+ out.println("catches");
+ catches.debugPrint(out, prefix2);
+ }
+
+ if (debugInfo != null) {
+ out.print(prefix);
+ out.println("debug info");
+ debugInfo.debugPrint(out, prefix2);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ final DexFile file = addedTo.getFile();
+ int catchesSize;
+
+ /*
+ * In order to get the catches and insns, all the code's
+ * constants need to be assigned indices.
*/
- private final TypeList throwsList;
+ code.assignIndices(new DalvCode.AssignIndicesCallback() {
+ @Override
+ public int getIndex(Constant cst) {
+ IndexedItem item = file.findItemOrNull(cst);
+ if (item == null) {
+ return -1;
+ }
+ return item.getIndex();
+ }
+ });
- /**
- * {@code null-ok;} the debug info or {@code null} if there is none;
- * set in {@link #addContents}
+ if (catches != null) {
+ catches.encode(file);
+ catchesSize = catches.writeSize();
+ } else {
+ catchesSize = 0;
+ }
+
+ /*
+ * The write size includes the header, two bytes per code
+ * unit, post-code padding if necessary, and however much
+ * space the catches need.
*/
- private DebugInfoItem debugInfo;
- /**
- * Constructs an instance.
- *
- * @param ref {@code non-null;} method that this code implements
- * @param code {@code non-null;} the underlying code
- * @param isStatic whether this instance is for a {@code static}
- * method
- * @param throwsList {@code non-null;} list of possibly-thrown exceptions,
- * just used in generating debugging output (listings)
- */
- public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic,
- TypeList throwsList) {
- super(ALIGNMENT, -1);
-
- if (ref == null) {
- throw new NullPointerException("ref == null");
- }
-
- if (code == null) {
- throw new NullPointerException("code == null");
- }
-
- if (throwsList == null) {
- throw new NullPointerException("throwsList == null");
- }
-
- this.ref = ref;
- this.code = code;
- this.isStatic = isStatic;
- this.throwsList = throwsList;
- this.catches = null;
- this.debugInfo = null;
+int insnsSize = code.getInsns().codeSize();
+ if ((insnsSize & 1) != 0) {
+ insnsSize++;
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_CODE_ITEM;
+ setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ int regSz = getRegistersSize();
+ int outsSz = getOutsSize();
+ int insSz = getInsSize();
+ int insnsSz = code.getInsns().codeSize();
+ boolean needPadding = (insnsSz & 1) != 0;
+ int triesSz = (catches == null) ? 0 : catches.triesSize();
+ int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset();
+
+ if (annotates) {
+ out.annotate(0, offsetString() + ' ' + ref.toHuman());
+ out.annotate(2, " registers_size: " + Hex.u2(regSz));
+ out.annotate(2, " ins_size: " + Hex.u2(insSz));
+ out.annotate(2, " outs_size: " + Hex.u2(outsSz));
+ out.annotate(2, " tries_size: " + Hex.u2(triesSz));
+ out.annotate(4, " debug_off: " + Hex.u4(debugOff));
+ out.annotate(4, " insns_size: " + Hex.u4(insnsSz));
+
+ // This isn't represented directly here, but it is useful to see.
+ int size = throwsList.size();
+ if (size != 0) {
+ out.annotate(0, " throws " + StdTypeList.toHuman(throwsList));
+ }
}
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- MixedItemSection byteData = file.getByteData();
- TypeIdsSection typeIds = file.getTypeIds();
+ out.writeShort(regSz);
+ out.writeShort(insSz);
+ out.writeShort(outsSz);
+ out.writeShort(triesSz);
+ out.writeInt(debugOff);
+ out.writeInt(insnsSz);
- if (code.hasPositions() || code.hasLocals()) {
- debugInfo = new DebugInfoItem(code, isStatic, ref);
- byteData.add(debugInfo);
- }
+ writeCodes(file, out);
- if (code.hasAnyCatches()) {
- for (Type type : code.getCatchTypes()) {
- typeIds.intern(type);
- }
- catches = new CatchStructs(code);
- }
-
- for (Constant c : code.getInsnConstants()) {
- file.internIfAppropriate(c);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return "CodeItem{" + toHuman() + "}";
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return ref.toHuman();
- }
-
- /**
- * Gets the reference to the method this instance implements.
- *
- * @return {@code non-null;} the method reference
- */
- public CstMethodRef getRef() {
- return ref;
- }
-
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} per-line prefix to use
- * @param verbose whether to be verbose with the output
- */
- @Override
- public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
- out.println(ref.toHuman() + ":");
-
- DalvInsnList insns = code.getInsns();
- out.println("regs: " + Hex.u2(getRegistersSize()) +
- "; ins: " + Hex.u2(getInsSize()) + "; outs: " +
- Hex.u2(getOutsSize()));
-
- insns.debugPrint(out, prefix, verbose);
-
- String prefix2 = prefix + " ";
-
- if (catches != null) {
- out.print(prefix);
- out.println("catches");
- catches.debugPrint(out, prefix2);
- }
-
- if (debugInfo != null) {
- out.print(prefix);
- out.println("debug info");
- debugInfo.debugPrint(out, prefix2);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- final DexFile file = addedTo.getFile();
- int catchesSize;
-
- /*
- * In order to get the catches and insns, all the code's
- * constants need to be assigned indices.
- */
- code.assignIndices(new DalvCode.AssignIndicesCallback() {
- @Override
- public int getIndex(Constant cst) {
- IndexedItem item = file.findItemOrNull(cst);
- if (item == null) {
- return -1;
- }
- return item.getIndex();
- }
- });
-
- if (catches != null) {
- catches.encode(file);
- catchesSize = catches.writeSize();
- } else {
- catchesSize = 0;
- }
-
- /*
- * The write size includes the header, two bytes per code
- * unit, post-code padding if necessary, and however much
- * space the catches need.
- */
-
- int insnsSize = code.getInsns().codeSize();
- if ((insnsSize & 1) != 0) {
- insnsSize++;
- }
-
- setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
- int regSz = getRegistersSize();
- int outsSz = getOutsSize();
- int insSz = getInsSize();
- int insnsSz = code.getInsns().codeSize();
- boolean needPadding = (insnsSz & 1) != 0;
- int triesSz = (catches == null) ? 0 : catches.triesSize();
- int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset();
-
+ if (catches != null) {
+ if (needPadding) {
if (annotates) {
- out.annotate(0, offsetString() + ' ' + ref.toHuman());
- out.annotate(2, " registers_size: " + Hex.u2(regSz));
- out.annotate(2, " ins_size: " + Hex.u2(insSz));
- out.annotate(2, " outs_size: " + Hex.u2(outsSz));
- out.annotate(2, " tries_size: " + Hex.u2(triesSz));
- out.annotate(4, " debug_off: " + Hex.u4(debugOff));
- out.annotate(4, " insns_size: " + Hex.u4(insnsSz));
-
- // This isn't represented directly here, but it is useful to see.
- int size = throwsList.size();
- if (size != 0) {
- out.annotate(0, " throws " + StdTypeList.toHuman(throwsList));
- }
+ out.annotate(2, " padding: 0");
}
+ out.writeShort(0);
+ }
- out.writeShort(regSz);
- out.writeShort(insSz);
- out.writeShort(outsSz);
- out.writeShort(triesSz);
- out.writeInt(debugOff);
- out.writeInt(insnsSz);
-
- writeCodes(file, out);
-
- if (catches != null) {
- if (needPadding) {
- if (annotates) {
- out.annotate(2, " padding: 0");
- }
- out.writeShort(0);
- }
-
- catches.writeTo(file, out);
- }
-
- if (annotates) {
- /*
- * These are pointed at in the code header (above), but it's less
- * distracting to expand on them at the bottom of the code.
- */
- if (debugInfo != null) {
- out.annotate(0, " debug info");
- debugInfo.annotateTo(file, out, " ");
- }
- }
+ catches.writeTo(file, out);
}
- /**
- * Helper for {@link #writeTo0} which writes out the actual bytecode.
- *
- * @param file {@code non-null;} file we are part of
- * @param out {@code non-null;} where to write to
- */
- private void writeCodes(DexFile file, AnnotatedOutput out) {
- DalvInsnList insns = code.getInsns();
-
- try {
- insns.writeTo(out);
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex, "...while writing " +
- "instructions for " + ref.toHuman());
- }
+ if (annotates) {
+ /*
+ * These are pointed at in the code header (above), but it's less
+ * distracting to expand on them at the bottom of the code.
+ */
+ if (debugInfo != null) {
+ out.annotate(0, " debug info");
+ debugInfo.annotateTo(file, out, " ");
+ }
}
+ }
- /**
- * Get the in registers count.
- *
- * @return the count
- */
- private int getInsSize() {
- return ref.getParameterWordCount(isStatic);
- }
+ /**
+ * Helper for {@link #writeTo0} which writes out the actual bytecode.
+ *
+ * @param file {@code non-null;} file we are part of
+ * @param out {@code non-null;} where to write to
+ */
+ private void writeCodes(DexFile file, AnnotatedOutput out) {
+ DalvInsnList insns = code.getInsns();
- /**
- * Get the out registers count.
- *
- * @return the count
- */
- private int getOutsSize() {
- return code.getInsns().getOutsSize();
+ try {
+ insns.writeTo(out);
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex,
+ "...while writing " + "instructions for " + ref.toHuman());
}
+ }
- /**
- * Get the total registers count.
- *
- * @return the count
- */
- private int getRegistersSize() {
- return code.getInsns().getRegistersSize();
- }
+ /**
+ * Get the in registers count.
+ *
+ * @return the count
+ */
+ private int getInsSize() {
+ return ref.getParameterWordCount(isStatic);
+ }
+
+ /**
+ * Get the out registers count.
+ *
+ * @return the count
+ */
+ private int getOutsSize() {
+ return code.getInsns().getOutsSize();
+ }
+
+ /**
+ * Get the total registers count.
+ *
+ * @return the count
+ */
+ private int getRegistersSize() {
+ return code.getInsns().getRegistersSize();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/DebugInfoConstants.java b/dx/src/com/android/jack/dx/dex/file/DebugInfoConstants.java
index 63d8a34..1e2d520 100644
--- a/dx/src/com/android/jack/dx/dex/file/DebugInfoConstants.java
+++ b/dx/src/com/android/jack/dx/dex/file/DebugInfoConstants.java
@@ -21,134 +21,134 @@
*/
public interface DebugInfoConstants {
- /*
- * normal opcodes
- */
+ /*
+ * normal opcodes
+ */
- /**
- * Terminates a debug info sequence for a method.<p>
- * Args: none
- *
- */
- static final int DBG_END_SEQUENCE = 0x00;
+ /**
+ * Terminates a debug info sequence for a method.<p>
+ * Args: none
+ *
+ */
+ static final int DBG_END_SEQUENCE = 0x00;
- /**
- * Advances the program counter/address register without emitting
- * a positions entry.<p>
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — amount to advance pc by
- * </ol>
- */
- static final int DBG_ADVANCE_PC = 0x01;
+ /**
+ * Advances the program counter/address register without emitting
+ * a positions entry.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — amount to advance pc by
+ * </ol>
+ */
+ static final int DBG_ADVANCE_PC = 0x01;
- /**
- * Advances the line register without emitting
- * a positions entry.<p>
- *
- * Args:
- * <ol>
- * <li>Signed LEB128 — amount to change line register by.
- * </ol>
- */
- static final int DBG_ADVANCE_LINE = 0x02;
+ /**
+ * Advances the line register without emitting
+ * a positions entry.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Signed LEB128 — amount to change line register by.
+ * </ol>
+ */
+ static final int DBG_ADVANCE_LINE = 0x02;
- /**
- * Introduces a local variable at the current address.<p>
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — register that will contain local.
- * <li>Unsigned LEB128 — string index (shifted by 1) of local name.
- * <li>Unsigned LEB128 — type index (shifted by 1) of type.
- * </ol>
- */
- static final int DBG_START_LOCAL = 0x03;
+ /**
+ * Introduces a local variable at the current address.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — register that will contain local.
+ * <li>Unsigned LEB128 — string index (shifted by 1) of local name.
+ * <li>Unsigned LEB128 — type index (shifted by 1) of type.
+ * </ol>
+ */
+ static final int DBG_START_LOCAL = 0x03;
- /**
- * Introduces a local variable at the current address with a type
- * signature specified.<p>
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — register that will contain local.
- * <li>Unsigned LEB128 — string index (shifted by 1) of local name.
- * <li>Unsigned LEB128 — type index (shifted by 1) of type.
- * <li>Unsigned LEB128 — string index (shifted by 1) of
- * type signature.
- * </ol>
- */
- static final int DBG_START_LOCAL_EXTENDED = 0x04;
+ /**
+ * Introduces a local variable at the current address with a type
+ * signature specified.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — register that will contain local.
+ * <li>Unsigned LEB128 — string index (shifted by 1) of local name.
+ * <li>Unsigned LEB128 — type index (shifted by 1) of type.
+ * <li>Unsigned LEB128 — string index (shifted by 1) of
+ * type signature.
+ * </ol>
+ */
+ static final int DBG_START_LOCAL_EXTENDED = 0x04;
- /**
- * Marks a currently-live local variable as out of scope at the
- * current address.<p>
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — register that contained local
- * </ol>
- */
- static final int DBG_END_LOCAL = 0x05;
+ /**
+ * Marks a currently-live local variable as out of scope at the
+ * current address.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — register that contained local
+ * </ol>
+ */
+ static final int DBG_END_LOCAL = 0x05;
- /**
- * Re-introduces a local variable at the current address. The name
- * and type are the same as the last local that was live in the specified
- * register.<p>
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — register to re-start.
- * </ol>
- */
- static final int DBG_RESTART_LOCAL = 0x06;
+ /**
+ * Re-introduces a local variable at the current address. The name
+ * and type are the same as the last local that was live in the specified
+ * register.<p>
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — register to re-start.
+ * </ol>
+ */
+ static final int DBG_RESTART_LOCAL = 0x06;
- /**
- * Sets the "prologue_end" state machine register, indicating that the
- * next position entry that is added should be considered the end of
- * a method prologue (an appropriate place for a method breakpoint).<p>
- *
- * The prologue_end register is cleared by any special
- * ({@code >= OPCODE_BASE}) opcode.
- */
- static final int DBG_SET_PROLOGUE_END = 0x07;
+ /**
+ * Sets the "prologue_end" state machine register, indicating that the
+ * next position entry that is added should be considered the end of
+ * a method prologue (an appropriate place for a method breakpoint).<p>
+ *
+ * The prologue_end register is cleared by any special
+ * ({@code >= OPCODE_BASE}) opcode.
+ */
+ static final int DBG_SET_PROLOGUE_END = 0x07;
- /**
- * Sets the "epilogue_begin" state machine register, indicating that the
- * next position entry that is added should be considered the beginning of
- * a method epilogue (an appropriate place to suspend execution before
- * method exit).<p>
- *
- * The epilogue_begin register is cleared by any special
- * ({@code >= OPCODE_BASE}) opcode.
- */
- static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
+ /**
+ * Sets the "epilogue_begin" state machine register, indicating that the
+ * next position entry that is added should be considered the beginning of
+ * a method epilogue (an appropriate place to suspend execution before
+ * method exit).<p>
+ *
+ * The epilogue_begin register is cleared by any special
+ * ({@code >= OPCODE_BASE}) opcode.
+ */
+ static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
- /**
- * Sets the current file that that line numbers refer to. All subsequent
- * line number entries make reference to this source file name, instead
- * of the default name specified in code_item.
- *
- * Args:
- * <ol>
- * <li>Unsigned LEB128 — string index (shifted by 1) of source
- * file name.
- * </ol>
- */
- static final int DBG_SET_FILE = 0x09;
+ /**
+ * Sets the current file that that line numbers refer to. All subsequent
+ * line number entries make reference to this source file name, instead
+ * of the default name specified in code_item.
+ *
+ * Args:
+ * <ol>
+ * <li>Unsigned LEB128 — string index (shifted by 1) of source
+ * file name.
+ * </ol>
+ */
+ static final int DBG_SET_FILE = 0x09;
- /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */
+ /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */
- /*
- * "special opcode" configuration, essentially what's found in
- * the line number program header in DWARFv3, Section 6.2.4
- */
+ /*
+ * "special opcode" configuration, essentially what's found in
+ * the line number program header in DWARFv3, Section 6.2.4
+ */
- /** the smallest value a special opcode can take */
- static final int DBG_FIRST_SPECIAL = 0x0a;
- static final int DBG_LINE_BASE = -4;
- static final int DBG_LINE_RANGE = 15;
- // MIN_INSN_LENGTH is always 1
+ /** the smallest value a special opcode can take */
+ static final int DBG_FIRST_SPECIAL = 0x0a;
+ static final int DBG_LINE_BASE = -4;
+ static final int DBG_LINE_RANGE = 15;
+ // MIN_INSN_LENGTH is always 1
}
diff --git a/dx/src/com/android/jack/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/jack/dx/dex/file/DebugInfoDecoder.java
index 98ebc08..acd7939 100644
--- a/dx/src/com/android/jack/dx/dex/file/DebugInfoDecoder.java
+++ b/dx/src/com/android/jack/dx/dex/file/DebugInfoDecoder.java
@@ -16,6 +16,20 @@
package com.android.jack.dx.dex.file;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_LINE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_PC;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_END_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_END_SEQUENCE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_FIRST_SPECIAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_LINE_BASE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_LINE_RANGE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_RESTART_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_SET_EPILOGUE_BEGIN;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_SET_FILE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_SET_PROLOGUE_END;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL_EXTENDED;
+
import com.android.jack.dx.dex.code.DalvCode;
import com.android.jack.dx.dex.code.DalvInsnList;
import com.android.jack.dx.dex.code.LocalList;
@@ -35,563 +49,560 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.jack.dx.dex.file.DebugInfoConstants.*;
-
/**
* A decoder for the dex debug info state machine format.
* This code exists mostly as a reference implementation and test for
* for the {@code DebugInfoEncoder}
*/
public class DebugInfoDecoder {
- /** encoded debug info */
- private final ByteInput encoded;
+ /** encoded debug info */
+ private final ByteInput encoded;
- /** positions decoded */
- private final ArrayList<PositionEntry> positions;
+ /** positions decoded */
+ private final ArrayList<PositionEntry> positions;
- /** locals decoded */
- private final ArrayList<LocalEntry> locals;
+ /** locals decoded */
+ private final ArrayList<LocalEntry> locals;
- /** indexed by register, the last local variable live in a reg */
- private final LocalEntry[] lastEntryForReg;
+ /** indexed by register, the last local variable live in a reg */
+ private final LocalEntry[] lastEntryForReg;
- /** method descriptor of method this debug info is for */
- private final Prototype desc;
+ /** method descriptor of method this debug info is for */
+ private final Prototype desc;
- /** true if method is static */
- private final boolean isStatic;
+ /** true if method is static */
+ private final boolean isStatic;
- /**
- * register size, in register units, of the register space
- * used by this method
- */
- private final int regSize;
+ /**
+ * register size, in register units, of the register space
+ * used by this method
+ */
+ private final int regSize;
- /** current decoding state: line number */
- private int line = 1;
+ /** current decoding state: line number */
+ private int line = 1;
- /** current decoding state: bytecode address */
- private int address = 0;
+ /** current decoding state: bytecode address */
+ private int address = 0;
- /** string index of the string "this" */
- private final int thisStringIdx;
+ /** string index of the string "this" */
+ private final int thisStringIdx;
- /**
- * Constructs an instance.
- *
- * @param encoded encoded debug info
- * @param regSize register size, in register units, of the register space
- * used by this method
- * @param isStatic true if method is static
- * @param ref method descriptor of method this debug info is for
- * @param file dex file this debug info will be stored in
- */
- DebugInfoDecoder(byte[] encoded, int regSize,
- boolean isStatic, CstMethodRef ref, DexFile file) {
- this(new ByteArrayByteInput(encoded), regSize, isStatic, ref.getPrototype(),
- extractThisIdx(file));
+ /**
+ * Constructs an instance.
+ *
+ * @param encoded encoded debug info
+ * @param regSize register size, in register units, of the register space
+ * used by this method
+ * @param isStatic true if method is static
+ * @param ref method descriptor of method this debug info is for
+ * @param file dex file this debug info will be stored in
+ */
+ DebugInfoDecoder(byte[] encoded, int regSize, boolean isStatic, CstMethodRef ref, DexFile file) {
+ this(new ByteArrayByteInput(encoded), regSize, isStatic, ref.getPrototype(), extractThisIdx(
+ file));
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param encoded encoded debug info
+ * @param regSize register size, in register units, of the register space
+ * used by this method
+ * @param isStatic true if method is static
+ * @param desc method descriptor of method this debug info is for
+ * @param thisIdx string index of the string "this" or -1 if the string does not exists in the
+ * dex.
+ */
+ public DebugInfoDecoder(ByteInput encoded, int regSize, boolean isStatic, Prototype desc,
+ int thisIdx) {
+ if (encoded == null) {
+ throw new NullPointerException("encoded == null");
}
- /**
- * Constructs an instance.
- *
- * @param encoded encoded debug info
- * @param regSize register size, in register units, of the register space
- * used by this method
- * @param isStatic true if method is static
- * @param desc method descriptor of method this debug info is for
- * @param thisIdx string index of the string "this" or -1 if the string does not exists in the
- * dex.
- */
- public DebugInfoDecoder(ByteInput encoded, int regSize,
- boolean isStatic, Prototype desc, int thisIdx) {
- if (encoded == null) {
- throw new NullPointerException("encoded == null");
- }
+ this.encoded = encoded;
+ this.isStatic = isStatic;
+ this.desc = desc;
+ this.regSize = regSize;
- this.encoded = encoded;
- this.isStatic = isStatic;
- this.desc = desc;
- this.regSize = regSize;
+ positions = new ArrayList<PositionEntry>();
+ locals = new ArrayList<LocalEntry>();
+ lastEntryForReg = new LocalEntry[regSize];
- positions = new ArrayList<PositionEntry>();
- locals = new ArrayList<LocalEntry>();
- lastEntryForReg = new LocalEntry[regSize];
+ thisStringIdx = thisIdx;
+ }
- thisStringIdx = thisIdx;
+ /**
+ * An entry in the resulting postions table
+ */
+ public static class PositionEntry {
+ /** bytecode address */
+ public int address;
+
+ /** line number */
+ public int line;
+
+ public PositionEntry(int address, int line) {
+ this.address = address;
+ this.line = line;
+ }
+ }
+
+ /**
+ * An entry in the resulting locals table
+ */
+ public static class LocalEntry {
+ /** address of event */
+ public int address;
+
+ /** {@code true} iff it's a local start */
+ public boolean isStart;
+
+ /** register number */
+ public int reg;
+
+ /** index of name in strings table */
+ public int nameIndex;
+
+ /** index of type in types table */
+ public int typeIndex;
+
+ /** index of type signature in strings table */
+ public int signatureIndex;
+
+ public LocalEntry(int address,
+ boolean isStart,
+ int reg,
+ int nameIndex,
+ int typeIndex,
+ int signatureIndex) {
+ this.address = address;
+ this.isStart = isStart;
+ this.reg = reg;
+ this.nameIndex = nameIndex;
+ this.typeIndex = typeIndex;
+ this.signatureIndex = signatureIndex;
}
- /**
- * An entry in the resulting postions table
- */
- static public class PositionEntry {
- /** bytecode address */
- public int address;
+ @Override
+ public String toString() {
+ return String.format("[%x %s v%d %04x %04x %04x]",
+ address,
+ isStart ? "start" : "end",
+ reg,
+ nameIndex,
+ typeIndex,
+ signatureIndex);
+ }
+ }
- /** line number */
- public int line;
+ /**
+ * Gets the decoded positions list.
+ * Valid after calling {@code decode}.
+ *
+ * @return positions list in ascending address order.
+ */
+ public List<PositionEntry> getPositionList() {
+ return positions;
+ }
- public PositionEntry(int address, int line) {
- this.address = address;
- this.line = line;
- }
+ /**
+ * Gets the decoded locals list, in ascending start-address order.
+ * Valid after calling {@code decode}.
+ *
+ * @return locals list in ascending address order.
+ */
+ public List<LocalEntry> getLocals() {
+ return locals;
+ }
+
+ /**
+ * Decodes the debug info sequence.
+ */
+ public void decode() {
+ try {
+ decode0();
+ } catch (Exception ex) {
+ throw ExceptionWithContext.withContext(ex, "...while decoding debug info");
+ }
+ }
+
+ /**
+ * Reads a string index. String indicies are offset by 1, and a 0 value
+ * in the stream (-1 as returned by this method) means "null"
+ *
+ * @return index into file's string ids table, -1 means null
+ * @throws IOException
+ */
+ private int readStringIndex(ByteInput bs) throws IOException {
+ int offsetIndex = Leb128Utils.readUnsignedLeb128(bs);
+
+ return offsetIndex - 1;
+ }
+
+ /**
+ * Gets the register that begins the method's parameter range (including
+ * the 'this' parameter for non-static methods). The range continues until
+ * {@code regSize}
+ *
+ * @return register as noted above.
+ */
+ private int getParamBase() {
+ return regSize - desc.getParameterTypes().getWordCount() - (isStatic ? 0 : 1);
+ }
+
+ private void decode0() throws IOException {
+ line = Leb128Utils.readUnsignedLeb128(encoded);
+ int szParams = Leb128Utils.readUnsignedLeb128(encoded);
+ StdTypeList params = desc.getParameterTypes();
+ int curReg = getParamBase();
+
+ if (szParams != params.size()) {
+ throw new RuntimeException("Mismatch between parameters_size and prototype");
}
- /**
- * An entry in the resulting locals table
- */
- static public class LocalEntry {
- /** address of event */
- public int address;
-
- /** {@code true} iff it's a local start */
- public boolean isStart;
-
- /** register number */
- public int reg;
-
- /** index of name in strings table */
- public int nameIndex;
-
- /** index of type in types table */
- public int typeIndex;
-
- /** index of type signature in strings table */
- public int signatureIndex;
-
- public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
- int typeIndex, int signatureIndex) {
- this.address = address;
- this.isStart = isStart;
- this.reg = reg;
- this.nameIndex = nameIndex;
- this.typeIndex = typeIndex;
- this.signatureIndex = signatureIndex;
- }
-
- public String toString() {
- return String.format("[%x %s v%d %04x %04x %04x]",
- address, isStart ? "start" : "end", reg,
- nameIndex, typeIndex, signatureIndex);
- }
+ if (!isStatic) {
+ // Start off with implicit 'this' entry
+ LocalEntry thisEntry =
+ new LocalEntry(0, true, curReg, thisStringIdx, ClassDef.NO_INDEX, ClassDef.NO_INDEX);
+ locals.add(thisEntry);
+ lastEntryForReg[curReg] = thisEntry;
+ curReg++;
}
- /**
- * Gets the decoded positions list.
- * Valid after calling {@code decode}.
- *
- * @return positions list in ascending address order.
- */
- public List<PositionEntry> getPositionList() {
- return positions;
- }
+ for (int i = 0; i < szParams; i++) {
+ Type paramType = params.getType(i);
+ LocalEntry le;
- /**
- * Gets the decoded locals list, in ascending start-address order.
- * Valid after calling {@code decode}.
- *
- * @return locals list in ascending address order.
- */
- public List<LocalEntry> getLocals() {
- return locals;
- }
+ int nameIdx = readStringIndex(encoded);
- /**
- * Decodes the debug info sequence.
- */
- public void decode() {
- try {
- decode0();
- } catch (Exception ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while decoding debug info");
- }
- }
-
- /**
- * Reads a string index. String indicies are offset by 1, and a 0 value
- * in the stream (-1 as returned by this method) means "null"
- *
- * @return index into file's string ids table, -1 means null
- * @throws IOException
- */
- private int readStringIndex(ByteInput bs) throws IOException {
- int offsetIndex = Leb128Utils.readUnsignedLeb128(bs);
-
- return offsetIndex - 1;
- }
-
- /**
- * Gets the register that begins the method's parameter range (including
- * the 'this' parameter for non-static methods). The range continues until
- * {@code regSize}
- *
- * @return register as noted above.
- */
- private int getParamBase() {
- return regSize
- - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
- }
-
- private void decode0() throws IOException {
- line = Leb128Utils.readUnsignedLeb128(encoded);
- int szParams = Leb128Utils.readUnsignedLeb128(encoded);
- StdTypeList params = desc.getParameterTypes();
- int curReg = getParamBase();
-
- if (szParams != params.size()) {
- throw new RuntimeException(
- "Mismatch between parameters_size and prototype");
- }
-
- if (!isStatic) {
- // Start off with implicit 'this' entry
- LocalEntry thisEntry =
- new LocalEntry(0, true, curReg, thisStringIdx, ClassDef.NO_INDEX,
- ClassDef.NO_INDEX);
- locals.add(thisEntry);
- lastEntryForReg[curReg] = thisEntry;
- curReg++;
- }
-
- for (int i = 0; i < szParams; i++) {
- Type paramType = params.getType(i);
- LocalEntry le;
-
- int nameIdx = readStringIndex(encoded);
-
- if (nameIdx == -1) {
- /*
- * Unnamed parameter; often but not always filled in by an
- * extended start op after the prologue
- */
- le = new LocalEntry(0, true, curReg, ClassDef.NO_INDEX, ClassDef.NO_INDEX,
- ClassDef.NO_INDEX);
- } else {
- // TODO: Final 0 should be idx of paramType.getDescriptor().
- le = new LocalEntry(0, true, curReg, nameIdx, ClassDef.NO_INDEX, ClassDef.NO_INDEX);
- }
-
- locals.add(le);
- lastEntryForReg[curReg] = le;
- curReg += paramType.getCategory();
- }
-
- for (;;) {
- int opcode = encoded.readByte() & 0xff;
-
- switch (opcode) {
- case DBG_START_LOCAL: {
- int reg = Leb128Utils.readUnsignedLeb128(encoded);
- int nameIdx = readStringIndex(encoded);
- int typeIdx = readStringIndex(encoded);
- LocalEntry le = new LocalEntry(
- address, true, reg, nameIdx, typeIdx, ClassDef.NO_INDEX);
-
- locals.add(le);
- lastEntryForReg[reg] = le;
- }
- break;
-
- case DBG_START_LOCAL_EXTENDED: {
- int reg = Leb128Utils.readUnsignedLeb128(encoded);
- int nameIdx = readStringIndex(encoded);
- int typeIdx = readStringIndex(encoded);
- int sigIdx = readStringIndex(encoded);
- LocalEntry le = new LocalEntry(
- address, true, reg, nameIdx, typeIdx, sigIdx);
-
- locals.add(le);
- lastEntryForReg[reg] = le;
- }
- break;
-
- case DBG_RESTART_LOCAL: {
- int reg = Leb128Utils.readUnsignedLeb128(encoded);
- LocalEntry prevle;
- LocalEntry le;
-
- try {
- prevle = lastEntryForReg[reg];
-
- if (prevle.isStart) {
- throw new RuntimeException("nonsensical "
- + "RESTART_LOCAL on live register v"
- + reg);
- }
-
- le = new LocalEntry(address, true, reg,
- prevle.nameIndex, prevle.typeIndex, prevle.signatureIndex);
- } catch (NullPointerException ex) {
- throw new RuntimeException(
- "Encountered RESTART_LOCAL on new v" + reg);
- }
-
- locals.add(le);
- lastEntryForReg[reg] = le;
- }
- break;
-
- case DBG_END_LOCAL: {
- int reg = Leb128Utils.readUnsignedLeb128(encoded);
- LocalEntry prevle;
- LocalEntry le;
-
- try {
- prevle = lastEntryForReg[reg];
-
- if (!prevle.isStart) {
- throw new RuntimeException("nonsensical "
- + "END_LOCAL on dead register v" + reg);
- }
-
- le = new LocalEntry(address, false, reg,
- prevle.nameIndex, prevle.typeIndex,
- prevle.signatureIndex);
- } catch (NullPointerException ex) {
- throw new RuntimeException(
- "Encountered END_LOCAL on new v" + reg);
- }
-
- locals.add(le);
- lastEntryForReg[reg] = le;
- }
- break;
-
- case DBG_END_SEQUENCE:
- // all done
- return;
-
- case DBG_ADVANCE_PC:
- address += Leb128Utils.readUnsignedLeb128(encoded);
- break;
-
- case DBG_ADVANCE_LINE:
- line += Leb128Utils.readSignedLeb128(encoded);
- break;
-
- case DBG_SET_PROLOGUE_END:
- //TODO do something with this.
- break;
-
- case DBG_SET_EPILOGUE_BEGIN:
- //TODO do something with this.
- break;
-
- case DBG_SET_FILE:
- //TODO do something with this.
- break;
-
- default:
- if (opcode < DBG_FIRST_SPECIAL) {
- throw new RuntimeException(
- "Invalid extended opcode encountered "
- + opcode);
- }
-
- int adjopcode = opcode - DBG_FIRST_SPECIAL;
-
- address += adjopcode / DBG_LINE_RANGE;
- line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
-
- positions.add(new PositionEntry(address, line));
- break;
-
- }
- }
- }
-
- /**
- * Validates an encoded debug info stream against data used to encode it,
- * throwing an exception if they do not match. Used to validate the
- * encoder.
- *
- * @param info encoded debug info
- * @param file {@code non-null;} file to refer to during decoding
- * @param ref {@code non-null;} method whose info is being decoded
- * @param code {@code non-null;} original code object that was encoded
- * @param isStatic whether the method is static
- */
- public static void validateEncode(byte[] info, DexFile file,
- CstMethodRef ref, DalvCode code, boolean isStatic) {
- PositionList pl = code.getPositions();
- LocalList ll = code.getLocals();
- DalvInsnList insns = code.getInsns();
- int countRegisters = insns.getRegistersSize();
-
- try {
- validateEncode0(info, countRegisters,
- isStatic, ref, file, pl, ll);
- } catch (RuntimeException ex) {
- System.err.println("instructions:");
- insns.debugPrint(System.err, " ", true);
- System.err.println("local list:");
- ll.debugPrint(System.err, " ");
- throw ExceptionWithContext.withContext(ex,
- "while processing " + ref.toHuman());
- }
- }
-
- private static void validateEncode0(byte[] info,
- int countRegisters, boolean isStatic, CstMethodRef ref,
- DexFile file, PositionList pl, LocalList ll) {
- DebugInfoDecoder decoder
- = new DebugInfoDecoder(info, countRegisters,
- isStatic, ref, file);
-
- decoder.decode();
-
+ if (nameIdx == -1) {
/*
- * Go through the decoded position entries, matching up
- * with original entries.
+ * Unnamed parameter; often but not always filled in by an
+ * extended start op after the prologue
*/
+ le = new LocalEntry(0,
+ true,
+ curReg,
+ ClassDef.NO_INDEX,
+ ClassDef.NO_INDEX,
+ ClassDef.NO_INDEX);
+ } else {
+ // TODO(dx team): Final 0 should be idx of paramType.getDescriptor().
+ le = new LocalEntry(0, true, curReg, nameIdx, ClassDef.NO_INDEX, ClassDef.NO_INDEX);
+ }
- List<PositionEntry> decodedEntries = decoder.getPositionList();
-
- if (decodedEntries.size() != pl.size()) {
- throw new RuntimeException(
- "Decoded positions table not same size was "
- + decodedEntries.size() + " expected " + pl.size());
- }
-
- for (PositionEntry entry : decodedEntries) {
- boolean found = false;
- for (int i = pl.size() - 1; i >= 0; i--) {
- PositionList.Entry ple = pl.get(i);
-
- if (entry.line == ple.getPosition().getLine()
- && entry.address == ple.getAddress()) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- throw new RuntimeException ("Could not match position entry: "
- + entry.address + ", " + entry.line);
- }
- }
-
- /*
- * Go through the original local list, in order, matching up
- * with decoded entries.
- */
-
- List<LocalEntry> decodedLocals = decoder.getLocals();
- int thisStringIdx = decoder.thisStringIdx;
- int decodedSz = decodedLocals.size();
- int paramBase = decoder.getParamBase();
-
- /*
- * Preflight to fill in any parameters that were skipped in
- * the prologue (including an implied "this") but then
- * identified by full signature.
- */
- for (int i = 0; i < decodedSz; i++) {
- LocalEntry entry = decodedLocals.get(i);
- int idx = entry.nameIndex;
-
- if ((idx < 0) || (idx == thisStringIdx)) {
- for (int j = i + 1; j < decodedSz; j++) {
- LocalEntry e2 = decodedLocals.get(j);
- if (e2.address != 0) {
- break;
- }
- if ((entry.reg == e2.reg) && e2.isStart) {
- decodedLocals.set(i, e2);
- decodedLocals.remove(j);
- decodedSz--;
- break;
- }
- }
- }
- }
-
- int origSz = ll.size();
- int decodeAt = 0;
- boolean problem = false;
-
- for (int i = 0; i < origSz; i++) {
- LocalList.Entry origEntry = ll.get(i);
-
- if (origEntry.getDisposition()
- == LocalList.Disposition.END_REPLACED) {
- /*
- * The encoded list doesn't represent replacements, so
- * ignore them for the sake of comparison.
- */
- continue;
- }
-
- LocalEntry decodedEntry;
-
- do {
- decodedEntry = decodedLocals.get(decodeAt);
- if (decodedEntry.nameIndex >= 0) {
- break;
- }
- /*
- * A negative name index means this is an anonymous
- * parameter, and we shouldn't expect to see it in the
- * original list. So, skip it.
- */
- decodeAt++;
- } while (decodeAt < decodedSz);
-
- int decodedAddress = decodedEntry.address;
-
- if (decodedEntry.reg != origEntry.getRegister()) {
- System.err.println("local register mismatch at orig " + i +
- " / decoded " + decodeAt);
- problem = true;
- break;
- }
-
- if (decodedEntry.isStart != origEntry.isStart()) {
- System.err.println("local start/end mismatch at orig " + i +
- " / decoded " + decodeAt);
- problem = true;
- break;
- }
-
- /*
- * The secondary check here accounts for the fact that a
- * parameter might not be marked as starting at 0 in the
- * original list.
- */
- if ((decodedAddress != origEntry.getAddress())
- && !((decodedAddress == 0)
- && (decodedEntry.reg >= paramBase))) {
- System.err.println("local address mismatch at orig " + i +
- " / decoded " + decodeAt);
- problem = true;
- break;
- }
-
- decodeAt++;
- }
-
- if (problem) {
- System.err.println("decoded locals:");
- for (LocalEntry e : decodedLocals) {
- System.err.println(" " + e);
- }
- throw new RuntimeException("local table problem");
- }
+ locals.add(le);
+ lastEntryForReg[curReg] = le;
+ curReg += paramType.getCategory();
}
- private static int extractThisIdx(DexFile file) {
- int idx = -1;
+ for (;;) {
+ int opcode = encoded.readByte() & 0xff;
- try {
- idx = file.getStringIds().indexOf(new CstString("this"));
- } catch (IllegalArgumentException ex) {
- /*
- * Silently tolerate not finding "this". It just means that
- * no method has local variable info that looks like
- * a standard instance method.
- */
+ switch (opcode) {
+ case DBG_START_LOCAL: {
+ int reg = Leb128Utils.readUnsignedLeb128(encoded);
+ int nameIdx = readStringIndex(encoded);
+ int typeIdx = readStringIndex(encoded);
+ LocalEntry le = new LocalEntry(address, true, reg, nameIdx, typeIdx, ClassDef.NO_INDEX);
+
+ locals.add(le);
+ lastEntryForReg[reg] = le;
}
- return idx;
+ break;
+
+ case DBG_START_LOCAL_EXTENDED: {
+ int reg = Leb128Utils.readUnsignedLeb128(encoded);
+ int nameIdx = readStringIndex(encoded);
+ int typeIdx = readStringIndex(encoded);
+ int sigIdx = readStringIndex(encoded);
+ LocalEntry le = new LocalEntry(address, true, reg, nameIdx, typeIdx, sigIdx);
+
+ locals.add(le);
+ lastEntryForReg[reg] = le;
+ }
+ break;
+
+ case DBG_RESTART_LOCAL: {
+ int reg = Leb128Utils.readUnsignedLeb128(encoded);
+ LocalEntry prevle;
+ LocalEntry le;
+
+ try {
+ prevle = lastEntryForReg[reg];
+
+ if (prevle.isStart) {
+ throw new RuntimeException("nonsensical " + "RESTART_LOCAL on live register v" + reg);
+ }
+
+ le = new LocalEntry(address,
+ true,
+ reg,
+ prevle.nameIndex,
+ prevle.typeIndex,
+ prevle.signatureIndex);
+ } catch (NullPointerException ex) {
+ throw new RuntimeException("Encountered RESTART_LOCAL on new v" + reg);
+ }
+
+ locals.add(le);
+ lastEntryForReg[reg] = le;
+ }
+ break;
+
+ case DBG_END_LOCAL: {
+ int reg = Leb128Utils.readUnsignedLeb128(encoded);
+ LocalEntry prevle;
+ LocalEntry le;
+
+ try {
+ prevle = lastEntryForReg[reg];
+
+ if (!prevle.isStart) {
+ throw new RuntimeException("nonsensical " + "END_LOCAL on dead register v" + reg);
+ }
+
+ le = new LocalEntry(address,
+ false,
+ reg,
+ prevle.nameIndex,
+ prevle.typeIndex,
+ prevle.signatureIndex);
+ } catch (NullPointerException ex) {
+ throw new RuntimeException("Encountered END_LOCAL on new v" + reg);
+ }
+
+ locals.add(le);
+ lastEntryForReg[reg] = le;
+ }
+ break;
+
+ case DBG_END_SEQUENCE:
+ // all done
+ return;
+
+ case DBG_ADVANCE_PC:
+ address += Leb128Utils.readUnsignedLeb128(encoded);
+ break;
+
+ case DBG_ADVANCE_LINE:
+ line += Leb128Utils.readSignedLeb128(encoded);
+ break;
+
+ case DBG_SET_PROLOGUE_END:
+ //TODO(dx team) do something with this.
+ break;
+
+ case DBG_SET_EPILOGUE_BEGIN:
+ //TODO(dx team) do something with this.
+ break;
+
+ case DBG_SET_FILE:
+ //TODO(dx team) do something with this.
+ break;
+
+ default:
+ if (opcode < DBG_FIRST_SPECIAL) {
+ throw new RuntimeException("Invalid extended opcode encountered " + opcode);
+ }
+
+ int adjopcode = opcode - DBG_FIRST_SPECIAL;
+
+ address += adjopcode / DBG_LINE_RANGE;
+ line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+ positions.add(new PositionEntry(address, line));
+ break;
+
+ }
}
+ }
+
+ /**
+ * Validates an encoded debug info stream against data used to encode it,
+ * throwing an exception if they do not match. Used to validate the
+ * encoder.
+ *
+ * @param info encoded debug info
+ * @param file {@code non-null;} file to refer to during decoding
+ * @param ref {@code non-null;} method whose info is being decoded
+ * @param code {@code non-null;} original code object that was encoded
+ * @param isStatic whether the method is static
+ */
+ public static void validateEncode(byte[] info, DexFile file, CstMethodRef ref, DalvCode code,
+ boolean isStatic) {
+ PositionList pl = code.getPositions();
+ LocalList ll = code.getLocals();
+ DalvInsnList insns = code.getInsns();
+ int countRegisters = insns.getRegistersSize();
+
+ try {
+ validateEncode0(info, countRegisters, isStatic, ref, file, pl, ll);
+ } catch (RuntimeException ex) {
+ System.err.println("instructions:");
+ insns.debugPrint(System.err, " ", true);
+ System.err.println("local list:");
+ ll.debugPrint(System.err, " ");
+ throw ExceptionWithContext.withContext(ex, "while processing " + ref.toHuman());
+ }
+ }
+
+ private static void validateEncode0(byte[] info,
+ int countRegisters,
+ boolean isStatic,
+ CstMethodRef ref,
+ DexFile file,
+ PositionList pl,
+ LocalList ll) {
+ DebugInfoDecoder decoder = new DebugInfoDecoder(info, countRegisters, isStatic, ref, file);
+
+ decoder.decode();
+
+ /*
+ * Go through the decoded position entries, matching up
+ * with original entries.
+ */
+
+List<PositionEntry> decodedEntries = decoder.getPositionList();
+
+ if (decodedEntries.size() != pl.size()) {
+ throw new RuntimeException("Decoded positions table not same size was "
+ + decodedEntries.size() + " expected " + pl.size());
+ }
+
+ for (PositionEntry entry : decodedEntries) {
+ boolean found = false;
+ for (int i = pl.size() - 1; i >= 0; i--) {
+ PositionList.Entry ple = pl.get(i);
+
+ if (entry.line == ple.getPosition().getLine() && entry.address == ple.getAddress()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ throw new RuntimeException(
+ "Could not match position entry: " + entry.address + ", " + entry.line);
+ }
+ }
+
+ /*
+ * Go through the original local list, in order, matching up
+ * with decoded entries.
+ */
+
+List<LocalEntry> decodedLocals = decoder.getLocals();
+ int thisStringIdx = decoder.thisStringIdx;
+ int decodedSz = decodedLocals.size();
+ int paramBase = decoder.getParamBase();
+
+ /*
+ * Preflight to fill in any parameters that were skipped in
+ * the prologue (including an implied "this") but then
+ * identified by full signature.
+ */
+ for (int i = 0; i < decodedSz; i++) {
+ LocalEntry entry = decodedLocals.get(i);
+ int idx = entry.nameIndex;
+
+ if ((idx < 0) || (idx == thisStringIdx)) {
+ for (int j = i + 1; j < decodedSz; j++) {
+ LocalEntry e2 = decodedLocals.get(j);
+ if (e2.address != 0) {
+ break;
+ }
+ if ((entry.reg == e2.reg) && e2.isStart) {
+ decodedLocals.set(i, e2);
+ decodedLocals.remove(j);
+ decodedSz--;
+ break;
+ }
+ }
+ }
+ }
+
+ int origSz = ll.size();
+ int decodeAt = 0;
+ boolean problem = false;
+
+ for (int i = 0; i < origSz; i++) {
+ LocalList.Entry origEntry = ll.get(i);
+
+ if (origEntry.getDisposition() == LocalList.Disposition.END_REPLACED) {
+ /*
+ * The encoded list doesn't represent replacements, so
+ * ignore them for the sake of comparison.
+ */
+ continue;
+ }
+
+ LocalEntry decodedEntry;
+
+ do {
+ decodedEntry = decodedLocals.get(decodeAt);
+ if (decodedEntry.nameIndex >= 0) {
+ break;
+ }
+ /*
+ * A negative name index means this is an anonymous
+ * parameter, and we shouldn't expect to see it in the
+ * original list. So, skip it.
+ */
+ decodeAt++;
+ } while (decodeAt < decodedSz);
+
+ int decodedAddress = decodedEntry.address;
+
+ if (decodedEntry.reg != origEntry.getRegister()) {
+ System.err.println("local register mismatch at orig " + i + " / decoded " + decodeAt);
+ problem = true;
+ break;
+ }
+
+ if (decodedEntry.isStart != origEntry.isStart()) {
+ System.err.println("local start/end mismatch at orig " + i + " / decoded " + decodeAt);
+ problem = true;
+ break;
+ }
+
+ /*
+ * The secondary check here accounts for the fact that a
+ * parameter might not be marked as starting at 0 in the
+ * original list.
+ */
+ if ((decodedAddress != origEntry.getAddress())
+ && !((decodedAddress == 0) && (decodedEntry.reg >= paramBase))) {
+ System.err.println("local address mismatch at orig " + i + " / decoded " + decodeAt);
+ problem = true;
+ break;
+ }
+
+ decodeAt++;
+ }
+
+ if (problem) {
+ System.err.println("decoded locals:");
+ for (LocalEntry e : decodedLocals) {
+ System.err.println(" " + e);
+ }
+ throw new RuntimeException("local table problem");
+ }
+ }
+
+ private static int extractThisIdx(DexFile file) {
+ int idx = -1;
+
+ try {
+ idx = file.getStringIds().indexOf(new CstString("this"));
+ } catch (IllegalArgumentException ex) {
+ /*
+ * Silently tolerate not finding "this". It just means that
+ * no method has local variable info that looks like
+ * a standard instance method.
+ */
+ }
+ return idx;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/DebugInfoEncoder.java b/dx/src/com/android/jack/dx/dex/file/DebugInfoEncoder.java
index 026d0c0..725200d 100644
--- a/dx/src/com/android/jack/dx/dex/file/DebugInfoEncoder.java
+++ b/dx/src/com/android/jack/dx/dex/file/DebugInfoEncoder.java
@@ -16,6 +16,18 @@
package com.android.jack.dx.dex.file;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_LINE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_PC;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_END_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_END_SEQUENCE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_FIRST_SPECIAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_LINE_BASE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_LINE_RANGE;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_RESTART_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_SET_PROLOGUE_END;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL;
+import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL_EXTENDED;
+
import com.android.jack.dx.dex.code.LocalList;
import com.android.jack.dx.dex.code.PositionList;
import com.android.jack.dx.rop.code.RegisterSpec;
@@ -33,11 +45,9 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
-import java.util.BitSet;
-
-import static com.android.jack.dx.dex.file.DebugInfoConstants.*;
/**
* An encoder for the dex debug info state machine format. The format
@@ -53,868 +63,842 @@
* </ol>
*/
public final class DebugInfoEncoder {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = false;
- /** {@code null-ok;} positions (line numbers) to encode */
- private final PositionList positions;
+ /** {@code null-ok;} positions (line numbers) to encode */
+ private final PositionList positions;
- /** {@code null-ok;} local variables to encode */
- private final LocalList locals;
+ /** {@code null-ok;} local variables to encode */
+ private final LocalList locals;
- private final ByteArrayAnnotatedOutput output;
- private final DexFile file;
- private final int codeSize;
- private final int regSize;
+ private final ByteArrayAnnotatedOutput output;
+ private final DexFile file;
+ private final int codeSize;
+ private final int regSize;
- private final Prototype desc;
- private final boolean isStatic;
+ private final Prototype desc;
+ private final boolean isStatic;
- /** current encoding state: bytecode address */
- private int address = 0;
+ /** current encoding state: bytecode address */
+ private int address = 0;
- /** current encoding state: line number */
- private int line = 1;
+ /** current encoding state: line number */
+ private int line = 1;
- /**
- * if non-null: the output to write annotations to. No normal
- * output is written to this.
- */
- private AnnotatedOutput annotateTo;
+ /**
+ * if non-null: the output to write annotations to. No normal
+ * output is written to this.
+ */
+ private AnnotatedOutput annotateTo;
- /** if non-null: another possible output for annotations */
- private PrintWriter debugPrint;
+ /** if non-null: another possible output for annotations */
+ private PrintWriter debugPrint;
- /** if non-null: the prefix for each annotation or debugPrint line */
- private String prefix;
+ /** if non-null: the prefix for each annotation or debugPrint line */
+ private String prefix;
- /** true if output should be consumed during annotation */
- private boolean shouldConsume;
+ /** true if output should be consumed during annotation */
+ private boolean shouldConsume;
- /** indexed by register; last local alive in register */
- private final LocalList.Entry[] lastEntryForReg;
+ /** indexed by register; last local alive in register */
+ private final LocalList.Entry[] lastEntryForReg;
- /**
- * Creates an instance.
- *
- * @param positions {@code null-ok;} positions (line numbers) to encode
- * @param locals {@code null-ok;} local variables to encode
- * @param file {@code null-ok;} may only be {@code null} if simply using
- * this class to do a debug print
- * @param codeSize
- * @param regSize
- * @param isStatic
- * @param ref
- */
- public DebugInfoEncoder(PositionList positions, LocalList locals,
- DexFile file, int codeSize, int regSize,
- boolean isStatic, CstMethodRef ref) {
- this.positions = positions;
- this.locals = locals;
- this.file = file;
- this.desc = ref.getPrototype();
- this.isStatic = isStatic;
- this.codeSize = codeSize;
- this.regSize = regSize;
+ /**
+ * Creates an instance.
+ *
+ * @param positions {@code null-ok;} positions (line numbers) to encode
+ * @param locals {@code null-ok;} local variables to encode
+ * @param file {@code null-ok;} may only be {@code null} if simply using
+ * this class to do a debug print
+ * @param codeSize
+ * @param regSize
+ * @param isStatic
+ * @param ref
+ */
+ public DebugInfoEncoder(PositionList positions,
+ LocalList locals,
+ DexFile file,
+ int codeSize,
+ int regSize,
+ boolean isStatic,
+ CstMethodRef ref) {
+ this.positions = positions;
+ this.locals = locals;
+ this.file = file;
+ this.desc = ref.getPrototype();
+ this.isStatic = isStatic;
+ this.codeSize = codeSize;
+ this.regSize = regSize;
- output = new ByteArrayAnnotatedOutput();
- lastEntryForReg = new LocalList.Entry[regSize];
+ output = new ByteArrayAnnotatedOutput();
+ lastEntryForReg = new LocalList.Entry[regSize];
+ }
+
+ /**
+ * Annotates or writes a message to the {@code debugPrint} writer
+ * if applicable.
+ *
+ * @param length the number of bytes associated with this message
+ * @param message the message itself
+ */
+ private void annotate(int length, String message) {
+ if (prefix != null) {
+ message = prefix + message;
}
- /**
- * Annotates or writes a message to the {@code debugPrint} writer
- * if applicable.
- *
- * @param length the number of bytes associated with this message
- * @param message the message itself
- */
- private void annotate(int length, String message) {
- if (prefix != null) {
- message = prefix + message;
- }
-
- if (annotateTo != null) {
- annotateTo.annotate(shouldConsume ? length : 0, message);
- }
-
- if (debugPrint != null) {
- debugPrint.println(message);
- }
+ if (annotateTo != null) {
+ annotateTo.annotate(shouldConsume ? length : 0, message);
}
- /**
- * Converts this (PositionList, LocalList) pair into a state machine
- * sequence.
- *
- * @return {@code non-null;} encoded byte sequence without padding and
- * terminated with a {@code 0x00} byte
- */
- public byte[] convert() {
- try {
- byte[] ret;
- ret = convert0();
+ if (debugPrint != null) {
+ debugPrint.println(message);
+ }
+ }
- if (DEBUG) {
- for (int i = 0 ; i < ret.length; i++) {
- System.err.printf("byte %02x\n", (0xff & ret[i]));
- }
- }
+ /**
+ * Converts this (PositionList, LocalList) pair into a state machine
+ * sequence.
+ *
+ * @return {@code non-null;} encoded byte sequence without padding and
+ * terminated with a {@code 0x00} byte
+ */
+ public byte[] convert() {
+ try {
+ byte[] ret;
+ ret = convert0();
- return ret;
- } catch (IOException ex) {
- throw ExceptionWithContext
- .withContext(ex, "...while encoding debug info");
+ if (DEBUG) {
+ for (int i = 0; i < ret.length; i++) {
+ System.err.printf("byte %02x\n", (0xff & ret[i]));
}
+ }
+
+ return ret;
+ } catch (IOException ex) {
+ throw ExceptionWithContext.withContext(ex, "...while encoding debug info");
+ }
+ }
+
+ /**
+ * Converts and produces annotations on a stream. Does not write
+ * actual bits to the {@code AnnotatedOutput}.
+ *
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
+ * annotations
+ * @param out {@code null-ok;} if specified, where annotations should go
+ * @param consume whether to claim to have consumed output for
+ * {@code out}
+ * @return {@code non-null;} encoded output
+ */
+ public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint, AnnotatedOutput out,
+ boolean consume) {
+ this.prefix = prefix;
+ this.debugPrint = debugPrint;
+ annotateTo = out;
+ shouldConsume = consume;
+
+ byte[] result = convert();
+
+ return result;
+ }
+
+ private byte[] convert0() throws IOException {
+ ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
+ ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
+
+ emitHeader(sortedPositions, methodArgs);
+
+ // TODO(dx team): Make this mark be the actual prologue end.
+ output.writeByte(DBG_SET_PROLOGUE_END);
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(1, String.format("%04x: prologue end", address));
}
- /**
- * Converts and produces annotations on a stream. Does not write
- * actual bits to the {@code AnnotatedOutput}.
- *
- * @param prefix {@code null-ok;} prefix to attach to each line of output
- * @param debugPrint {@code null-ok;} if specified, an alternate output for
- * annotations
- * @param out {@code null-ok;} if specified, where annotations should go
- * @param consume whether to claim to have consumed output for
- * {@code out}
- * @return {@code non-null;} encoded output
- */
- public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint,
- AnnotatedOutput out, boolean consume) {
- this.prefix = prefix;
- this.debugPrint = debugPrint;
- annotateTo = out;
- shouldConsume = consume;
+ int positionsSz = sortedPositions.size();
+ int localsSz = locals.size();
- byte[] result = convert();
+ // Current index in sortedPositions
+ int curPositionIdx = 0;
+ // Current index in locals
+ int curLocalIdx = 0;
- return result;
+ for (;;) {
+ /*
+ * Emit any information for the current address.
+ */
+
+curLocalIdx = emitLocalsAtAddress(curLocalIdx);
+ curPositionIdx = emitPositionsAtAddress(curPositionIdx, sortedPositions);
+
+ /*
+ * Figure out what the next important address is.
+ */
+
+int nextAddrL = Integer.MAX_VALUE; // local variable
+ int nextAddrP = Integer.MAX_VALUE; // position (line number)
+
+ if (curLocalIdx < localsSz) {
+ nextAddrL = locals.get(curLocalIdx).getAddress();
+ }
+
+ if (curPositionIdx < positionsSz) {
+ nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
+ }
+
+ int next = Math.min(nextAddrP, nextAddrL);
+
+ // No next important address == done.
+ if (next == Integer.MAX_VALUE) {
+ break;
+ }
+
+ /*
+ * If the only work remaining are local ends at the end of the
+ * block, stop here. Those are implied anyway.
+ */
+ if (next == codeSize && nextAddrL == Integer.MAX_VALUE && nextAddrP == Integer.MAX_VALUE) {
+ break;
+ }
+
+ if (next == nextAddrP) {
+ // Combined advance PC + position entry
+ emitPosition(sortedPositions.get(curPositionIdx++));
+ } else {
+ emitAdvancePc(next - address);
+ }
}
- private byte[] convert0() throws IOException {
- ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
- ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
+ emitEndSequence();
- emitHeader(sortedPositions, methodArgs);
+ return output.toByteArray();
+ }
- // TODO: Make this mark be the actual prologue end.
- output.writeByte(DBG_SET_PROLOGUE_END);
+ /**
+ * Emits all local variable activity that occurs at the current
+ * {@link #address} starting at the given index into {@code
+ * locals} and including all subsequent activity at the same
+ * address.
+ *
+ * @param curLocalIdx Current index in locals
+ * @return new value for {@code curLocalIdx}
+ * @throws IOException
+ */
+ private int emitLocalsAtAddress(int curLocalIdx) throws IOException {
+ int sz = locals.size();
- if (annotateTo != null || debugPrint != null) {
- annotate(1, String.format("%04x: prologue end",address));
- }
+ // TODO(dx team): Don't emit ends implied by starts.
- int positionsSz = sortedPositions.size();
- int localsSz = locals.size();
+ while ((curLocalIdx < sz) && (locals.get(curLocalIdx).getAddress() == address)) {
+ LocalList.Entry entry = locals.get(curLocalIdx++);
+ int reg = entry.getRegister();
+ LocalList.Entry prevEntry = lastEntryForReg[reg];
- // Current index in sortedPositions
- int curPositionIdx = 0;
- // Current index in locals
- int curLocalIdx = 0;
-
- for (;;) {
- /*
- * Emit any information for the current address.
- */
-
- curLocalIdx = emitLocalsAtAddress(curLocalIdx);
- curPositionIdx =
- emitPositionsAtAddress(curPositionIdx, sortedPositions);
-
- /*
- * Figure out what the next important address is.
- */
-
- int nextAddrL = Integer.MAX_VALUE; // local variable
- int nextAddrP = Integer.MAX_VALUE; // position (line number)
-
- if (curLocalIdx < localsSz) {
- nextAddrL = locals.get(curLocalIdx).getAddress();
- }
-
- if (curPositionIdx < positionsSz) {
- nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
- }
-
- int next = Math.min(nextAddrP, nextAddrL);
-
- // No next important address == done.
- if (next == Integer.MAX_VALUE) {
- break;
- }
-
- /*
- * If the only work remaining are local ends at the end of the
- * block, stop here. Those are implied anyway.
- */
- if (next == codeSize
- && nextAddrL == Integer.MAX_VALUE
- && nextAddrP == Integer.MAX_VALUE) {
- break;
- }
-
- if (next == nextAddrP) {
- // Combined advance PC + position entry
- emitPosition(sortedPositions.get(curPositionIdx++));
- } else {
- emitAdvancePc(next - address);
- }
- }
-
- emitEndSequence();
-
- return output.toByteArray();
- }
-
- /**
- * Emits all local variable activity that occurs at the current
- * {@link #address} starting at the given index into {@code
- * locals} and including all subsequent activity at the same
- * address.
- *
- * @param curLocalIdx Current index in locals
- * @return new value for {@code curLocalIdx}
- * @throws IOException
- */
- private int emitLocalsAtAddress(int curLocalIdx)
- throws IOException {
- int sz = locals.size();
-
- // TODO: Don't emit ends implied by starts.
-
- while ((curLocalIdx < sz)
- && (locals.get(curLocalIdx).getAddress() == address)) {
- LocalList.Entry entry = locals.get(curLocalIdx++);
- int reg = entry.getRegister();
- LocalList.Entry prevEntry = lastEntryForReg[reg];
-
- if (entry == prevEntry) {
- /*
- * Here we ignore locals entries for parameters,
- * which have already been represented and placed in the
- * lastEntryForReg array.
- */
- continue;
- }
-
- // At this point we have a new entry one way or another.
- lastEntryForReg[reg] = entry;
-
- if (entry.isStart()) {
- if ((prevEntry != null) && entry.matches(prevEntry)) {
- /*
- * The previous local in this register has the same
- * name and type as the one being introduced now, so
- * use the more efficient "restart" form.
- */
- if (prevEntry.isStart()) {
- /*
- * We should never be handed a start when a
- * a matching local is already active.
- */
- throw new RuntimeException("shouldn't happen");
- }
- emitLocalRestart(entry);
- } else {
- emitLocalStart(entry);
- }
- } else {
- /*
- * Only emit a local end if it is *not* due to a direct
- * replacement. Direct replacements imply an end of the
- * previous local in the same register.
- *
- * TODO: Make sure the runtime can deal with implied
- * local ends from category-2 interactions, and when so,
- * also stop emitting local ends for those cases.
- */
- if (entry.getDisposition()
- != LocalList.Disposition.END_REPLACED) {
- emitLocalEnd(entry);
- }
- }
- }
-
- return curLocalIdx;
- }
-
- /**
- * Emits all positions that occur at the current {@code address}
- *
- * @param curPositionIdx Current index in sortedPositions
- * @param sortedPositions positions, sorted by ascending address
- * @return new value for {@code curPositionIdx}
- * @throws IOException
- */
- private int emitPositionsAtAddress(int curPositionIdx,
- ArrayList<PositionList.Entry> sortedPositions)
- throws IOException {
- int positionsSz = sortedPositions.size();
- while ((curPositionIdx < positionsSz)
- && (sortedPositions.get(curPositionIdx).getAddress()
- == address)) {
- emitPosition(sortedPositions.get(curPositionIdx++));
- }
- return curPositionIdx;
- }
-
- /**
- * Emits the header sequence, which consists of LEB128-encoded initial
- * line number and string indicies for names of all non-"this" arguments.
- *
- * @param sortedPositions positions, sorted by ascending address
- * @param methodArgs local list entries for method argumens arguments,
- * in left-to-right order omitting "this"
- * @throws IOException
- */
- private void emitHeader(ArrayList<PositionList.Entry> sortedPositions,
- ArrayList<LocalList.Entry> methodArgs) throws IOException {
- boolean annotate = (annotateTo != null) || (debugPrint != null);
- int mark = output.getCursor();
-
- // Start by initializing the line number register.
- if (sortedPositions.size() > 0) {
- PositionList.Entry entry = sortedPositions.get(0);
- line = entry.getPosition().getLine();
- }
- output.writeUleb128(line);
-
- if (annotate) {
- annotate(output.getCursor() - mark, "line_start: " + line);
- }
-
- int curParam = getParamBase();
- // paramTypes will not include 'this'
- StdTypeList paramTypes = desc.getParameterTypes();
- int szParamTypes = paramTypes.size();
-
+ if (entry == prevEntry) {
/*
- * Initialize lastEntryForReg to have an initial
- * entry for the 'this' pointer.
+ * Here we ignore locals entries for parameters,
+ * which have already been represented and placed in the
+ * lastEntryForReg array.
*/
- if (!isStatic) {
- for (LocalList.Entry arg : methodArgs) {
- if (curParam == arg.getRegister()) {
- lastEntryForReg[curParam] = arg;
- break;
- }
- }
- curParam++;
+ continue;
+ }
+
+ // At this point we have a new entry one way or another.
+ lastEntryForReg[reg] = entry;
+
+ if (entry.isStart()) {
+ if ((prevEntry != null) && entry.matches(prevEntry)) {
+ /*
+ * The previous local in this register has the same
+ * name and type as the one being introduced now, so
+ * use the more efficient "restart" form.
+ */
+ if (prevEntry.isStart()) {
+ /*
+ * We should never be handed a start when a
+ * a matching local is already active.
+ */
+ throw new RuntimeException("shouldn't happen");
+ }
+ emitLocalRestart(entry);
+ } else {
+ emitLocalStart(entry);
}
-
- // Write out the number of parameter entries that will follow.
- mark = output.getCursor();
- output.writeUleb128(szParamTypes);
-
- if (annotate) {
- annotate(output.getCursor() - mark,
- String.format("parameters_size: %04x", szParamTypes));
- }
-
+ } else {
/*
- * Then emit the string indicies of all the method parameters.
- * Note that 'this', if applicable, is excluded.
+ * Only emit a local end if it is *not* due to a direct
+ * replacement. Direct replacements imply an end of the
+ * previous local in the same register.
+ *
+ * TODO(dx team): Make sure the runtime can deal with implied
+ * local ends from category-2 interactions, and when so,
+ * also stop emitting local ends for those cases.
*/
- for (int i = 0; i < szParamTypes; i++) {
- Type pt = paramTypes.get(i);
- LocalList.Entry found = null;
-
- mark = output.getCursor();
-
- for (LocalList.Entry arg : methodArgs) {
- if (curParam == arg.getRegister()) {
- found = arg;
-
- if (arg.getSignature() != null) {
- /*
- * Parameters with signatures will be re-emitted
- * in complete as LOCAL_START_EXTENDED's below.
- */
- emitStringIndex(null);
- } else {
- emitStringIndex(arg.getName());
- }
- lastEntryForReg[curParam] = arg;
-
- break;
- }
- }
-
- if (found == null) {
- /*
- * Emit a null symbol for "unnamed." This is common
- * for, e.g., synthesized methods and inner-class
- * this$0 arguments.
- */
- emitStringIndex(null);
- }
-
- if (annotate) {
- String parameterName
- = (found == null || found.getSignature() != null)
- ? "<unnamed>" : found.getName().toHuman();
- annotate(output.getCursor() - mark,
- "parameter " + parameterName + " "
- + RegisterSpec.PREFIX + curParam);
- }
-
- curParam += pt.getCategory();
+ if (entry.getDisposition() != LocalList.Disposition.END_REPLACED) {
+ emitLocalEnd(entry);
}
+ }
+ }
+ return curLocalIdx;
+ }
+
+ /**
+ * Emits all positions that occur at the current {@code address}
+ *
+ * @param curPositionIdx Current index in sortedPositions
+ * @param sortedPositions positions, sorted by ascending address
+ * @return new value for {@code curPositionIdx}
+ * @throws IOException
+ */
+ private int emitPositionsAtAddress(int curPositionIdx,
+ ArrayList<PositionList.Entry> sortedPositions) throws IOException {
+ int positionsSz = sortedPositions.size();
+ while ((curPositionIdx < positionsSz)
+ && (sortedPositions.get(curPositionIdx).getAddress() == address)) {
+ emitPosition(sortedPositions.get(curPositionIdx++));
+ }
+ return curPositionIdx;
+ }
+
+ /**
+ * Emits the header sequence, which consists of LEB128-encoded initial
+ * line number and string indicies for names of all non-"this" arguments.
+ *
+ * @param sortedPositions positions, sorted by ascending address
+ * @param methodArgs local list entries for method argumens arguments,
+ * in left-to-right order omitting "this"
+ * @throws IOException
+ */
+ private void emitHeader(ArrayList<PositionList.Entry> sortedPositions,
+ ArrayList<LocalList.Entry> methodArgs) throws IOException {
+ boolean annotate = (annotateTo != null) || (debugPrint != null);
+ int mark = output.getCursor();
+
+ // Start by initializing the line number register.
+ if (sortedPositions.size() > 0) {
+ PositionList.Entry entry = sortedPositions.get(0);
+ line = entry.getPosition().getLine();
+ }
+ output.writeUleb128(line);
+
+ if (annotate) {
+ annotate(output.getCursor() - mark, "line_start: " + line);
+ }
+
+ int curParam = getParamBase();
+ // paramTypes will not include 'this'
+ StdTypeList paramTypes = desc.getParameterTypes();
+ int szParamTypes = paramTypes.size();
+
+ /*
+ * Initialize lastEntryForReg to have an initial
+ * entry for the 'this' pointer.
+ */
+ if (!isStatic) {
+ for (LocalList.Entry arg : methodArgs) {
+ if (curParam == arg.getRegister()) {
+ lastEntryForReg[curParam] = arg;
+ break;
+ }
+ }
+ curParam++;
+ }
+
+ // Write out the number of parameter entries that will follow.
+ mark = output.getCursor();
+ output.writeUleb128(szParamTypes);
+
+ if (annotate) {
+ annotate(output.getCursor() - mark, String.format("parameters_size: %04x", szParamTypes));
+ }
+
+ /*
+ * Then emit the string indicies of all the method parameters.
+ * Note that 'this', if applicable, is excluded.
+ */
+ for (int i = 0; i < szParamTypes; i++) {
+ Type pt = paramTypes.get(i);
+ LocalList.Entry found = null;
+
+ mark = output.getCursor();
+
+ for (LocalList.Entry arg : methodArgs) {
+ if (curParam == arg.getRegister()) {
+ found = arg;
+
+ if (arg.getSignature() != null) {
+ /*
+ * Parameters with signatures will be re-emitted
+ * in complete as LOCAL_START_EXTENDED's below.
+ */
+ emitStringIndex(null);
+ } else {
+ emitStringIndex(arg.getName());
+ }
+ lastEntryForReg[curParam] = arg;
+
+ break;
+ }
+ }
+
+ if (found == null) {
/*
- * If anything emitted above has a type signature, emit it again as
- * a LOCAL_RESTART_EXTENDED
+ * Emit a null symbol for "unnamed." This is common
+ * for, e.g., synthesized methods and inner-class
+ * this$0 arguments.
*/
+ emitStringIndex(null);
+ }
- for (LocalList.Entry arg : lastEntryForReg) {
- if (arg == null) {
- continue;
- }
+ if (annotate) {
+ String parameterName = (found == null || found.getSignature() != null) ? "<unnamed>"
+ : found.getName().toHuman();
+ annotate(output.getCursor() - mark,
+ "parameter " + parameterName + " " + RegisterSpec.PREFIX + curParam);
+ }
- CstString signature = arg.getSignature();
-
- if (signature != null) {
- emitLocalStartExtended(arg);
- }
- }
+ curParam += pt.getCategory();
}
- /**
- * Builds a list of position entries, sorted by ascending address.
- *
- * @return A sorted positions list
+ /*
+ * If anything emitted above has a type signature, emit it again as
+ * a LOCAL_RESTART_EXTENDED
*/
- private ArrayList<PositionList.Entry> buildSortedPositions() {
- int sz = (positions == null) ? 0 : positions.size();
- ArrayList<PositionList.Entry> result = new ArrayList(sz);
- for (int i = 0; i < sz; i++) {
- result.add(positions.get(i));
- }
+for (LocalList.Entry arg : lastEntryForReg) {
+ if (arg == null) {
+ continue;
+ }
- // Sort ascending by address.
- Collections.sort (result, new Comparator<PositionList.Entry>() {
- public int compare (PositionList.Entry a, PositionList.Entry b) {
- return a.getAddress() - b.getAddress();
- }
+ CstString signature = arg.getSignature();
- public boolean equals (Object obj) {
- return obj == this;
- }
- });
- return result;
+ if (signature != null) {
+ emitLocalStartExtended(arg);
+ }
+ }
+ }
+
+ /**
+ * Builds a list of position entries, sorted by ascending address.
+ *
+ * @return A sorted positions list
+ */
+ private ArrayList<PositionList.Entry> buildSortedPositions() {
+ int sz = (positions == null) ? 0 : positions.size();
+ ArrayList<PositionList.Entry> result = new ArrayList<PositionList.Entry>(sz);
+
+ for (int i = 0; i < sz; i++) {
+ result.add(positions.get(i));
}
- /**
- * Gets the register that begins the method's parameter range (including
- * the 'this' parameter for non-static methods). The range continues until
- * {@code regSize}
- *
- * @return register as noted above
- */
- private int getParamBase() {
- return regSize
- - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
+ // Sort ascending by address.
+ Collections.sort(result, new Comparator<PositionList.Entry>() {
+ @Override
+ public int compare(PositionList.Entry a, PositionList.Entry b) {
+ return a.getAddress() - b.getAddress();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the register that begins the method's parameter range (including
+ * the 'this' parameter for non-static methods). The range continues until
+ * {@code regSize}
+ *
+ * @return register as noted above
+ */
+ private int getParamBase() {
+ return regSize - desc.getParameterTypes().getWordCount() - (isStatic ? 0 : 1);
+ }
+
+ /**
+ * Extracts method arguments from a locals list. These will be collected
+ * from the input list and sorted by ascending register in the
+ * returned list.
+ *
+ * @return list of non-{@code this} method argument locals,
+ * sorted by ascending register
+ */
+ private ArrayList<LocalList.Entry> extractMethodArguments() {
+ ArrayList<LocalList.Entry> result =
+ new ArrayList<LocalList.Entry>(desc.getParameterTypes().size());
+ int argBase = getParamBase();
+ BitSet seen = new BitSet(regSize - argBase);
+ int sz = locals.size();
+
+ for (int i = 0; i < sz; i++) {
+ LocalList.Entry e = locals.get(i);
+ int reg = e.getRegister();
+
+ if (reg < argBase) {
+ continue;
+ }
+
+ // only the lowest-start-address entry is included.
+ if (seen.get(reg - argBase)) {
+ continue;
+ }
+
+ seen.set(reg - argBase);
+ result.add(e);
}
- /**
- * Extracts method arguments from a locals list. These will be collected
- * from the input list and sorted by ascending register in the
- * returned list.
- *
- * @return list of non-{@code this} method argument locals,
- * sorted by ascending register
- */
- private ArrayList<LocalList.Entry> extractMethodArguments() {
- ArrayList<LocalList.Entry> result
- = new ArrayList(desc.getParameterTypes().size());
- int argBase = getParamBase();
- BitSet seen = new BitSet(regSize - argBase);
- int sz = locals.size();
+ // Sort by ascending register.
+ Collections.sort(result, new Comparator<LocalList.Entry>() {
+ @Override
+ public int compare(LocalList.Entry a, LocalList.Entry b) {
+ return a.getRegister() - b.getRegister();
+ }
- for (int i = 0; i < sz; i++) {
- LocalList.Entry e = locals.get(i);
- int reg = e.getRegister();
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+ });
- if (reg < argBase) {
- continue;
- }
+ return result;
+ }
- // only the lowest-start-address entry is included.
- if (seen.get(reg - argBase)) {
- continue;
- }
+ /**
+ * Returns a string representation of this LocalList entry that is
+ * appropriate for emitting as an annotation.
+ *
+ * @param e {@code non-null;} entry
+ * @return {@code non-null;} annotation string
+ */
+ private String entryAnnotationString(LocalList.Entry e) {
+ StringBuilder sb = new StringBuilder();
- seen.set(reg - argBase);
- result.add(e);
- }
+ sb.append(RegisterSpec.PREFIX);
+ sb.append(e.getRegister());
+ sb.append(' ');
- // Sort by ascending register.
- Collections.sort(result, new Comparator<LocalList.Entry>() {
- public int compare(LocalList.Entry a, LocalList.Entry b) {
- return a.getRegister() - b.getRegister();
- }
+ CstString name = e.getName();
+ if (name == null) {
+ sb.append("null");
+ } else {
+ sb.append(name.toHuman());
+ }
+ sb.append(' ');
- public boolean equals(Object obj) {
- return obj == this;
- }
- });
-
- return result;
+ CstType type = e.getType();
+ if (type == null) {
+ sb.append("null");
+ } else {
+ sb.append(type.toHuman());
}
- /**
- * Returns a string representation of this LocalList entry that is
- * appropriate for emitting as an annotation.
- *
- * @param e {@code non-null;} entry
- * @return {@code non-null;} annotation string
- */
- private String entryAnnotationString(LocalList.Entry e) {
- StringBuilder sb = new StringBuilder();
+ CstString signature = e.getSignature();
- sb.append(RegisterSpec.PREFIX);
- sb.append(e.getRegister());
- sb.append(' ');
-
- CstString name = e.getName();
- if (name == null) {
- sb.append("null");
- } else {
- sb.append(name.toHuman());
- }
- sb.append(' ');
-
- CstType type = e.getType();
- if (type == null) {
- sb.append("null");
- } else {
- sb.append(type.toHuman());
- }
-
- CstString signature = e.getSignature();
-
- if (signature != null) {
- sb.append(' ');
- sb.append(signature.toHuman());
- }
-
- return sb.toString();
+ if (signature != null) {
+ sb.append(' ');
+ sb.append(signature.toHuman());
}
- /**
- * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL}
- * sequence.
- *
- * @param entry entry associated with this restart
- * @throws IOException
- */
- private void emitLocalRestart(LocalList.Entry entry)
- throws IOException {
+ return sb.toString();
+ }
- int mark = output.getCursor();
+ /**
+ * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL}
+ * sequence.
+ *
+ * @param entry entry associated with this restart
+ * @throws IOException
+ */
+ private void emitLocalRestart(LocalList.Entry entry) throws IOException {
- output.writeByte(DBG_RESTART_LOCAL);
- emitUnsignedLeb128(entry.getRegister());
+ int mark = output.getCursor();
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("%04x: +local restart %s",
- address, entryAnnotationString(entry)));
- }
+ output.writeByte(DBG_RESTART_LOCAL);
+ emitUnsignedLeb128(entry.getRegister());
- if (DEBUG) {
- System.err.println("emit local restart");
- }
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark,
+ String.format("%04x: +local restart %s", address, entryAnnotationString(entry)));
}
- /**
- * Emits a string index as an unsigned LEB128. The actual value written
- * is shifted by 1, so that the '0' value is reserved for "null". The
- * null symbol is used in some cases by the parameter name list
- * at the beginning of the sequence.
- *
- * @param string {@code null-ok;} string to emit
- * @throws IOException
- */
- private void emitStringIndex(CstString string) throws IOException {
- if ((string == null) || (file == null)) {
- output.writeUleb128(0);
- } else {
- output.writeUleb128(
- 1 + file.getStringIds().indexOf(string));
- }
+ if (DEBUG) {
+ System.err.println("emit local restart");
+ }
+ }
- if (DEBUG) {
- System.err.printf("Emit string %s\n",
- string == null ? "<null>" : string.toQuoted());
- }
+ /**
+ * Emits a string index as an unsigned LEB128. The actual value written
+ * is shifted by 1, so that the '0' value is reserved for "null". The
+ * null symbol is used in some cases by the parameter name list
+ * at the beginning of the sequence.
+ *
+ * @param string {@code null-ok;} string to emit
+ * @throws IOException
+ */
+ private void emitStringIndex(CstString string) throws IOException {
+ if ((string == null) || (file == null)) {
+ output.writeUleb128(0);
+ } else {
+ output.writeUleb128(1 + file.getStringIds().indexOf(string));
}
- /**
- * Emits a type index as an unsigned LEB128. The actual value written
- * is shifted by 1, so that the '0' value is reserved for "null".
- *
- * @param type {@code null-ok;} type to emit
- * @throws IOException
- */
- private void emitTypeIndex(CstType type) throws IOException {
- if ((type == null) || (file == null)) {
- output.writeUleb128(0);
- } else {
- output.writeUleb128(
- 1 + file.getTypeIds().indexOf(type));
- }
+ if (DEBUG) {
+ System.err.printf("Emit string %s\n", string == null ? "<null>" : string.toQuoted());
+ }
+ }
- if (DEBUG) {
- System.err.printf("Emit type %s\n",
- type == null ? "<null>" : type.toHuman());
- }
+ /**
+ * Emits a type index as an unsigned LEB128. The actual value written
+ * is shifted by 1, so that the '0' value is reserved for "null".
+ *
+ * @param type {@code null-ok;} type to emit
+ * @throws IOException
+ */
+ private void emitTypeIndex(CstType type) throws IOException {
+ if ((type == null) || (file == null)) {
+ output.writeUleb128(0);
+ } else {
+ output.writeUleb128(1 + file.getTypeIds().indexOf(type));
}
- /**
- * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or
- * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
- * DBG_START_LOCAL_EXTENDED} sequence.
- *
- * @param entry entry to emit
- * @throws IOException
- */
- private void emitLocalStart(LocalList.Entry entry)
- throws IOException {
+ if (DEBUG) {
+ System.err.printf("Emit type %s\n", type == null ? "<null>" : type.toHuman());
+ }
+ }
- if (entry.getSignature() != null) {
- emitLocalStartExtended(entry);
- return;
- }
+ /**
+ * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or
+ * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+ * DBG_START_LOCAL_EXTENDED} sequence.
+ *
+ * @param entry entry to emit
+ * @throws IOException
+ */
+ private void emitLocalStart(LocalList.Entry entry) throws IOException {
- int mark = output.getCursor();
-
- output.writeByte(DBG_START_LOCAL);
-
- emitUnsignedLeb128(entry.getRegister());
- emitStringIndex(entry.getName());
- emitTypeIndex(entry.getType());
-
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("%04x: +local %s", address,
- entryAnnotationString(entry)));
- }
-
- if (DEBUG) {
- System.err.println("emit local start");
- }
+ if (entry.getSignature() != null) {
+ emitLocalStartExtended(entry);
+ return;
}
- /**
- * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
- * DBG_START_LOCAL_EXTENDED} sequence.
- *
- * @param entry entry to emit
- * @throws IOException
- */
- private void emitLocalStartExtended(LocalList.Entry entry)
- throws IOException {
+ int mark = output.getCursor();
- int mark = output.getCursor();
+ output.writeByte(DBG_START_LOCAL);
- output.writeByte(DBG_START_LOCAL_EXTENDED);
+ emitUnsignedLeb128(entry.getRegister());
+ emitStringIndex(entry.getName());
+ emitTypeIndex(entry.getType());
- emitUnsignedLeb128(entry.getRegister());
- emitStringIndex(entry.getName());
- emitTypeIndex(entry.getType());
- emitStringIndex(entry.getSignature());
-
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("%04x: +localx %s", address,
- entryAnnotationString(entry)));
- }
-
- if (DEBUG) {
- System.err.println("emit local start");
- }
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark,
+ String.format("%04x: +local %s", address, entryAnnotationString(entry)));
}
- /**
- * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
- *
- * @param entry {@code entry non-null;} entry associated with end.
- * @throws IOException
- */
- private void emitLocalEnd(LocalList.Entry entry)
- throws IOException {
+ if (DEBUG) {
+ System.err.println("emit local start");
+ }
+ }
- int mark = output.getCursor();
+ /**
+ * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+ * DBG_START_LOCAL_EXTENDED} sequence.
+ *
+ * @param entry entry to emit
+ * @throws IOException
+ */
+ private void emitLocalStartExtended(LocalList.Entry entry) throws IOException {
- output.writeByte(DBG_END_LOCAL);
- output.writeUleb128(entry.getRegister());
+ int mark = output.getCursor();
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("%04x: -local %s", address,
- entryAnnotationString(entry)));
- }
+ output.writeByte(DBG_START_LOCAL_EXTENDED);
- if (DEBUG) {
- System.err.println("emit local end");
- }
+ emitUnsignedLeb128(entry.getRegister());
+ emitStringIndex(entry.getName());
+ emitTypeIndex(entry.getType());
+ emitStringIndex(entry.getSignature());
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark,
+ String.format("%04x: +localx %s", address, entryAnnotationString(entry)));
}
- /**
- * Emits the necessary byte sequences to emit the given position table
- * entry. This will typically be a single special opcode, although
- * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
- *
- * @param entry position entry to emit.
- * @throws IOException
- */
- private void emitPosition(PositionList.Entry entry)
- throws IOException {
+ if (DEBUG) {
+ System.err.println("emit local start");
+ }
+ }
- SourcePosition pos = entry.getPosition();
- int newLine = pos.getLine();
- int newAddress = entry.getAddress();
+ /**
+ * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
+ *
+ * @param entry {@code entry non-null;} entry associated with end.
+ * @throws IOException
+ */
+ private void emitLocalEnd(LocalList.Entry entry) throws IOException {
- int opcode;
+ int mark = output.getCursor();
- int deltaLines = newLine - line;
- int deltaAddress = newAddress - address;
+ output.writeByte(DBG_END_LOCAL);
+ output.writeUleb128(entry.getRegister());
- if (deltaAddress < 0) {
- throw new RuntimeException(
- "Position entries must be in ascending address order");
- }
-
- if ((deltaLines < DBG_LINE_BASE)
- || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) {
- emitAdvanceLine(deltaLines);
- deltaLines = 0;
- }
-
- opcode = computeOpcode (deltaLines, deltaAddress);
-
- if ((opcode & ~0xff) > 0) {
- emitAdvancePc(deltaAddress);
- deltaAddress = 0;
- opcode = computeOpcode (deltaLines, deltaAddress);
-
- if ((opcode & ~0xff) > 0) {
- emitAdvanceLine(deltaLines);
- deltaLines = 0;
- opcode = computeOpcode (deltaLines, deltaAddress);
- }
- }
-
- output.writeByte(opcode);
-
- line += deltaLines;
- address += deltaAddress;
-
- if (annotateTo != null || debugPrint != null) {
- annotate(1,
- String.format("%04x: line %d", address, line));
- }
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark,
+ String.format("%04x: -local %s", address, entryAnnotationString(entry)));
}
- /**
- * Computes a special opcode that will encode the given position change.
- * If the return value is > 0xff, then the request cannot be fulfilled.
- * Essentially the same as described in "DWARF Debugging Format Version 3"
- * section 6.2.5.1.
- *
- * @param deltaLines {@code >= DBG_LINE_BASE, <= DBG_LINE_BASE +
- * DBG_LINE_RANGE;} the line change to encode
- * @param deltaAddress {@code >= 0;} the address change to encode
- * @return {@code <= 0xff} if in range, otherwise parameters are out
- * of range
- */
- private static int computeOpcode(int deltaLines, int deltaAddress) {
- if (deltaLines < DBG_LINE_BASE
- || deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1)) {
+ if (DEBUG) {
+ System.err.println("emit local end");
+ }
+ }
- throw new RuntimeException("Parameter out of range");
- }
+ /**
+ * Emits the necessary byte sequences to emit the given position table
+ * entry. This will typically be a single special opcode, although
+ * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
+ *
+ * @param entry position entry to emit.
+ * @throws IOException
+ */
+ private void emitPosition(PositionList.Entry entry) throws IOException {
- return (deltaLines - DBG_LINE_BASE)
- + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL;
+ SourcePosition pos = entry.getPosition();
+ int newLine = pos.getLine();
+ int newAddress = entry.getAddress();
+
+ int opcode;
+
+ int deltaLines = newLine - line;
+ int deltaAddress = newAddress - address;
+
+ if (deltaAddress < 0) {
+ throw new RuntimeException("Position entries must be in ascending address order");
}
- /**
- * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE}
- * sequence.
- *
- * @param deltaLines amount to change line number register by
- * @throws IOException
- */
- private void emitAdvanceLine(int deltaLines) throws IOException {
- int mark = output.getCursor();
-
- output.writeByte(DBG_ADVANCE_LINE);
- output.writeSleb128(deltaLines);
- line += deltaLines;
-
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("line = %d", line));
- }
-
- if (DEBUG) {
- System.err.printf("Emitting advance_line for %d\n", deltaLines);
- }
+ if ((deltaLines < DBG_LINE_BASE) || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE - 1))) {
+ emitAdvanceLine(deltaLines);
+ deltaLines = 0;
}
- /**
- * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
- * sequence.
- *
- * @param deltaAddress {@code >= 0;} amount to change program counter by
- * @throws IOException
- */
- private void emitAdvancePc(int deltaAddress) throws IOException {
- int mark = output.getCursor();
+ opcode = computeOpcode(deltaLines, deltaAddress);
- output.writeByte(DBG_ADVANCE_PC);
- output.writeUleb128(deltaAddress);
- address += deltaAddress;
+ if ((opcode & ~0xff) > 0) {
+ emitAdvancePc(deltaAddress);
+ deltaAddress = 0;
+ opcode = computeOpcode(deltaLines, deltaAddress);
- if (annotateTo != null || debugPrint != null) {
- annotate(output.getCursor() - mark,
- String.format("%04x: advance pc", address));
- }
-
- if (DEBUG) {
- System.err.printf("Emitting advance_pc for %d\n", deltaAddress);
- }
+ if ((opcode & ~0xff) > 0) {
+ emitAdvanceLine(deltaLines);
+ deltaLines = 0;
+ opcode = computeOpcode(deltaLines, deltaAddress);
+ }
}
- /**
- * Emits an unsigned LEB128 value.
- *
- * @param n {@code >= 0;} value to emit. Note that, although this can
- * represent integers larger than Integer.MAX_VALUE, we currently don't
- * allow that.
- * @throws IOException
- */
- private void emitUnsignedLeb128(int n) throws IOException {
- // We'll never need the top end of the unsigned range anyway.
- if (n < 0) {
- throw new RuntimeException(
- "Signed value where unsigned required: " + n);
- }
+ output.writeByte(opcode);
- output.writeUleb128(n);
+ line += deltaLines;
+ address += deltaAddress;
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(1, String.format("%04x: line %d", address, line));
+ }
+ }
+
+ /**
+ * Computes a special opcode that will encode the given position change.
+ * If the return value is > 0xff, then the request cannot be fulfilled.
+ * Essentially the same as described in "DWARF Debugging Format Version 3"
+ * section 6.2.5.1.
+ *
+ * @param deltaLines {@code >= DBG_LINE_BASE, <= DBG_LINE_BASE +
+ * DBG_LINE_RANGE;} the line change to encode
+ * @param deltaAddress {@code >= 0;} the address change to encode
+ * @return {@code <= 0xff} if in range, otherwise parameters are out
+ * of range
+ */
+ private static int computeOpcode(int deltaLines, int deltaAddress) {
+ if (deltaLines < DBG_LINE_BASE || deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE - 1)) {
+
+ throw new RuntimeException("Parameter out of range");
}
- /**
- * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE}
- * bytecode.
- */
- private void emitEndSequence() {
- output.writeByte(DBG_END_SEQUENCE);
+ return (deltaLines - DBG_LINE_BASE) + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL;
+ }
- if (annotateTo != null || debugPrint != null) {
- annotate(1, "end sequence");
- }
+ /**
+ * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE}
+ * sequence.
+ *
+ * @param deltaLines amount to change line number register by
+ * @throws IOException
+ */
+ private void emitAdvanceLine(int deltaLines) throws IOException {
+ int mark = output.getCursor();
+
+ output.writeByte(DBG_ADVANCE_LINE);
+ output.writeSleb128(deltaLines);
+ line += deltaLines;
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark, String.format("line = %d", line));
}
+
+ if (DEBUG) {
+ System.err.printf("Emitting advance_line for %d\n", deltaLines);
+ }
+ }
+
+ /**
+ * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
+ * sequence.
+ *
+ * @param deltaAddress {@code >= 0;} amount to change program counter by
+ * @throws IOException
+ */
+ private void emitAdvancePc(int deltaAddress) throws IOException {
+ int mark = output.getCursor();
+
+ output.writeByte(DBG_ADVANCE_PC);
+ output.writeUleb128(deltaAddress);
+ address += deltaAddress;
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(output.getCursor() - mark, String.format("%04x: advance pc", address));
+ }
+
+ if (DEBUG) {
+ System.err.printf("Emitting advance_pc for %d\n", deltaAddress);
+ }
+ }
+
+ /**
+ * Emits an unsigned LEB128 value.
+ *
+ * @param n {@code >= 0;} value to emit. Note that, although this can
+ * represent integers larger than Integer.MAX_VALUE, we currently don't
+ * allow that.
+ * @throws IOException
+ */
+ private void emitUnsignedLeb128(int n) throws IOException {
+ // We'll never need the top end of the unsigned range anyway.
+ if (n < 0) {
+ throw new RuntimeException("Signed value where unsigned required: " + n);
+ }
+
+ output.writeUleb128(n);
+ }
+
+ /**
+ * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE}
+ * bytecode.
+ */
+ private void emitEndSequence() {
+ output.writeByte(DBG_END_SEQUENCE);
+
+ if (annotateTo != null || debugPrint != null) {
+ annotate(1, "end sequence");
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/jack/dx/dex/file/DebugInfoItem.java
index 61db8d9..8f5ceb6 100644
--- a/dx/src/com/android/jack/dx/dex/file/DebugInfoItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/DebugInfoItem.java
@@ -26,169 +26,168 @@
import java.io.PrintWriter;
+/**
+ * TODO(jack team)
+ */
public class DebugInfoItem extends OffsettedItem {
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 1;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 1;
- private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
+ private static boolean enableEncoderSelfCheck = false;
- /** {@code non-null;} the code this item represents */
- private final DalvCode code;
+ /** {@code non-null;} the code this item represents */
+ private final DalvCode code;
- private byte[] encoded;
+ private byte[] encoded;
- private final boolean isStatic;
- private final CstMethodRef ref;
+ private final boolean isStatic;
+ private final CstMethodRef ref;
- public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
- // We don't know the write size yet.
- super (ALIGNMENT, -1);
+ public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
+ // We don't know the write size yet.
+ super(ALIGNMENT, -1);
- if (code == null) {
- throw new NullPointerException("code == null");
- }
-
- this.code = code;
- this.isStatic = isStatic;
- this.ref = ref;
+ if (code == null) {
+ throw new NullPointerException("code == null");
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_DEBUG_INFO_ITEM;
+ this.code = code;
+ this.isStatic = isStatic;
+ this.ref = ref;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_DEBUG_INFO_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ // No contents to add.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // Encode the data and note the size.
+
+ try {
+ encoded = encode(addedTo.getFile(), null, null, null, false);
+ setWriteSize(encoded.length);
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex,
+ "...while placing debug info for " + ref.toHuman());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ throw new RuntimeException("unsupported");
+ }
+
+ /**
+ * Writes annotations for the elements of this list, as
+ * zero-length. This is meant to be used for dumping this instance
+ * directly after a code dump (with the real local list actually
+ * existing elsewhere in the output).
+ *
+ * @param file {@code non-null;} the file to use for referencing other sections
+ * @param out {@code non-null;} where to annotate to
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ */
+ public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
+ encode(file, prefix, null, out, false);
+ }
+
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
+ */
+ public void debugPrint(PrintWriter out, String prefix) {
+ encode(null, prefix, out, null, false);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ if (out.annotates()) {
+ /*
+ * Re-run the encoder to generate the annotations,
+ * but write the bits from the original encode
+ */
+
+out.annotate(offsetString() + " debug info");
+ encode(file, null, null, out, true);
}
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- // No contents to add.
+ out.write(encoded);
+ }
+
+ /**
+ * Performs debug info encoding.
+ *
+ * @param file {@code null-ok;} file to refer to during encoding
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
+ * annotations
+ * @param out {@code null-ok;} if specified, where annotations should go
+ * @param consume whether to claim to have consumed output for
+ * {@code out}
+ * @return {@code non-null;} the encoded array
+ */
+ private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out,
+ boolean consume) {
+ byte[] result = encode0(file, prefix, debugPrint, out, consume);
+
+ if (enableEncoderSelfCheck && (file != null)) {
+ try {
+ DebugInfoDecoder.validateEncode(result, file, ref, code, isStatic);
+ } catch (RuntimeException ex) {
+ // Reconvert, annotating to System.err.
+ encode0(file, "", new PrintWriter(System.err, true), null, false);
+ throw ex;
+ }
}
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // Encode the data and note the size.
+ return result;
+ }
- try {
- encoded = encode(addedTo.getFile(), null, null, null, false);
- setWriteSize(encoded.length);
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while placing debug info for " + ref.toHuman());
- }
+ /**
+ * Helper for {@link #encode} to do most of the work.
+ *
+ * @param file {@code null-ok;} file to refer to during encoding
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
+ * annotations
+ * @param out {@code null-ok;} if specified, where annotations should go
+ * @param consume whether to claim to have consumed output for
+ * {@code out}
+ * @return {@code non-null;} the encoded array
+ */
+ private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out,
+ boolean consume) {
+ PositionList positions = code.getPositions();
+ LocalList locals = code.getLocals();
+ DalvInsnList insns = code.getInsns();
+ int codeSize = insns.codeSize();
+ int regSize = insns.getRegistersSize();
+
+ DebugInfoEncoder encoder =
+ new DebugInfoEncoder(positions, locals, file, codeSize, regSize, isStatic, ref);
+
+ byte[] result;
+
+ if ((debugPrint == null) && (out == null)) {
+ result = encoder.convert();
+ } else {
+ result = encoder.convertAndAnnotate(prefix, debugPrint, out, consume);
}
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- throw new RuntimeException("unsupported");
- }
-
- /**
- * Writes annotations for the elements of this list, as
- * zero-length. This is meant to be used for dumping this instance
- * directly after a code dump (with the real local list actually
- * existing elsewhere in the output).
- *
- * @param file {@code non-null;} the file to use for referencing other sections
- * @param out {@code non-null;} where to annotate to
- * @param prefix {@code null-ok;} prefix to attach to each line of output
- */
- public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
- encode(file, prefix, null, out, false);
- }
-
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param prefix {@code non-null;} prefix to attach to each line of output
- */
- public void debugPrint(PrintWriter out, String prefix) {
- encode(null, prefix, out, null, false);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- if (out.annotates()) {
- /*
- * Re-run the encoder to generate the annotations,
- * but write the bits from the original encode
- */
-
- out.annotate(offsetString() + " debug info");
- encode(file, null, null, out, true);
- }
-
- out.write(encoded);
- }
-
- /**
- * Performs debug info encoding.
- *
- * @param file {@code null-ok;} file to refer to during encoding
- * @param prefix {@code null-ok;} prefix to attach to each line of output
- * @param debugPrint {@code null-ok;} if specified, an alternate output for
- * annotations
- * @param out {@code null-ok;} if specified, where annotations should go
- * @param consume whether to claim to have consumed output for
- * {@code out}
- * @return {@code non-null;} the encoded array
- */
- private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
- AnnotatedOutput out, boolean consume) {
- byte[] result = encode0(file, prefix, debugPrint, out, consume);
-
- if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
- try {
- DebugInfoDecoder.validateEncode(result, file, ref, code,
- isStatic);
- } catch (RuntimeException ex) {
- // Reconvert, annotating to System.err.
- encode0(file, "", new PrintWriter(System.err, true), null,
- false);
- throw ex;
- }
- }
-
- return result;
- }
-
- /**
- * Helper for {@link #encode} to do most of the work.
- *
- * @param file {@code null-ok;} file to refer to during encoding
- * @param prefix {@code null-ok;} prefix to attach to each line of output
- * @param debugPrint {@code null-ok;} if specified, an alternate output for
- * annotations
- * @param out {@code null-ok;} if specified, where annotations should go
- * @param consume whether to claim to have consumed output for
- * {@code out}
- * @return {@code non-null;} the encoded array
- */
- private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
- AnnotatedOutput out, boolean consume) {
- PositionList positions = code.getPositions();
- LocalList locals = code.getLocals();
- DalvInsnList insns = code.getInsns();
- int codeSize = insns.codeSize();
- int regSize = insns.getRegistersSize();
-
- DebugInfoEncoder encoder =
- new DebugInfoEncoder(positions, locals,
- file, codeSize, regSize, isStatic, ref);
-
- byte[] result;
-
- if ((debugPrint == null) && (out == null)) {
- result = encoder.convert();
- } else {
- result = encoder.convertAndAnnotate(prefix, debugPrint, out,
- consume);
- }
-
- return result;
- }
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/DexFile.java b/dx/src/com/android/jack/dx/dex/file/DexFile.java
index c0fa5b1..027cb25 100644
--- a/dx/src/com/android/jack/dx/dex/file/DexFile.java
+++ b/dx/src/com/android/jack/dx/dex/file/DexFile.java
@@ -17,6 +17,7 @@
package com.android.jack.dx.dex.file;
import com.android.jack.dx.dex.DexOptions;
+import com.android.jack.dx.dex.file.MixedItemSection.SortType;
import com.android.jack.dx.rop.cst.Constant;
import com.android.jack.dx.rop.cst.CstBaseMethodRef;
import com.android.jack.dx.rop.cst.CstEnumRef;
@@ -37,642 +38,641 @@
import java.util.List;
import java.util.zip.Adler32;
-import static com.android.jack.dx.dex.file.MixedItemSection.SortType;
-
/**
* Representation of an entire {@code .dex} (Dalvik EXecutable)
* file, which itself consists of a set of Dalvik classes.
*/
public final class DexFile {
- /** options controlling the creation of the file */
- private DexOptions dexOptions;
+ /** options controlling the creation of the file */
+ private DexOptions dexOptions;
- /** {@code non-null;} word data section */
- private final MixedItemSection wordData;
+ /** {@code non-null;} word data section */
+ private final MixedItemSection wordData;
- /**
- * {@code non-null;} type lists section. This is word data, but separating
- * it from {@link #wordData} helps break what would otherwise be a
- * circular dependency between the that and {@link #protoIds}.
+ /**
+ * {@code non-null;} type lists section. This is word data, but separating
+ * it from {@link #wordData} helps break what would otherwise be a
+ * circular dependency between the that and {@link #protoIds}.
+ */
+ private final MixedItemSection typeLists;
+
+ /**
+ * {@code non-null;} map section. The map needs to be in a section by itself
+ * for the self-reference mechanics to work in a reasonably
+ * straightforward way. See {@link MapItem#addMap} for more detail.
+ */
+ private final MixedItemSection map;
+
+ /** {@code non-null;} string data section */
+ private final MixedItemSection stringData;
+
+ /** {@code non-null;} string identifiers section */
+ private final StringIdsSection stringIds;
+
+ /** {@code non-null;} type identifiers section */
+ private final TypeIdsSection typeIds;
+
+ /** {@code non-null;} prototype identifiers section */
+ private final ProtoIdsSection protoIds;
+
+ /** {@code non-null;} field identifiers section */
+ private final FieldIdsSection fieldIds;
+
+ /** {@code non-null;} method identifiers section */
+ private final MethodIdsSection methodIds;
+
+ /** {@code non-null;} class definitions section */
+ private final ClassDefsSection classDefs;
+
+ /** {@code non-null;} class data section */
+ private final MixedItemSection classData;
+
+ /** {@code non-null;} byte data section */
+ private final MixedItemSection byteData;
+
+ /** {@code non-null;} file header */
+ private final HeaderSection header;
+
+ /**
+ * {@code non-null;} array of sections in the order they will appear in the
+ * final output file
+ */
+ private final Section[] sections;
+
+ /** {@code >= -1;} total file size or {@code -1} if unknown */
+ private int fileSize;
+
+ /** {@code >= 40;} maximum width of the file dump */
+ private int dumpWidth;
+
+ /** List of constant index mapping that must be used to remap binary */
+ private List<CstIndexMap> cstIndexMaps;
+
+ public DexFile(DexOptions dexOptions, List<CstIndexMap> cstIndexMaps) {
+ this.cstIndexMaps = cstIndexMaps;
+ this.dexOptions = dexOptions;
+
+ header = new HeaderSection(this);
+ typeLists = new MixedItemSection(null, this, 4, SortType.NONE);
+ wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE);
+ stringData = new MixedItemSection("string_data", this, 1, SortType.INSTANCE);
+ classData = new MixedItemSection(null, this, 1, SortType.NONE);
+ byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE);
+ stringIds = new StringIdsSection(this);
+ typeIds = new TypeIdsSection(this);
+ protoIds = new ProtoIdsSection(this);
+ fieldIds = new FieldIdsSection(this);
+ methodIds = new MethodIdsSection(this);
+ classDefs = new ClassDefsSection(this);
+ map = new MixedItemSection("map", this, 4, SortType.NONE);
+
+ /*
+ * This is the list of sections in the order they appear in
+ * the final output.
*/
- private final MixedItemSection typeLists;
+ sections = new Section[] {header,
+ stringIds,
+ typeIds,
+ protoIds,
+ fieldIds,
+ methodIds,
+ classDefs,
+ wordData,
+ typeLists,
+ stringData,
+ byteData,
+ classData,
+ map};
- /**
- * {@code non-null;} map section. The map needs to be in a section by itself
- * for the self-reference mechanics to work in a reasonably
- * straightforward way. See {@link MapItem#addMap} for more detail.
- */
- private final MixedItemSection map;
+ fileSize = -1;
+ dumpWidth = 79;
+ }
- /** {@code non-null;} string data section */
- private final MixedItemSection stringData;
+ /**
+ * Constructs an instance. It is initially empty.
+ */
+ public DexFile(DexOptions dexOptions) {
+ this(dexOptions, null);
+ }
- /** {@code non-null;} string identifiers section */
- private final StringIdsSection stringIds;
+ /**
+ * Returns true if this dex doesn't contain any class defs.
+ */
+ public boolean isEmpty() {
+ return classDefs.items().isEmpty();
+ }
- /** {@code non-null;} type identifiers section */
- private final TypeIdsSection typeIds;
+ /**
+ * Gets the dex-creation options object.
+ */
+ public DexOptions getDexOptions() {
+ return dexOptions;
+ }
- /** {@code non-null;} prototype identifiers section */
- private final ProtoIdsSection protoIds;
+ /**
+ * Adds a class to this instance. It is illegal to attempt to add more
+ * than one class with the same name.
+ *
+ * @param clazz {@code non-null;} the class to add
+ */
+ public void add(ClassDefItem clazz) {
+ classDefs.add(clazz);
+ }
- /** {@code non-null;} field identifiers section */
- private final FieldIdsSection fieldIds;
+ /**
+ * Gets the class definition with the given name, if any.
+ *
+ * @param name {@code non-null;} the class name to look for
+ * @return {@code null-ok;} the class with the given name, or {@code null}
+ * if there is no such class
+ */
+ public ClassDefItem getClassOrNull(String name) {
+ try {
+ Type type = Type.internClassName(name);
+ return (ClassDefItem) classDefs.get(new CstType(type));
+ } catch (IllegalArgumentException ex) {
+ // Translate exception, per contract.
+ return null;
+ }
+ }
- /** {@code non-null;} method identifiers section */
- private final MethodIdsSection methodIds;
+ /**
+ * Writes the contents of this instance as either a binary or a
+ * human-readable form, or both.
+ *
+ * @param out {@code null-ok;} where to write to
+ * @param humanOut {@code null-ok;} where to write human-oriented output to
+ * @param verbose whether to be verbose when writing human-oriented output
+ */
+ public void writeTo(OutputStream out, Writer humanOut, boolean verbose) throws IOException {
+ boolean annotate = (humanOut != null);
+ ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
- /** {@code non-null;} class definitions section */
- private final ClassDefsSection classDefs;
-
- /** {@code non-null;} class data section */
- private final MixedItemSection classData;
-
- /** {@code non-null;} byte data section */
- private final MixedItemSection byteData;
-
- /** {@code non-null;} file header */
- private final HeaderSection header;
-
- /**
- * {@code non-null;} array of sections in the order they will appear in the
- * final output file
- */
- private final Section[] sections;
-
- /** {@code >= -1;} total file size or {@code -1} if unknown */
- private int fileSize;
-
- /** {@code >= 40;} maximum width of the file dump */
- private int dumpWidth;
-
- /** List of constant index mapping that must be used to remap binary */
- private List<CstIndexMap> cstIndexMaps;
-
- public DexFile(DexOptions dexOptions, List<CstIndexMap> cstIndexMaps) {
- this.cstIndexMaps = cstIndexMaps;
- this.dexOptions = dexOptions;
-
- header = new HeaderSection(this);
- typeLists = new MixedItemSection(null, this, 4, SortType.NONE);
- wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE);
- stringData =
- new MixedItemSection("string_data", this, 1, SortType.INSTANCE);
- classData = new MixedItemSection(null, this, 1, SortType.NONE);
- byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE);
- stringIds = new StringIdsSection(this);
- typeIds = new TypeIdsSection(this);
- protoIds = new ProtoIdsSection(this);
- fieldIds = new FieldIdsSection(this);
- methodIds = new MethodIdsSection(this);
- classDefs = new ClassDefsSection(this);
- map = new MixedItemSection("map", this, 4, SortType.NONE);
-
- /*
- * This is the list of sections in the order they appear in
- * the final output.
- */
- sections = new Section[] {
- header, stringIds, typeIds, protoIds, fieldIds, methodIds,
- classDefs, wordData, typeLists, stringData, byteData,
- classData, map };
-
- fileSize = -1;
- dumpWidth = 79;
+ if (out != null) {
+ out.write(result.getArray());
}
- /**
- * Constructs an instance. It is initially empty.
- */
- public DexFile(DexOptions dexOptions) {
- this(dexOptions, null);
+ if (annotate) {
+ result.writeAnnotationsTo(humanOut);
+ }
+ }
+
+ /**
+ * Returns the contents of this instance as a {@code .dex} file,
+ * in {@code byte[]} form.
+ *
+ * @param humanOut {@code null-ok;} where to write human-oriented output to
+ * @param verbose whether to be verbose when writing human-oriented output
+ * @return {@code non-null;} a {@code .dex} file for this instance
+ */
+ public byte[] toDex(Writer humanOut, boolean verbose) throws IOException {
+ boolean annotate = (humanOut != null);
+ ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+
+ if (annotate) {
+ result.writeAnnotationsTo(humanOut);
}
- /**
- * Returns true if this dex doesn't contain any class defs.
- */
- public boolean isEmpty() {
- return classDefs.items().isEmpty();
+ return result.getArray();
+ }
+
+ /**
+ * Sets the maximum width of the human-oriented dump of the instance.
+ *
+ * @param dumpWidth {@code >= 40;} the width
+ */
+ public void setDumpWidth(int dumpWidth) {
+ if (dumpWidth < 40) {
+ throw new IllegalArgumentException("dumpWidth < 40");
}
- /**
- * Gets the dex-creation options object.
- */
- public DexOptions getDexOptions() {
- return dexOptions;
+ this.dumpWidth = dumpWidth;
+ }
+
+ /**
+ * Gets the total file size, if known.
+ *
+ * <p>This is package-scope in order to allow
+ * the {@link HeaderSection} to set itself up properly.</p>
+ *
+ * @return {@code >= 0;} the total file size
+ * @throws RuntimeException thrown if the file size is not yet known
+ */
+ /*package*/int getFileSize() {
+ if (fileSize < 0) {
+ throw new RuntimeException("file size not yet known");
}
- /**
- * Adds a class to this instance. It is illegal to attempt to add more
- * than one class with the same name.
- *
- * @param clazz {@code non-null;} the class to add
+ return fileSize;
+ }
+
+ /**
+ * Gets the string data section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the string data section
+ */
+ /*package*/MixedItemSection getStringData() {
+ return stringData;
+ }
+
+ /**
+ * Gets the word data section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the word data section
+ */
+ /*package*/MixedItemSection getWordData() {
+ return wordData;
+ }
+
+ /**
+ * Gets the type lists section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the word data section
+ */
+ /*package*/MixedItemSection getTypeLists() {
+ return typeLists;
+ }
+
+ /**
+ * Gets the map section.
+ *
+ * <p>This is package-scope in order to allow the header section
+ * to query it.</p>
+ *
+ * @return {@code non-null;} the map section
+ */
+ /*package*/MixedItemSection getMap() {
+ return map;
+ }
+
+ /**
+ * Gets the string identifiers section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the string identifiers section
+ */
+ public StringIdsSection getStringIds() {
+ return stringIds;
+ }
+
+ /**
+ * Gets the class definitions section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the class definitions section
+ */
+ /*package*/ClassDefsSection getClassDefs() {
+ return classDefs;
+ }
+
+ /**
+ * Gets the class data section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the class data section
+ */
+ /*package*/MixedItemSection getClassData() {
+ return classData;
+ }
+
+ /**
+ * Gets the type identifiers section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the class identifiers section
+ */
+ public TypeIdsSection getTypeIds() {
+ return typeIds;
+ }
+
+ /**
+ * Gets the prototype identifiers section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the prototype identifiers section
+ */
+ /*package*/ProtoIdsSection getProtoIds() {
+ return protoIds;
+ }
+
+ /**
+ * Gets the field identifiers section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the field identifiers section
+ */
+ public FieldIdsSection getFieldIds() {
+ return fieldIds;
+ }
+
+ /**
+ * Gets the method identifiers section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the method identifiers section
+ */
+ public MethodIdsSection getMethodIds() {
+ return methodIds;
+ }
+
+ /**
+ * Gets the byte data section.
+ *
+ * <p>This is package-scope in order to allow
+ * the various {@link Item} instances to add items to the
+ * instance.</p>
+ *
+ * @return {@code non-null;} the byte data section
+ */
+ /*package*/MixedItemSection getByteData() {
+ return byteData;
+ }
+
+ /**
+ * Gets the first section of the file that is to be considered
+ * part of the data section.
+ *
+ * <p>This is package-scope in order to allow the header section
+ * to query it.</p>
+ *
+ * @return {@code non-null;} the section
+ */
+ /*package*/Section getFirstDataSection() {
+ return wordData;
+ }
+
+ /**
+ * Gets the last section of the file that is to be considered
+ * part of the data section.
+ *
+ * <p>This is package-scope in order to allow the header section
+ * to query it.</p>
+ *
+ * @return {@code non-null;} the section
+ */
+ /*package*/Section getLastDataSection() {
+ return map;
+ }
+
+ /**
+ * Interns the given constant in the appropriate section of this
+ * instance, or do nothing if the given constant isn't the sort
+ * that should be interned.
+ *
+ * @param cst {@code non-null;} constant to possibly intern
+ */
+ /*package*/void internIfAppropriate(Constant cst) {
+ if (cst instanceof CstString) {
+ stringIds.intern((CstString) cst);
+ } else if (cst instanceof CstType) {
+ typeIds.intern((CstType) cst);
+ } else if (cst instanceof CstBaseMethodRef) {
+ methodIds.intern((CstBaseMethodRef) cst);
+ } else if (cst instanceof CstFieldRef) {
+ fieldIds.intern((CstFieldRef) cst);
+ } else if (cst instanceof CstEnumRef) {
+ fieldIds.intern(((CstEnumRef) cst).getFieldRef());
+ } else if (cst == null) {
+ throw new NullPointerException("cst == null");
+ }
+ }
+
+ /**
+ * Gets the {@link IndexedItem} corresponding to the given constant,
+ * if it is a constant that has such a correspondence, or return
+ * {@code null} if it isn't such a constant. This will throw
+ * an exception if the given constant <i>should</i> have been found
+ * but wasn't.
+ *
+ * @param cst {@code non-null;} the constant to look up
+ * @return {@code null-ok;} its corresponding item, if it has a corresponding
+ * item, or {@code null} if it's not that sort of constant
+ */
+ public IndexedItem findItemOrNull(Constant cst) {
+ if (cst instanceof CstString) {
+ return stringIds.get(cst);
+ } else if (cst instanceof CstType) {
+ return typeIds.get(cst);
+ } else if (cst instanceof CstBaseMethodRef) {
+ return methodIds.get(cst);
+ } else if (cst instanceof CstFieldRef) {
+ return fieldIds.get(cst);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the contents of this instance as a {@code .dex} file,
+ * in a {@link ByteArrayAnnotatedOutput} instance.
+ *
+ * @param annotate whether or not to keep annotations
+ * @param verbose if annotating, whether to be verbose
+ * @return {@code non-null;} a {@code .dex} file for this instance
+ */
+ private ByteArrayAnnotatedOutput toDex0(boolean annotate, boolean verbose) {
+ /*
+ * The following is ordered so that the prepare() calls which
+ * add items happen before the calls to the sections that get
+ * added to.
*/
- public void add(ClassDefItem clazz) {
- classDefs.add(clazz);
+
+if (cstIndexMaps != null) {
+ for (CstIndexMap cstIndexMap : cstIndexMaps) {
+ cstIndexMap.mergeConstantsIntoDexFile(this);
+ }
}
- /**
- * Gets the class definition with the given name, if any.
- *
- * @param name {@code non-null;} the class name to look for
- * @return {@code null-ok;} the class with the given name, or {@code null}
- * if there is no such class
- */
- public ClassDefItem getClassOrNull(String name) {
- try {
- Type type = Type.internClassName(name);
- return (ClassDefItem) classDefs.get(new CstType(type));
- } catch (IllegalArgumentException ex) {
- // Translate exception, per contract.
- return null;
- }
- }
+ classDefs.prepare();
+ classData.prepare();
+ wordData.prepare();
+ byteData.prepare();
+ methodIds.prepare();
+ fieldIds.prepare();
+ protoIds.prepare();
+ typeLists.prepare();
+ typeIds.prepare();
+ stringIds.prepare();
+ stringData.prepare();
+ header.prepare();
- /**
- * Writes the contents of this instance as either a binary or a
- * human-readable form, or both.
- *
- * @param out {@code null-ok;} where to write to
- * @param humanOut {@code null-ok;} where to write human-oriented output to
- * @param verbose whether to be verbose when writing human-oriented output
- */
- public void writeTo(OutputStream out, Writer humanOut, boolean verbose)
- throws IOException {
- boolean annotate = (humanOut != null);
- ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+ // Place the sections within the file.
- if (out != null) {
- out.write(result.getArray());
+ int count = sections.length;
+ int offset = 0;
+
+ for (int i = 0; i < count; i++) {
+ Section one = sections[i];
+ int placedAt = one.setFileOffset(offset);
+ if (placedAt < offset) {
+ throw new RuntimeException("bogus placement for section " + i);
+ }
+
+ try {
+ if (one == map) {
+ /*
+ * Inform the map of all the sections, and add it
+ * to the file. This can only be done after all
+ * the other items have been sorted and placed.
+ */
+ MapItem.addMap(sections, map);
+ map.prepare();
}
- if (annotate) {
- result.writeAnnotationsTo(humanOut);
- }
- }
-
- /**
- * Returns the contents of this instance as a {@code .dex} file,
- * in {@code byte[]} form.
- *
- * @param humanOut {@code null-ok;} where to write human-oriented output to
- * @param verbose whether to be verbose when writing human-oriented output
- * @return {@code non-null;} a {@code .dex} file for this instance
- */
- public byte[] toDex(Writer humanOut, boolean verbose)
- throws IOException {
- boolean annotate = (humanOut != null);
- ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
-
- if (annotate) {
- result.writeAnnotationsTo(humanOut);
+ if (one instanceof MixedItemSection) {
+ /*
+ * Place the items of a MixedItemSection that just
+ * got placed.
+ */
+ ((MixedItemSection) one).placeItems();
}
- return result.getArray();
+ offset = placedAt + one.writeSize();
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex, "...while writing section " + i);
+ }
}
- /**
- * Sets the maximum width of the human-oriented dump of the instance.
- *
- * @param dumpWidth {@code >= 40;} the width
- */
- public void setDumpWidth(int dumpWidth) {
- if (dumpWidth < 40) {
- throw new IllegalArgumentException("dumpWidth < 40");
+ // Write out all the sections.
+
+ fileSize = offset;
+ byte[] barr = new byte[fileSize];
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr);
+
+ if (annotate) {
+ out.enableAnnotations(dumpWidth, verbose);
+ }
+
+ for (int i = 0; i < count; i++) {
+ try {
+ Section one = sections[i];
+ int zeroCount = one.getFileOffset() - out.getCursor();
+ if (zeroCount < 0) {
+ throw new ExceptionWithContext("excess write of " + (-zeroCount));
}
-
- this.dumpWidth = dumpWidth;
- }
-
- /**
- * Gets the total file size, if known.
- *
- * <p>This is package-scope in order to allow
- * the {@link HeaderSection} to set itself up properly.</p>
- *
- * @return {@code >= 0;} the total file size
- * @throws RuntimeException thrown if the file size is not yet known
- */
- /*package*/ int getFileSize() {
- if (fileSize < 0) {
- throw new RuntimeException("file size not yet known");
- }
-
- return fileSize;
- }
-
- /**
- * Gets the string data section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the string data section
- */
- /*package*/ MixedItemSection getStringData() {
- return stringData;
- }
-
- /**
- * Gets the word data section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the word data section
- */
- /*package*/ MixedItemSection getWordData() {
- return wordData;
- }
-
- /**
- * Gets the type lists section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the word data section
- */
- /*package*/ MixedItemSection getTypeLists() {
- return typeLists;
- }
-
- /**
- * Gets the map section.
- *
- * <p>This is package-scope in order to allow the header section
- * to query it.</p>
- *
- * @return {@code non-null;} the map section
- */
- /*package*/ MixedItemSection getMap() {
- return map;
- }
-
- /**
- * Gets the string identifiers section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the string identifiers section
- */
- public StringIdsSection getStringIds() {
- return stringIds;
- }
-
- /**
- * Gets the class definitions section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the class definitions section
- */
- /*package*/ ClassDefsSection getClassDefs() {
- return classDefs;
- }
-
- /**
- * Gets the class data section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the class data section
- */
- /*package*/ MixedItemSection getClassData() {
- return classData;
- }
-
- /**
- * Gets the type identifiers section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the class identifiers section
- */
- public TypeIdsSection getTypeIds() {
- return typeIds;
- }
-
- /**
- * Gets the prototype identifiers section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the prototype identifiers section
- */
- /*package*/ ProtoIdsSection getProtoIds() {
- return protoIds;
- }
-
- /**
- * Gets the field identifiers section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the field identifiers section
- */
- public FieldIdsSection getFieldIds() {
- return fieldIds;
- }
-
- /**
- * Gets the method identifiers section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the method identifiers section
- */
- public MethodIdsSection getMethodIds() {
- return methodIds;
- }
-
- /**
- * Gets the byte data section.
- *
- * <p>This is package-scope in order to allow
- * the various {@link Item} instances to add items to the
- * instance.</p>
- *
- * @return {@code non-null;} the byte data section
- */
- /*package*/ MixedItemSection getByteData() {
- return byteData;
- }
-
- /**
- * Gets the first section of the file that is to be considered
- * part of the data section.
- *
- * <p>This is package-scope in order to allow the header section
- * to query it.</p>
- *
- * @return {@code non-null;} the section
- */
- /*package*/ Section getFirstDataSection() {
- return wordData;
- }
-
- /**
- * Gets the last section of the file that is to be considered
- * part of the data section.
- *
- * <p>This is package-scope in order to allow the header section
- * to query it.</p>
- *
- * @return {@code non-null;} the section
- */
- /*package*/ Section getLastDataSection() {
- return map;
- }
-
- /**
- * Interns the given constant in the appropriate section of this
- * instance, or do nothing if the given constant isn't the sort
- * that should be interned.
- *
- * @param cst {@code non-null;} constant to possibly intern
- */
- /*package*/ void internIfAppropriate(Constant cst) {
- if (cst instanceof CstString) {
- stringIds.intern((CstString) cst);
- } else if (cst instanceof CstType) {
- typeIds.intern((CstType) cst);
- } else if (cst instanceof CstBaseMethodRef) {
- methodIds.intern((CstBaseMethodRef) cst);
- } else if (cst instanceof CstFieldRef) {
- fieldIds.intern((CstFieldRef) cst);
- } else if (cst instanceof CstEnumRef) {
- fieldIds.intern(((CstEnumRef) cst).getFieldRef());
- } else if (cst == null) {
- throw new NullPointerException("cst == null");
- }
- }
-
- /**
- * Gets the {@link IndexedItem} corresponding to the given constant,
- * if it is a constant that has such a correspondence, or return
- * {@code null} if it isn't such a constant. This will throw
- * an exception if the given constant <i>should</i> have been found
- * but wasn't.
- *
- * @param cst {@code non-null;} the constant to look up
- * @return {@code null-ok;} its corresponding item, if it has a corresponding
- * item, or {@code null} if it's not that sort of constant
- */
- public IndexedItem findItemOrNull(Constant cst) {
- if (cst instanceof CstString) {
- return stringIds.get(cst);
- } else if (cst instanceof CstType) {
- return typeIds.get(cst);
- } else if (cst instanceof CstBaseMethodRef) {
- return methodIds.get(cst);
- } else if (cst instanceof CstFieldRef) {
- return fieldIds.get(cst);
+ out.writeZeroes(one.getFileOffset() - out.getCursor());
+ one.writeTo(out);
+ } catch (RuntimeException ex) {
+ ExceptionWithContext ec;
+ if (ex instanceof ExceptionWithContext) {
+ ec = (ExceptionWithContext) ex;
} else {
- return null;
+ ec = new ExceptionWithContext(ex);
}
+ ec.addContext("...while writing section " + i);
+ throw ec;
+ }
}
- /**
- * Returns the contents of this instance as a {@code .dex} file,
- * in a {@link ByteArrayAnnotatedOutput} instance.
- *
- * @param annotate whether or not to keep annotations
- * @param verbose if annotating, whether to be verbose
- * @return {@code non-null;} a {@code .dex} file for this instance
- */
- private ByteArrayAnnotatedOutput toDex0(boolean annotate,
- boolean verbose) {
- /*
- * The following is ordered so that the prepare() calls which
- * add items happen before the calls to the sections that get
- * added to.
- */
-
- if (cstIndexMaps != null) {
- for (CstIndexMap cstIndexMap : cstIndexMaps) {
- cstIndexMap.mergeConstantsIntoDexFile(this);
- }
- }
-
- classDefs.prepare();
- classData.prepare();
- wordData.prepare();
- byteData.prepare();
- methodIds.prepare();
- fieldIds.prepare();
- protoIds.prepare();
- typeLists.prepare();
- typeIds.prepare();
- stringIds.prepare();
- stringData.prepare();
- header.prepare();
-
- // Place the sections within the file.
-
- int count = sections.length;
- int offset = 0;
-
- for (int i = 0; i < count; i++) {
- Section one = sections[i];
- int placedAt = one.setFileOffset(offset);
- if (placedAt < offset) {
- throw new RuntimeException("bogus placement for section " + i);
- }
-
- try {
- if (one == map) {
- /*
- * Inform the map of all the sections, and add it
- * to the file. This can only be done after all
- * the other items have been sorted and placed.
- */
- MapItem.addMap(sections, map);
- map.prepare();
- }
-
- if (one instanceof MixedItemSection) {
- /*
- * Place the items of a MixedItemSection that just
- * got placed.
- */
- ((MixedItemSection) one).placeItems();
- }
-
- offset = placedAt + one.writeSize();
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while writing section " + i);
- }
- }
-
- // Write out all the sections.
-
- fileSize = offset;
- byte[] barr = new byte[fileSize];
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr);
-
- if (annotate) {
- out.enableAnnotations(dumpWidth, verbose);
- }
-
- for (int i = 0; i < count; i++) {
- try {
- Section one = sections[i];
- int zeroCount = one.getFileOffset() - out.getCursor();
- if (zeroCount < 0) {
- throw new ExceptionWithContext("excess write of " +
- (-zeroCount));
- }
- out.writeZeroes(one.getFileOffset() - out.getCursor());
- one.writeTo(out);
- } catch (RuntimeException ex) {
- ExceptionWithContext ec;
- if (ex instanceof ExceptionWithContext) {
- ec = (ExceptionWithContext) ex;
- } else {
- ec = new ExceptionWithContext(ex);
- }
- ec.addContext("...while writing section " + i);
- throw ec;
- }
- }
-
- if (out.getCursor() != fileSize) {
- throw new RuntimeException("foreshortened write");
- }
-
- // Perform final bookkeeping.
-
- calcSignature(barr);
- calcChecksum(barr);
-
- if (annotate) {
- wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM,
- "\nmethod code index:\n\n");
- getStatistics().writeAnnotation(out);
- out.finishAnnotating();
- }
-
- return out;
+ if (out.getCursor() != fileSize) {
+ throw new RuntimeException("foreshortened write");
}
- /**
- * Generates and returns statistics for all the items in the file.
- *
- * @return {@code non-null;} the statistics
- */
- public Statistics getStatistics() {
- Statistics stats = new Statistics();
+ // Perform final bookkeeping.
- for (Section s : sections) {
- stats.addAll(s);
- }
+ calcSignature(barr);
+ calcChecksum(barr);
- return stats;
+ if (annotate) {
+ wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM, "\nmethod code index:\n\n");
+ getStatistics().writeAnnotation(out);
+ out.finishAnnotating();
}
- /**
- * Calculates the signature for the {@code .dex} file in the
- * given array, and modify the array to contain it.
- *
- * @param bytes {@code non-null;} the bytes of the file
- */
- private static void calcSignature(byte[] bytes) {
- MessageDigest md;
+ return out;
+ }
- try {
- md = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException ex) {
- throw new RuntimeException(ex);
- }
+ /**
+ * Generates and returns statistics for all the items in the file.
+ *
+ * @return {@code non-null;} the statistics
+ */
+ public Statistics getStatistics() {
+ Statistics stats = new Statistics();
- md.update(bytes, 32, bytes.length - 32);
-
- try {
- int amt = md.digest(bytes, 12, 20);
- if (amt != 20) {
- throw new RuntimeException("unexpected digest write: " + amt +
- " bytes");
- }
- } catch (DigestException ex) {
- throw new RuntimeException(ex);
- }
+ for (Section s : sections) {
+ stats.addAll(s);
}
- /**
- * Calculates the checksum for the {@code .dex} file in the
- * given array, and modify the array to contain it.
- *
- * @param bytes {@code non-null;} the bytes of the file
- */
- private static void calcChecksum(byte[] bytes) {
- Adler32 a32 = new Adler32();
+ return stats;
+ }
- a32.update(bytes, 12, bytes.length - 12);
+ /**
+ * Calculates the signature for the {@code .dex} file in the
+ * given array, and modify the array to contain it.
+ *
+ * @param bytes {@code non-null;} the bytes of the file
+ */
+ private static void calcSignature(byte[] bytes) {
+ MessageDigest md;
- int sum = (int) a32.getValue();
-
- bytes[8] = (byte) sum;
- bytes[9] = (byte) (sum >> 8);
- bytes[10] = (byte) (sum >> 16);
- bytes[11] = (byte) (sum >> 24);
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException(ex);
}
+
+ md.update(bytes, 32, bytes.length - 32);
+
+ try {
+ int amt = md.digest(bytes, 12, 20);
+ if (amt != 20) {
+ throw new RuntimeException("unexpected digest write: " + amt + " bytes");
+ }
+ } catch (DigestException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Calculates the checksum for the {@code .dex} file in the
+ * given array, and modify the array to contain it.
+ *
+ * @param bytes {@code non-null;} the bytes of the file
+ */
+ private static void calcChecksum(byte[] bytes) {
+ Adler32 a32 = new Adler32();
+
+ a32.update(bytes, 12, bytes.length - 12);
+
+ int sum = (int) a32.getValue();
+
+ bytes[8] = (byte) sum;
+ bytes[9] = (byte) (sum >> 8);
+ bytes[10] = (byte) (sum >> 16);
+ bytes[11] = (byte) (sum >> 24);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/jack/dx/dex/file/EncodedArrayItem.java
index b87b7cc..7bad073 100644
--- a/dx/src/com/android/jack/dx/dex/file/EncodedArrayItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/EncodedArrayItem.java
@@ -24,99 +24,100 @@
* Encoded array of constant values.
*/
public final class EncodedArrayItem extends OffsettedItem {
- /** the required alignment for instances of this class */
- private static final int ALIGNMENT = 1;
+ /** the required alignment for instances of this class */
+ private static final int ALIGNMENT = 1;
- /** {@code non-null;} the array to represent */
- private final CstArray array;
+ /** {@code non-null;} the array to represent */
+ private final CstArray array;
- /**
- * {@code null-ok;} encoded form, ready for writing to a file; set during
- * {@link #place0}
+ /**
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
+ * {@link #place0}
+ */
+ private byte[] encodedForm;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param array {@code non-null;} array to represent
+ */
+ public EncodedArrayItem(CstArray array) {
+ /*
+ * The write size isn't known up-front because (the variable-lengthed)
+ * leb128 type is used to represent some things.
*/
- private byte[] encodedForm;
+ super(ALIGNMENT, -1);
- /**
- * Constructs an instance.
- *
- * @param array {@code non-null;} array to represent
- */
- public EncodedArrayItem(CstArray array) {
- /*
- * The write size isn't known up-front because (the variable-lengthed)
- * leb128 type is used to represent some things.
- */
- super(ALIGNMENT, -1);
-
- if (array == null) {
- throw new NullPointerException("array == null");
- }
-
- this.array = array;
- this.encodedForm = null;
+ if (array == null) {
+ throw new NullPointerException("array == null");
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_ENCODED_ARRAY_ITEM;
+ this.array = array;
+ this.encodedForm = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_ENCODED_ARRAY_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return array.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(OffsettedItem other) {
+ EncodedArrayItem otherArray = (EncodedArrayItem) other;
+
+ return array.compareTo(otherArray.array);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return array.toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ ValueEncoder.addContents(file, array);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ // Encode the data and note the size.
+
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+ ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+ encoder.writeArray(array, false);
+ encodedForm = out.toByteArray();
+ setWriteSize(encodedForm.length);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+
+ if (annotates) {
+ out.annotate(0, offsetString() + " encoded array");
+
+ /*
+ * The output is to be annotated, so redo the work previously
+ * done by place0(), except this time annotations will actually
+ * get emitted.
+ */
+ ValueEncoder encoder = new ValueEncoder(file, out);
+ encoder.writeArray(array, true);
+ } else {
+ out.write(encodedForm);
}
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return array.hashCode();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(OffsettedItem other) {
- EncodedArrayItem otherArray = (EncodedArrayItem) other;
-
- return array.compareTo(otherArray.array);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return array.toHuman();
- }
-
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- ValueEncoder.addContents(file, array);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- // Encode the data and note the size.
-
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
- ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
-
- encoder.writeArray(array, false);
- encodedForm = out.toByteArray();
- setWriteSize(encodedForm.length);
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- boolean annotates = out.annotates();
-
- if (annotates) {
- out.annotate(0, offsetString() + " encoded array");
-
- /*
- * The output is to be annotated, so redo the work previously
- * done by place0(), except this time annotations will actually
- * get emitted.
- */
- ValueEncoder encoder = new ValueEncoder(file, out);
- encoder.writeArray(array, true);
- } else {
- out.write(encodedForm);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/EncodedField.java b/dx/src/com/android/jack/dx/dex/file/EncodedField.java
index 29a6484..cc3d068 100644
--- a/dx/src/com/android/jack/dx/dex/file/EncodedField.java
+++ b/dx/src/com/android/jack/dx/dex/file/EncodedField.java
@@ -28,127 +28,126 @@
/**
* Representation of a field of a class, of any sort.
*/
-public final class EncodedField extends EncodedMember
- implements Comparable<EncodedField> {
- /** {@code non-null;} constant for the field */
- private final CstFieldRef field;
+public final class EncodedField extends EncodedMember implements Comparable<EncodedField> {
+ /** {@code non-null;} constant for the field */
+ private final CstFieldRef field;
- /**
- * Constructs an instance.
- *
- * @param field {@code non-null;} constant for the field
- * @param accessFlags access flags
+ /**
+ * Constructs an instance.
+ *
+ * @param field {@code non-null;} constant for the field
+ * @param accessFlags access flags
+ */
+ public EncodedField(CstFieldRef field, int accessFlags) {
+ super(accessFlags);
+
+ if (field == null) {
+ throw new NullPointerException("field == null");
+ }
+
+ /*
+ * TODO(dx team): Maybe check accessFlags, at least for
+ * easily-checked stuff?
*/
- public EncodedField(CstFieldRef field, int accessFlags) {
- super(accessFlags);
- if (field == null) {
- throw new NullPointerException("field == null");
- }
+this.field = field;
+ }
- /*
- * TODO: Maybe check accessFlags, at least for
- * easily-checked stuff?
- */
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return field.hashCode();
+ }
- this.field = field;
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof EncodedField)) {
+ return false;
}
- /** {@inheritDoc} */
- public int hashCode() {
- return field.hashCode();
+ return compareTo((EncodedField) other) == 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b> This compares the method constants only,
+ * ignoring any associated code, because it should never be the
+ * case that two different items with the same method constant
+ * ever appear in the same list (or same file, even).</p>
+ */
+ @Override
+ public int compareTo(EncodedField other) {
+ return field.compareTo(other.field);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append(getClass().getName());
+ sb.append('{');
+ sb.append(Hex.u2(getAccessFlags()));
+ sb.append(' ');
+ sb.append(field);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ FieldIdsSection fieldIds = file.getFieldIds();
+ fieldIds.intern(field);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public CstString getName() {
+ return field.getNat().getName();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return field.toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void debugPrint(PrintWriter out, boolean verbose) {
+ // TODO(dx team): Maybe put something better here?
+ out.println(toString());
+ }
+
+ /**
+ * Gets the constant for the field.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public CstFieldRef getRef() {
+ return field;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int encode(DexFile file, AnnotatedOutput out, int lastIndex, int dumpSeq) {
+ int fieldIdx = file.getFieldIds().indexOf(field);
+ int diff = fieldIdx - lastIndex;
+ int accessFlags = getAccessFlags();
+
+ if (out.annotates()) {
+ out.annotate(0, String.format(" [%x] %s", dumpSeq, field.toHuman()));
+ out.annotate(Leb128Utils.unsignedLeb128Size(diff), " field_idx: " + Hex.u4(fieldIdx));
+ out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+ " access_flags: " + AccessFlags.fieldString(accessFlags));
}
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (! (other instanceof EncodedField)) {
- return false;
- }
+ out.writeUleb128(diff);
+ out.writeUleb128(accessFlags);
- return compareTo((EncodedField) other) == 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * <p><b>Note:</b> This compares the method constants only,
- * ignoring any associated code, because it should never be the
- * case that two different items with the same method constant
- * ever appear in the same list (or same file, even).</p>
- */
- public int compareTo(EncodedField other) {
- return field.compareTo(other.field);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(100);
-
- sb.append(getClass().getName());
- sb.append('{');
- sb.append(Hex.u2(getAccessFlags()));
- sb.append(' ');
- sb.append(field);
- sb.append('}');
- return sb.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- FieldIdsSection fieldIds = file.getFieldIds();
- fieldIds.intern(field);
- }
-
- /** {@inheritDoc} */
- @Override
- public CstString getName() {
- return field.getNat().getName();
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return field.toHuman();
- }
-
- /** {@inheritDoc} */
- @Override
- public void debugPrint(PrintWriter out, boolean verbose) {
- // TODO: Maybe put something better here?
- out.println(toString());
- }
-
- /**
- * Gets the constant for the field.
- *
- * @return {@code non-null;} the constant
- */
- public CstFieldRef getRef() {
- return field;
- }
-
- /** {@inheritDoc} */
- @Override
- public int encode(DexFile file, AnnotatedOutput out,
- int lastIndex, int dumpSeq) {
- int fieldIdx = file.getFieldIds().indexOf(field);
- int diff = fieldIdx - lastIndex;
- int accessFlags = getAccessFlags();
-
- if (out.annotates()) {
- out.annotate(0, String.format(" [%x] %s", dumpSeq,
- field.toHuman()));
- out.annotate(Leb128Utils.unsignedLeb128Size(diff),
- " field_idx: " + Hex.u4(fieldIdx));
- out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
- " access_flags: " +
- AccessFlags.fieldString(accessFlags));
- }
-
- out.writeUleb128(diff);
- out.writeUleb128(accessFlags);
-
- return fieldIdx;
- }
+ return fieldIdx;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/EncodedMember.java b/dx/src/com/android/jack/dx/dex/file/EncodedMember.java
index 6502d0f..0a1a962 100644
--- a/dx/src/com/android/jack/dx/dex/file/EncodedMember.java
+++ b/dx/src/com/android/jack/dx/dex/file/EncodedMember.java
@@ -27,60 +27,59 @@
* purposes of encoding it inside a {@link ClassDataItem}.
*/
public abstract class EncodedMember implements ToHuman {
- /** access flags */
- private final int accessFlags;
+ /** access flags */
+ private final int accessFlags;
- /**
- * Constructs an instance.
- *
- * @param accessFlags access flags for the member
- */
- public EncodedMember(int accessFlags) {
- this.accessFlags = accessFlags;
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param accessFlags access flags for the member
+ */
+ public EncodedMember(int accessFlags) {
+ this.accessFlags = accessFlags;
+ }
- /**
- * Gets the access flags.
- *
- * @return the access flags
- */
- public final int getAccessFlags() {
- return accessFlags;
- }
+ /**
+ * Gets the access flags.
+ *
+ * @return the access flags
+ */
+ public final int getAccessFlags() {
+ return accessFlags;
+ }
- /**
- * Gets the name.
- *
- * @return {@code non-null;} the name
- */
- public abstract CstString getName();
+ /**
+ * Gets the name.
+ *
+ * @return {@code non-null;} the name
+ */
+ public abstract CstString getName();
- /**
- * Does a human-friendly dump of this instance.
- *
- * @param out {@code non-null;} where to dump
- * @param verbose whether to be verbose with the output
- */
- public abstract void debugPrint(PrintWriter out, boolean verbose);
+ /**
+ * Does a human-friendly dump of this instance.
+ *
+ * @param out {@code non-null;} where to dump
+ * @param verbose whether to be verbose with the output
+ */
+ public abstract void debugPrint(PrintWriter out, boolean verbose);
- /**
- * Populates a {@link DexFile} with items from within this instance.
- *
- * @param file {@code non-null;} the file to populate
- */
- public abstract void addContents(DexFile file);
+ /**
+ * Populates a {@link DexFile} with items from within this instance.
+ *
+ * @param file {@code non-null;} the file to populate
+ */
+ public abstract void addContents(DexFile file);
- /**
- * Encodes this instance to the given output.
- *
- * @param file {@code non-null;} file this instance is part of
- * @param out {@code non-null;} where to write to
- * @param lastIndex {@code >= 0;} the previous member index value encoded, or
- * {@code 0} if this is the first element to encode
- * @param dumpSeq {@code >= 0;} sequence number of this instance for
- * annotation purposes
- * @return {@code >= 0;} the member index value that was encoded
- */
- public abstract int encode(DexFile file, AnnotatedOutput out,
- int lastIndex, int dumpSeq);
+ /**
+ * Encodes this instance to the given output.
+ *
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
+ * @param lastIndex {@code >= 0;} the previous member index value encoded, or
+ * {@code 0} if this is the first element to encode
+ * @param dumpSeq {@code >= 0;} sequence number of this instance for
+ * annotation purposes
+ * @return {@code >= 0;} the member index value that was encoded
+ */
+ public abstract int encode(DexFile file, AnnotatedOutput out, int lastIndex, int dumpSeq);
}
diff --git a/dx/src/com/android/jack/dx/dex/file/EncodedMethod.java b/dx/src/com/android/jack/dx/dex/file/EncodedMethod.java
index 924a604..c75fa04 100644
--- a/dx/src/com/android/jack/dx/dex/file/EncodedMethod.java
+++ b/dx/src/com/android/jack/dx/dex/file/EncodedMethod.java
@@ -28,164 +28,157 @@
/**
* Class that representats a method of a class.
*/
-public final class EncodedMethod extends EncodedMember
- implements Comparable<EncodedMethod> {
- /** {@code non-null;} constant for the method */
- private final CstMethodRef method;
+public final class EncodedMethod extends EncodedMember implements Comparable<EncodedMethod> {
+ /** {@code non-null;} constant for the method */
+ private final CstMethodRef method;
- /**
- * {@code null-ok;} code for the method, if the method is neither
- * {@code abstract} nor {@code native}
+ /**
+ * {@code null-ok;} code for the method, if the method is neither
+ * {@code abstract} nor {@code native}
+ */
+ private final OffsettedItem code;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} constant for the method
+ * @param accessFlags access flags
+ * @param code {@code null-ok;} code for the method, if it is neither
+ * {@code abstract} nor {@code native}
+ */
+ public EncodedMethod(CstMethodRef method, int accessFlags, OffsettedItem code) {
+ super(accessFlags);
+
+ assert code == null || code instanceof Code;
+
+ if (method == null) {
+ throw new NullPointerException("method == null");
+ }
+
+ this.method = method;
+
+ this.code = code;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof EncodedMethod)) {
+ return false;
+ }
+
+ return compareTo((EncodedMethod) other) == 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b> This compares the method constants only,
+ * ignoring any associated code, because it should never be the
+ * case that two different items with the same method constant
+ * ever appear in the same list (or same file, even).</p>
+ */
+ @Override
+ public int compareTo(EncodedMethod other) {
+ return method.compareTo(other.method);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append(getClass().getName());
+ sb.append('{');
+ sb.append(Hex.u2(getAccessFlags()));
+ sb.append(' ');
+ sb.append(method);
+
+ if (code != null) {
+ sb.append(' ');
+ sb.append(code);
+ }
+
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ MethodIdsSection methodIds = file.getMethodIds();
+ MixedItemSection wordData = file.getWordData();
+
+ methodIds.intern(method);
+
+ if (code != null) {
+ wordData.add(code);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final String toHuman() {
+ return method.toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final CstString getName() {
+ return method.getNat().getName();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void debugPrint(PrintWriter out, boolean verbose) {
+ if (code == null) {
+ out.println(getRef().toHuman() + ": abstract or native");
+ } else {
+ ((Code) code).debugPrint(out, " ", verbose);
+ }
+ }
+
+ /**
+ * Gets the constant for the method.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public final CstMethodRef getRef() {
+ return method;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int encode(DexFile file, AnnotatedOutput out, int lastIndex, int dumpSeq) {
+ int methodIdx = file.getMethodIds().indexOf(method);
+ int diff = methodIdx - lastIndex;
+ int accessFlags = getAccessFlags();
+ int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code);
+ boolean hasCode = (codeOff != 0);
+ boolean shouldHaveCode =
+ (accessFlags & (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0;
+
+ /*
+ * Verify that code appears if and only if a method is
+ * declared to have it.
*/
- private final OffsettedItem code;
-
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} constant for the method
- * @param accessFlags access flags
- * @param code {@code null-ok;} code for the method, if it is neither
- * {@code abstract} nor {@code native}
- */
- public EncodedMethod(CstMethodRef method, int accessFlags, OffsettedItem code) {
- super(accessFlags);
-
- assert code == null || code instanceof Code;
-
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- this.method = method;
-
- this.code = code;
+ if (hasCode != shouldHaveCode) {
+ throw new UnsupportedOperationException("code vs. access_flags mismatch");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (! (other instanceof EncodedMethod)) {
- return false;
- }
-
- return compareTo((EncodedMethod) other) == 0;
+ if (out.annotates()) {
+ out.annotate(0, String.format(" [%x] %s", dumpSeq, method.toHuman()));
+ out.annotate(Leb128Utils.unsignedLeb128Size(diff), " method_idx: " + Hex.u4(methodIdx));
+ out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+ " access_flags: " + AccessFlags.methodString(accessFlags));
+ out.annotate(Leb128Utils.unsignedLeb128Size(codeOff), " code_off: " + Hex.u4(codeOff));
}
- /**
- * {@inheritDoc}
- *
- * <p><b>Note:</b> This compares the method constants only,
- * ignoring any associated code, because it should never be the
- * case that two different items with the same method constant
- * ever appear in the same list (or same file, even).</p>
- */
- @Override
- public int compareTo(EncodedMethod other) {
- return method.compareTo(other.method);
- }
+ out.writeUleb128(diff);
+ out.writeUleb128(accessFlags);
+ out.writeUleb128(codeOff);
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(100);
-
- sb.append(getClass().getName());
- sb.append('{');
- sb.append(Hex.u2(getAccessFlags()));
- sb.append(' ');
- sb.append(method);
-
- if (code != null) {
- sb.append(' ');
- sb.append(code);
- }
-
- sb.append('}');
-
- return sb.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- MethodIdsSection methodIds = file.getMethodIds();
- MixedItemSection wordData = file.getWordData();
-
- methodIds.intern(method);
-
- if (code != null) {
- wordData.add(code);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public final String toHuman() {
- return method.toHuman();
- }
-
- /** {@inheritDoc} */
- @Override
- public final CstString getName() {
- return method.getNat().getName();
- }
-
- /** {@inheritDoc} */
- @Override
- public void debugPrint(PrintWriter out, boolean verbose) {
- if (code == null) {
- out.println(getRef().toHuman() + ": abstract or native");
- } else {
- ((Code) code).debugPrint(out, " ", verbose);
- }
- }
-
- /**
- * Gets the constant for the method.
- *
- * @return {@code non-null;} the constant
- */
- public final CstMethodRef getRef() {
- return method;
- }
-
- /** {@inheritDoc} */
- @Override
- public int encode(DexFile file, AnnotatedOutput out,
- int lastIndex, int dumpSeq) {
- int methodIdx = file.getMethodIds().indexOf(method);
- int diff = methodIdx - lastIndex;
- int accessFlags = getAccessFlags();
- int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code);
- boolean hasCode = (codeOff != 0);
- boolean shouldHaveCode = (accessFlags &
- (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0;
-
- /*
- * Verify that code appears if and only if a method is
- * declared to have it.
- */
- if (hasCode != shouldHaveCode) {
- throw new UnsupportedOperationException(
- "code vs. access_flags mismatch");
- }
-
- if (out.annotates()) {
- out.annotate(0, String.format(" [%x] %s", dumpSeq,
- method.toHuman()));
- out.annotate(Leb128Utils.unsignedLeb128Size(diff),
- " method_idx: " + Hex.u4(methodIdx));
- out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
- " access_flags: " +
- AccessFlags.methodString(accessFlags));
- out.annotate(Leb128Utils.unsignedLeb128Size(codeOff),
- " code_off: " + Hex.u4(codeOff));
- }
-
- out.writeUleb128(diff);
- out.writeUleb128(accessFlags);
- out.writeUleb128(codeOff);
-
- return methodIdx;
- }
+ return methodIdx;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/jack/dx/dex/file/FieldAnnotationStruct.java
index 8d11f73..afe4c56 100644
--- a/dx/src/com/android/jack/dx/dex/file/FieldAnnotationStruct.java
+++ b/dx/src/com/android/jack/dx/dex/file/FieldAnnotationStruct.java
@@ -25,98 +25,99 @@
/**
* Association of a field and its annotations.
*/
-public final class FieldAnnotationStruct
- implements ToHuman, Comparable<FieldAnnotationStruct> {
- /** {@code non-null;} the field in question */
- private final CstFieldRef field;
+public final class FieldAnnotationStruct implements ToHuman, Comparable<FieldAnnotationStruct> {
+ /** {@code non-null;} the field in question */
+ private final CstFieldRef field;
- /** {@code non-null;} the associated annotations */
- private AnnotationSetItem annotations;
+ /** {@code non-null;} the associated annotations */
+ private AnnotationSetItem annotations;
- /**
- * Constructs an instance.
- *
- * @param field {@code non-null;} the field in question
- * @param annotations {@code non-null;} the associated annotations
- */
- public FieldAnnotationStruct(CstFieldRef field,
- AnnotationSetItem annotations) {
- if (field == null) {
- throw new NullPointerException("field == null");
- }
-
- if (annotations == null) {
- throw new NullPointerException("annotations == null");
- }
-
- this.field = field;
- this.annotations = annotations;
+ /**
+ * Constructs an instance.
+ *
+ * @param field {@code non-null;} the field in question
+ * @param annotations {@code non-null;} the associated annotations
+ */
+ public FieldAnnotationStruct(CstFieldRef field, AnnotationSetItem annotations) {
+ if (field == null) {
+ throw new NullPointerException("field == null");
}
- /** {@inheritDoc} */
- public int hashCode() {
- return field.hashCode();
+ if (annotations == null) {
+ throw new NullPointerException("annotations == null");
}
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (! (other instanceof FieldAnnotationStruct)) {
- return false;
- }
+ this.field = field;
+ this.annotations = annotations;
+ }
- return field.equals(((FieldAnnotationStruct) other).field);
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return field.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof FieldAnnotationStruct)) {
+ return false;
}
- /** {@inheritDoc} */
- public int compareTo(FieldAnnotationStruct other) {
- return field.compareTo(other.field);
+ return field.equals(((FieldAnnotationStruct) other).field);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(FieldAnnotationStruct other) {
+ return field.compareTo(other.field);
+ }
+
+ /** {@inheritDoc} */
+ public void addContents(DexFile file) {
+ FieldIdsSection fieldIds = file.getFieldIds();
+ MixedItemSection wordData = file.getWordData();
+
+ fieldIds.intern(field);
+ annotations = wordData.intern(annotations);
+ }
+
+ /** {@inheritDoc} */
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int fieldIdx = file.getFieldIds().indexOf(field);
+ int annotationsOff = annotations.getAbsoluteOffset();
+
+ if (out.annotates()) {
+ out.annotate(0, " " + field.toHuman());
+ out.annotate(4, " field_idx: " + Hex.u4(fieldIdx));
+ out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff));
}
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- FieldIdsSection fieldIds = file.getFieldIds();
- MixedItemSection wordData = file.getWordData();
+ out.writeInt(fieldIdx);
+ out.writeInt(annotationsOff);
+ }
- fieldIds.intern(field);
- annotations = wordData.intern(annotations);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return field.toHuman() + ": " + annotations;
+ }
- /** {@inheritDoc} */
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int fieldIdx = file.getFieldIds().indexOf(field);
- int annotationsOff = annotations.getAbsoluteOffset();
+ /**
+ * Gets the field this item is for.
+ *
+ * @return {@code non-null;} the field
+ */
+ public CstFieldRef getField() {
+ return field;
+ }
- if (out.annotates()) {
- out.annotate(0, " " + field.toHuman());
- out.annotate(4, " field_idx: " + Hex.u4(fieldIdx));
- out.annotate(4, " annotations_off: " +
- Hex.u4(annotationsOff));
- }
-
- out.writeInt(fieldIdx);
- out.writeInt(annotationsOff);
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return field.toHuman() + ": " + annotations;
- }
-
- /**
- * Gets the field this item is for.
- *
- * @return {@code non-null;} the field
- */
- public CstFieldRef getField() {
- return field;
- }
-
- /**
- * Gets the associated annotations.
- *
- * @return {@code non-null;} the annotations
- */
- public Annotations getAnnotations() {
- return annotations.getAnnotations();
- }
+ /**
+ * Gets the associated annotations.
+ *
+ * @return {@code non-null;} the annotations
+ */
+ public Annotations getAnnotations() {
+ return annotations.getAnnotations();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/FieldIdItem.java b/dx/src/com/android/jack/dx/dex/file/FieldIdItem.java
index 373ae6c..df58131 100644
--- a/dx/src/com/android/jack/dx/dex/file/FieldIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/FieldIdItem.java
@@ -22,49 +22,49 @@
* Representation of a field reference inside a Dalvik file.
*/
public final class FieldIdItem extends MemberIdItem {
- /**
- * Constructs an instance.
- *
- * @param field {@code non-null;} the constant for the field
- */
- public FieldIdItem(CstFieldRef field) {
- super(field);
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param field {@code non-null;} the constant for the field
+ */
+ public FieldIdItem(CstFieldRef field) {
+ super(field);
+ }
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_FIELD_ID_ITEM;
- }
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_FIELD_ID_ITEM;
+ }
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- super.addContents(file);
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ super.addContents(file);
- TypeIdsSection typeIds = file.getTypeIds();
- typeIds.intern(getFieldRef().getType());
- }
+ TypeIdsSection typeIds = file.getTypeIds();
+ typeIds.intern(getFieldRef().getType());
+ }
- /**
- * Gets the field constant.
- *
- * @return {@code non-null;} the constant
- */
- public CstFieldRef getFieldRef() {
- return (CstFieldRef) getRef();
- }
+ /**
+ * Gets the field constant.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public CstFieldRef getFieldRef() {
+ return (CstFieldRef) getRef();
+ }
- /** {@inheritDoc} */
- @Override
- protected int getTypoidIdx(DexFile file) {
- TypeIdsSection typeIds = file.getTypeIds();
- return typeIds.indexOf(getFieldRef().getType());
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int getTypoidIdx(DexFile file) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ return typeIds.indexOf(getFieldRef().getType());
+ }
- /** {@inheritDoc} */
- @Override
- protected String getTypoidName() {
- return "type_idx";
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String getTypoidName() {
+ return "type_idx";
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/jack/dx/dex/file/FieldIdsSection.java
index 66d30f4..d623b74 100644
--- a/dx/src/com/android/jack/dx/dex/file/FieldIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/FieldIdsSection.java
@@ -28,110 +28,110 @@
* Field refs list section of a {@code .dex} file.
*/
public final class FieldIdsSection extends MemberIdsSection {
- /**
- * {@code non-null;} map from field constants to {@link
- * FieldIdItem} instances
- */
- private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
+ /**
+ * {@code non-null;} map from field constants to {@link
+ * FieldIdItem} instances
+ */
+ private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public FieldIdsSection(DexFile file) {
- super("field_ids", file);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public FieldIdsSection(DexFile file) {
+ super("field_ids", file);
- fieldIds = new TreeMap<CstFieldRef, FieldIdItem>();
+ fieldIds = new TreeMap<CstFieldRef, FieldIdItem>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return fieldIds.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return fieldIds.values();
+ throwIfNotPrepared();
+
+ IndexedItem result = fieldIds.get(cst);
+
+ if (result == null) {
+ throw new IllegalArgumentException("not found");
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
- IndexedItem result = fieldIds.get((CstFieldRef) cst);
+ int sz = fieldIds.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
- if (result == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return result;
+ if (out.annotates()) {
+ out.annotate(4, "field_ids_size: " + Hex.u4(sz));
+ out.annotate(4, "field_ids_off: " + Hex.u4(offset));
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
- int sz = fieldIds.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
-
- if (out.annotates()) {
- out.annotate(4, "field_ids_size: " + Hex.u4(sz));
- out.annotate(4, "field_ids_off: " + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ /**
+ * Interns an element into this instance.
+ *
+ * @param field {@code non-null;} the reference to intern
+ * @return {@code non-null;} the interned reference
+ */
+ public FieldIdItem intern(CstFieldRef field) {
+ if (field == null) {
+ throw new NullPointerException("field == null");
}
- /**
- * Interns an element into this instance.
- *
- * @param field {@code non-null;} the reference to intern
- * @return {@code non-null;} the interned reference
- */
- public FieldIdItem intern(CstFieldRef field) {
- if (field == null) {
- throw new NullPointerException("field == null");
- }
+ throwIfPrepared();
- throwIfPrepared();
+ FieldIdItem result = fieldIds.get(field);
- FieldIdItem result = fieldIds.get(field);
-
- if (result == null) {
- result = new FieldIdItem(field);
- fieldIds.put(field, result);
- }
-
- return result;
+ if (result == null) {
+ result = new FieldIdItem(field);
+ fieldIds.put(field, result);
}
- /**
- * Gets the index of the given reference, which must have been added
- * to this instance.
- *
- * @param ref {@code non-null;} the reference to look up
- * @return {@code >= 0;} the reference's index
- */
- public int indexOf(CstFieldRef ref) {
- if (ref == null) {
- throw new NullPointerException("ref == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
-
- FieldIdItem item = fieldIds.get(ref);
-
- if (item == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return item.getIndex();
+ /**
+ * Gets the index of the given reference, which must have been added
+ * to this instance.
+ *
+ * @param ref {@code non-null;} the reference to look up
+ * @return {@code >= 0;} the reference's index
+ */
+ public int indexOf(CstFieldRef ref) {
+ if (ref == null) {
+ throw new NullPointerException("ref == null");
}
+
+ throwIfNotPrepared();
+
+ FieldIdItem item = fieldIds.get(ref);
+
+ if (item == null) {
+ throw new IllegalArgumentException("not found");
+ }
+
+ return item.getIndex();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/HeaderItem.java b/dx/src/com/android/jack/dx/dex/file/HeaderItem.java
index 4846235..281b8b2 100644
--- a/dx/src/com/android/jack/dx/dex/file/HeaderItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/HeaderItem.java
@@ -26,90 +26,88 @@
* File header section of a {@code .dex} file.
*/
public final class HeaderItem extends IndexedItem {
- /**
- * Constructs an instance.
+ /**
+ * Constructs an instance.
+ */
+ public HeaderItem() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_HEADER_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.HEADER_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ // Nothing to do here.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int mapOff = file.getMap().getFileOffset();
+ Section firstDataSection = file.getFirstDataSection();
+ Section lastDataSection = file.getLastDataSection();
+ int dataOff = firstDataSection.getFileOffset();
+ int dataSize = lastDataSection.getFileOffset() + lastDataSection.writeSize() - dataOff;
+
+ String magic = file.getDexOptions().getMagic();
+
+ if (out.annotates()) {
+ out.annotate(8, "magic: " + new CstString(magic).toQuoted());
+ out.annotate(4, "checksum");
+ out.annotate(20, "signature");
+ out.annotate(4, "file_size: " + Hex.u4(file.getFileSize()));
+ out.annotate(4, "header_size: " + Hex.u4(SizeOf.HEADER_ITEM));
+ out.annotate(4, "endian_tag: " + Hex.u4(DexFormat.ENDIAN_TAG));
+ out.annotate(4, "link_size: 0");
+ out.annotate(4, "link_off: 0");
+ out.annotate(4, "map_off: " + Hex.u4(mapOff));
+ }
+
+ // Write the magic number.
+ for (int i = 0; i < 8; i++) {
+ out.writeByte(magic.charAt(i));
+ }
+
+ // Leave space for the checksum and signature.
+ out.writeZeroes(24);
+
+ out.writeInt(file.getFileSize());
+ out.writeInt(SizeOf.HEADER_ITEM);
+ out.writeInt(DexFormat.ENDIAN_TAG);
+
+ /*
+ * Write zeroes for the link size and data, as the output
+ * isn't a staticly linked file.
*/
- public HeaderItem() {
- // This space intentionally left blank.
+ out.writeZeroes(8);
+
+ out.writeInt(mapOff);
+
+ // Write out each section's respective header part.
+ file.getStringIds().writeHeaderPart(out);
+ file.getTypeIds().writeHeaderPart(out);
+ file.getProtoIds().writeHeaderPart(out);
+ file.getFieldIds().writeHeaderPart(out);
+ file.getMethodIds().writeHeaderPart(out);
+ file.getClassDefs().writeHeaderPart(out);
+
+ if (out.annotates()) {
+ out.annotate(4, "data_size: " + Hex.u4(dataSize));
+ out.annotate(4, "data_off: " + Hex.u4(dataOff));
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_HEADER_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.HEADER_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- // Nothing to do here.
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int mapOff = file.getMap().getFileOffset();
- Section firstDataSection = file.getFirstDataSection();
- Section lastDataSection = file.getLastDataSection();
- int dataOff = firstDataSection.getFileOffset();
- int dataSize = lastDataSection.getFileOffset() +
- lastDataSection.writeSize() - dataOff;
-
- String magic = file.getDexOptions().getMagic();
-
- if (out.annotates()) {
- out.annotate(8, "magic: " + new CstString(magic).toQuoted());
- out.annotate(4, "checksum");
- out.annotate(20, "signature");
- out.annotate(4, "file_size: " +
- Hex.u4(file.getFileSize()));
- out.annotate(4, "header_size: " + Hex.u4(SizeOf.HEADER_ITEM));
- out.annotate(4, "endian_tag: " + Hex.u4(DexFormat.ENDIAN_TAG));
- out.annotate(4, "link_size: 0");
- out.annotate(4, "link_off: 0");
- out.annotate(4, "map_off: " + Hex.u4(mapOff));
- }
-
- // Write the magic number.
- for (int i = 0; i < 8; i++) {
- out.writeByte(magic.charAt(i));
- }
-
- // Leave space for the checksum and signature.
- out.writeZeroes(24);
-
- out.writeInt(file.getFileSize());
- out.writeInt(SizeOf.HEADER_ITEM);
- out.writeInt(DexFormat.ENDIAN_TAG);
-
- /*
- * Write zeroes for the link size and data, as the output
- * isn't a staticly linked file.
- */
- out.writeZeroes(8);
-
- out.writeInt(mapOff);
-
- // Write out each section's respective header part.
- file.getStringIds().writeHeaderPart(out);
- file.getTypeIds().writeHeaderPart(out);
- file.getProtoIds().writeHeaderPart(out);
- file.getFieldIds().writeHeaderPart(out);
- file.getMethodIds().writeHeaderPart(out);
- file.getClassDefs().writeHeaderPart(out);
-
- if (out.annotates()) {
- out.annotate(4, "data_size: " + Hex.u4(dataSize));
- out.annotate(4, "data_off: " + Hex.u4(dataOff));
- }
-
- out.writeInt(dataSize);
- out.writeInt(dataOff);
- }
+ out.writeInt(dataSize);
+ out.writeInt(dataOff);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/HeaderSection.java b/dx/src/com/android/jack/dx/dex/file/HeaderSection.java
index e2043e6..a5df91b 100644
--- a/dx/src/com/android/jack/dx/dex/file/HeaderSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/HeaderSection.java
@@ -26,38 +26,38 @@
* File header section of a {@code .dex} file.
*/
public final class HeaderSection extends UniformItemSection {
- /** {@code non-null;} the list of the one item in the section */
- private final List<HeaderItem> list;
+ /** {@code non-null;} the list of the one item in the section */
+ private final List<HeaderItem> list;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public HeaderSection(DexFile file) {
- super(null, file, 4);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public HeaderSection(DexFile file) {
+ super(null, file, 4);
- HeaderItem item = new HeaderItem();
- item.setIndex(0);
+ HeaderItem item = new HeaderItem();
+ item.setIndex(0);
- this.list = Collections.singletonList(item);
- }
+ this.list = Collections.singletonList(item);
+ }
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- return null;
- }
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ return null;
+ }
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return list;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return list;
+ }
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- // Nothing to do here.
- }
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ // Nothing to do here.
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/IdItem.java b/dx/src/com/android/jack/dx/dex/file/IdItem.java
index acf82c4..df27a71 100644
--- a/dx/src/com/android/jack/dx/dex/file/IdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/IdItem.java
@@ -22,40 +22,40 @@
* Representation of a reference to an item inside a Dalvik file.
*/
public abstract class IdItem extends IndexedItem {
- /**
- * {@code non-null;} the type constant for the defining class of
- * the reference
- */
- private final CstType type;
+ /**
+ * {@code non-null;} the type constant for the defining class of
+ * the reference
+ */
+ private final CstType type;
- /**
- * Constructs an instance.
- *
- * @param type {@code non-null;} the type constant for the defining
- * class of the reference
- */
- public IdItem(CstType type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
-
- this.type = type;
+ /**
+ * Constructs an instance.
+ *
+ * @param type {@code non-null;} the type constant for the defining
+ * class of the reference
+ */
+ public IdItem(CstType type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- TypeIdsSection typeIds = file.getTypeIds();
- typeIds.intern(type);
- }
+ this.type = type;
+ }
- /**
- * Gets the type constant for the defining class of the
- * reference.
- *
- * @return {@code non-null;} the type constant
- */
- public final CstType getDefiningClass() {
- return type;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ typeIds.intern(type);
+ }
+
+ /**
+ * Gets the type constant for the defining class of the
+ * reference.
+ *
+ * @return {@code non-null;} the type constant
+ */
+ public final CstType getDefiningClass() {
+ return type;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ImportedCodeItem.java b/dx/src/com/android/jack/dx/dex/file/ImportedCodeItem.java
index c3d6fd1..0bf8a04 100644
--- a/dx/src/com/android/jack/dx/dex/file/ImportedCodeItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/ImportedCodeItem.java
@@ -16,16 +16,13 @@
package com.android.jack.dx.dex.file;
-import java.io.PrintWriter;
-
import com.android.jack.dx.io.Code;
-import com.android.jack.dx.io.CodeReader;
-import com.android.jack.dx.io.Opcodes;
import com.android.jack.dx.io.Code.CatchHandler;
import com.android.jack.dx.io.Code.Try;
+import com.android.jack.dx.io.CodeReader;
+import com.android.jack.dx.io.Opcodes;
import com.android.jack.dx.io.instructions.DecodedInstruction;
import com.android.jack.dx.io.instructions.ShortArrayCodeOutput;
-import com.android.jack.dx.rop.cst.Constant;
import com.android.jack.dx.rop.cst.CstIndexMap;
import com.android.jack.dx.rop.cst.CstMethodRef;
import com.android.jack.dx.util.AnnotatedOutput;
@@ -33,10 +30,13 @@
import com.android.jack.dx.util.DexException;
import com.android.jack.dx.util.Hex;
+import java.io.PrintWriter;
+
/**
* Representation of all the parts needed to import methods from a {@code dex} file into another.
*/
-public final class ImportedCodeItem extends OffsettedItem implements com.android.jack.dx.dex.file.Code {
+public final class ImportedCodeItem extends OffsettedItem implements
+ com.android.jack.dx.dex.file.Code {
/** {@code null-ok;} the imported debug info or {@code null} if there is none; */
ImportedDebugInfoItem debugInfoItem = null;
@@ -101,6 +101,7 @@
}
/** {@inheritDoc} */
+ @Override
public void addContents(DexFile file) {
if (debugInfoItem != null) {
file.getByteData().add(debugInfoItem);
@@ -132,7 +133,8 @@
protected void place0(Section addedTo, int offset) {
int triesLength = code.getTries().length;
- encodedHandlers = triesLength != 0 ? encodeAndRemapCatchHandler(addedTo.getFile()) : new byte[0];
+ encodedHandlers =
+ triesLength != 0 ? encodeAndRemapCatchHandler(addedTo.getFile()) : new byte[0];
int catchesSize = triesLength * CatchStructs.TRY_ITEM_WRITE_SIZE + encodedHandlers.length;
@@ -314,6 +316,7 @@
private class GenericVisitor implements CodeReader.Visitor {
+ @Override
public void visit(DecodedInstruction[] all, DecodedInstruction decodedInst) {
remappedInstructions[remappingIndex++] = decodedInst;
}
@@ -335,8 +338,8 @@
int newIndex = cstIndexMap.getRemappedCstStringIndex(file, decodedInst.getIndex());
if (decodedInst.getOpcode() != Opcodes.CONST_STRING_JUMBO && (newIndex > 0xffff)) {
- throw new DexException("Cannot remap new index " + newIndex
- + " into a non-jumbo instruction!");
+ throw new DexException(
+ "Cannot remap new index " + newIndex + " into a non-jumbo instruction!");
}
remappedInstructions[remappingIndex++] = decodedInst.withIndex(newIndex);
@@ -356,8 +359,8 @@
@Override
public void visit(DecodedInstruction[] all, DecodedInstruction decodedInst) {
- remappedInstructions[remappingIndex++] =
- decodedInst.withIndex(cstIndexMap.getRemappedCstFieldRefIndex(file, decodedInst.getIndex()));
+ remappedInstructions[remappingIndex++] = decodedInst.withIndex(
+ cstIndexMap.getRemappedCstFieldRefIndex(file, decodedInst.getIndex()));
}
}
@@ -392,9 +395,8 @@
@Override
public void visit(DecodedInstruction[] all, DecodedInstruction decodedInst) {
- remappedInstructions[remappingIndex++] =
- decodedInst.withIndex(cstIndexMap.getRemappedCstBaseMethodRefIndex(file,
- decodedInst.getIndex()));
+ remappedInstructions[remappingIndex++] = decodedInst.withIndex(
+ cstIndexMap.getRemappedCstBaseMethodRefIndex(file, decodedInst.getIndex()));
}
}
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ImportedDebugInfoItem.java b/dx/src/com/android/jack/dx/dex/file/ImportedDebugInfoItem.java
index 1d7b4cb..4219ebb 100644
--- a/dx/src/com/android/jack/dx/dex/file/ImportedDebugInfoItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/ImportedDebugInfoItem.java
@@ -27,13 +27,15 @@
import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL;
import static com.android.jack.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL_EXTENDED;
-import java.io.PrintWriter;
-
import com.android.jack.dx.io.DexBuffer;
-import com.android.jack.dx.rop.cst.Constant;
import com.android.jack.dx.rop.cst.CstIndexMap;
import com.android.jack.dx.util.AnnotatedOutput;
+import java.io.PrintWriter;
+
+/**
+ * TODO(jack team)
+ */
public class ImportedDebugInfoItem extends OffsettedItem {
/** the required alignment for instances of this class */
diff --git a/dx/src/com/android/jack/dx/dex/file/IndexedItem.java b/dx/src/com/android/jack/dx/dex/file/IndexedItem.java
index 6e2c83b..9bfefec 100644
--- a/dx/src/com/android/jack/dx/dex/file/IndexedItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/IndexedItem.java
@@ -20,62 +20,62 @@
* An item in a Dalvik file which is referenced by index.
*/
public abstract class IndexedItem extends Item {
- /** {@code >= -1;} assigned index of the item, or {@code -1} if not
- * yet assigned */
- private int index;
+ /** {@code >= -1;} assigned index of the item, or {@code -1} if not
+ * yet assigned */
+ private int index;
- /**
- * Constructs an instance. The index is initially unassigned.
- */
- public IndexedItem() {
- index = -1;
+ /**
+ * Constructs an instance. The index is initially unassigned.
+ */
+ public IndexedItem() {
+ index = -1;
+ }
+
+ /**
+ * Gets whether or not this instance has been assigned an index.
+ *
+ * @return {@code true} iff this instance has been assigned an index
+ */
+ public final boolean hasIndex() {
+ return (index >= 0);
+ }
+
+ /**
+ * Gets the item index.
+ *
+ * @return {@code >= 0;} the index
+ * @throws RuntimeException thrown if the item index is not yet assigned
+ */
+ public final int getIndex() {
+ if (index < 0) {
+ throw new RuntimeException("index not yet set");
}
- /**
- * Gets whether or not this instance has been assigned an index.
- *
- * @return {@code true} iff this instance has been assigned an index
- */
- public final boolean hasIndex() {
- return (index >= 0);
+ return index;
+ }
+
+ /**
+ * Sets the item index. This method may only ever be called once
+ * per instance, and this will throw a {@code RuntimeException} if
+ * called a second (or subsequent) time.
+ *
+ * @param index {@code >= 0;} the item index
+ */
+ public final void setIndex(int index) {
+ if (this.index != -1) {
+ throw new RuntimeException("index already set");
}
- /**
- * Gets the item index.
- *
- * @return {@code >= 0;} the index
- * @throws RuntimeException thrown if the item index is not yet assigned
- */
- public final int getIndex() {
- if (index < 0) {
- throw new RuntimeException("index not yet set");
- }
+ this.index = index;
+ }
- return index;
- }
-
- /**
- * Sets the item index. This method may only ever be called once
- * per instance, and this will throw a {@code RuntimeException} if
- * called a second (or subsequent) time.
- *
- * @param index {@code >= 0;} the item index
- */
- public final void setIndex(int index) {
- if (this.index != -1) {
- throw new RuntimeException("index already set");
- }
-
- this.index = index;
- }
-
- /**
- * Gets the index of this item as a string, suitable for including in
- * annotations.
- *
- * @return {@code non-null;} the index string
- */
- public final String indexString() {
- return '[' + Integer.toHexString(index) + ']';
- }
+ /**
+ * Gets the index of this item as a string, suitable for including in
+ * annotations.
+ *
+ * @return {@code non-null;} the index string
+ */
+ public final String indexString() {
+ return '[' + Integer.toHexString(index) + ']';
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/Item.java b/dx/src/com/android/jack/dx/dex/file/Item.java
index 6dca0e5..f1ecd64 100644
--- a/dx/src/com/android/jack/dx/dex/file/Item.java
+++ b/dx/src/com/android/jack/dx/dex/file/Item.java
@@ -23,58 +23,58 @@
* repeated piece of a Dalvik file.
*/
public abstract class Item {
- /**
- * Constructs an instance.
- */
- public Item() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance.
+ */
+ public Item() {
+ // This space intentionally left blank.
+ }
- /**
- * Returns the item type for this instance.
- *
- * @return {@code non-null;} the item type
- */
- public abstract ItemType itemType();
+ /**
+ * Returns the item type for this instance.
+ *
+ * @return {@code non-null;} the item type
+ */
+ public abstract ItemType itemType();
- /**
- * Returns the human name for the particular type of item this
- * instance is.
- *
- * @return {@code non-null;} the name
- */
- public final String typeName() {
- return itemType().toHuman();
- }
+ /**
+ * Returns the human name for the particular type of item this
+ * instance is.
+ *
+ * @return {@code non-null;} the name
+ */
+ public final String typeName() {
+ return itemType().toHuman();
+ }
- /**
- * Gets the size of this instance when written, in bytes.
- *
- * @return {@code >= 0;} the write size
- */
- public abstract int writeSize();
+ /**
+ * Gets the size of this instance when written, in bytes.
+ *
+ * @return {@code >= 0;} the write size
+ */
+ public abstract int writeSize();
- /**
- * Populates a {@link DexFile} with items from within this instance.
- * This will <i>not</i> add an item to the file for this instance itself
- * (which should have been done by whatever refers to this instance).
- *
- * <p><b>Note:</b> Subclasses must override this to do something
- * appropriate.</p>
- *
- * @param file {@code non-null;} the file to populate
- */
- public abstract void addContents(DexFile file);
+ /**
+ * Populates a {@link DexFile} with items from within this instance.
+ * This will <i>not</i> add an item to the file for this instance itself
+ * (which should have been done by whatever refers to this instance).
+ *
+ * <p><b>Note:</b> Subclasses must override this to do something
+ * appropriate.</p>
+ *
+ * @param file {@code non-null;} the file to populate
+ */
+ public abstract void addContents(DexFile file);
- /**
- * Writes the representation of this instance to the given data section,
- * using the given {@link DexFile} to look things up as needed.
- * If this instance keeps track of its offset, then this method will
- * note the written offset and will also throw an exception if this
- * instance has already been written.
- *
- * @param file {@code non-null;} the file to use for reference
- * @param out {@code non-null;} where to write to
- */
- public abstract void writeTo(DexFile file, AnnotatedOutput out);
+ /**
+ * Writes the representation of this instance to the given data section,
+ * using the given {@link DexFile} to look things up as needed.
+ * If this instance keeps track of its offset, then this method will
+ * note the written offset and will also throw an exception if this
+ * instance has already been written.
+ *
+ * @param file {@code non-null;} the file to use for reference
+ * @param out {@code non-null;} where to write to
+ */
+ public abstract void writeTo(DexFile file, AnnotatedOutput out);
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ItemType.java b/dx/src/com/android/jack/dx/dex/file/ItemType.java
index 6d8f274..2516994 100644
--- a/dx/src/com/android/jack/dx/dex/file/ItemType.java
+++ b/dx/src/com/android/jack/dx/dex/file/ItemType.java
@@ -22,76 +22,77 @@
* Enumeration of all the top-level item types.
*/
public enum ItemType implements ToHuman {
- TYPE_HEADER_ITEM( 0x0000, "header_item"),
- TYPE_STRING_ID_ITEM( 0x0001, "string_id_item"),
- TYPE_TYPE_ID_ITEM( 0x0002, "type_id_item"),
- TYPE_PROTO_ID_ITEM( 0x0003, "proto_id_item"),
- TYPE_FIELD_ID_ITEM( 0x0004, "field_id_item"),
- TYPE_METHOD_ID_ITEM( 0x0005, "method_id_item"),
- TYPE_CLASS_DEF_ITEM( 0x0006, "class_def_item"),
- TYPE_MAP_LIST( 0x1000, "map_list"),
- TYPE_TYPE_LIST( 0x1001, "type_list"),
- TYPE_ANNOTATION_SET_REF_LIST( 0x1002, "annotation_set_ref_list"),
- TYPE_ANNOTATION_SET_ITEM( 0x1003, "annotation_set_item"),
- TYPE_CLASS_DATA_ITEM( 0x2000, "class_data_item"),
- TYPE_CODE_ITEM( 0x2001, "code_item"),
- TYPE_STRING_DATA_ITEM( 0x2002, "string_data_item"),
- TYPE_DEBUG_INFO_ITEM( 0x2003, "debug_info_item"),
- TYPE_ANNOTATION_ITEM( 0x2004, "annotation_item"),
- TYPE_ENCODED_ARRAY_ITEM( 0x2005, "encoded_array_item"),
- TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"),
- TYPE_MAP_ITEM( -1, "map_item"),
- TYPE_TYPE_ITEM( -1, "type_item"),
- TYPE_EXCEPTION_HANDLER_ITEM( -1, "exception_handler_item"),
- TYPE_ANNOTATION_SET_REF_ITEM( -1, "annotation_set_ref_item");
+ TYPE_HEADER_ITEM(0x0000, "header_item"),
+ TYPE_STRING_ID_ITEM(0x0001, "string_id_item"),
+ TYPE_TYPE_ID_ITEM(0x0002, "type_id_item"),
+ TYPE_PROTO_ID_ITEM(0x0003, "proto_id_item"),
+ TYPE_FIELD_ID_ITEM(0x0004, "field_id_item"),
+ TYPE_METHOD_ID_ITEM(0x0005, "method_id_item"),
+ TYPE_CLASS_DEF_ITEM(0x0006, "class_def_item"),
+ TYPE_MAP_LIST(0x1000, "map_list"),
+ TYPE_TYPE_LIST(0x1001, "type_list"),
+ TYPE_ANNOTATION_SET_REF_LIST(0x1002, "annotation_set_ref_list"),
+ TYPE_ANNOTATION_SET_ITEM(0x1003, "annotation_set_item"),
+ TYPE_CLASS_DATA_ITEM(0x2000, "class_data_item"),
+ TYPE_CODE_ITEM(0x2001, "code_item"),
+ TYPE_STRING_DATA_ITEM(0x2002, "string_data_item"),
+ TYPE_DEBUG_INFO_ITEM(0x2003, "debug_info_item"),
+ TYPE_ANNOTATION_ITEM(0x2004, "annotation_item"),
+ TYPE_ENCODED_ARRAY_ITEM(0x2005, "encoded_array_item"),
+ TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"),
+ TYPE_MAP_ITEM(-1, "map_item"),
+ TYPE_TYPE_ITEM(-1, "type_item"),
+ TYPE_EXCEPTION_HANDLER_ITEM(-1, "exception_handler_item"),
+ TYPE_ANNOTATION_SET_REF_ITEM(-1, "annotation_set_ref_item");
- /** value when represented in a {@link MapItem} */
- private final int mapValue;
+ /** value when represented in a {@link MapItem} */
+ private final int mapValue;
- /** {@code non-null;} name of the type */
- private final String typeName;
+ /** {@code non-null;} name of the type */
+ private final String typeName;
- /** {@code non-null;} the short human name */
- private final String humanName;
+ /** {@code non-null;} the short human name */
+ private final String humanName;
- /**
- * Constructs an instance.
- *
- * @param mapValue value when represented in a {@link MapItem}
- * @param typeName {@code non-null;} name of the type
- */
- private ItemType(int mapValue, String typeName) {
- this.mapValue = mapValue;
- this.typeName = typeName;
+ /**
+ * Constructs an instance.
+ *
+ * @param mapValue value when represented in a {@link MapItem}
+ * @param typeName {@code non-null;} name of the type
+ */
+ private ItemType(int mapValue, String typeName) {
+ this.mapValue = mapValue;
+ this.typeName = typeName;
- // Make the human name.
- String human = typeName;
- if (human.endsWith("_item")) {
- human = human.substring(0, human.length() - 5);
- }
- this.humanName = human.replace('_', ' ');
+ // Make the human name.
+ String human = typeName;
+ if (human.endsWith("_item")) {
+ human = human.substring(0, human.length() - 5);
}
+ this.humanName = human.replace('_', ' ');
+ }
- /**
- * Gets the map value.
- *
- * @return the map value
- */
- public int getMapValue() {
- return mapValue;
- }
+ /**
+ * Gets the map value.
+ *
+ * @return the map value
+ */
+ public int getMapValue() {
+ return mapValue;
+ }
- /**
- * Gets the type name.
- *
- * @return {@code non-null;} the type name
- */
- public String getTypeName() {
- return typeName;
- }
+ /**
+ * Gets the type name.
+ *
+ * @return {@code non-null;} the type name
+ */
+ public String getTypeName() {
+ return typeName;
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return humanName;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return humanName;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MapItem.java b/dx/src/com/android/jack/dx/dex/file/MapItem.java
index d0bc331..21f1724 100644
--- a/dx/src/com/android/jack/dx/dex/file/MapItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/MapItem.java
@@ -25,211 +25,188 @@
* Class that represents a map item.
*/
public final class MapItem extends OffsettedItem {
- /** file alignment of this class, in bytes */
- private static final int ALIGNMENT = 4;
+ /** file alignment of this class, in bytes */
+ private static final int ALIGNMENT = 4;
- /** write size of this class, in bytes: three {@code uint}s */
- private static final int WRITE_SIZE = (4 * 3);
+ /** write size of this class, in bytes: three {@code uint}s */
+ private static final int WRITE_SIZE = (4 * 3);
- /** {@code non-null;} item type this instance covers */
- private final ItemType type;
+ /** {@code non-null;} item type this instance covers */
+ private final ItemType type;
- /** {@code non-null;} section this instance covers */
- private final Section section;
+ /** {@code non-null;} section this instance covers */
+ private final Section section;
- /**
- * {@code null-ok;} first item covered or {@code null} if this is
- * a self-reference
- */
- private final Item firstItem;
+ /**
+ * {@code null-ok;} first item covered or {@code null} if this is
+ * a self-reference
+ */
+ private final Item firstItem;
- /**
- * {@code null-ok;} last item covered or {@code null} if this is
- * a self-reference
- */
- private final Item lastItem;
+ /**
+ * {@code > 0;} count of items covered; {@code 1} if this
+ * is a self-reference
+ */
+ private final int itemCount;
- /**
- * {@code > 0;} count of items covered; {@code 1} if this
- * is a self-reference
- */
- private final int itemCount;
-
- /**
- * Constructs a list item with instances of this class representing
- * the contents of the given array of sections, adding it to the
- * given map section.
- *
- * @param sections {@code non-null;} the sections
- * @param mapSection {@code non-null;} the section that the resulting map
- * should be added to; it should be empty on entry to this method
- */
- public static void addMap(Section[] sections,
- MixedItemSection mapSection) {
- if (sections == null) {
- throw new NullPointerException("sections == null");
- }
-
- if (mapSection.items().size() != 0) {
- throw new IllegalArgumentException(
- "mapSection.items().size() != 0");
- }
-
- ArrayList<MapItem> items = new ArrayList<MapItem>(50);
-
- for (Section section : sections) {
- ItemType currentType = null;
- Item firstItem = null;
- Item lastItem = null;
- int count = 0;
-
- for (Item item : section.items()) {
- ItemType type = item.itemType();
- if (type != currentType) {
- if (count != 0) {
- items.add(new MapItem(currentType, section,
- firstItem, lastItem, count));
- }
- currentType = type;
- firstItem = item;
- count = 0;
- }
- lastItem = item;
- count++;
- }
-
- if (count != 0) {
- // Add a MapItem for the final items in the section.
- items.add(new MapItem(currentType, section,
- firstItem, lastItem, count));
- } else if (section == mapSection) {
- // Add a MapItem for the self-referential section.
- items.add(new MapItem(mapSection));
- }
- }
-
- mapSection.add(
- new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
+ /**
+ * Constructs a list item with instances of this class representing
+ * the contents of the given array of sections, adding it to the
+ * given map section.
+ *
+ * @param sections {@code non-null;} the sections
+ * @param mapSection {@code non-null;} the section that the resulting map
+ * should be added to; it should be empty on entry to this method
+ */
+ public static void addMap(Section[] sections, MixedItemSection mapSection) {
+ if (sections == null) {
+ throw new NullPointerException("sections == null");
}
- /**
- * Constructs an instance.
- *
- * @param type {@code non-null;} item type this instance covers
- * @param section {@code non-null;} section this instance covers
- * @param firstItem {@code non-null;} first item covered
- * @param lastItem {@code non-null;} last item covered
- * @param itemCount {@code > 0;} count of items covered
- */
- private MapItem(ItemType type, Section section, Item firstItem,
- Item lastItem, int itemCount) {
- super(ALIGNMENT, WRITE_SIZE);
-
- if (type == null) {
- throw new NullPointerException("type == null");
- }
-
- if (section == null) {
- throw new NullPointerException("section == null");
- }
-
- if (firstItem == null) {
- throw new NullPointerException("firstItem == null");
- }
-
- if (lastItem == null) {
- throw new NullPointerException("lastItem == null");
- }
-
- if (itemCount <= 0) {
- throw new IllegalArgumentException("itemCount <= 0");
- }
-
- this.type = type;
- this.section = section;
- this.firstItem = firstItem;
- this.lastItem = lastItem;
- this.itemCount = itemCount;
+ if (mapSection.items().size() != 0) {
+ throw new IllegalArgumentException("mapSection.items().size() != 0");
}
- /**
- * Constructs a self-referential instance. This instance is meant to
- * represent the section containing the {@code map_list}.
- *
- * @param section {@code non-null;} section this instance covers
- */
- private MapItem(Section section) {
- super(ALIGNMENT, WRITE_SIZE);
+ ArrayList<MapItem> items = new ArrayList<MapItem>(50);
- if (section == null) {
- throw new NullPointerException("section == null");
+ for (Section section : sections) {
+ ItemType currentType = null;
+ Item firstItem = null;
+ int count = 0;
+
+ for (Item item : section.items()) {
+ ItemType type = item.itemType();
+ if (type != currentType) {
+ if (count != 0) {
+ items.add(new MapItem(currentType, section, firstItem, count));
+ }
+ currentType = type;
+ firstItem = item;
+ count = 0;
}
+ count++;
+ }
- this.type = ItemType.TYPE_MAP_LIST;
- this.section = section;
- this.firstItem = null;
- this.lastItem = null;
- this.itemCount = 1;
+ if (count != 0) {
+ // Add a MapItem for the final items in the section.
+ items.add(new MapItem(currentType, section, firstItem, count));
+ } else if (section == mapSection) {
+ // Add a MapItem for the self-referential section.
+ items.add(new MapItem(mapSection));
+ }
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_MAP_ITEM;
+ mapSection.add(new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param type {@code non-null;} item type this instance covers
+ * @param section {@code non-null;} section this instance covers
+ * @param firstItem {@code non-null;} first item covered
+ * @param itemCount {@code > 0;} count of items covered
+ */
+ private MapItem(ItemType type, Section section, Item firstItem, int itemCount) {
+ super(ALIGNMENT, WRITE_SIZE);
+
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(100);
-
- sb.append(getClass().getName());
- sb.append('{');
- sb.append(section.toString());
- sb.append(' ');
- sb.append(type.toHuman());
- sb.append('}');
-
- return sb.toString();
+ if (section == null) {
+ throw new NullPointerException("section == null");
}
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- // We have nothing to add.
+ if (firstItem == null) {
+ throw new NullPointerException("firstItem == null");
}
- /** {@inheritDoc} */
- @Override
- public final String toHuman() {
- return toString();
+ if (itemCount <= 0) {
+ throw new IllegalArgumentException("itemCount <= 0");
}
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- int value = type.getMapValue();
- int offset;
+ this.type = type;
+ this.section = section;
+ this.firstItem = firstItem;
+ this.itemCount = itemCount;
+ }
- if (firstItem == null) {
- offset = section.getFileOffset();
- } else {
- offset = section.getAbsoluteItemOffset(firstItem);
- }
+ /**
+ * Constructs a self-referential instance. This instance is meant to
+ * represent the section containing the {@code map_list}.
+ *
+ * @param section {@code non-null;} section this instance covers
+ */
+ private MapItem(Section section) {
+ super(ALIGNMENT, WRITE_SIZE);
- if (out.annotates()) {
- out.annotate(0, offsetString() + ' ' + type.getTypeName() +
- " map");
- out.annotate(2, " type: " + Hex.u2(value) + " // " +
- type.toString());
- out.annotate(2, " unused: 0");
- out.annotate(4, " size: " + Hex.u4(itemCount));
- out.annotate(4, " offset: " + Hex.u4(offset));
- }
-
- out.writeShort(value);
- out.writeShort(0); // unused
- out.writeInt(itemCount);
- out.writeInt(offset);
+ if (section == null) {
+ throw new NullPointerException("section == null");
}
+
+ this.type = ItemType.TYPE_MAP_LIST;
+ this.section = section;
+ this.firstItem = null;
+ this.itemCount = 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_MAP_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append(getClass().getName());
+ sb.append('{');
+ sb.append(section.toString());
+ sb.append(' ');
+ sb.append(type.toHuman());
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ // We have nothing to add.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final String toHuman() {
+ return toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ int value = type.getMapValue();
+ int offset;
+
+ if (firstItem == null) {
+ offset = section.getFileOffset();
+ } else {
+ offset = section.getAbsoluteItemOffset(firstItem);
+ }
+
+ if (out.annotates()) {
+ out.annotate(0, offsetString() + ' ' + type.getTypeName() + " map");
+ out.annotate(2, " type: " + Hex.u2(value) + " // " + type.toString());
+ out.annotate(2, " unused: 0");
+ out.annotate(4, " size: " + Hex.u4(itemCount));
+ out.annotate(4, " offset: " + Hex.u4(offset));
+ }
+
+ out.writeShort(value);
+ out.writeShort(0); // unused
+ out.writeInt(itemCount);
+ out.writeInt(offset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MemberIdItem.java b/dx/src/com/android/jack/dx/dex/file/MemberIdItem.java
index bb6674a..c2011a4 100644
--- a/dx/src/com/android/jack/dx/dex/file/MemberIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/MemberIdItem.java
@@ -27,83 +27,82 @@
* Dalvik file.
*/
public abstract class MemberIdItem extends IdItem {
- /** {@code non-null;} the constant for the member */
- private final CstMemberRef cst;
+ /** {@code non-null;} the constant for the member */
+ private final CstMemberRef cst;
- /**
- * Constructs an instance.
- *
- * @param cst {@code non-null;} the constant for the member
- */
- public MemberIdItem(CstMemberRef cst) {
- super(cst.getDefiningClass());
+ /**
+ * Constructs an instance.
+ *
+ * @param cst {@code non-null;} the constant for the member
+ */
+ public MemberIdItem(CstMemberRef cst) {
+ super(cst.getDefiningClass());
- this.cst = cst;
+ this.cst = cst;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.MEMBER_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ super.addContents(file);
+
+ StringIdsSection stringIds = file.getStringIds();
+ stringIds.intern(getRef().getNat().getName());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void writeTo(DexFile file, AnnotatedOutput out) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ StringIdsSection stringIds = file.getStringIds();
+ CstNat nat = cst.getNat();
+ int classIdx = typeIds.indexOf(getDefiningClass());
+ int nameIdx = stringIds.indexOf(nat.getName());
+ int typoidIdx = getTypoidIdx(file);
+
+ if (out.annotates()) {
+ out.annotate(0, indexString() + ' ' + cst.toHuman());
+ out.annotate(2, " class_idx: " + Hex.u2(classIdx));
+ out.annotate(2, String.format(" %-10s %s", getTypoidName() + ':', Hex.u2(typoidIdx)));
+ out.annotate(4, " name_idx: " + Hex.u4(nameIdx));
}
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.MEMBER_ID_ITEM;
- }
+ out.writeShort(classIdx);
+ out.writeShort(typoidIdx);
+ out.writeInt(nameIdx);
+ }
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- super.addContents(file);
+ /**
+ * Returns the index of the type-like thing associated with
+ * this item, in order that it may be written out. Subclasses must
+ * override this to get whatever it is they need to store.
+ *
+ * @param file {@code non-null;} the file being written
+ * @return the index in question
+ */
+ protected abstract int getTypoidIdx(DexFile file);
- StringIdsSection stringIds = file.getStringIds();
- stringIds.intern(getRef().getNat().getName());
- }
+ /**
+ * Returns the field name of the type-like thing associated with
+ * this item, for listing-generating purposes. Subclasses must override
+ * this.
+ *
+ * @return {@code non-null;} the name in question
+ */
+ protected abstract String getTypoidName();
- /** {@inheritDoc} */
- @Override
- public final void writeTo(DexFile file, AnnotatedOutput out) {
- TypeIdsSection typeIds = file.getTypeIds();
- StringIdsSection stringIds = file.getStringIds();
- CstNat nat = cst.getNat();
- int classIdx = typeIds.indexOf(getDefiningClass());
- int nameIdx = stringIds.indexOf(nat.getName());
- int typoidIdx = getTypoidIdx(file);
-
- if (out.annotates()) {
- out.annotate(0, indexString() + ' ' + cst.toHuman());
- out.annotate(2, " class_idx: " + Hex.u2(classIdx));
- out.annotate(2, String.format(" %-10s %s", getTypoidName() + ':',
- Hex.u2(typoidIdx)));
- out.annotate(4, " name_idx: " + Hex.u4(nameIdx));
- }
-
- out.writeShort(classIdx);
- out.writeShort(typoidIdx);
- out.writeInt(nameIdx);
- }
-
- /**
- * Returns the index of the type-like thing associated with
- * this item, in order that it may be written out. Subclasses must
- * override this to get whatever it is they need to store.
- *
- * @param file {@code non-null;} the file being written
- * @return the index in question
- */
- protected abstract int getTypoidIdx(DexFile file);
-
- /**
- * Returns the field name of the type-like thing associated with
- * this item, for listing-generating purposes. Subclasses must override
- * this.
- *
- * @return {@code non-null;} the name in question
- */
- protected abstract String getTypoidName();
-
- /**
- * Gets the member constant.
- *
- * @return {@code non-null;} the constant
- */
- public final CstMemberRef getRef() {
- return cst;
- }
+ /**
+ * Gets the member constant.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public final CstMemberRef getRef() {
+ return cst;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/jack/dx/dex/file/MemberIdsSection.java
index 628f109..e173590 100644
--- a/dx/src/com/android/jack/dx/dex/file/MemberIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/MemberIdsSection.java
@@ -27,54 +27,59 @@
* Member (field or method) refs list section of a {@code .dex} file.
*/
public abstract class MemberIdsSection extends UniformItemSection {
- /** The largest addressable member is 0xffff, in the dex spec as field@CCCC or meth@CCCC. */
- private static final int MAX_MEMBERS = 0x10000;
+ /** The largest addressable member is 0xffff, in the dex spec as field@CCCC or meth@CCCC. */
+ private static final int MAX_MEMBERS = 0x10000;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param name {@code null-ok;} the name of this instance, for annotation
- * purposes
- * @param file {@code non-null;} file that this instance is part of
- */
- public MemberIdsSection(String name, DexFile file) {
- super(name, file, 4);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param name {@code null-ok;} the name of this instance, for annotation
+ * purposes
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public MemberIdsSection(String name, DexFile file) {
+ super(name, file, 4);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ int idx = 0;
+
+ if (items().size() > MAX_MEMBERS) {
+ throw new DexException(tooManyMembersMessage());
}
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- int idx = 0;
+ for (Object i : items()) {
+ ((MemberIdItem) i).setIndex(idx);
+ idx++;
+ }
+ }
- if (items().size() > MAX_MEMBERS) {
- throw new DexException(tooManyMembersMessage());
- }
-
- for (Object i : items()) {
- ((MemberIdItem) i).setIndex(idx);
- idx++;
- }
+ private String tooManyMembersMessage() {
+ Map<String, AtomicInteger> membersByPackage = new TreeMap<String, AtomicInteger>();
+ for (Object member : items()) {
+ String packageName = ((MemberIdItem) member).getDefiningClass().getPackageName();
+ AtomicInteger count = membersByPackage.get(packageName);
+ if (count == null) {
+ count = new AtomicInteger();
+ membersByPackage.put(packageName, count);
+ }
+ count.incrementAndGet();
}
- private String tooManyMembersMessage() {
- Map<String, AtomicInteger> membersByPackage = new TreeMap<String, AtomicInteger>();
- for (Object member : items()) {
- String packageName = ((MemberIdItem) member).getDefiningClass().getPackageName();
- AtomicInteger count = membersByPackage.get(packageName);
- if (count == null) {
- count = new AtomicInteger();
- membersByPackage.put(packageName, count);
- }
- count.incrementAndGet();
- }
-
- Formatter formatter = new Formatter();
- String memberType = this instanceof MethodIdsSection ? "methods" : "fields";
- formatter.format("Too many %s: %d; max is %d. By package:",
- memberType, items().size(), MAX_MEMBERS);
- for (Map.Entry<String, AtomicInteger> entry : membersByPackage.entrySet()) {
- formatter.format("%n%6d %s", entry.getValue().get(), entry.getKey());
- }
- return formatter.toString();
+ Formatter formatter = null;
+ try {
+ formatter = new Formatter();
+ String memberType = this instanceof MethodIdsSection ? "methods" : "fields";
+ formatter.format("Too many %s: %d; max is %d. By package:", memberType, items().size(),
+ MAX_MEMBERS);
+ for (Map.Entry<String, AtomicInteger> entry : membersByPackage.entrySet()) {
+ formatter.format("%n%6d %s", entry.getValue().get(), entry.getKey());
+ }
+ return formatter.toString();
+ } finally {
+ formatter.close();
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/jack/dx/dex/file/MethodAnnotationStruct.java
index 8e2ca32..a12fa0f 100644
--- a/dx/src/com/android/jack/dx/dex/file/MethodAnnotationStruct.java
+++ b/dx/src/com/android/jack/dx/dex/file/MethodAnnotationStruct.java
@@ -25,98 +25,99 @@
/**
* Association of a method and its annotations.
*/
-public final class MethodAnnotationStruct
- implements ToHuman, Comparable<MethodAnnotationStruct> {
- /** {@code non-null;} the method in question */
- private final CstMethodRef method;
+public final class MethodAnnotationStruct implements ToHuman, Comparable<MethodAnnotationStruct> {
+ /** {@code non-null;} the method in question */
+ private final CstMethodRef method;
- /** {@code non-null;} the associated annotations */
- private AnnotationSetItem annotations;
+ /** {@code non-null;} the associated annotations */
+ private AnnotationSetItem annotations;
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the method in question
- * @param annotations {@code non-null;} the associated annotations
- */
- public MethodAnnotationStruct(CstMethodRef method,
- AnnotationSetItem annotations) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- if (annotations == null) {
- throw new NullPointerException("annotations == null");
- }
-
- this.method = method;
- this.annotations = annotations;
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the method in question
+ * @param annotations {@code non-null;} the associated annotations
+ */
+ public MethodAnnotationStruct(CstMethodRef method, AnnotationSetItem annotations) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /** {@inheritDoc} */
- public int hashCode() {
- return method.hashCode();
+ if (annotations == null) {
+ throw new NullPointerException("annotations == null");
}
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (! (other instanceof MethodAnnotationStruct)) {
- return false;
- }
+ this.method = method;
+ this.annotations = annotations;
+ }
- return method.equals(((MethodAnnotationStruct) other).method);
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return method.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof MethodAnnotationStruct)) {
+ return false;
}
- /** {@inheritDoc} */
- public int compareTo(MethodAnnotationStruct other) {
- return method.compareTo(other.method);
+ return method.equals(((MethodAnnotationStruct) other).method);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(MethodAnnotationStruct other) {
+ return method.compareTo(other.method);
+ }
+
+ /** {@inheritDoc} */
+ public void addContents(DexFile file) {
+ MethodIdsSection methodIds = file.getMethodIds();
+ MixedItemSection wordData = file.getWordData();
+
+ methodIds.intern(method);
+ annotations = wordData.intern(annotations);
+ }
+
+ /** {@inheritDoc} */
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int methodIdx = file.getMethodIds().indexOf(method);
+ int annotationsOff = annotations.getAbsoluteOffset();
+
+ if (out.annotates()) {
+ out.annotate(0, " " + method.toHuman());
+ out.annotate(4, " method_idx: " + Hex.u4(methodIdx));
+ out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff));
}
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- MethodIdsSection methodIds = file.getMethodIds();
- MixedItemSection wordData = file.getWordData();
+ out.writeInt(methodIdx);
+ out.writeInt(annotationsOff);
+ }
- methodIds.intern(method);
- annotations = wordData.intern(annotations);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return method.toHuman() + ": " + annotations;
+ }
- /** {@inheritDoc} */
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int methodIdx = file.getMethodIds().indexOf(method);
- int annotationsOff = annotations.getAbsoluteOffset();
+ /**
+ * Gets the method this item is for.
+ *
+ * @return {@code non-null;} the method
+ */
+ public CstMethodRef getMethod() {
+ return method;
+ }
- if (out.annotates()) {
- out.annotate(0, " " + method.toHuman());
- out.annotate(4, " method_idx: " + Hex.u4(methodIdx));
- out.annotate(4, " annotations_off: " +
- Hex.u4(annotationsOff));
- }
-
- out.writeInt(methodIdx);
- out.writeInt(annotationsOff);
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return method.toHuman() + ": " + annotations;
- }
-
- /**
- * Gets the method this item is for.
- *
- * @return {@code non-null;} the method
- */
- public CstMethodRef getMethod() {
- return method;
- }
-
- /**
- * Gets the associated annotations.
- *
- * @return {@code non-null;} the annotations
- */
- public Annotations getAnnotations() {
- return annotations.getAnnotations();
- }
+ /**
+ * Gets the associated annotations.
+ *
+ * @return {@code non-null;} the annotations
+ */
+ public Annotations getAnnotations() {
+ return annotations.getAnnotations();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MethodIdItem.java b/dx/src/com/android/jack/dx/dex/file/MethodIdItem.java
index 3684172..6efc3b0 100644
--- a/dx/src/com/android/jack/dx/dex/file/MethodIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/MethodIdItem.java
@@ -22,49 +22,49 @@
* Representation of a method reference inside a Dalvik file.
*/
public final class MethodIdItem extends MemberIdItem {
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the constant for the method
- */
- public MethodIdItem(CstBaseMethodRef method) {
- super(method);
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the constant for the method
+ */
+ public MethodIdItem(CstBaseMethodRef method) {
+ super(method);
+ }
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_METHOD_ID_ITEM;
- }
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_METHOD_ID_ITEM;
+ }
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- super.addContents(file);
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ super.addContents(file);
- ProtoIdsSection protoIds = file.getProtoIds();
- protoIds.intern(getMethodRef().getPrototype());
- }
+ ProtoIdsSection protoIds = file.getProtoIds();
+ protoIds.intern(getMethodRef().getPrototype());
+ }
- /**
- * Gets the method constant.
- *
- * @return {@code non-null;} the constant
- */
- public CstBaseMethodRef getMethodRef() {
- return (CstBaseMethodRef) getRef();
- }
+ /**
+ * Gets the method constant.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public CstBaseMethodRef getMethodRef() {
+ return (CstBaseMethodRef) getRef();
+ }
- /** {@inheritDoc} */
- @Override
- protected int getTypoidIdx(DexFile file) {
- ProtoIdsSection protoIds = file.getProtoIds();
- return protoIds.indexOf(getMethodRef().getPrototype());
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int getTypoidIdx(DexFile file) {
+ ProtoIdsSection protoIds = file.getProtoIds();
+ return protoIds.indexOf(getMethodRef().getPrototype());
+ }
- /** {@inheritDoc} */
- @Override
- protected String getTypoidName() {
- return "proto_idx";
- }
+ /** {@inheritDoc} */
+ @Override
+ protected String getTypoidName() {
+ return "proto_idx";
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/jack/dx/dex/file/MethodIdsSection.java
index 34f528e..f3dc0a6 100644
--- a/dx/src/com/android/jack/dx/dex/file/MethodIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/MethodIdsSection.java
@@ -28,110 +28,110 @@
* Method refs list section of a {@code .dex} file.
*/
public final class MethodIdsSection extends MemberIdsSection {
- /**
- * {@code non-null;} map from method constants to {@link
- * MethodIdItem} instances
- */
- private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
+ /**
+ * {@code non-null;} map from method constants to {@link
+ * MethodIdItem} instances
+ */
+ private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public MethodIdsSection(DexFile file) {
- super("method_ids", file);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public MethodIdsSection(DexFile file) {
+ super("method_ids", file);
- methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>();
+ methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return methodIds.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return methodIds.values();
+ throwIfNotPrepared();
+
+ IndexedItem result = methodIds.get(cst);
+
+ if (result == null) {
+ throw new IllegalArgumentException("not found");
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
- IndexedItem result = methodIds.get((CstBaseMethodRef) cst);
+ int sz = methodIds.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
- if (result == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return result;
+ if (out.annotates()) {
+ out.annotate(4, "method_ids_size: " + Hex.u4(sz));
+ out.annotate(4, "method_ids_off: " + Hex.u4(offset));
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
- int sz = methodIds.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
-
- if (out.annotates()) {
- out.annotate(4, "method_ids_size: " + Hex.u4(sz));
- out.annotate(4, "method_ids_off: " + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ /**
+ * Interns an element into this instance.
+ *
+ * @param method {@code non-null;} the reference to intern
+ * @return {@code non-null;} the interned reference
+ */
+ public MethodIdItem intern(CstBaseMethodRef method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /**
- * Interns an element into this instance.
- *
- * @param method {@code non-null;} the reference to intern
- * @return {@code non-null;} the interned reference
- */
- public MethodIdItem intern(CstBaseMethodRef method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
+ throwIfPrepared();
- throwIfPrepared();
+ MethodIdItem result = methodIds.get(method);
- MethodIdItem result = methodIds.get(method);
-
- if (result == null) {
- result = new MethodIdItem(method);
- methodIds.put(method, result);
- }
-
- return result;
+ if (result == null) {
+ result = new MethodIdItem(method);
+ methodIds.put(method, result);
}
- /**
- * Gets the index of the given reference, which must have been added
- * to this instance.
- *
- * @param ref {@code non-null;} the reference to look up
- * @return {@code >= 0;} the reference's index
- */
- public int indexOf(CstBaseMethodRef ref) {
- if (ref == null) {
- throw new NullPointerException("ref == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
-
- MethodIdItem item = methodIds.get(ref);
-
- if (item == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return item.getIndex();
+ /**
+ * Gets the index of the given reference, which must have been added
+ * to this instance.
+ *
+ * @param ref {@code non-null;} the reference to look up
+ * @return {@code >= 0;} the reference's index
+ */
+ public int indexOf(CstBaseMethodRef ref) {
+ if (ref == null) {
+ throw new NullPointerException("ref == null");
}
+
+ throwIfNotPrepared();
+
+ MethodIdItem item = methodIds.get(ref);
+
+ if (item == null) {
+ throw new IllegalArgumentException("not found");
+ }
+
+ return item.getIndex();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/MixedItemSection.java b/dx/src/com/android/jack/dx/dex/file/MixedItemSection.java
index 914f78a..ad45a50 100644
--- a/dx/src/com/android/jack/dx/dex/file/MixedItemSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/MixedItemSection.java
@@ -39,324 +39,323 @@
* have a larger alignment requirement than the alignment of this instance.
*/
public final class MixedItemSection extends Section {
- static enum SortType {
- /** no sorting */
- NONE,
+ static enum SortType {
+ /** no sorting */
+ NONE,
- /** sort by type only */
- TYPE,
+ /** sort by type only */
+ TYPE,
- /** sort in class-major order, with instances sorted per-class */
- INSTANCE;
- };
+ /** sort in class-major order, with instances sorted per-class */
+ INSTANCE;
+ };
- /** {@code non-null;} sorter which sorts instances by type */
- private static final Comparator<OffsettedItem> TYPE_SORTER =
- new Comparator<OffsettedItem>() {
- public int compare(OffsettedItem item1, OffsettedItem item2) {
- ItemType type1 = item1.itemType();
- ItemType type2 = item2.itemType();
- return type1.compareTo(type2);
- }
- };
-
- /** {@code non-null;} the items in this part */
- private final ArrayList<OffsettedItem> items;
-
- /** {@code non-null;} items that have been explicitly interned */
- private final HashMap<OffsettedItem, OffsettedItem> interns;
-
- /** {@code non-null;} how to sort the items */
- private final SortType sort;
-
- /**
- * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
- * if not yet calculated
- */
- private int writeSize;
-
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param name {@code null-ok;} the name of this instance, for annotation
- * purposes
- * @param file {@code non-null;} file that this instance is part of
- * @param alignment {@code > 0;} alignment requirement for the final output;
- * must be a power of 2
- * @param sort how the items should be sorted in the final output
- */
- public MixedItemSection(String name, DexFile file, int alignment,
- SortType sort) {
- super(name, file, alignment);
-
- this.items = new ArrayList<OffsettedItem>(100);
- this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
- this.sort = sort;
- this.writeSize = -1;
- }
-
- /** {@inheritDoc} */
+ /** {@code non-null;} sorter which sorts instances by type */
+ private static final Comparator<OffsettedItem> TYPE_SORTER = new Comparator<OffsettedItem>() {
@Override
- public Collection<? extends Item> items() {
- return items;
+ public int compare(OffsettedItem item1, OffsettedItem item2) {
+ ItemType type1 = item1.itemType();
+ ItemType type2 = item2.itemType();
+ return type1.compareTo(type2);
+ }
+ };
+
+ /** {@code non-null;} the items in this part */
+ private final ArrayList<OffsettedItem> items;
+
+ /** {@code non-null;} items that have been explicitly interned */
+ private final HashMap<OffsettedItem, OffsettedItem> interns;
+
+ /** {@code non-null;} how to sort the items */
+ private final SortType sort;
+
+ /**
+ * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
+ * if not yet calculated
+ */
+ private int writeSize;
+
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param name {@code null-ok;} the name of this instance, for annotation
+ * purposes
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
+ * must be a power of 2
+ * @param sort how the items should be sorted in the final output
+ */
+ public MixedItemSection(String name, DexFile file, int alignment, SortType sort) {
+ super(name, file, alignment);
+
+ this.items = new ArrayList<OffsettedItem>(100);
+ this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
+ this.sort = sort;
+ this.writeSize = -1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return items;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ throwIfNotPrepared();
+ return writeSize;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getAbsoluteItemOffset(Item item) {
+ OffsettedItem oi = (OffsettedItem) item;
+ return oi.getAbsoluteOffset();
+ }
+
+ /**
+ * Gets the size of this instance, in items.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int size() {
+ return items.size();
+ }
+
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
+
+ if (writeSize == -1) {
+ throw new RuntimeException("write size not yet set");
}
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- throwIfNotPrepared();
- return writeSize;
+ int sz = writeSize;
+ int offset = (sz == 0) ? 0 : getFileOffset();
+ String name = getName();
+
+ if (name == null) {
+ name = "<unnamed>";
}
- /** {@inheritDoc} */
- @Override
- public int getAbsoluteItemOffset(Item item) {
- OffsettedItem oi = (OffsettedItem) item;
- return oi.getAbsoluteOffset();
+ int spaceCount = 15 - name.length();
+ char[] spaceArr = new char[spaceCount];
+ Arrays.fill(spaceArr, ' ');
+ String spaces = new String(spaceArr);
+
+ if (out.annotates()) {
+ out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
+ out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
}
- /**
- * Gets the size of this instance, in items.
- *
- * @return {@code >= 0;} the size
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
+
+ /**
+ * Adds an item to this instance. This will in turn tell the given item
+ * that it has been added to this instance. It is invalid to add the
+ * same item to more than one instance, nor to add the same items
+ * multiple times to a single instance.
+ *
+ * @param item {@code non-null;} the item to add
+ */
+ public void add(OffsettedItem item) {
+ throwIfPrepared();
+
+ try {
+ if (item.getAlignment() > getAlignment()) {
+ throw new IllegalArgumentException("incompatible item alignment");
+ }
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("item == null");
+ }
+
+ items.add(item);
+ }
+
+ /**
+ * Interns an item in this instance, returning the interned instance
+ * (which may not be the one passed in). This will add the item if no
+ * equal item has been added.
+ *
+ * @param item {@code non-null;} the item to intern
+ * @return {@code non-null;} the equivalent interned instance
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends OffsettedItem> T intern(T item) {
+ throwIfPrepared();
+
+ OffsettedItem result = interns.get(item);
+
+ if (result != null) {
+ return (T) result;
+ }
+
+ add(item);
+ interns.put(item, item);
+ return item;
+ }
+
+ /**
+ * Gets an item which was previously interned.
+ *
+ * @param item {@code non-null;} the item to look for
+ * @return {@code non-null;} the equivalent already-interned instance
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends OffsettedItem> T get(T item) {
+ throwIfNotPrepared();
+
+ OffsettedItem result = interns.get(item);
+
+ if (result != null) {
+ return (T) result;
+ }
+
+ throw new NoSuchElementException(item.toString());
+ }
+
+ /**
+ * Writes an index of contents of the items in this instance of the
+ * given type. If there are none, this writes nothing. If there are any,
+ * then the index is preceded by the given intro string.
+ *
+ * @param out {@code non-null;} where to write to
+ * @param itemType {@code non-null;} the item type of interest
+ * @param intro {@code non-null;} the introductory string for non-empty indices
+ */
+ public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType, String intro) {
+ throwIfNotPrepared();
+
+ TreeMap<String, OffsettedItem> index = new TreeMap<String, OffsettedItem>();
+
+ for (OffsettedItem item : items) {
+ if (item.itemType() == itemType) {
+ String label = item.toHuman();
+ index.put(label, item);
+ }
+ }
+
+ if (index.size() == 0) {
+ return;
+ }
+
+ out.annotate(0, intro);
+
+ for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
+ String label = entry.getKey();
+ OffsettedItem item = entry.getValue();
+ out.annotate(0, item.offsetString() + ' ' + label + '\n');
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void prepare0() {
+ DexFile file = getFile();
+
+ /*
+ * It's okay for new items to be added as a result of an
+ * addContents() call; we just have to deal with the possibility.
*/
- public int size() {
- return items.size();
+
+int i = 0;
+ for (;;) {
+ int sz = items.size();
+ if (i >= sz) {
+ break;
+ }
+
+ for (/*i*/; i < sz; i++) {
+ OffsettedItem one = items.get(i);
+ one.addContents(file);
+ }
+ }
+ }
+
+ /**
+ * Places all the items in this instance at particular offsets. This
+ * will call {@link OffsettedItem#place} on each item. If an item
+ * does not know its write size before the call to {@code place},
+ * it is that call which is responsible for setting the write size.
+ * This method may only be called once per instance; subsequent calls
+ * will throw an exception.
+ */
+ public void placeItems() {
+ throwIfNotPrepared();
+
+ switch (sort) {
+ case INSTANCE: {
+ Collections.sort(items);
+ break;
+ }
+ case TYPE: {
+ Collections.sort(items, TYPE_SORTER);
+ break;
+ }
+ default:
+ /* continue */
+ break;
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
+ int sz = items.size();
+ int outAt = 0;
+ for (int i = 0; i < sz; i++) {
+ OffsettedItem one = items.get(i);
+ try {
+ int placedAt = one.place(this, outAt);
- if (writeSize == -1) {
- throw new RuntimeException("write size not yet set");
+ if (placedAt < outAt) {
+ throw new RuntimeException("bogus place() result for " + one);
}
- int sz = writeSize;
- int offset = (sz == 0) ? 0 : getFileOffset();
- String name = getName();
-
- if (name == null) {
- name = "<unnamed>";
- }
-
- int spaceCount = 15 - name.length();
- char[] spaceArr = new char[spaceCount];
- Arrays.fill(spaceArr, ' ');
- String spaces = new String(spaceArr);
-
- if (out.annotates()) {
- out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
- out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ outAt = placedAt + one.writeSize();
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex, "...while placing " + one);
+ }
}
- /**
- * Adds an item to this instance. This will in turn tell the given item
- * that it has been added to this instance. It is invalid to add the
- * same item to more than one instance, nor to add the same items
- * multiple times to a single instance.
- *
- * @param item {@code non-null;} the item to add
- */
- public void add(OffsettedItem item) {
- throwIfPrepared();
+ writeSize = outAt;
+ }
- try {
- if (item.getAlignment() > getAlignment()) {
- throw new IllegalArgumentException(
- "incompatible item alignment");
- }
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("item == null");
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(AnnotatedOutput out) {
+ boolean annotates = out.annotates();
+ boolean first = true;
+ DexFile file = getFile();
+ int at = 0;
+
+ for (OffsettedItem one : items) {
+ if (annotates) {
+ if (first) {
+ first = false;
+ } else {
+ out.annotate(0, "\n");
}
+ }
- items.add(item);
+ int alignMask = one.getAlignment() - 1;
+ int writeAt = (at + alignMask) & ~alignMask;
+
+ if (at != writeAt) {
+ out.writeZeroes(writeAt - at);
+ at = writeAt;
+ }
+
+ one.writeTo(file, out);
+ at += one.writeSize();
}
- /**
- * Interns an item in this instance, returning the interned instance
- * (which may not be the one passed in). This will add the item if no
- * equal item has been added.
- *
- * @param item {@code non-null;} the item to intern
- * @return {@code non-null;} the equivalent interned instance
- */
- public <T extends OffsettedItem> T intern(T item) {
- throwIfPrepared();
-
- OffsettedItem result = interns.get(item);
-
- if (result != null) {
- return (T) result;
- }
-
- add(item);
- interns.put(item, item);
- return item;
+ if (at != writeSize) {
+ throw new RuntimeException("output size mismatch");
}
-
- /**
- * Gets an item which was previously interned.
- *
- * @param item {@code non-null;} the item to look for
- * @return {@code non-null;} the equivalent already-interned instance
- */
- public <T extends OffsettedItem> T get(T item) {
- throwIfNotPrepared();
-
- OffsettedItem result = interns.get(item);
-
- if (result != null) {
- return (T) result;
- }
-
- throw new NoSuchElementException(item.toString());
- }
-
- /**
- * Writes an index of contents of the items in this instance of the
- * given type. If there are none, this writes nothing. If there are any,
- * then the index is preceded by the given intro string.
- *
- * @param out {@code non-null;} where to write to
- * @param itemType {@code non-null;} the item type of interest
- * @param intro {@code non-null;} the introductory string for non-empty indices
- */
- public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType,
- String intro) {
- throwIfNotPrepared();
-
- TreeMap<String, OffsettedItem> index =
- new TreeMap<String, OffsettedItem>();
-
- for (OffsettedItem item : items) {
- if (item.itemType() == itemType) {
- String label = item.toHuman();
- index.put(label, item);
- }
- }
-
- if (index.size() == 0) {
- return;
- }
-
- out.annotate(0, intro);
-
- for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
- String label = entry.getKey();
- OffsettedItem item = entry.getValue();
- out.annotate(0, item.offsetString() + ' ' + label + '\n');
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected void prepare0() {
- DexFile file = getFile();
-
- /*
- * It's okay for new items to be added as a result of an
- * addContents() call; we just have to deal with the possibility.
- */
-
- int i = 0;
- for (;;) {
- int sz = items.size();
- if (i >= sz) {
- break;
- }
-
- for (/*i*/; i < sz; i++) {
- OffsettedItem one = items.get(i);
- one.addContents(file);
- }
- }
- }
-
- /**
- * Places all the items in this instance at particular offsets. This
- * will call {@link OffsettedItem#place} on each item. If an item
- * does not know its write size before the call to {@code place},
- * it is that call which is responsible for setting the write size.
- * This method may only be called once per instance; subsequent calls
- * will throw an exception.
- */
- public void placeItems() {
- throwIfNotPrepared();
-
- switch (sort) {
- case INSTANCE: {
- Collections.sort(items);
- break;
- }
- case TYPE: {
- Collections.sort(items, TYPE_SORTER);
- break;
- }
- }
-
- int sz = items.size();
- int outAt = 0;
- for (int i = 0; i < sz; i++) {
- OffsettedItem one = items.get(i);
- try {
- int placedAt = one.place(this, outAt);
-
- if (placedAt < outAt) {
- throw new RuntimeException("bogus place() result for " +
- one);
- }
-
- outAt = placedAt + one.writeSize();
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while placing " + one);
- }
- }
-
- writeSize = outAt;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(AnnotatedOutput out) {
- boolean annotates = out.annotates();
- boolean first = true;
- DexFile file = getFile();
- int at = 0;
-
- for (OffsettedItem one : items) {
- if (annotates) {
- if (first) {
- first = false;
- } else {
- out.annotate(0, "\n");
- }
- }
-
- int alignMask = one.getAlignment() - 1;
- int writeAt = (at + alignMask) & ~alignMask;
-
- if (at != writeAt) {
- out.writeZeroes(writeAt - at);
- at = writeAt;
- }
-
- one.writeTo(file, out);
- at += one.writeSize();
- }
-
- if (at != writeSize) {
- throw new RuntimeException("output size mismatch");
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/OffsettedItem.java b/dx/src/com/android/jack/dx/dex/file/OffsettedItem.java
index b171f68..6c294aa 100644
--- a/dx/src/com/android/jack/dx/dex/file/OffsettedItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/OffsettedItem.java
@@ -22,293 +22,291 @@
/**
* An item in a Dalvik file which is referenced by absolute offset.
*/
-public abstract class OffsettedItem extends Item
- implements Comparable<OffsettedItem> {
- /** {@code > 0;} alignment requirement */
- private final int alignment;
+public abstract class OffsettedItem extends Item implements Comparable<OffsettedItem> {
+ /** {@code > 0;} alignment requirement */
+ private final int alignment;
- /** {@code >= -1;} the size of this instance when written, in bytes, or
- * {@code -1} if not yet known */
- private int writeSize;
+ /** {@code >= -1;} the size of this instance when written, in bytes, or
+ * {@code -1} if not yet known */
+ private int writeSize;
- /**
- * {@code null-ok;} section the item was added to, or {@code null} if
- * not yet added
- */
- private Section addedTo;
+ /**
+ * {@code null-ok;} section the item was added to, or {@code null} if
+ * not yet added
+ */
+ private Section addedTo;
- /**
- * {@code >= -1;} assigned offset of the item from the start of its section,
- * or {@code -1} if not yet assigned
- */
- private int offset;
+ /**
+ * {@code >= -1;} assigned offset of the item from the start of its section,
+ * or {@code -1} if not yet assigned
+ */
+ private int offset;
- /**
- * Gets the absolute offset of the given item, returning {@code 0}
- * if handed {@code null}.
- *
- * @param item {@code null-ok;} the item in question
- * @return {@code >= 0;} the item's absolute offset, or {@code 0}
- * if {@code item == null}
- */
- public static int getAbsoluteOffsetOr0(OffsettedItem item) {
- if (item == null) {
- return 0;
- }
-
- return item.getAbsoluteOffset();
+ /**
+ * Gets the absolute offset of the given item, returning {@code 0}
+ * if handed {@code null}.
+ *
+ * @param item {@code null-ok;} the item in question
+ * @return {@code >= 0;} the item's absolute offset, or {@code 0}
+ * if {@code item == null}
+ */
+ public static int getAbsoluteOffsetOr0(OffsettedItem item) {
+ if (item == null) {
+ return 0;
}
- /**
- * Constructs an instance. The offset is initially unassigned.
- *
- * @param alignment {@code > 0;} output alignment requirement; must be a
- * power of 2
- * @param writeSize {@code >= -1;} the size of this instance when written,
- * in bytes, or {@code -1} if not immediately known
- */
- public OffsettedItem(int alignment, int writeSize) {
- Section.validateAlignment(alignment);
+ return item.getAbsoluteOffset();
+ }
- if (writeSize < -1) {
- throw new IllegalArgumentException("writeSize < -1");
- }
+ /**
+ * Constructs an instance. The offset is initially unassigned.
+ *
+ * @param alignment {@code > 0;} output alignment requirement; must be a
+ * power of 2
+ * @param writeSize {@code >= -1;} the size of this instance when written,
+ * in bytes, or {@code -1} if not immediately known
+ */
+ public OffsettedItem(int alignment, int writeSize) {
+ Section.validateAlignment(alignment);
- this.alignment = alignment;
- this.writeSize = writeSize;
- this.addedTo = null;
- this.offset = -1;
+ if (writeSize < -1) {
+ throw new IllegalArgumentException("writeSize < -1");
}
- /**
- * {@inheritDoc}
- *
- * Comparisons for this class are defined to be type-major (if the
- * types don't match then the objects are not equal), with
- * {@link #compareTo0} deciding same-type comparisons.
- */
- @Override
- public final boolean equals(Object other) {
- if (this == other) {
- return true;
- }
+ this.alignment = alignment;
+ this.writeSize = writeSize;
+ this.addedTo = null;
+ this.offset = -1;
+ }
- OffsettedItem otherItem = (OffsettedItem) other;
- ItemType thisType = itemType();
- ItemType otherType = otherItem.itemType();
-
- if (thisType != otherType) {
- return false;
- }
-
- return (compareTo0(otherItem) == 0);
+ /**
+ * {@inheritDoc}
+ *
+ * Comparisons for this class are defined to be type-major (if the
+ * types don't match then the objects are not equal), with
+ * {@link #compareTo0} deciding same-type comparisons.
+ */
+ @Override
+ public final boolean equals(Object other) {
+ if (this == other) {
+ return true;
}
- /**
- * {@inheritDoc}
- *
- * Comparisons for this class are defined to be class-major (if the
- * classes don't match then the objects are not equal), with
- * {@link #compareTo0} deciding same-class comparisons.
- */
- public final int compareTo(OffsettedItem other) {
- if (this == other) {
- return 0;
- }
+ OffsettedItem otherItem = (OffsettedItem) other;
+ ItemType thisType = itemType();
+ ItemType otherType = otherItem.itemType();
- ItemType thisType = itemType();
- ItemType otherType = other.itemType();
-
- if (thisType != otherType) {
- return thisType.compareTo(otherType);
- }
-
- return compareTo0(other);
+ if (thisType != otherType) {
+ return false;
}
- /**
- * Sets the write size of this item. This may only be called once
- * per instance, and only if the size was unknown upon instance
- * creation.
- *
- * @param writeSize {@code > 0;} the write size, in bytes
- */
- public final void setWriteSize(int writeSize) {
- if (writeSize < 0) {
- throw new IllegalArgumentException("writeSize < 0");
- }
+ return (compareTo0(otherItem) == 0);
+ }
- if (this.writeSize >= 0) {
- throw new UnsupportedOperationException("writeSize already set");
- }
-
- this.writeSize = writeSize;
+ /**
+ * {@inheritDoc}
+ *
+ * Comparisons for this class are defined to be class-major (if the
+ * classes don't match then the objects are not equal), with
+ * {@link #compareTo0} deciding same-class comparisons.
+ */
+ @Override
+ public final int compareTo(OffsettedItem other) {
+ if (this == other) {
+ return 0;
}
- /** {@inheritDoc}
- *
- * @throws UnsupportedOperationException thrown if the write size
- * is not yet known
- */
- @Override
- public final int writeSize() {
- if (writeSize < 0) {
- throw new UnsupportedOperationException("writeSize is unknown");
- }
+ ItemType thisType = itemType();
+ ItemType otherType = other.itemType();
- return writeSize;
+ if (thisType != otherType) {
+ return thisType.compareTo(otherType);
}
- /** {@inheritDoc} */
- @Override
- public final void writeTo(DexFile file, AnnotatedOutput out) {
- out.alignTo(alignment);
+ return compareTo0(other);
+ }
- try {
- if (writeSize < 0) {
- throw new UnsupportedOperationException(
- "writeSize is unknown");
- }
- out.assertCursor(getAbsoluteOffset());
- } catch (RuntimeException ex) {
- throw ExceptionWithContext.withContext(ex,
- "...while writing " + this);
- }
-
- writeTo0(file, out);
+ /**
+ * Sets the write size of this item. This may only be called once
+ * per instance, and only if the size was unknown upon instance
+ * creation.
+ *
+ * @param writeSize {@code > 0;} the write size, in bytes
+ */
+ public final void setWriteSize(int writeSize) {
+ if (writeSize < 0) {
+ throw new IllegalArgumentException("writeSize < 0");
}
- /**
- * Gets the relative item offset. The offset is from the start of
- * the section which the instance was written to.
- *
- * @return {@code >= 0;} the offset
- * @throws RuntimeException thrown if the offset is not yet known
- */
- public final int getRelativeOffset() {
- if (offset < 0) {
- throw new RuntimeException("offset not yet known");
- }
-
- return offset;
+ if (this.writeSize >= 0) {
+ throw new UnsupportedOperationException("writeSize already set");
}
- /**
- * Gets the absolute item offset. The offset is from the start of
- * the file which the instance was written to.
- *
- * @return {@code >= 0;} the offset
- * @throws RuntimeException thrown if the offset is not yet known
- */
- public final int getAbsoluteOffset() {
- if (offset < 0) {
- throw new RuntimeException("offset not yet known");
- }
+ this.writeSize = writeSize;
+ }
- return addedTo.getAbsoluteOffset(offset);
+ /** {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException thrown if the write size
+ * is not yet known
+ */
+ @Override
+ public final int writeSize() {
+ if (writeSize < 0) {
+ throw new UnsupportedOperationException("writeSize is unknown");
}
- /**
- * Indicates that this item has been added to the given section at
- * the given offset. It is only valid to call this method once per
- * instance.
- *
- * @param addedTo {@code non-null;} the section this instance has
- * been added to
- * @param offset {@code >= 0;} the desired offset from the start of the
- * section where this instance was placed
- * @return {@code >= 0;} the offset that this instance should be placed at
- * in order to meet its alignment constraint
- */
- public final int place(Section addedTo, int offset) {
- if (addedTo == null) {
- throw new NullPointerException("addedTo == null");
- }
+ return writeSize;
+ }
- if (offset < 0) {
- throw new IllegalArgumentException("offset < 0");
- }
+ /** {@inheritDoc} */
+ @Override
+ public final void writeTo(DexFile file, AnnotatedOutput out) {
+ out.alignTo(alignment);
- if (this.addedTo != null) {
- throw new RuntimeException("already written");
- }
-
- int mask = alignment - 1;
- offset = (offset + mask) & ~mask;
-
- this.addedTo = addedTo;
- this.offset = offset;
-
- place0(addedTo, offset);
-
- return offset;
+ try {
+ if (writeSize < 0) {
+ throw new UnsupportedOperationException("writeSize is unknown");
+ }
+ out.assertCursor(getAbsoluteOffset());
+ } catch (RuntimeException ex) {
+ throw ExceptionWithContext.withContext(ex, "...while writing " + this);
}
- /**
- * Gets the alignment requirement of this instance. An instance should
- * only be written when so aligned.
- *
- * @return {@code > 0;} the alignment requirement; must be a power of 2
- */
- public final int getAlignment() {
- return alignment;
+ writeTo0(file, out);
+ }
+
+ /**
+ * Gets the relative item offset. The offset is from the start of
+ * the section which the instance was written to.
+ *
+ * @return {@code >= 0;} the offset
+ * @throws RuntimeException thrown if the offset is not yet known
+ */
+ public final int getRelativeOffset() {
+ if (offset < 0) {
+ throw new RuntimeException("offset not yet known");
}
- /**
- * Gets the absolute offset of this item as a string, suitable for
- * including in annotations.
- *
- * @return {@code non-null;} the offset string
- */
- public final String offsetString() {
- return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
+ return offset;
+ }
+
+ /**
+ * Gets the absolute item offset. The offset is from the start of
+ * the file which the instance was written to.
+ *
+ * @return {@code >= 0;} the offset
+ * @throws RuntimeException thrown if the offset is not yet known
+ */
+ public final int getAbsoluteOffset() {
+ if (offset < 0) {
+ throw new RuntimeException("offset not yet known");
}
- /**
- * Gets a short human-readable string representing this instance.
- *
- * @return {@code non-null;} the human form
- */
- public abstract String toHuman();
+ return addedTo.getAbsoluteOffset(offset);
+ }
- /**
- * Compares this instance to another which is guaranteed to be of
- * the same class. The default implementation of this method is to
- * throw an exception (unsupported operation). If a particular
- * class needs to actually sort, then it should override this
- * method.
- *
- * @param other {@code non-null;} instance to compare to
- * @return {@code -1}, {@code 0}, or {@code 1}, depending
- * on the sort order of this instance and the other
- */
- protected int compareTo0(OffsettedItem other) {
- throw new UnsupportedOperationException("unsupported");
+ /**
+ * Indicates that this item has been added to the given section at
+ * the given offset. It is only valid to call this method once per
+ * instance.
+ *
+ * @param addedTo {@code non-null;} the section this instance has
+ * been added to
+ * @param offset {@code >= 0;} the desired offset from the start of the
+ * section where this instance was placed
+ * @return {@code >= 0;} the offset that this instance should be placed at
+ * in order to meet its alignment constraint
+ */
+ public final int place(Section addedTo, int offset) {
+ if (addedTo == null) {
+ throw new NullPointerException("addedTo == null");
}
- /**
- * Does additional work required when placing an instance. The
- * default implementation of this method is a no-op. If a
- * particular class needs to do something special, then it should
- * override this method. In particular, if this instance did not
- * know its write size up-front, then this method is responsible
- * for setting it.
- *
- * @param addedTo {@code non-null;} the section this instance has been added to
- * @param offset {@code >= 0;} the offset from the start of the
- * section where this instance was placed
- */
- protected void place0(Section addedTo, int offset) {
- // This space intentionally left blank.
+ if (offset < 0) {
+ throw new IllegalArgumentException("offset < 0");
}
- /**
- * Performs the actual write of the contents of this instance to
- * the given data section. This is called by {@link #writeTo},
- * which will have taken care of ensuring alignment.
- *
- * @param file {@code non-null;} the file to use for reference
- * @param out {@code non-null;} where to write to
- */
- protected abstract void writeTo0(DexFile file, AnnotatedOutput out);
+ if (this.addedTo != null) {
+ throw new RuntimeException("already written");
+ }
+
+ int mask = alignment - 1;
+ offset = (offset + mask) & ~mask;
+
+ this.addedTo = addedTo;
+ this.offset = offset;
+
+ place0(addedTo, offset);
+
+ return offset;
+ }
+
+ /**
+ * Gets the alignment requirement of this instance. An instance should
+ * only be written when so aligned.
+ *
+ * @return {@code > 0;} the alignment requirement; must be a power of 2
+ */
+ public final int getAlignment() {
+ return alignment;
+ }
+
+ /**
+ * Gets the absolute offset of this item as a string, suitable for
+ * including in annotations.
+ *
+ * @return {@code non-null;} the offset string
+ */
+ public final String offsetString() {
+ return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
+ }
+
+ /**
+ * Gets a short human-readable string representing this instance.
+ *
+ * @return {@code non-null;} the human form
+ */
+ public abstract String toHuman();
+
+ /**
+ * Compares this instance to another which is guaranteed to be of
+ * the same class. The default implementation of this method is to
+ * throw an exception (unsupported operation). If a particular
+ * class needs to actually sort, then it should override this
+ * method.
+ *
+ * @param other {@code non-null;} instance to compare to
+ * @return {@code -1}, {@code 0}, or {@code 1}, depending
+ * on the sort order of this instance and the other
+ */
+ protected int compareTo0(OffsettedItem other) {
+ throw new UnsupportedOperationException("unsupported");
+ }
+
+ /**
+ * Does additional work required when placing an instance. The
+ * default implementation of this method is a no-op. If a
+ * particular class needs to do something special, then it should
+ * override this method. In particular, if this instance did not
+ * know its write size up-front, then this method is responsible
+ * for setting it.
+ *
+ * @param addedTo {@code non-null;} the section this instance has been added to
+ * @param offset {@code >= 0;} the offset from the start of the
+ * section where this instance was placed
+ */
+ protected void place0(Section addedTo, int offset) {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Performs the actual write of the contents of this instance to
+ * the given data section. This is called by {@link #writeTo},
+ * which will have taken care of ensuring alignment.
+ *
+ * @param file {@code non-null;} the file to use for reference
+ * @param out {@code non-null;} where to write to
+ */
+ protected abstract void writeTo0(DexFile file, AnnotatedOutput out);
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ParameterAnnotationStruct.java b/dx/src/com/android/jack/dx/dex/file/ParameterAnnotationStruct.java
index 57c4db5..c8ad228 100644
--- a/dx/src/com/android/jack/dx/dex/file/ParameterAnnotationStruct.java
+++ b/dx/src/com/android/jack/dx/dex/file/ParameterAnnotationStruct.java
@@ -28,134 +28,135 @@
/**
* Association of a method and its parameter annotations.
*/
-public final class ParameterAnnotationStruct
- implements ToHuman, Comparable<ParameterAnnotationStruct> {
- /** {@code non-null;} the method in question */
- private final CstMethodRef method;
+public final class ParameterAnnotationStruct implements ToHuman,
+ Comparable<ParameterAnnotationStruct> {
+ /** {@code non-null;} the method in question */
+ private final CstMethodRef method;
- /** {@code non-null;} the associated annotations list */
- private final AnnotationsList annotationsList;
+ /** {@code non-null;} the associated annotations list */
+ private final AnnotationsList annotationsList;
- /** {@code non-null;} the associated annotations list, as an item */
- private final UniformListItem<AnnotationSetRefItem> annotationsItem;
+ /** {@code non-null;} the associated annotations list, as an item */
+ private final UniformListItem<AnnotationSetRefItem> annotationsItem;
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the method in question
- * @param annotationsList {@code non-null;} the associated annotations list
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the method in question
+ * @param annotationsList {@code non-null;} the associated annotations list
+ */
+ public ParameterAnnotationStruct(CstMethodRef method, AnnotationsList annotationsList) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
+ }
+
+ if (annotationsList == null) {
+ throw new NullPointerException("annotationsList == null");
+ }
+
+ this.method = method;
+ this.annotationsList = annotationsList;
+
+ /*
+ * Construct an item for the annotations list. TODO(dx team): This
+ * requires way too much copying; fix it.
*/
- public ParameterAnnotationStruct(CstMethodRef method,
- AnnotationsList annotationsList) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
- if (annotationsList == null) {
- throw new NullPointerException("annotationsList == null");
- }
+int size = annotationsList.size();
+ ArrayList<AnnotationSetRefItem> arrayList = new ArrayList<AnnotationSetRefItem>(size);
- this.method = method;
- this.annotationsList = annotationsList;
-
- /*
- * Construct an item for the annotations list. TODO: This
- * requires way too much copying; fix it.
- */
-
- int size = annotationsList.size();
- ArrayList<AnnotationSetRefItem> arrayList = new
- ArrayList<AnnotationSetRefItem>(size);
-
- for (int i = 0; i < size; i++) {
- Annotations annotations = annotationsList.get(i);
- AnnotationSetItem item = new AnnotationSetItem(annotations);
- arrayList.add(new AnnotationSetRefItem(item));
- }
-
- this.annotationsItem = new UniformListItem<AnnotationSetRefItem>(
- ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
+ for (int i = 0; i < size; i++) {
+ Annotations annotations = annotationsList.get(i);
+ AnnotationSetItem item = new AnnotationSetItem(annotations);
+ arrayList.add(new AnnotationSetRefItem(item));
}
- /** {@inheritDoc} */
- public int hashCode() {
- return method.hashCode();
+ this.annotationsItem =
+ new UniformListItem<AnnotationSetRefItem>(ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return method.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ParameterAnnotationStruct)) {
+ return false;
}
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (! (other instanceof ParameterAnnotationStruct)) {
- return false;
- }
+ return method.equals(((ParameterAnnotationStruct) other).method);
+ }
- return method.equals(((ParameterAnnotationStruct) other).method);
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(ParameterAnnotationStruct other) {
+ return method.compareTo(other.method);
+ }
+
+ /** {@inheritDoc} */
+ public void addContents(DexFile file) {
+ MethodIdsSection methodIds = file.getMethodIds();
+ MixedItemSection wordData = file.getWordData();
+
+ methodIds.intern(method);
+ wordData.add(annotationsItem);
+ }
+
+ /** {@inheritDoc} */
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int methodIdx = file.getMethodIds().indexOf(method);
+ int annotationsOff = annotationsItem.getAbsoluteOffset();
+
+ if (out.annotates()) {
+ out.annotate(0, " " + method.toHuman());
+ out.annotate(4, " method_idx: " + Hex.u4(methodIdx));
+ out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff));
}
- /** {@inheritDoc} */
- public int compareTo(ParameterAnnotationStruct other) {
- return method.compareTo(other.method);
+ out.writeInt(methodIdx);
+ out.writeInt(annotationsOff);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(method.toHuman());
+ sb.append(": ");
+
+ boolean first = true;
+ for (AnnotationSetRefItem item : annotationsItem.getItems()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(item.toHuman());
}
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- MethodIdsSection methodIds = file.getMethodIds();
- MixedItemSection wordData = file.getWordData();
+ return sb.toString();
+ }
- methodIds.intern(method);
- wordData.add(annotationsItem);
- }
+ /**
+ * Gets the method this item is for.
+ *
+ * @return {@code non-null;} the method
+ */
+ public CstMethodRef getMethod() {
+ return method;
+ }
- /** {@inheritDoc} */
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int methodIdx = file.getMethodIds().indexOf(method);
- int annotationsOff = annotationsItem.getAbsoluteOffset();
-
- if (out.annotates()) {
- out.annotate(0, " " + method.toHuman());
- out.annotate(4, " method_idx: " + Hex.u4(methodIdx));
- out.annotate(4, " annotations_off: " +
- Hex.u4(annotationsOff));
- }
-
- out.writeInt(methodIdx);
- out.writeInt(annotationsOff);
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- StringBuilder sb = new StringBuilder();
-
- sb.append(method.toHuman());
- sb.append(": ");
-
- boolean first = true;
- for (AnnotationSetRefItem item : annotationsItem.getItems()) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(item.toHuman());
- }
-
- return sb.toString();
- }
-
- /**
- * Gets the method this item is for.
- *
- * @return {@code non-null;} the method
- */
- public CstMethodRef getMethod() {
- return method;
- }
-
- /**
- * Gets the associated annotations list.
- *
- * @return {@code non-null;} the annotations list
- */
- public AnnotationsList getAnnotationsList() {
- return annotationsList;
- }
+ /**
+ * Gets the associated annotations list.
+ *
+ * @return {@code non-null;} the annotations list
+ */
+ public AnnotationsList getAnnotationsList() {
+ return annotationsList;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ProtoIdItem.java b/dx/src/com/android/jack/dx/dex/file/ProtoIdItem.java
index 1707125..9db6c26 100644
--- a/dx/src/com/android/jack/dx/dex/file/ProtoIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/ProtoIdItem.java
@@ -28,132 +28,130 @@
* Representation of a method prototype reference inside a Dalvik file.
*/
public final class ProtoIdItem extends IndexedItem {
- /** {@code non-null;} the wrapped prototype */
- private final Prototype prototype;
+ /** {@code non-null;} the wrapped prototype */
+ private final Prototype prototype;
- /** {@code non-null;} the short-form of the prototype */
- private final CstString shortForm;
+ /** {@code non-null;} the short-form of the prototype */
+ private final CstString shortForm;
- /**
- * {@code null-ok;} the list of parameter types or {@code null} if this
- * prototype has no parameters
- */
- private TypeListItem parameterTypes;
+ /**
+ * {@code null-ok;} the list of parameter types or {@code null} if this
+ * prototype has no parameters
+ */
+ private TypeListItem parameterTypes;
- /**
- * Constructs an instance.
- *
- * @param prototype {@code non-null;} the constant for the prototype
- */
- public ProtoIdItem(Prototype prototype) {
- if (prototype == null) {
- throw new NullPointerException("prototype == null");
+ /**
+ * Constructs an instance.
+ *
+ * @param prototype {@code non-null;} the constant for the prototype
+ */
+ public ProtoIdItem(Prototype prototype) {
+ if (prototype == null) {
+ throw new NullPointerException("prototype == null");
+ }
+
+ this.prototype = prototype;
+ this.shortForm = makeShortForm(prototype);
+
+ StdTypeList parameters = prototype.getParameterTypes();
+ this.parameterTypes = (parameters.size() == 0) ? null : new TypeListItem(parameters);
+ }
+
+ /**
+ * Creates the short-form of the given prototype.
+ *
+ * @param prototype {@code non-null;} the prototype
+ * @return {@code non-null;} the short form
+ */
+ private static CstString makeShortForm(Prototype prototype) {
+ StdTypeList parameters = prototype.getParameterTypes();
+ int size = parameters.size();
+ StringBuilder sb = new StringBuilder(size + 1);
+
+ sb.append(shortFormCharFor(prototype.getReturnType()));
+
+ for (int i = 0; i < size; i++) {
+ sb.append(shortFormCharFor(parameters.getType(i)));
+ }
+
+ return new CstString(sb.toString());
+ }
+
+ /**
+ * Gets the short-form character for the given type.
+ *
+ * @param type {@code non-null;} the type
+ * @return the corresponding short-form character
+ */
+ private static char shortFormCharFor(Type type) {
+ char descriptorChar = type.getDescriptor().charAt(0);
+
+ if (descriptorChar == '[') {
+ return 'L';
+ }
+
+ return descriptorChar;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_PROTO_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.PROTO_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ StringIdsSection stringIds = file.getStringIds();
+ TypeIdsSection typeIds = file.getTypeIds();
+ MixedItemSection typeLists = file.getTypeLists();
+
+ typeIds.intern(prototype.getReturnType());
+ stringIds.intern(shortForm);
+
+ if (parameterTypes != null) {
+ parameterTypes = typeLists.intern(parameterTypes);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int shortyIdx = file.getStringIds().indexOf(shortForm);
+ int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType());
+ int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes);
+
+ if (out.annotates()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(prototype.getReturnType().toHuman());
+ sb.append(" proto(");
+
+ StdTypeList params = prototype.getParameterTypes();
+ int size = params.size();
+
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.append(", ");
}
+ sb.append(params.getType(i).toHuman());
+ }
- this.prototype = prototype;
- this.shortForm = makeShortForm(prototype);
-
- StdTypeList parameters = prototype.getParameterTypes();
- this.parameterTypes = (parameters.size() == 0) ? null
- : new TypeListItem(parameters);
+ sb.append(")");
+ out.annotate(0, indexString() + ' ' + sb.toString());
+ out.annotate(4, " shorty_idx: " + Hex.u4(shortyIdx) + " // " + shortForm.toQuoted());
+ out.annotate(4,
+ " return_type_idx: " + Hex.u4(returnIdx) + " // " + prototype.getReturnType().toHuman());
+ out.annotate(4, " parameters_off: " + Hex.u4(paramsOff));
}
- /**
- * Creates the short-form of the given prototype.
- *
- * @param prototype {@code non-null;} the prototype
- * @return {@code non-null;} the short form
- */
- private static CstString makeShortForm(Prototype prototype) {
- StdTypeList parameters = prototype.getParameterTypes();
- int size = parameters.size();
- StringBuilder sb = new StringBuilder(size + 1);
-
- sb.append(shortFormCharFor(prototype.getReturnType()));
-
- for (int i = 0; i < size; i++) {
- sb.append(shortFormCharFor(parameters.getType(i)));
- }
-
- return new CstString(sb.toString());
- }
-
- /**
- * Gets the short-form character for the given type.
- *
- * @param type {@code non-null;} the type
- * @return the corresponding short-form character
- */
- private static char shortFormCharFor(Type type) {
- char descriptorChar = type.getDescriptor().charAt(0);
-
- if (descriptorChar == '[') {
- return 'L';
- }
-
- return descriptorChar;
- }
-
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_PROTO_ID_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.PROTO_ID_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- StringIdsSection stringIds = file.getStringIds();
- TypeIdsSection typeIds = file.getTypeIds();
- MixedItemSection typeLists = file.getTypeLists();
-
- typeIds.intern(prototype.getReturnType());
- stringIds.intern(shortForm);
-
- if (parameterTypes != null) {
- parameterTypes = typeLists.intern(parameterTypes);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int shortyIdx = file.getStringIds().indexOf(shortForm);
- int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType());
- int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes);
-
- if (out.annotates()) {
- StringBuilder sb = new StringBuilder();
- sb.append(prototype.getReturnType().toHuman());
- sb.append(" proto(");
-
- StdTypeList params = prototype.getParameterTypes();
- int size = params.size();
-
- for (int i = 0; i < size; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(params.getType(i).toHuman());
- }
-
- sb.append(")");
- out.annotate(0, indexString() + ' ' + sb.toString());
- out.annotate(4, " shorty_idx: " + Hex.u4(shortyIdx) +
- " // " + shortForm.toQuoted());
- out.annotate(4, " return_type_idx: " + Hex.u4(returnIdx) +
- " // " + prototype.getReturnType().toHuman());
- out.annotate(4, " parameters_off: " + Hex.u4(paramsOff));
- }
-
- out.writeInt(shortyIdx);
- out.writeInt(returnIdx);
- out.writeInt(paramsOff);
- }
+ out.writeInt(shortyIdx);
+ out.writeInt(returnIdx);
+ out.writeInt(paramsOff);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/jack/dx/dex/file/ProtoIdsSection.java
index a588d00..33cb976 100644
--- a/dx/src/com/android/jack/dx/dex/file/ProtoIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/ProtoIdsSection.java
@@ -29,112 +29,112 @@
* {@code .dex} file.
*/
public final class ProtoIdsSection extends UniformItemSection {
- /**
- * {@code non-null;} map from method prototypes to {@link ProtoIdItem} instances
- */
- private final TreeMap<Prototype, ProtoIdItem> protoIds;
+ /**
+ * {@code non-null;} map from method prototypes to {@link ProtoIdItem} instances
+ */
+ private final TreeMap<Prototype, ProtoIdItem> protoIds;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public ProtoIdsSection(DexFile file) {
- super("proto_ids", file, 4);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public ProtoIdsSection(DexFile file) {
+ super("proto_ids", file, 4);
- protoIds = new TreeMap<Prototype, ProtoIdItem>();
+ protoIds = new TreeMap<Prototype, ProtoIdItem>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return protoIds.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ throw new UnsupportedOperationException("unsupported");
+ }
+
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
+
+ int sz = protoIds.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
+
+ if (sz > 65536) {
+ throw new UnsupportedOperationException("too many proto ids");
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return protoIds.values();
+ if (out.annotates()) {
+ out.annotate(4, "proto_ids_size: " + Hex.u4(sz));
+ out.annotate(4, "proto_ids_off: " + Hex.u4(offset));
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- throw new UnsupportedOperationException("unsupported");
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
+
+ /**
+ * Interns an element into this instance.
+ *
+ * @param prototype {@code non-null;} the prototype to intern
+ * @return {@code non-null;} the interned reference
+ */
+ public ProtoIdItem intern(Prototype prototype) {
+ if (prototype == null) {
+ throw new NullPointerException("prototype == null");
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
+ throwIfPrepared();
- int sz = protoIds.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
+ ProtoIdItem result = protoIds.get(prototype);
- if (sz > 65536) {
- throw new UnsupportedOperationException("too many proto ids");
- }
-
- if (out.annotates()) {
- out.annotate(4, "proto_ids_size: " + Hex.u4(sz));
- out.annotate(4, "proto_ids_off: " + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ if (result == null) {
+ result = new ProtoIdItem(prototype);
+ protoIds.put(prototype, result);
}
- /**
- * Interns an element into this instance.
- *
- * @param prototype {@code non-null;} the prototype to intern
- * @return {@code non-null;} the interned reference
- */
- public ProtoIdItem intern(Prototype prototype) {
- if (prototype == null) {
- throw new NullPointerException("prototype == null");
- }
+ return result;
+ }
- throwIfPrepared();
-
- ProtoIdItem result = protoIds.get(prototype);
-
- if (result == null) {
- result = new ProtoIdItem(prototype);
- protoIds.put(prototype, result);
- }
-
- return result;
+ /**
+ * Gets the index of the given prototype, which must have
+ * been added to this instance.
+ *
+ * @param prototype {@code non-null;} the prototype to look up
+ * @return {@code >= 0;} the reference's index
+ */
+ public int indexOf(Prototype prototype) {
+ if (prototype == null) {
+ throw new NullPointerException("prototype == null");
}
- /**
- * Gets the index of the given prototype, which must have
- * been added to this instance.
- *
- * @param prototype {@code non-null;} the prototype to look up
- * @return {@code >= 0;} the reference's index
- */
- public int indexOf(Prototype prototype) {
- if (prototype == null) {
- throw new NullPointerException("prototype == null");
- }
+ throwIfNotPrepared();
- throwIfNotPrepared();
+ ProtoIdItem item = protoIds.get(prototype);
- ProtoIdItem item = protoIds.get(prototype);
-
- if (item == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return item.getIndex();
+ if (item == null) {
+ throw new IllegalArgumentException("not found");
}
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- int idx = 0;
+ return item.getIndex();
+ }
- for (Object i : items()) {
- ((ProtoIdItem) i).setIndex(idx);
- idx++;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ int idx = 0;
+
+ for (Object i : items()) {
+ ((ProtoIdItem) i).setIndex(idx);
+ idx++;
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/Section.java b/dx/src/com/android/jack/dx/dex/file/Section.java
index 6b86364..46d332d 100644
--- a/dx/src/com/android/jack/dx/dex/file/Section.java
+++ b/dx/src/com/android/jack/dx/dex/file/Section.java
@@ -25,263 +25,261 @@
* of items of some sort or other.
*/
public abstract class Section {
- /** {@code null-ok;} name of this part, for annotation purposes */
- private final String name;
+ /** {@code null-ok;} name of this part, for annotation purposes */
+ private final String name;
- /** {@code non-null;} file that this instance is part of */
- private final DexFile file;
+ /** {@code non-null;} file that this instance is part of */
+ private final DexFile file;
- /** {@code > 0;} alignment requirement for the final output;
- * must be a power of 2 */
- private final int alignment;
+ /** {@code > 0;} alignment requirement for the final output;
+ * must be a power of 2 */
+ private final int alignment;
- /** {@code >= -1;} offset from the start of the file to this part, or
- * {@code -1} if not yet known */
- private int fileOffset;
+ /** {@code >= -1;} offset from the start of the file to this part, or
+ * {@code -1} if not yet known */
+ private int fileOffset;
- /** whether {@link #prepare} has been called successfully on this
- * instance */
- private boolean prepared;
+ /** whether {@link #prepare} has been called successfully on this
+ * instance */
+ private boolean prepared;
- /**
- * Validates an alignment.
- *
- * @param alignment the alignment
- * @throws IllegalArgumentException thrown if {@code alignment}
- * isn't a positive power of 2
- */
- public static void validateAlignment(int alignment) {
- if ((alignment <= 0) ||
- (alignment & (alignment - 1)) != 0) {
- throw new IllegalArgumentException("invalid alignment");
- }
+ /**
+ * Validates an alignment.
+ *
+ * @param alignment the alignment
+ * @throws IllegalArgumentException thrown if {@code alignment}
+ * isn't a positive power of 2
+ */
+ public static void validateAlignment(int alignment) {
+ if ((alignment <= 0) || (alignment & (alignment - 1)) != 0) {
+ throw new IllegalArgumentException("invalid alignment");
+ }
+ }
+
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param name {@code null-ok;} the name of this instance, for annotation
+ * purposes
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
+ * must be a power of 2
+ */
+ public Section(String name, DexFile file, int alignment) {
+ if (file == null) {
+ throw new NullPointerException("file == null");
}
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param name {@code null-ok;} the name of this instance, for annotation
- * purposes
- * @param file {@code non-null;} file that this instance is part of
- * @param alignment {@code > 0;} alignment requirement for the final output;
- * must be a power of 2
- */
- public Section(String name, DexFile file, int alignment) {
- if (file == null) {
- throw new NullPointerException("file == null");
- }
+ validateAlignment(alignment);
- validateAlignment(alignment);
+ this.name = name;
+ this.file = file;
+ this.alignment = alignment;
+ this.fileOffset = -1;
+ this.prepared = false;
+ }
- this.name = name;
- this.file = file;
- this.alignment = alignment;
- this.fileOffset = -1;
- this.prepared = false;
+ /**
+ * Gets the file that this instance is part of.
+ *
+ * @return {@code non-null;} the file
+ */
+ public final DexFile getFile() {
+ return file;
+ }
+
+ /**
+ * Gets the alignment for this instance's final output.
+ *
+ * @return {@code > 0;} the alignment
+ */
+ public final int getAlignment() {
+ return alignment;
+ }
+
+ /**
+ * Gets the offset from the start of the file to this part. This
+ * throws an exception if the offset has not yet been set.
+ *
+ * @return {@code >= 0;} the file offset
+ */
+ public final int getFileOffset() {
+ if (fileOffset < 0) {
+ throw new RuntimeException("fileOffset not set");
}
- /**
- * Gets the file that this instance is part of.
- *
- * @return {@code non-null;} the file
- */
- public final DexFile getFile() {
- return file;
+ return fileOffset;
+ }
+
+ /**
+ * Sets the file offset. It is only valid to call this method once
+ * once per instance.
+ *
+ * @param fileOffset {@code >= 0;} the desired offset from the start of the
+ * file where this for this instance
+ * @return {@code >= 0;} the offset that this instance should be placed at
+ * in order to meet its alignment constraint
+ */
+ public final int setFileOffset(int fileOffset) {
+ if (fileOffset < 0) {
+ throw new IllegalArgumentException("fileOffset < 0");
}
- /**
- * Gets the alignment for this instance's final output.
- *
- * @return {@code > 0;} the alignment
- */
- public final int getAlignment() {
- return alignment;
+ if (this.fileOffset >= 0) {
+ throw new RuntimeException("fileOffset already set");
}
- /**
- * Gets the offset from the start of the file to this part. This
- * throws an exception if the offset has not yet been set.
- *
- * @return {@code >= 0;} the file offset
- */
- public final int getFileOffset() {
- if (fileOffset < 0) {
- throw new RuntimeException("fileOffset not set");
- }
+ int mask = alignment - 1;
+ fileOffset = (fileOffset + mask) & ~mask;
- return fileOffset;
+ this.fileOffset = fileOffset;
+
+ return fileOffset;
+ }
+
+ /**
+ * Writes this instance to the given raw data object.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ public final void writeTo(AnnotatedOutput out) {
+ throwIfNotPrepared();
+ align(out);
+
+ int cursor = out.getCursor();
+
+ if (fileOffset < 0) {
+ fileOffset = cursor;
+ } else if (fileOffset != cursor) {
+ throw new RuntimeException(
+ "alignment mismatch: for " + this + ", at " + cursor + ", but expected " + fileOffset);
}
- /**
- * Sets the file offset. It is only valid to call this method once
- * once per instance.
- *
- * @param fileOffset {@code >= 0;} the desired offset from the start of the
- * file where this for this instance
- * @return {@code >= 0;} the offset that this instance should be placed at
- * in order to meet its alignment constraint
- */
- public final int setFileOffset(int fileOffset) {
- if (fileOffset < 0) {
- throw new IllegalArgumentException("fileOffset < 0");
- }
-
- if (this.fileOffset >= 0) {
- throw new RuntimeException("fileOffset already set");
- }
-
- int mask = alignment - 1;
- fileOffset = (fileOffset + mask) & ~mask;
-
- this.fileOffset = fileOffset;
-
- return fileOffset;
+ if (out.annotates()) {
+ if (name != null) {
+ out.annotate(0, "\n" + name + ":");
+ } else if (cursor != 0) {
+ out.annotate(0, "\n");
+ }
}
- /**
- * Writes this instance to the given raw data object.
- *
- * @param out {@code non-null;} where to write to
- */
- public final void writeTo(AnnotatedOutput out) {
- throwIfNotPrepared();
- align(out);
+ writeTo0(out);
+ }
- int cursor = out.getCursor();
-
- if (fileOffset < 0) {
- fileOffset = cursor;
- } else if (fileOffset != cursor) {
- throw new RuntimeException("alignment mismatch: for " + this +
- ", at " + cursor +
- ", but expected " + fileOffset);
- }
-
- if (out.annotates()) {
- if (name != null) {
- out.annotate(0, "\n" + name + ":");
- } else if (cursor != 0) {
- out.annotate(0, "\n");
- }
- }
-
- writeTo0(out);
+ /**
+ * Returns the absolute file offset, given an offset from the
+ * start of this instance's output. This is only valid to call
+ * once this instance has been assigned a file offset (via {@link
+ * #setFileOffset}).
+ *
+ * @param relative {@code >= 0;} the relative offset
+ * @return {@code >= 0;} the corresponding absolute file offset
+ */
+ public final int getAbsoluteOffset(int relative) {
+ if (relative < 0) {
+ throw new IllegalArgumentException("relative < 0");
}
- /**
- * Returns the absolute file offset, given an offset from the
- * start of this instance's output. This is only valid to call
- * once this instance has been assigned a file offset (via {@link
- * #setFileOffset}).
- *
- * @param relative {@code >= 0;} the relative offset
- * @return {@code >= 0;} the corresponding absolute file offset
- */
- public final int getAbsoluteOffset(int relative) {
- if (relative < 0) {
- throw new IllegalArgumentException("relative < 0");
- }
-
- if (fileOffset < 0) {
- throw new RuntimeException("fileOffset not yet set");
- }
-
- return fileOffset + relative;
+ if (fileOffset < 0) {
+ throw new RuntimeException("fileOffset not yet set");
}
- /**
- * Returns the absolute file offset of the given item which must
- * be contained in this section. This is only valid to call
- * once this instance has been assigned a file offset (via {@link
- * #setFileOffset}).
- *
- * <p><b>Note:</b> Subclasses must implement this as appropriate for
- * their contents.</p>
- *
- * @param item {@code non-null;} the item in question
- * @return {@code >= 0;} the item's absolute file offset
- */
- public abstract int getAbsoluteItemOffset(Item item);
+ return fileOffset + relative;
+ }
- /**
- * Prepares this instance for writing. This performs any necessary
- * prerequisites, including particularly adding stuff to other
- * sections. This method may only be called once per instance;
- * subsequent calls will throw an exception.
- */
- public final void prepare() {
- throwIfPrepared();
- prepare0();
- prepared = true;
+ /**
+ * Returns the absolute file offset of the given item which must
+ * be contained in this section. This is only valid to call
+ * once this instance has been assigned a file offset (via {@link
+ * #setFileOffset}).
+ *
+ * <p><b>Note:</b> Subclasses must implement this as appropriate for
+ * their contents.</p>
+ *
+ * @param item {@code non-null;} the item in question
+ * @return {@code >= 0;} the item's absolute file offset
+ */
+ public abstract int getAbsoluteItemOffset(Item item);
+
+ /**
+ * Prepares this instance for writing. This performs any necessary
+ * prerequisites, including particularly adding stuff to other
+ * sections. This method may only be called once per instance;
+ * subsequent calls will throw an exception.
+ */
+ public final void prepare() {
+ throwIfPrepared();
+ prepare0();
+ prepared = true;
+ }
+
+ /**
+ * Gets the collection of all the items in this section.
+ * It is not valid to attempt to change the returned list.
+ *
+ * @return {@code non-null;} the items
+ */
+ public abstract Collection<? extends Item> items();
+
+ /**
+ * Does the main work of {@link #prepare}.
+ */
+ protected abstract void prepare0();
+
+ /**
+ * Gets the size of this instance when output, in bytes.
+ *
+ * @return {@code >= 0;} the size of this instance, in bytes
+ */
+ public abstract int writeSize();
+
+ /**
+ * Throws an exception if {@link #prepare} has not been
+ * called on this instance.
+ */
+ protected final void throwIfNotPrepared() {
+ if (!prepared) {
+ throw new RuntimeException("not prepared");
}
+ }
- /**
- * Gets the collection of all the items in this section.
- * It is not valid to attempt to change the returned list.
- *
- * @return {@code non-null;} the items
- */
- public abstract Collection<? extends Item> items();
-
- /**
- * Does the main work of {@link #prepare}.
- */
- protected abstract void prepare0();
-
- /**
- * Gets the size of this instance when output, in bytes.
- *
- * @return {@code >= 0;} the size of this instance, in bytes
- */
- public abstract int writeSize();
-
- /**
- * Throws an exception if {@link #prepare} has not been
- * called on this instance.
- */
- protected final void throwIfNotPrepared() {
- if (!prepared) {
- throw new RuntimeException("not prepared");
- }
+ /**
+ * Throws an exception if {@link #prepare} has already been called
+ * on this instance.
+ */
+ protected final void throwIfPrepared() {
+ if (prepared) {
+ throw new RuntimeException("already prepared");
}
+ }
- /**
- * Throws an exception if {@link #prepare} has already been called
- * on this instance.
- */
- protected final void throwIfPrepared() {
- if (prepared) {
- throw new RuntimeException("already prepared");
- }
- }
+ /**
+ * Aligns the output of the given data to the alignment of this instance.
+ *
+ * @param out {@code non-null;} the output to align
+ */
+ protected final void align(AnnotatedOutput out) {
+ out.alignTo(alignment);
+ }
- /**
- * Aligns the output of the given data to the alignment of this instance.
- *
- * @param out {@code non-null;} the output to align
- */
- protected final void align(AnnotatedOutput out) {
- out.alignTo(alignment);
- }
+ /**
+ * Writes this instance to the given raw data object. This gets
+ * called by {@link #writeTo} after aligning the cursor of
+ * {@code out} and verifying that either the assigned file
+ * offset matches the actual cursor {@code out} or that the
+ * file offset was not previously assigned, in which case it gets
+ * assigned to {@code out}'s cursor.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ protected abstract void writeTo0(AnnotatedOutput out);
- /**
- * Writes this instance to the given raw data object. This gets
- * called by {@link #writeTo} after aligning the cursor of
- * {@code out} and verifying that either the assigned file
- * offset matches the actual cursor {@code out} or that the
- * file offset was not previously assigned, in which case it gets
- * assigned to {@code out}'s cursor.
- *
- * @param out {@code non-null;} where to write to
- */
- protected abstract void writeTo0(AnnotatedOutput out);
-
- /**
- * Returns the name of this section, for annotation purposes.
- *
- * @return {@code null-ok;} name of this part, for annotation purposes
- */
- protected final String getName() {
- return name;
- }
+ /**
+ * Returns the name of this section, for annotation purposes.
+ *
+ * @return {@code null-ok;} name of this part, for annotation purposes
+ */
+ protected final String getName() {
+ return name;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/Statistics.java b/dx/src/com/android/jack/dx/dex/file/Statistics.java
index c31a9d8..9e75182 100644
--- a/dx/src/com/android/jack/dx/dex/file/Statistics.java
+++ b/dx/src/com/android/jack/dx/dex/file/Statistics.java
@@ -26,170 +26,169 @@
* Statistics about the contents of a file.
*/
public final class Statistics {
- /** {@code non-null;} data about each type of item */
- private final HashMap<String, Data> dataMap;
+ /** {@code non-null;} data about each type of item */
+ private final HashMap<String, Data> dataMap;
+
+ /**
+ * Constructs an instance.
+ */
+ public Statistics() {
+ dataMap = new HashMap<String, Data>(50);
+ }
+
+ /**
+ * Adds the given item to the statistics.
+ *
+ * @param item {@code non-null;} the item to add
+ */
+ public void add(Item item) {
+ String typeName = item.typeName();
+ Data data = dataMap.get(typeName);
+
+ if (data == null) {
+ dataMap.put(typeName, new Data(item, typeName));
+ } else {
+ data.add(item);
+ }
+ }
+
+ /**
+ * Adds the given list of items to the statistics.
+ *
+ * @param list {@code non-null;} the list of items to add
+ */
+ public void addAll(Section list) {
+ Collection<? extends Item> items = list.items();
+ for (Item item : items) {
+ add(item);
+ }
+ }
+
+ /**
+ * Writes the statistics as an annotation.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ public final void writeAnnotation(AnnotatedOutput out) {
+ if (dataMap.size() == 0) {
+ return;
+ }
+
+ out.annotate(0, "\nstatistics:\n");
+
+ TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+ for (Data data : dataMap.values()) {
+ sortedData.put(data.name, data);
+ }
+
+ for (Data data : sortedData.values()) {
+ data.writeAnnotation(out);
+ }
+ }
+
+ public String toHuman() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Statistics:\n");
+
+ TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+ for (Data data : dataMap.values()) {
+ sortedData.put(data.name, data);
+ }
+
+ for (Data data : sortedData.values()) {
+ sb.append(data.toHuman());
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Statistical data about a particular class.
+ */
+ private static class Data {
+ /** {@code non-null;} name to use as a label */
+ private final String name;
+
+ /** {@code >= 0;} number of instances */
+ private int count;
+
+ /** {@code >= 0;} total size of instances in bytes */
+ private int totalSize;
+
+ /** {@code >= 0;} largest size of any individual item */
+ private int largestSize;
+
+ /** {@code >= 0;} smallest size of any individual item */
+ private int smallestSize;
/**
- * Constructs an instance.
+ * Constructs an instance for the given item.
+ *
+ * @param item {@code non-null;} item in question
+ * @param name {@code non-null;} type name to use
*/
- public Statistics() {
- dataMap = new HashMap<String, Data>(50);
+ public Data(Item item, String name) {
+ int size = item.writeSize();
+
+ this.name = name;
+ this.count = 1;
+ this.totalSize = size;
+ this.largestSize = size;
+ this.smallestSize = size;
}
/**
- * Adds the given item to the statistics.
+ * Incorporates a new item. This assumes the type name matches.
*
- * @param item {@code non-null;} the item to add
+ * @param item {@code non-null;} item to incorporate
*/
public void add(Item item) {
- String typeName = item.typeName();
- Data data = dataMap.get(typeName);
+ int size = item.writeSize();
- if (data == null) {
- dataMap.put(typeName, new Data(item, typeName));
- } else {
- data.add(item);
- }
+ count++;
+ totalSize += size;
+
+ if (size > largestSize) {
+ largestSize = size;
+ }
+
+ if (size < smallestSize) {
+ smallestSize = size;
+ }
}
/**
- * Adds the given list of items to the statistics.
- *
- * @param list {@code non-null;} the list of items to add
- */
- public void addAll(Section list) {
- Collection<? extends Item> items = list.items();
- for (Item item : items) {
- add(item);
- }
- }
-
- /**
- * Writes the statistics as an annotation.
+ * Writes this instance as an annotation.
*
* @param out {@code non-null;} where to write to
*/
- public final void writeAnnotation(AnnotatedOutput out) {
- if (dataMap.size() == 0) {
- return;
- }
-
- out.annotate(0, "\nstatistics:\n");
-
- TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
-
- for (Data data : dataMap.values()) {
- sortedData.put(data.name, data);
- }
-
- for (Data data : sortedData.values()) {
- data.writeAnnotation(out);
- }
- }
-
- public String toHuman() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("Statistics:\n");
-
- TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
-
- for (Data data : dataMap.values()) {
- sortedData.put(data.name, data);
- }
-
- for (Data data : sortedData.values()) {
- sb.append(data.toHuman());
- }
-
- return sb.toString();
+ public void writeAnnotation(AnnotatedOutput out) {
+ out.annotate(toHuman());
}
/**
- * Statistical data about a particular class.
+ * Generates a human-readable string for this data item.
+ *
+ * @return string for human consumption.
*/
- private static class Data {
- /** {@code non-null;} name to use as a label */
- private final String name;
+ public String toHuman() {
+ StringBuilder sb = new StringBuilder();
- /** {@code >= 0;} number of instances */
- private int count;
+ sb.append(" " + name + ": " + count + " item" + (count == 1 ? "" : "s") + "; " + totalSize
+ + " bytes total\n");
- /** {@code >= 0;} total size of instances in bytes */
- private int totalSize;
+ if (smallestSize == largestSize) {
+ sb.append(" " + smallestSize + " bytes/item\n");
+ } else {
+ int average = totalSize / count;
+ sb.append(
+ " " + smallestSize + ".." + largestSize + " bytes/item; average " + average + "\n");
+ }
- /** {@code >= 0;} largest size of any individual item */
- private int largestSize;
-
- /** {@code >= 0;} smallest size of any individual item */
- private int smallestSize;
-
- /**
- * Constructs an instance for the given item.
- *
- * @param item {@code non-null;} item in question
- * @param name {@code non-null;} type name to use
- */
- public Data(Item item, String name) {
- int size = item.writeSize();
-
- this.name = name;
- this.count = 1;
- this.totalSize = size;
- this.largestSize = size;
- this.smallestSize = size;
- }
-
- /**
- * Incorporates a new item. This assumes the type name matches.
- *
- * @param item {@code non-null;} item to incorporate
- */
- public void add(Item item) {
- int size = item.writeSize();
-
- count++;
- totalSize += size;
-
- if (size > largestSize) {
- largestSize = size;
- }
-
- if (size < smallestSize) {
- smallestSize = size;
- }
- }
-
- /**
- * Writes this instance as an annotation.
- *
- * @param out {@code non-null;} where to write to
- */
- public void writeAnnotation(AnnotatedOutput out) {
- out.annotate(toHuman());
- }
-
- /**
- * Generates a human-readable string for this data item.
- *
- * @return string for human consumption.
- */
- public String toHuman() {
- StringBuilder sb = new StringBuilder();
-
- sb.append(" " + name + ": " +
- count + " item" + (count == 1 ? "" : "s") + "; " +
- totalSize + " bytes total\n");
-
- if (smallestSize == largestSize) {
- sb.append(" " + smallestSize + " bytes/item\n");
- } else {
- int average = totalSize / count;
- sb.append(" " + smallestSize + ".." + largestSize +
- " bytes/item; average " + average + "\n");
- }
-
- return sb.toString();
- }
+ return sb.toString();
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/StringDataItem.java b/dx/src/com/android/jack/dx/dex/file/StringDataItem.java
index ee91266..bf15879 100644
--- a/dx/src/com/android/jack/dx/dex/file/StringDataItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/StringDataItem.java
@@ -26,74 +26,72 @@
* Representation of string data for a particular string, in a Dalvik file.
*/
public final class StringDataItem extends OffsettedItem {
- /** {@code non-null;} the string value */
- private final CstString value;
+ /** {@code non-null;} the string value */
+ private final CstString value;
- /**
- * Constructs an instance.
- *
- * @param value {@code non-null;} the string value
- */
- public StringDataItem(CstString value) {
- super(1, writeSize(value));
+ /**
+ * Constructs an instance.
+ *
+ * @param value {@code non-null;} the string value
+ */
+ public StringDataItem(CstString value) {
+ super(1, writeSize(value));
- this.value = value;
+ this.value = value;
+ }
+
+ /**
+ * Gets the write size for a given value.
+ *
+ * @param value {@code non-null;} the string value
+ * @return {@code >= 2}; the write size, in bytes
+ */
+ private static int writeSize(CstString value) {
+ int utf16Size = value.getUtf16Size();
+
+ // The +1 is for the '\0' termination byte.
+ return Leb128Utils.unsignedLeb128Size(utf16Size) + value.getUtf8Size() + 1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_STRING_DATA_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ // Nothing to do here.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo0(DexFile file, AnnotatedOutput out) {
+ ByteArray bytes = value.getBytes();
+ int utf16Size = value.getUtf16Size();
+
+ if (out.annotates()) {
+ out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size), "utf16_size: " + Hex.u4(utf16Size));
+ out.annotate(bytes.size() + 1, value.toQuoted());
}
- /**
- * Gets the write size for a given value.
- *
- * @param value {@code non-null;} the string value
- * @return {@code >= 2}; the write size, in bytes
- */
- private static int writeSize(CstString value) {
- int utf16Size = value.getUtf16Size();
+ out.writeUleb128(utf16Size);
+ out.write(bytes);
+ out.writeByte(0);
+ }
- // The +1 is for the '\0' termination byte.
- return Leb128Utils.unsignedLeb128Size(utf16Size)
- + value.getUtf8Size() + 1;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return value.toQuoted();
+ }
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_STRING_DATA_ITEM;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(OffsettedItem other) {
+ StringDataItem otherData = (StringDataItem) other;
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- // Nothing to do here.
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo0(DexFile file, AnnotatedOutput out) {
- ByteArray bytes = value.getBytes();
- int utf16Size = value.getUtf16Size();
-
- if (out.annotates()) {
- out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size),
- "utf16_size: " + Hex.u4(utf16Size));
- out.annotate(bytes.size() + 1, value.toQuoted());
- }
-
- out.writeUleb128(utf16Size);
- out.write(bytes);
- out.writeByte(0);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- return value.toQuoted();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(OffsettedItem other) {
- StringDataItem otherData = (StringDataItem) other;
-
- return value.compareTo(otherData.value);
- }
+ return value.compareTo(otherData.value);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/StringIdItem.java b/dx/src/com/android/jack/dx/dex/file/StringIdItem.java
index ec2bc18..5d2e74a 100644
--- a/dx/src/com/android/jack/dx/dex/file/StringIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/StringIdItem.java
@@ -24,103 +24,103 @@
/**
* Representation of a string inside a Dalvik file.
*/
-public final class StringIdItem
- extends IndexedItem implements Comparable {
- /** {@code non-null;} the string value */
- private final CstString value;
+public final class StringIdItem extends IndexedItem implements Comparable<StringIdItem> {
+ /** {@code non-null;} the string value */
+ private final CstString value;
- /** {@code null-ok;} associated string data object, if known */
- private StringDataItem data;
+ /** {@code null-ok;} associated string data object, if known */
+ private StringDataItem data;
- /**
- * Constructs an instance.
- *
- * @param value {@code non-null;} the string value
- */
- public StringIdItem(CstString value) {
- if (value == null) {
- throw new NullPointerException("value == null");
- }
-
- this.value = value;
- this.data = null;
+ /**
+ * Constructs an instance.
+ *
+ * @param value {@code non-null;} the string value
+ */
+ public StringIdItem(CstString value) {
+ if (value == null) {
+ throw new NullPointerException("value == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof StringIdItem)) {
- return false;
- }
+ this.value = value;
+ this.data = null;
+ }
- StringIdItem otherString = (StringIdItem) other;
- return value.equals(otherString.value);
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof StringIdItem)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return value.hashCode();
+ StringIdItem otherString = (StringIdItem) other;
+ return value.equals(otherString.value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(StringIdItem other) {
+ StringIdItem otherString = (StringIdItem) other;
+ return value.compareTo(otherString.value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_STRING_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.STRING_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ if (data == null) {
+ // The string data hasn't yet been added, so add it.
+ MixedItemSection stringData = file.getStringData();
+ data = new StringDataItem(value);
+ stringData.add(data);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ int dataOff = data.getAbsoluteOffset();
+
+ if (out.annotates()) {
+ out.annotate(0, indexString() + ' ' + value.toQuoted(100));
+ out.annotate(4, " string_data_off: " + Hex.u4(dataOff));
}
- /** {@inheritDoc} */
- public int compareTo(Object other) {
- StringIdItem otherString = (StringIdItem) other;
- return value.compareTo(otherString.value);
- }
+ out.writeInt(dataOff);
+ }
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_STRING_ID_ITEM;
- }
+ /**
+ * Gets the string value.
+ *
+ * @return {@code non-null;} the value
+ */
+ public CstString getValue() {
+ return value;
+ }
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.STRING_ID_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- if (data == null) {
- // The string data hasn't yet been added, so add it.
- MixedItemSection stringData = file.getStringData();
- data = new StringDataItem(value);
- stringData.add(data);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(DexFile file, AnnotatedOutput out) {
- int dataOff = data.getAbsoluteOffset();
-
- if (out.annotates()) {
- out.annotate(0, indexString() + ' ' + value.toQuoted(100));
- out.annotate(4, " string_data_off: " + Hex.u4(dataOff));
- }
-
- out.writeInt(dataOff);
- }
-
- /**
- * Gets the string value.
- *
- * @return {@code non-null;} the value
- */
- public CstString getValue() {
- return value;
- }
-
- /**
- * Gets the associated data object for this instance, if known.
- *
- * @return {@code null-ok;} the associated data object or {@code null}
- * if not yet known
- */
- public StringDataItem getData() {
- return data;
- }
+ /**
+ * Gets the associated data object for this instance, if known.
+ *
+ * @return {@code null-ok;} the associated data object or {@code null}
+ * if not yet known
+ */
+ public StringDataItem getData() {
+ return data;
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/StringIdsSection.java b/dx/src/com/android/jack/dx/dex/file/StringIdsSection.java
index d09563e..b9d6c0d 100644
--- a/dx/src/com/android/jack/dx/dex/file/StringIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/StringIdsSection.java
@@ -28,155 +28,154 @@
/**
* Strings list section of a {@code .dex} file.
*/
-public final class StringIdsSection
- extends UniformItemSection {
- /**
- * {@code non-null;} map from string constants to {@link
- * StringIdItem} instances
- */
- private final TreeMap<CstString, StringIdItem> strings;
+public final class StringIdsSection extends UniformItemSection {
+ /**
+ * {@code non-null;} map from string constants to {@link
+ * StringIdItem} instances
+ */
+ private final TreeMap<CstString, StringIdItem> strings;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public StringIdsSection(DexFile file) {
- super("string_ids", file, 4);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public StringIdsSection(DexFile file) {
+ super("string_ids", file, 4);
- strings = new TreeMap<CstString, StringIdItem>();
+ strings = new TreeMap<CstString, StringIdItem>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return strings.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return strings.values();
+ throwIfNotPrepared();
+
+ IndexedItem result = strings.get(cst);
+
+ if (result == null) {
+ throw new IllegalArgumentException("not found");
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
- IndexedItem result = strings.get((CstString) cst);
+ int sz = strings.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
- if (result == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return result;
+ if (out.annotates()) {
+ out.annotate(4, "string_ids_size: " + Hex.u4(sz));
+ out.annotate(4, "string_ids_off: " + Hex.u4(offset));
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
- int sz = strings.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
+ /**
+ * Interns an element into this instance.
+ *
+ * @param string {@code non-null;} the string to intern, as a regular Java
+ * {@code String}
+ * @return {@code non-null;} the interned string
+ */
+ public StringIdItem intern(String string) {
+ return intern(new StringIdItem(new CstString(string)));
+ }
- if (out.annotates()) {
- out.annotate(4, "string_ids_size: " + Hex.u4(sz));
- out.annotate(4, "string_ids_off: " + Hex.u4(offset));
- }
+ /**
+ * Interns an element into this instance.
+ *
+ * @param string {@code non-null;} the string to intern, as a constant
+ * @return {@code non-null;} the interned string
+ */
+ public StringIdItem intern(CstString string) {
+ return intern(new StringIdItem(string));
+ }
- out.writeInt(sz);
- out.writeInt(offset);
+ /**
+ * Interns an element into this instance.
+ *
+ * @param string {@code non-null;} the string to intern
+ * @return {@code non-null;} the interned string
+ */
+ public StringIdItem intern(StringIdItem string) {
+ if (string == null) {
+ throw new NullPointerException("string == null");
}
- /**
- * Interns an element into this instance.
- *
- * @param string {@code non-null;} the string to intern, as a regular Java
- * {@code String}
- * @return {@code non-null;} the interned string
- */
- public StringIdItem intern(String string) {
- return intern(new StringIdItem(new CstString(string)));
+ throwIfPrepared();
+
+ CstString value = string.getValue();
+ StringIdItem already = strings.get(value);
+
+ if (already != null) {
+ return already;
}
- /**
- * Interns an element into this instance.
- *
- * @param string {@code non-null;} the string to intern, as a constant
- * @return {@code non-null;} the interned string
- */
- public StringIdItem intern(CstString string) {
- return intern(new StringIdItem(string));
+ strings.put(value, string);
+ return string;
+ }
+
+ /**
+ * Interns the components of a name-and-type into this instance.
+ *
+ * @param nat {@code non-null;} the name-and-type
+ */
+ public void intern(CstNat nat) {
+ intern(nat.getName());
+ intern(nat.getDescriptor());
+ }
+
+ /**
+ * Gets the index of the given string, which must have been added
+ * to this instance.
+ *
+ * @param string {@code non-null;} the string to look up
+ * @return {@code >= 0;} the string's index
+ */
+ public int indexOf(CstString string) {
+ if (string == null) {
+ throw new NullPointerException("string == null");
}
- /**
- * Interns an element into this instance.
- *
- * @param string {@code non-null;} the string to intern
- * @return {@code non-null;} the interned string
- */
- public StringIdItem intern(StringIdItem string) {
- if (string == null) {
- throw new NullPointerException("string == null");
- }
+ throwIfNotPrepared();
- throwIfPrepared();
+ StringIdItem s = strings.get(string);
- CstString value = string.getValue();
- StringIdItem already = strings.get(value);
-
- if (already != null) {
- return already;
- }
-
- strings.put(value, string);
- return string;
+ if (s == null) {
+ throw new IllegalArgumentException("not found");
}
- /**
- * Interns the components of a name-and-type into this instance.
- *
- * @param nat {@code non-null;} the name-and-type
- */
- public void intern(CstNat nat) {
- intern(nat.getName());
- intern(nat.getDescriptor());
+ return s.getIndex();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ int idx = 0;
+
+ for (StringIdItem s : strings.values()) {
+ s.setIndex(idx);
+ idx++;
}
-
- /**
- * Gets the index of the given string, which must have been added
- * to this instance.
- *
- * @param string {@code non-null;} the string to look up
- * @return {@code >= 0;} the string's index
- */
- public int indexOf(CstString string) {
- if (string == null) {
- throw new NullPointerException("string == null");
- }
-
- throwIfNotPrepared();
-
- StringIdItem s = strings.get(string);
-
- if (s == null) {
- throw new IllegalArgumentException("not found");
- }
-
- return s.getIndex();
- }
-
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- int idx = 0;
-
- for (StringIdItem s : strings.values()) {
- s.setIndex(idx);
- idx++;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/TypeIdItem.java b/dx/src/com/android/jack/dx/dex/file/TypeIdItem.java
index cdbfb44..417afb5 100644
--- a/dx/src/com/android/jack/dx/dex/file/TypeIdItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/TypeIdItem.java
@@ -26,45 +26,45 @@
* Representation of a type reference inside a Dalvik file.
*/
public final class TypeIdItem extends IdItem {
- /**
- * Constructs an instance.
- *
- * @param type {@code non-null;} the constant for the type
- */
- public TypeIdItem(CstType type) {
- super(type);
+ /**
+ * Constructs an instance.
+ *
+ * @param type {@code non-null;} the constant for the type
+ */
+ public TypeIdItem(CstType type) {
+ super(type);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_TYPE_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSize() {
+ return SizeOf.TYPE_ID_ITEM;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ file.getStringIds().intern(getDefiningClass().getDescriptor());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeTo(DexFile file, AnnotatedOutput out) {
+ CstType type = getDefiningClass();
+ CstString descriptor = type.getDescriptor();
+ int idx = file.getStringIds().indexOf(descriptor);
+
+ if (out.annotates()) {
+ out.annotate(0, indexString() + ' ' + descriptor.toHuman());
+ out.annotate(4, " descriptor_idx: " + Hex.u4(idx));
}
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_TYPE_ID_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public int writeSize() {
- return SizeOf.TYPE_ID_ITEM;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- file.getStringIds().intern(getDefiningClass().getDescriptor());
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeTo(DexFile file, AnnotatedOutput out) {
- CstType type = getDefiningClass();
- CstString descriptor = type.getDescriptor();
- int idx = file.getStringIds().indexOf(descriptor);
-
- if (out.annotates()) {
- out.annotate(0, indexString() + ' ' + descriptor.toHuman());
- out.annotate(4, " descriptor_idx: " + Hex.u4(idx));
- }
-
- out.writeInt(idx);
- }
+ out.writeInt(idx);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/jack/dx/dex/file/TypeIdsSection.java
index fede94e..34599c0 100644
--- a/dx/src/com/android/jack/dx/dex/file/TypeIdsSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/TypeIdsSection.java
@@ -29,164 +29,164 @@
* Type identifiers list section of a {@code .dex} file.
*/
public final class TypeIdsSection extends UniformItemSection {
- /**
- * {@code non-null;} map from types to {@link TypeIdItem} instances
- */
- private final TreeMap<Type, TypeIdItem> typeIds;
+ /**
+ * {@code non-null;} map from types to {@link TypeIdItem} instances
+ */
+ private final TreeMap<Type, TypeIdItem> typeIds;
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param file {@code non-null;} file that this instance is part of
- */
- public TypeIdsSection(DexFile file) {
- super("type_ids", file, 4);
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param file {@code non-null;} file that this instance is part of
+ */
+ public TypeIdsSection(DexFile file) {
+ super("type_ids", file, 4);
- typeIds = new TreeMap<Type, TypeIdItem>();
+ typeIds = new TreeMap<Type, TypeIdItem>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Collection<? extends Item> items() {
+ return typeIds.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IndexedItem get(Constant cst) {
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
}
- /** {@inheritDoc} */
- @Override
- public Collection<? extends Item> items() {
- return typeIds.values();
+ throwIfNotPrepared();
+
+ Type type = ((CstType) cst).getClassType();
+ IndexedItem result = typeIds.get(type);
+
+ if (result == null) {
+ throw new IllegalArgumentException("not found: " + cst);
}
- /** {@inheritDoc} */
- @Override
- public IndexedItem get(Constant cst) {
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
+ /**
+ * Writes the portion of the file header that refers to this instance.
+ *
+ * @param out {@code non-null;} where to write
+ */
+ public void writeHeaderPart(AnnotatedOutput out) {
+ throwIfNotPrepared();
- Type type = ((CstType) cst).getClassType();
- IndexedItem result = typeIds.get(type);
+ int sz = typeIds.size();
+ int offset = (sz == 0) ? 0 : getFileOffset();
- if (result == null) {
- throw new IllegalArgumentException("not found: " + cst);
- }
-
- return result;
+ if (sz > 65536) {
+ throw new UnsupportedOperationException("too many type ids");
}
- /**
- * Writes the portion of the file header that refers to this instance.
- *
- * @param out {@code non-null;} where to write
- */
- public void writeHeaderPart(AnnotatedOutput out) {
- throwIfNotPrepared();
-
- int sz = typeIds.size();
- int offset = (sz == 0) ? 0 : getFileOffset();
-
- if (sz > 65536) {
- throw new UnsupportedOperationException("too many type ids");
- }
-
- if (out.annotates()) {
- out.annotate(4, "type_ids_size: " + Hex.u4(sz));
- out.annotate(4, "type_ids_off: " + Hex.u4(offset));
- }
-
- out.writeInt(sz);
- out.writeInt(offset);
+ if (out.annotates()) {
+ out.annotate(4, "type_ids_size: " + Hex.u4(sz));
+ out.annotate(4, "type_ids_off: " + Hex.u4(offset));
}
- /**
- * Interns an element into this instance.
- *
- * @param type {@code non-null;} the type to intern
- * @return {@code non-null;} the interned reference
- */
- public TypeIdItem intern(Type type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
+ out.writeInt(sz);
+ out.writeInt(offset);
+ }
- throwIfPrepared();
-
- TypeIdItem result = typeIds.get(type);
-
- if (result == null) {
- result = new TypeIdItem(new CstType(type));
- typeIds.put(type, result);
- }
-
- return result;
+ /**
+ * Interns an element into this instance.
+ *
+ * @param type {@code non-null;} the type to intern
+ * @return {@code non-null;} the interned reference
+ */
+ public TypeIdItem intern(Type type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /**
- * Interns an element into this instance.
- *
- * @param type {@code non-null;} the type to intern
- * @return {@code non-null;} the interned reference
- */
- public TypeIdItem intern(CstType type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
+ throwIfPrepared();
- throwIfPrepared();
+ TypeIdItem result = typeIds.get(type);
- Type typePerSe = type.getClassType();
- TypeIdItem result = typeIds.get(typePerSe);
-
- if (result == null) {
- result = new TypeIdItem(type);
- typeIds.put(typePerSe, result);
- }
-
- return result;
+ if (result == null) {
+ result = new TypeIdItem(new CstType(type));
+ typeIds.put(type, result);
}
- /**
- * Gets the index of the given type, which must have
- * been added to this instance.
- *
- * @param type {@code non-null;} the type to look up
- * @return {@code >= 0;} the reference's index
- */
- public int indexOf(Type type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
+ return result;
+ }
- throwIfNotPrepared();
-
- TypeIdItem item = typeIds.get(type);
-
- if (item == null) {
- throw new IllegalArgumentException("not found: " + type);
- }
-
- return item.getIndex();
+ /**
+ * Interns an element into this instance.
+ *
+ * @param type {@code non-null;} the type to intern
+ * @return {@code non-null;} the interned reference
+ */
+ public TypeIdItem intern(CstType type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /**
- * Gets the index of the given type, which must have
- * been added to this instance.
- *
- * @param type {@code non-null;} the type to look up
- * @return {@code >= 0;} the reference's index
- */
- public int indexOf(CstType type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
+ throwIfPrepared();
- return indexOf(type.getClassType());
+ Type typePerSe = type.getClassType();
+ TypeIdItem result = typeIds.get(typePerSe);
+
+ if (result == null) {
+ result = new TypeIdItem(type);
+ typeIds.put(typePerSe, result);
}
- /** {@inheritDoc} */
- @Override
- protected void orderItems() {
- int idx = 0;
+ return result;
+ }
- for (Object i : items()) {
- ((TypeIdItem) i).setIndex(idx);
- idx++;
- }
+ /**
+ * Gets the index of the given type, which must have
+ * been added to this instance.
+ *
+ * @param type {@code non-null;} the type to look up
+ * @return {@code >= 0;} the reference's index
+ */
+ public int indexOf(Type type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
+
+ throwIfNotPrepared();
+
+ TypeIdItem item = typeIds.get(type);
+
+ if (item == null) {
+ throw new IllegalArgumentException("not found: " + type);
+ }
+
+ return item.getIndex();
+ }
+
+ /**
+ * Gets the index of the given type, which must have
+ * been added to this instance.
+ *
+ * @param type {@code non-null;} the type to look up
+ * @return {@code >= 0;} the reference's index
+ */
+ public int indexOf(CstType type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
+ }
+
+ return indexOf(type.getClassType());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void orderItems() {
+ int idx = 0;
+
+ for (Object i : items()) {
+ ((TypeIdItem) i).setIndex(idx);
+ idx++;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/TypeListItem.java b/dx/src/com/android/jack/dx/dex/file/TypeListItem.java
index 42c1c5a..263d2b4 100644
--- a/dx/src/com/android/jack/dx/dex/file/TypeListItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/TypeListItem.java
@@ -16,7 +16,6 @@
package com.android.jack.dx.dex.file;
-import com.android.jack.dx.rop.cst.CstType;
import com.android.jack.dx.rop.type.StdTypeList;
import com.android.jack.dx.rop.type.Type;
import com.android.jack.dx.rop.type.TypeList;
@@ -27,96 +26,96 @@
* Representation of a list of class references.
*/
public final class TypeListItem extends OffsettedItem {
- /** alignment requirement */
- private static final int ALIGNMENT = 4;
+ /** alignment requirement */
+ private static final int ALIGNMENT = 4;
- /** element size in bytes */
- private static final int ELEMENT_SIZE = 2;
+ /** element size in bytes */
+ private static final int ELEMENT_SIZE = 2;
- /** header size in bytes */
- private static final int HEADER_SIZE = 4;
+ /** header size in bytes */
+ private static final int HEADER_SIZE = 4;
- /** {@code non-null;} the actual list */
- private final TypeList list;
+ /** {@code non-null;} the actual list */
+ private final TypeList list;
- /**
- * Constructs an instance.
- *
- * @param list {@code non-null;} the actual list
- */
- public TypeListItem(TypeList list) {
- super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE);
+ /**
+ * Constructs an instance.
+ *
+ * @param list {@code non-null;} the actual list
+ */
+ public TypeListItem(TypeList list) {
+ super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE);
- this.list = list;
+ this.list = list;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return StdTypeList.hashContents(list);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return ItemType.TYPE_TYPE_LIST;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ int sz = list.size();
+
+ for (int i = 0; i < sz; i++) {
+ typeIds.intern(list.getType(i));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ throw new RuntimeException("unsupported");
+ }
+
+ /**
+ * Gets the underlying list.
+ *
+ * @return {@code non-null;} the list
+ */
+ public TypeList getList() {
+ return list;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ int sz = list.size();
+
+ if (out.annotates()) {
+ out.annotate(0, offsetString() + " type_list");
+ out.annotate(HEADER_SIZE, " size: " + Hex.u4(sz));
+ for (int i = 0; i < sz; i++) {
+ Type one = list.getType(i);
+ int idx = typeIds.indexOf(one);
+ out.annotate(ELEMENT_SIZE, " " + Hex.u2(idx) + " // " + one.toHuman());
+ }
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return StdTypeList.hashContents(list);
+ out.writeInt(sz);
+
+ for (int i = 0; i < sz; i++) {
+ out.writeShort(typeIds.indexOf(list.getType(i)));
}
+ }
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return ItemType.TYPE_TYPE_LIST;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(OffsettedItem other) {
+ TypeList thisList = this.list;
+ TypeList otherList = ((TypeListItem) other).list;
- /** {@inheritDoc} */
- public void addContents(DexFile file) {
- TypeIdsSection typeIds = file.getTypeIds();
- int sz = list.size();
-
- for (int i = 0; i < sz; i++) {
- typeIds.intern(list.getType(i));
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public String toHuman() {
- throw new RuntimeException("unsupported");
- }
-
- /**
- * Gets the underlying list.
- *
- * @return {@code non-null;} the list
- */
- public TypeList getList() {
- return list;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- TypeIdsSection typeIds = file.getTypeIds();
- int sz = list.size();
-
- if (out.annotates()) {
- out.annotate(0, offsetString() + " type_list");
- out.annotate(HEADER_SIZE, " size: " + Hex.u4(sz));
- for (int i = 0; i < sz; i++) {
- Type one = list.getType(i);
- int idx = typeIds.indexOf(one);
- out.annotate(ELEMENT_SIZE,
- " " + Hex.u2(idx) + " // " + one.toHuman());
- }
- }
-
- out.writeInt(sz);
-
- for (int i = 0; i < sz; i++) {
- out.writeShort(typeIds.indexOf(list.getType(i)));
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(OffsettedItem other) {
- TypeList thisList = this.list;
- TypeList otherList = ((TypeListItem) other).list;
-
- return StdTypeList.compareContents(thisList, otherList);
- }
+ return StdTypeList.compareContents(thisList, otherList);
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/UniformItemSection.java b/dx/src/com/android/jack/dx/dex/file/UniformItemSection.java
index 0e4502d..82fea3b 100644
--- a/dx/src/com/android/jack/dx/dex/file/UniformItemSection.java
+++ b/dx/src/com/android/jack/dx/dex/file/UniformItemSection.java
@@ -27,86 +27,86 @@
* the output.
*/
public abstract class UniformItemSection extends Section {
- /**
- * Constructs an instance. The file offset is initially unknown.
- *
- * @param name {@code null-ok;} the name of this instance, for annotation
- * purposes
- * @param file {@code non-null;} file that this instance is part of
- * @param alignment {@code > 0;} alignment requirement for the final output;
- * must be a power of 2
+ /**
+ * Constructs an instance. The file offset is initially unknown.
+ *
+ * @param name {@code null-ok;} the name of this instance, for annotation
+ * purposes
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
+ * must be a power of 2
+ */
+ public UniformItemSection(String name, DexFile file, int alignment) {
+ super(name, file, alignment);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int writeSize() {
+ Collection<? extends Item> items = items();
+ int sz = items.size();
+
+ if (sz == 0) {
+ return 0;
+ }
+
+ // Since each item has to be the same size, we can pick any.
+ return sz * items.iterator().next().writeSize();
+ }
+
+ /**
+ * Gets the item corresponding to the given {@link Constant}. This
+ * will throw an exception if the constant is not found, including
+ * if this instance isn't the sort that maps constants to {@link
+ * IndexedItem} instances.
+ *
+ * @param cst {@code non-null;} constant to look for
+ * @return {@code non-null;} the corresponding item found in this instance
+ */
+ public abstract IndexedItem get(Constant cst);
+
+ /** {@inheritDoc} */
+ @Override
+ protected final void prepare0() {
+ DexFile file = getFile();
+
+ orderItems();
+
+ for (Item one : items()) {
+ one.addContents(file);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected final void writeTo0(AnnotatedOutput out) {
+ DexFile file = getFile();
+ int alignment = getAlignment();
+
+ for (Item one : items()) {
+ one.writeTo(file, out);
+ out.alignTo(alignment);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int getAbsoluteItemOffset(Item item) {
+ /*
+ * Since all items must be the same size, we can use the size
+ * of the one we're given to calculate its offset.
*/
- public UniformItemSection(String name, DexFile file, int alignment) {
- super(name, file, alignment);
- }
+ IndexedItem ii = (IndexedItem) item;
+ int relativeOffset = ii.getIndex() * ii.writeSize();
- /** {@inheritDoc} */
- @Override
- public final int writeSize() {
- Collection<? extends Item> items = items();
- int sz = items.size();
+ return getAbsoluteOffset(relativeOffset);
+ }
- if (sz == 0) {
- return 0;
- }
-
- // Since each item has to be the same size, we can pick any.
- return sz * items.iterator().next().writeSize();
- }
-
- /**
- * Gets the item corresponding to the given {@link Constant}. This
- * will throw an exception if the constant is not found, including
- * if this instance isn't the sort that maps constants to {@link
- * IndexedItem} instances.
- *
- * @param cst {@code non-null;} constant to look for
- * @return {@code non-null;} the corresponding item found in this instance
- */
- public abstract IndexedItem get(Constant cst);
-
- /** {@inheritDoc} */
- @Override
- protected final void prepare0() {
- DexFile file = getFile();
-
- orderItems();
-
- for (Item one : items()) {
- one.addContents(file);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected final void writeTo0(AnnotatedOutput out) {
- DexFile file = getFile();
- int alignment = getAlignment();
-
- for (Item one : items()) {
- one.writeTo(file, out);
- out.alignTo(alignment);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public final int getAbsoluteItemOffset(Item item) {
- /*
- * Since all items must be the same size, we can use the size
- * of the one we're given to calculate its offset.
- */
- IndexedItem ii = (IndexedItem) item;
- int relativeOffset = ii.getIndex() * ii.writeSize();
-
- return getAbsoluteOffset(relativeOffset);
- }
-
- /**
- * Alters or picks the order for items in this instance if desired,
- * so that subsequent calls to {@link #items} will yield a
- * so-ordered collection. If the items in this instance are indexed,
- * then this method should also assign indices.
- */
- protected abstract void orderItems();
+ /**
+ * Alters or picks the order for items in this instance if desired,
+ * so that subsequent calls to {@link #items} will yield a
+ * so-ordered collection. If the items in this instance are indexed,
+ * then this method should also assign indices.
+ */
+ protected abstract void orderItems();
}
diff --git a/dx/src/com/android/jack/dx/dex/file/UniformListItem.java b/dx/src/com/android/jack/dx/dex/file/UniformListItem.java
index 1046c19..9eb36ae 100644
--- a/dx/src/com/android/jack/dx/dex/file/UniformListItem.java
+++ b/dx/src/com/android/jack/dx/dex/file/UniformListItem.java
@@ -19,7 +19,6 @@
import com.android.jack.dx.util.AnnotatedOutput;
import com.android.jack.dx.util.Hex;
-import java.util.HashMap;
import java.util.List;
/**
@@ -34,183 +33,180 @@
*
* @param <T> type of element contained in an instance
*/
-public final class UniformListItem<T extends OffsettedItem>
- extends OffsettedItem {
- /** the size of the list header */
- private static final int HEADER_SIZE = 4;
+public final class UniformListItem<T extends OffsettedItem> extends OffsettedItem {
+ /** the size of the list header */
+ private static final int HEADER_SIZE = 4;
- /** {@code non-null;} the item type */
- private final ItemType itemType;
+ /** {@code non-null;} the item type */
+ private final ItemType itemType;
- /** {@code non-null;} the contents */
- private final List<T> items;
+ /** {@code non-null;} the contents */
+ private final List<T> items;
- /**
- * Constructs an instance. It is illegal to modify the given list once
- * it is used to construct an instance of this class.
- *
- * @param itemType {@code non-null;} the type of the item
- * @param items {@code non-null and non-empty;} list of items to represent
+ /**
+ * Constructs an instance. It is illegal to modify the given list once
+ * it is used to construct an instance of this class.
+ *
+ * @param itemType {@code non-null;} the type of the item
+ * @param items {@code non-null and non-empty;} list of items to represent
+ */
+ public UniformListItem(ItemType itemType, List<T> items) {
+ super(getAlignment(items), writeSize(items));
+
+ if (itemType == null) {
+ throw new NullPointerException("itemType == null");
+ }
+
+ this.items = items;
+ this.itemType = itemType;
+ }
+
+ /**
+ * Helper for {@link #UniformListItem}, which returns the alignment
+ * requirement implied by the given list. See the header comment for
+ * more details.
+ *
+ * @param items {@code non-null;} list of items being represented
+ * @return {@code >= 4;} the alignment requirement
+ */
+ private static int getAlignment(List<? extends OffsettedItem> items) {
+ try {
+ // Since they all must have the same alignment, any one will do.
+ return Math.max(HEADER_SIZE, items.get(0).getAlignment());
+ } catch (IndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("items.size() == 0");
+ } catch (NullPointerException ex) {
+ // Translate the exception.
+ throw new NullPointerException("items == null");
+ }
+ }
+
+ /**
+ * Calculates the write size for the given list.
+ *
+ * @param items {@code non-null;} the list in question
+ * @return {@code >= 0;} the write size
+ */
+ private static int writeSize(List<? extends OffsettedItem> items) {
+ /*
+ * This class assumes all included items are the same size,
+ * an assumption which is verified in place0().
*/
- public UniformListItem(ItemType itemType, List<T> items) {
- super(getAlignment(items), writeSize(items));
+ OffsettedItem first = items.get(0);
+ return (items.size() * first.writeSize()) + getAlignment(items);
+ }
- if (itemType == null) {
- throw new NullPointerException("itemType == null");
- }
+ /** {@inheritDoc} */
+ @Override
+ public ItemType itemType() {
+ return itemType;
+ }
- this.items = items;
- this.itemType = itemType;
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append(getClass().getName());
+ sb.append(items);
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addContents(DexFile file) {
+ for (OffsettedItem i : items) {
+ i.addContents(file);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final String toHuman() {
+ StringBuffer sb = new StringBuffer(100);
+ boolean first = true;
+
+ sb.append("{");
+
+ for (OffsettedItem i : items) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(i.toHuman());
}
- /**
- * Helper for {@link #UniformListItem}, which returns the alignment
- * requirement implied by the given list. See the header comment for
- * more details.
- *
- * @param items {@code non-null;} list of items being represented
- * @return {@code >= 4;} the alignment requirement
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Gets the underlying list of items.
+ *
+ * @return {@code non-null;} the list
+ */
+ public final List<T> getItems() {
+ return items;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void place0(Section addedTo, int offset) {
+ offset += headerSize();
+
+ boolean first = true;
+ int theSize = -1;
+ int theAlignment = -1;
+
+ for (OffsettedItem i : items) {
+ int size = i.writeSize();
+ if (first) {
+ theSize = size;
+ theAlignment = i.getAlignment();
+ first = false;
+ } else {
+ if (size != theSize) {
+ throw new UnsupportedOperationException("item size mismatch");
+ }
+ if (i.getAlignment() != theAlignment) {
+ throw new UnsupportedOperationException("item alignment mismatch");
+ }
+ }
+
+ offset = i.place(addedTo, offset) + size;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeTo0(DexFile file, AnnotatedOutput out) {
+ int size = items.size();
+
+ if (out.annotates()) {
+ out.annotate(0, offsetString() + " " + typeName());
+ out.annotate(4, " size: " + Hex.u4(size));
+ }
+
+ out.writeInt(size);
+
+ for (OffsettedItem i : items) {
+ i.writeTo(file, out);
+ }
+ }
+
+ /**
+ * Get the size of the header of this list.
+ *
+ * @return {@code >= 0;} the header size
+ */
+ private int headerSize() {
+ /*
+ * Because of how this instance was set up, this is the same
+ * as the alignment.
*/
- private static int getAlignment(List<? extends OffsettedItem> items) {
- try {
- // Since they all must have the same alignment, any one will do.
- return Math.max(HEADER_SIZE, items.get(0).getAlignment());
- } catch (IndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("items.size() == 0");
- } catch (NullPointerException ex) {
- // Translate the exception.
- throw new NullPointerException("items == null");
- }
- }
-
- /**
- * Calculates the write size for the given list.
- *
- * @param items {@code non-null;} the list in question
- * @return {@code >= 0;} the write size
- */
- private static int writeSize(List<? extends OffsettedItem> items) {
- /*
- * This class assumes all included items are the same size,
- * an assumption which is verified in place0().
- */
- OffsettedItem first = items.get(0);
- return (items.size() * first.writeSize()) + getAlignment(items);
- }
-
- /** {@inheritDoc} */
- @Override
- public ItemType itemType() {
- return itemType;
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(100);
-
- sb.append(getClass().getName());
- sb.append(items);
-
- return sb.toString();
- }
-
- /** {@inheritDoc} */
- @Override
- public void addContents(DexFile file) {
- for (OffsettedItem i : items) {
- i.addContents(file);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public final String toHuman() {
- StringBuffer sb = new StringBuffer(100);
- boolean first = true;
-
- sb.append("{");
-
- for (OffsettedItem i : items) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(i.toHuman());
- }
-
- sb.append("}");
- return sb.toString();
- }
-
- /**
- * Gets the underlying list of items.
- *
- * @return {@code non-null;} the list
- */
- public final List<T> getItems() {
- return items;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void place0(Section addedTo, int offset) {
- offset += headerSize();
-
- boolean first = true;
- int theSize = -1;
- int theAlignment = -1;
-
- for (OffsettedItem i : items) {
- int size = i.writeSize();
- if (first) {
- theSize = size;
- theAlignment = i.getAlignment();
- first = false;
- } else {
- if (size != theSize) {
- throw new UnsupportedOperationException(
- "item size mismatch");
- }
- if (i.getAlignment() != theAlignment) {
- throw new UnsupportedOperationException(
- "item alignment mismatch");
- }
- }
-
- offset = i.place(addedTo, offset) + size;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- protected void writeTo0(DexFile file, AnnotatedOutput out) {
- int size = items.size();
-
- if (out.annotates()) {
- out.annotate(0, offsetString() + " " + typeName());
- out.annotate(4, " size: " + Hex.u4(size));
- }
-
- out.writeInt(size);
-
- for (OffsettedItem i : items) {
- i.writeTo(file, out);
- }
- }
-
- /**
- * Get the size of the header of this list.
- *
- * @return {@code >= 0;} the header size
- */
- private int headerSize() {
- /*
- * Because of how this instance was set up, this is the same
- * as the alignment.
- */
- return getAlignment();
- }
+ return getAlignment();
+ }
}
diff --git a/dx/src/com/android/jack/dx/dex/file/ValueEncoder.java b/dx/src/com/android/jack/dx/dex/file/ValueEncoder.java
index c8a8019..d671ac9 100644
--- a/dx/src/com/android/jack/dx/dex/file/ValueEncoder.java
+++ b/dx/src/com/android/jack/dx/dex/file/ValueEncoder.java
@@ -46,483 +46,477 @@
* thereof.
*/
public final class ValueEncoder {
- /** annotation value type constant: {@code byte} */
- private static final int VALUE_BYTE = 0x00;
+ /** annotation value type constant: {@code byte} */
+ private static final int VALUE_BYTE = 0x00;
- /** annotation value type constant: {@code short} */
- private static final int VALUE_SHORT = 0x02;
+ /** annotation value type constant: {@code short} */
+ private static final int VALUE_SHORT = 0x02;
- /** annotation value type constant: {@code char} */
- private static final int VALUE_CHAR = 0x03;
+ /** annotation value type constant: {@code char} */
+ private static final int VALUE_CHAR = 0x03;
- /** annotation value type constant: {@code int} */
- private static final int VALUE_INT = 0x04;
+ /** annotation value type constant: {@code int} */
+ private static final int VALUE_INT = 0x04;
- /** annotation value type constant: {@code long} */
- private static final int VALUE_LONG = 0x06;
+ /** annotation value type constant: {@code long} */
+ private static final int VALUE_LONG = 0x06;
- /** annotation value type constant: {@code float} */
- private static final int VALUE_FLOAT = 0x10;
+ /** annotation value type constant: {@code float} */
+ private static final int VALUE_FLOAT = 0x10;
- /** annotation value type constant: {@code double} */
- private static final int VALUE_DOUBLE = 0x11;
+ /** annotation value type constant: {@code double} */
+ private static final int VALUE_DOUBLE = 0x11;
- /** annotation value type constant: {@code string} */
- private static final int VALUE_STRING = 0x17;
+ /** annotation value type constant: {@code string} */
+ private static final int VALUE_STRING = 0x17;
- /** annotation value type constant: {@code type} */
- private static final int VALUE_TYPE = 0x18;
+ /** annotation value type constant: {@code type} */
+ private static final int VALUE_TYPE = 0x18;
- /** annotation value type constant: {@code field} */
- private static final int VALUE_FIELD = 0x19;
+ /** annotation value type constant: {@code field} */
+ private static final int VALUE_FIELD = 0x19;
- /** annotation value type constant: {@code method} */
- private static final int VALUE_METHOD = 0x1a;
+ /** annotation value type constant: {@code method} */
+ private static final int VALUE_METHOD = 0x1a;
- /** annotation value type constant: {@code enum} */
- private static final int VALUE_ENUM = 0x1b;
+ /** annotation value type constant: {@code enum} */
+ private static final int VALUE_ENUM = 0x1b;
- /** annotation value type constant: {@code array} */
- private static final int VALUE_ARRAY = 0x1c;
+ /** annotation value type constant: {@code array} */
+ private static final int VALUE_ARRAY = 0x1c;
- /** annotation value type constant: {@code annotation} */
- private static final int VALUE_ANNOTATION = 0x1d;
+ /** annotation value type constant: {@code annotation} */
+ private static final int VALUE_ANNOTATION = 0x1d;
- /** annotation value type constant: {@code null} */
- private static final int VALUE_NULL = 0x1e;
+ /** annotation value type constant: {@code null} */
+ private static final int VALUE_NULL = 0x1e;
- /** annotation value type constant: {@code boolean} */
- private static final int VALUE_BOOLEAN = 0x1f;
+ /** annotation value type constant: {@code boolean} */
+ private static final int VALUE_BOOLEAN = 0x1f;
- /** {@code non-null;} file being written */
- private final DexFile file;
+ /** {@code non-null;} file being written */
+ private final DexFile file;
- /** {@code non-null;} output stream to write to */
- private final AnnotatedOutput out;
+ /** {@code non-null;} output stream to write to */
+ private final AnnotatedOutput out;
- /**
- * Construct an instance.
- *
- * @param file {@code non-null;} file being written
- * @param out {@code non-null;} output stream to write to
- */
- public ValueEncoder(DexFile file, AnnotatedOutput out) {
- if (file == null) {
- throw new NullPointerException("file == null");
- }
-
- if (out == null) {
- throw new NullPointerException("out == null");
- }
-
- this.file = file;
- this.out = out;
+ /**
+ * Construct an instance.
+ *
+ * @param file {@code non-null;} file being written
+ * @param out {@code non-null;} output stream to write to
+ */
+ public ValueEncoder(DexFile file, AnnotatedOutput out) {
+ if (file == null) {
+ throw new NullPointerException("file == null");
}
- /**
- * Writes out the encoded form of the given constant.
- *
- * @param cst {@code non-null;} the constant to write
- */
- public void writeConstant(Constant cst) {
- int type = constantToValueType(cst);
- int arg;
-
- switch (type) {
- case VALUE_BYTE:
- case VALUE_SHORT:
- case VALUE_INT:
- case VALUE_LONG: {
- long value = ((CstLiteralBits) cst).getLongBits();
- writeSignedIntegralValue(type, value);
- break;
- }
- case VALUE_CHAR: {
- long value = ((CstLiteralBits) cst).getLongBits();
- writeUnsignedIntegralValue(type, value);
- break;
- }
- case VALUE_FLOAT: {
- // Shift value left 32 so that right-zero-extension works.
- long value = ((CstFloat) cst).getLongBits() << 32;
- writeRightZeroExtendedValue(type, value);
- break;
- }
- case VALUE_DOUBLE: {
- long value = ((CstDouble) cst).getLongBits();
- writeRightZeroExtendedValue(type, value);
- break;
- }
- case VALUE_STRING: {
- int index = file.getStringIds().indexOf((CstString) cst);
- writeUnsignedIntegralValue(type, (long) index);
- break;
- }
- case VALUE_TYPE: {
- int index = file.getTypeIds().indexOf((CstType) cst);
- writeUnsignedIntegralValue(type, (long) index);
- break;
- }
- case VALUE_FIELD: {
- int index = file.getFieldIds().indexOf((CstFieldRef) cst);
- writeUnsignedIntegralValue(type, (long) index);
- break;
- }
- case VALUE_METHOD: {
- int index = file.getMethodIds().indexOf((CstMethodRef) cst);
- writeUnsignedIntegralValue(type, (long) index);
- break;
- }
- case VALUE_ENUM: {
- CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
- int index = file.getFieldIds().indexOf(fieldRef);
- writeUnsignedIntegralValue(type, (long) index);
- break;
- }
- case VALUE_ARRAY: {
- out.writeByte(type);
- writeArray((CstArray) cst, false);
- break;
- }
- case VALUE_ANNOTATION: {
- out.writeByte(type);
- writeAnnotation(((CstAnnotation) cst).getAnnotation(),
- false);
- break;
- }
- case VALUE_NULL: {
- out.writeByte(type);
- break;
- }
- case VALUE_BOOLEAN: {
- int value = ((CstBoolean) cst).getIntBits();
- out.writeByte(type | (value << 5));
- break;
- }
- default: {
- throw new RuntimeException("Shouldn't happen");
- }
- }
+ if (out == null) {
+ throw new NullPointerException("out == null");
}
- /**
- * Gets the value type for the given constant.
- *
- * @param cst {@code non-null;} the constant
- * @return the value type; one of the {@code VALUE_*} constants
- * defined by this class
+ this.file = file;
+ this.out = out;
+ }
+
+ /**
+ * Writes out the encoded form of the given constant.
+ *
+ * @param cst {@code non-null;} the constant to write
+ */
+ public void writeConstant(Constant cst) {
+ int type = constantToValueType(cst);
+
+ switch (type) {
+ case VALUE_BYTE:
+ case VALUE_SHORT:
+ case VALUE_INT:
+ case VALUE_LONG: {
+ long value = ((CstLiteralBits) cst).getLongBits();
+ writeSignedIntegralValue(type, value);
+ break;
+ }
+ case VALUE_CHAR: {
+ long value = ((CstLiteralBits) cst).getLongBits();
+ writeUnsignedIntegralValue(type, value);
+ break;
+ }
+ case VALUE_FLOAT: {
+ // Shift value left 32 so that right-zero-extension works.
+ long value = ((CstFloat) cst).getLongBits() << 32;
+ writeRightZeroExtendedValue(type, value);
+ break;
+ }
+ case VALUE_DOUBLE: {
+ long value = ((CstDouble) cst).getLongBits();
+ writeRightZeroExtendedValue(type, value);
+ break;
+ }
+ case VALUE_STRING: {
+ int index = file.getStringIds().indexOf((CstString) cst);
+ writeUnsignedIntegralValue(type, index);
+ break;
+ }
+ case VALUE_TYPE: {
+ int index = file.getTypeIds().indexOf((CstType) cst);
+ writeUnsignedIntegralValue(type, index);
+ break;
+ }
+ case VALUE_FIELD: {
+ int index = file.getFieldIds().indexOf((CstFieldRef) cst);
+ writeUnsignedIntegralValue(type, index);
+ break;
+ }
+ case VALUE_METHOD: {
+ int index = file.getMethodIds().indexOf((CstMethodRef) cst);
+ writeUnsignedIntegralValue(type, index);
+ break;
+ }
+ case VALUE_ENUM: {
+ CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
+ int index = file.getFieldIds().indexOf(fieldRef);
+ writeUnsignedIntegralValue(type, index);
+ break;
+ }
+ case VALUE_ARRAY: {
+ out.writeByte(type);
+ writeArray((CstArray) cst, false);
+ break;
+ }
+ case VALUE_ANNOTATION: {
+ out.writeByte(type);
+ writeAnnotation(((CstAnnotation) cst).getAnnotation(), false);
+ break;
+ }
+ case VALUE_NULL: {
+ out.writeByte(type);
+ break;
+ }
+ case VALUE_BOOLEAN: {
+ int value = ((CstBoolean) cst).getIntBits();
+ out.writeByte(type | (value << 5));
+ break;
+ }
+ default: {
+ throw new RuntimeException("Shouldn't happen");
+ }
+ }
+ }
+
+ /**
+ * Gets the value type for the given constant.
+ *
+ * @param cst {@code non-null;} the constant
+ * @return the value type; one of the {@code VALUE_*} constants
+ * defined by this class
+ */
+ private static int constantToValueType(Constant cst) {
+ /*
+ * TODO(dx team): Constant should probable have an associated enum, so this
+ * can be a switch().
*/
- private static int constantToValueType(Constant cst) {
- /*
- * TODO: Constant should probable have an associated enum, so this
- * can be a switch().
- */
- if (cst instanceof CstByte) {
- return VALUE_BYTE;
- } else if (cst instanceof CstShort) {
- return VALUE_SHORT;
- } else if (cst instanceof CstChar) {
- return VALUE_CHAR;
- } else if (cst instanceof CstInteger) {
- return VALUE_INT;
- } else if (cst instanceof CstLong) {
- return VALUE_LONG;
- } else if (cst instanceof CstFloat) {
- return VALUE_FLOAT;
- } else if (cst instanceof CstDouble) {
- return VALUE_DOUBLE;
- } else if (cst instanceof CstString) {
- return VALUE_STRING;
- } else if (cst instanceof CstType) {
- return VALUE_TYPE;
- } else if (cst instanceof CstFieldRef) {
- return VALUE_FIELD;
- } else if (cst instanceof CstMethodRef) {
- return VALUE_METHOD;
- } else if (cst instanceof CstEnumRef) {
- return VALUE_ENUM;
- } else if (cst instanceof CstArray) {
- return VALUE_ARRAY;
- } else if (cst instanceof CstAnnotation) {
- return VALUE_ANNOTATION;
- } else if (cst instanceof CstKnownNull) {
- return VALUE_NULL;
- } else if (cst instanceof CstBoolean) {
- return VALUE_BOOLEAN;
- } else {
- throw new RuntimeException("Shouldn't happen");
- }
+ if (cst instanceof CstByte) {
+ return VALUE_BYTE;
+ } else if (cst instanceof CstShort) {
+ return VALUE_SHORT;
+ } else if (cst instanceof CstChar) {
+ return VALUE_CHAR;
+ } else if (cst instanceof CstInteger) {
+ return VALUE_INT;
+ } else if (cst instanceof CstLong) {
+ return VALUE_LONG;
+ } else if (cst instanceof CstFloat) {
+ return VALUE_FLOAT;
+ } else if (cst instanceof CstDouble) {
+ return VALUE_DOUBLE;
+ } else if (cst instanceof CstString) {
+ return VALUE_STRING;
+ } else if (cst instanceof CstType) {
+ return VALUE_TYPE;
+ } else if (cst instanceof CstFieldRef) {
+ return VALUE_FIELD;
+ } else if (cst instanceof CstMethodRef) {
+ return VALUE_METHOD;
+ } else if (cst instanceof CstEnumRef) {
+ return VALUE_ENUM;
+ } else if (cst instanceof CstArray) {
+ return VALUE_ARRAY;
+ } else if (cst instanceof CstAnnotation) {
+ return VALUE_ANNOTATION;
+ } else if (cst instanceof CstKnownNull) {
+ return VALUE_NULL;
+ } else if (cst instanceof CstBoolean) {
+ return VALUE_BOOLEAN;
+ } else {
+ throw new RuntimeException("Shouldn't happen");
+ }
+ }
+
+ /**
+ * Writes out the encoded form of the given array, that is, as
+ * an {@code encoded_array} and not including a
+ * {@code value_type} prefix. If the output stream keeps
+ * (debugging) annotations and {@code topLevel} is
+ * {@code true}, then this method will write (debugging)
+ * annotations.
+ *
+ * @param array {@code non-null;} array instance to write
+ * @param topLevel {@code true} iff the given annotation is the
+ * top-level annotation or {@code false} if it is a sub-annotation
+ * of some other annotation
+ */
+ public void writeArray(CstArray array, boolean topLevel) {
+ boolean annotates = topLevel && out.annotates();
+ CstArray.List list = array.getList();
+ int size = list.size();
+
+ if (annotates) {
+ out.annotate(" size: " + Hex.u4(size));
}
- /**
- * Writes out the encoded form of the given array, that is, as
- * an {@code encoded_array} and not including a
- * {@code value_type} prefix. If the output stream keeps
- * (debugging) annotations and {@code topLevel} is
- * {@code true}, then this method will write (debugging)
- * annotations.
- *
- * @param array {@code non-null;} array instance to write
- * @param topLevel {@code true} iff the given annotation is the
- * top-level annotation or {@code false} if it is a sub-annotation
- * of some other annotation
- */
- public void writeArray(CstArray array, boolean topLevel) {
- boolean annotates = topLevel && out.annotates();
- CstArray.List list = ((CstArray) array).getList();
- int size = list.size();
+ out.writeUleb128(size);
- if (annotates) {
- out.annotate(" size: " + Hex.u4(size));
- }
-
- out.writeUleb128(size);
-
- for (int i = 0; i < size; i++) {
- Constant cst = list.get(i);
- if (annotates) {
- out.annotate(" [" + Integer.toHexString(i) + "] " +
- constantToHuman(cst));
- }
- writeConstant(cst);
- }
-
- if (annotates) {
- out.endAnnotation();
- }
+ for (int i = 0; i < size; i++) {
+ Constant cst = list.get(i);
+ if (annotates) {
+ out.annotate(" [" + Integer.toHexString(i) + "] " + constantToHuman(cst));
+ }
+ writeConstant(cst);
}
- /**
- * Writes out the encoded form of the given annotation, that is,
- * as an {@code encoded_annotation} and not including a
- * {@code value_type} prefix. If the output stream keeps
- * (debugging) annotations and {@code topLevel} is
- * {@code true}, then this method will write (debugging)
- * annotations.
- *
- * @param annotation {@code non-null;} annotation instance to write
- * @param topLevel {@code true} iff the given annotation is the
- * top-level annotation or {@code false} if it is a sub-annotation
- * of some other annotation
- */
- public void writeAnnotation(Annotation annotation, boolean topLevel) {
- boolean annotates = topLevel && out.annotates();
- StringIdsSection stringIds = file.getStringIds();
- TypeIdsSection typeIds = file.getTypeIds();
+ if (annotates) {
+ out.endAnnotation();
+ }
+ }
- CstType type = annotation.getType();
- int typeIdx = typeIds.indexOf(type);
+ /**
+ * Writes out the encoded form of the given annotation, that is,
+ * as an {@code encoded_annotation} and not including a
+ * {@code value_type} prefix. If the output stream keeps
+ * (debugging) annotations and {@code topLevel} is
+ * {@code true}, then this method will write (debugging)
+ * annotations.
+ *
+ * @param annotation {@code non-null;} annotation instance to write
+ * @param topLevel {@code true} iff the given annotation is the
+ * top-level annotation or {@code false} if it is a sub-annotation
+ * of some other annotation
+ */
+ public void writeAnnotation(Annotation annotation, boolean topLevel) {
+ boolean annotates = topLevel && out.annotates();
+ StringIdsSection stringIds = file.getStringIds();
+ TypeIdsSection typeIds = file.getTypeIds();
- if (annotates) {
- out.annotate(" type_idx: " + Hex.u4(typeIdx) + " // " +
- type.toHuman());
- }
+ CstType type = annotation.getType();
+ int typeIdx = typeIds.indexOf(type);
- out.writeUleb128(typeIds.indexOf(annotation.getType()));
-
- Collection<NameValuePair> pairs = annotation.getNameValuePairs();
- int size = pairs.size();
-
- if (annotates) {
- out.annotate(" size: " + Hex.u4(size));
- }
-
- out.writeUleb128(size);
-
- int at = 0;
- for (NameValuePair pair : pairs) {
- CstString name = pair.getName();
- int nameIdx = stringIds.indexOf(name);
- Constant value = pair.getValue();
-
- if (annotates) {
- out.annotate(0, " elements[" + at + "]:");
- at++;
- out.annotate(" name_idx: " + Hex.u4(nameIdx) + " // " +
- name.toHuman());
- }
-
- out.writeUleb128(nameIdx);
-
- if (annotates) {
- out.annotate(" value: " + constantToHuman(value));
- }
-
- writeConstant(value);
- }
-
- if (annotates) {
- out.endAnnotation();
- }
+ if (annotates) {
+ out.annotate(" type_idx: " + Hex.u4(typeIdx) + " // " + type.toHuman());
}
- /**
- * Gets the colloquial type name and human form of the type of the
- * given constant, when used as an encoded value.
- *
- * @param cst {@code non-null;} the constant
- * @return {@code non-null;} its type name and human form
- */
- public static String constantToHuman(Constant cst) {
- int type = constantToValueType(cst);
+ out.writeUleb128(typeIds.indexOf(annotation.getType()));
- if (type == VALUE_NULL) {
- return "null";
- }
+ Collection<NameValuePair> pairs = annotation.getNameValuePairs();
+ int size = pairs.size();
- StringBuilder sb = new StringBuilder();
-
- sb.append(cst.typeName());
- sb.append(' ');
- sb.append(cst.toHuman());
-
- return sb.toString();
+ if (annotates) {
+ out.annotate(" size: " + Hex.u4(size));
}
- /**
- * Helper for {@link #writeConstant}, which writes out the value
- * for any signed integral type.
- *
- * @param type the type constant
- * @param value {@code long} bits of the value
- */
- private void writeSignedIntegralValue(int type, long value) {
- /*
- * Figure out how many bits are needed to represent the value,
- * including a sign bit: The bit count is subtracted from 65
- * and not 64 to account for the sign bit. The xor operation
- * has the effect of leaving non-negative values alone and
- * unary complementing negative values (so that a leading zero
- * count always returns a useful number for our present
- * purpose).
- */
- int requiredBits =
- 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
+ out.writeUleb128(size);
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
+ int at = 0;
+ for (NameValuePair pair : pairs) {
+ CstString name = pair.getName();
+ int nameIdx = stringIds.indexOf(name);
+ Constant value = pair.getValue();
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
+ if (annotates) {
+ out.annotate(0, " elements[" + at + "]:");
+ at++;
+ out.annotate(" name_idx: " + Hex.u4(nameIdx) + " // " + name.toHuman());
+ }
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
+ out.writeUleb128(nameIdx);
+
+ if (annotates) {
+ out.annotate(" value: " + constantToHuman(value));
+ }
+
+ writeConstant(value);
}
- /**
- * Helper for {@link #writeConstant}, which writes out the value
- * for any unsigned integral type.
- *
- * @param type the type constant
- * @param value {@code long} bits of the value
- */
- private void writeUnsignedIntegralValue(int type, long value) {
- // Figure out how many bits are needed to represent the value.
- int requiredBits = 64 - Long.numberOfLeadingZeros(value);
- if (requiredBits == 0) {
- requiredBits = 1;
- }
+ if (annotates) {
+ out.endAnnotation();
+ }
+ }
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
+ /**
+ * Gets the colloquial type name and human form of the type of the
+ * given constant, when used as an encoded value.
+ *
+ * @param cst {@code non-null;} the constant
+ * @return {@code non-null;} its type name and human form
+ */
+ public static String constantToHuman(Constant cst) {
+ int type = constantToValueType(cst);
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
-
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
+ if (type == VALUE_NULL) {
+ return "null";
}
- /**
- * Helper for {@link #writeConstant}, which writes out a
- * right-zero-extended value.
- *
- * @param type the type constant
- * @param value {@code long} bits of the value
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(cst.typeName());
+ sb.append(' ');
+ sb.append(cst.toHuman());
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper for {@link #writeConstant}, which writes out the value
+ * for any signed integral type.
+ *
+ * @param type the type constant
+ * @param value {@code long} bits of the value
+ */
+ private void writeSignedIntegralValue(int type, long value) {
+ /*
+ * Figure out how many bits are needed to represent the value,
+ * including a sign bit: The bit count is subtracted from 65
+ * and not 64 to account for the sign bit. The xor operation
+ * has the effect of leaving non-negative values alone and
+ * unary complementing negative values (so that a leading zero
+ * count always returns a useful number for our present
+ * purpose).
*/
- private void writeRightZeroExtendedValue(int type, long value) {
- // Figure out how many bits are needed to represent the value.
- int requiredBits = 64 - Long.numberOfTrailingZeros(value);
- if (requiredBits == 0) {
- requiredBits = 1;
- }
+ int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
+ // Round up the requiredBits to a number of bytes.
+ int requiredBytes = (requiredBits + 0x07) >> 3;
- // Scootch the first bits to be written down to the low-order bits.
- value >>= 64 - (requiredBytes * 8);
+ /*
+ * Write the header byte, which includes the type and
+ * requiredBytes - 1.
+ */
+ out.writeByte(type | ((requiredBytes - 1) << 5));
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
+ // Write the value, per se.
+ while (requiredBytes > 0) {
+ out.writeByte((byte) value);
+ value >>= 8;
+ requiredBytes--;
+ }
+ }
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
+ /**
+ * Helper for {@link #writeConstant}, which writes out the value
+ * for any unsigned integral type.
+ *
+ * @param type the type constant
+ * @param value {@code long} bits of the value
+ */
+ private void writeUnsignedIntegralValue(int type, long value) {
+ // Figure out how many bits are needed to represent the value.
+ int requiredBits = 64 - Long.numberOfLeadingZeros(value);
+ if (requiredBits == 0) {
+ requiredBits = 1;
}
+ // Round up the requiredBits to a number of bytes.
+ int requiredBytes = (requiredBits + 0x07) >> 3;
- /**
- * Helper for {@code addContents()} methods, which adds
- * contents for a particular {@link Annotation}, calling itself
- * recursively should it encounter a nested annotation.
- *
- * @param file {@code non-null;} the file to add to
- * @param annotation {@code non-null;} the annotation to add contents for
+ /*
+ * Write the header byte, which includes the type and
+ * requiredBytes - 1.
*/
- public static void addContents(DexFile file, Annotation annotation) {
- TypeIdsSection typeIds = file.getTypeIds();
- StringIdsSection stringIds = file.getStringIds();
+ out.writeByte(type | ((requiredBytes - 1) << 5));
- typeIds.intern(annotation.getType());
+ // Write the value, per se.
+ while (requiredBytes > 0) {
+ out.writeByte((byte) value);
+ value >>= 8;
+ requiredBytes--;
+ }
+ }
- for (NameValuePair pair : annotation.getNameValuePairs()) {
- stringIds.intern(pair.getName());
- addContents(file, pair.getValue());
- }
+ /**
+ * Helper for {@link #writeConstant}, which writes out a
+ * right-zero-extended value.
+ *
+ * @param type the type constant
+ * @param value {@code long} bits of the value
+ */
+ private void writeRightZeroExtendedValue(int type, long value) {
+ // Figure out how many bits are needed to represent the value.
+ int requiredBits = 64 - Long.numberOfTrailingZeros(value);
+ if (requiredBits == 0) {
+ requiredBits = 1;
}
- /**
- * Helper for {@code addContents()} methods, which adds
- * contents for a particular constant, calling itself recursively
- * should it encounter a {@link CstArray} and calling {@link
- * #addContents(DexFile,Annotation)} recursively should it
- * encounter a {@link CstAnnotation}.
- *
- * @param file {@code non-null;} the file to add to
- * @param cst {@code non-null;} the constant to add contents for
+ // Round up the requiredBits to a number of bytes.
+ int requiredBytes = (requiredBits + 0x07) >> 3;
+
+ // Scootch the first bits to be written down to the low-order bits.
+ value >>= 64 - (requiredBytes * 8);
+
+ /*
+ * Write the header byte, which includes the type and
+ * requiredBytes - 1.
*/
- public static void addContents(DexFile file, Constant cst) {
- if (cst instanceof CstAnnotation) {
- addContents(file, ((CstAnnotation) cst).getAnnotation());
- } else if (cst instanceof CstArray) {
- CstArray.List list = ((CstArray) cst).getList();
- int size = list.size();
- for (int i = 0; i < size; i++) {
- addContents(file, list.get(i));
- }
- } else {
- file.internIfAppropriate(cst);
- }
+ out.writeByte(type | ((requiredBytes - 1) << 5));
+
+ // Write the value, per se.
+ while (requiredBytes > 0) {
+ out.writeByte((byte) value);
+ value >>= 8;
+ requiredBytes--;
}
+ }
+
+
+ /**
+ * Helper for {@code addContents()} methods, which adds
+ * contents for a particular {@link Annotation}, calling itself
+ * recursively should it encounter a nested annotation.
+ *
+ * @param file {@code non-null;} the file to add to
+ * @param annotation {@code non-null;} the annotation to add contents for
+ */
+ public static void addContents(DexFile file, Annotation annotation) {
+ TypeIdsSection typeIds = file.getTypeIds();
+ StringIdsSection stringIds = file.getStringIds();
+
+ typeIds.intern(annotation.getType());
+
+ for (NameValuePair pair : annotation.getNameValuePairs()) {
+ stringIds.intern(pair.getName());
+ addContents(file, pair.getValue());
+ }
+ }
+
+ /**
+ * Helper for {@code addContents()} methods, which adds
+ * contents for a particular constant, calling itself recursively
+ * should it encounter a {@link CstArray} and calling {@link
+ * #addContents(DexFile,Annotation)} recursively should it
+ * encounter a {@link CstAnnotation}.
+ *
+ * @param file {@code non-null;} the file to add to
+ * @param cst {@code non-null;} the constant to add contents for
+ */
+ public static void addContents(DexFile file, Constant cst) {
+ if (cst instanceof CstAnnotation) {
+ addContents(file, ((CstAnnotation) cst).getAnnotation());
+ } else if (cst instanceof CstArray) {
+ CstArray.List list = ((CstArray) cst).getList();
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ addContents(file, list.get(i));
+ }
+ } else {
+ file.internIfAppropriate(cst);
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/Annotation.java b/dx/src/com/android/jack/dx/io/Annotation.java
index 47987b1..5dfef2c 100644
--- a/dx/src/com/android/jack/dx/io/Annotation.java
+++ b/dx/src/com/android/jack/dx/io/Annotation.java
@@ -22,83 +22,85 @@
* An annotation.
*/
public final class Annotation implements Comparable<Annotation> {
- private final DexBuffer buffer;
- private final byte visibility;
- private final int typeIndex;
- private final int[] names;
- private final EncodedValue[] values;
+ private final DexBuffer buffer;
+ private final byte visibility;
+ private final int typeIndex;
+ private final int[] names;
+ private final EncodedValue[] values;
- public Annotation(DexBuffer buffer, byte visibility, int typeIndex, int[] names,
- EncodedValue[] values) {
- this.buffer = buffer;
- this.visibility = visibility;
- this.typeIndex = typeIndex;
- this.names = names;
- this.values = values;
+ public Annotation(DexBuffer buffer, byte visibility, int typeIndex, int[] names,
+ EncodedValue[] values) {
+ this.buffer = buffer;
+ this.visibility = visibility;
+ this.typeIndex = typeIndex;
+ this.names = names;
+ this.values = values;
+ }
+
+ public byte getVisibility() {
+ return visibility;
+ }
+
+ public int getTypeIndex() {
+ return typeIndex;
+ }
+
+ public int[] getNames() {
+ return names;
+ }
+
+ public EncodedValue[] getValues() {
+ return values;
+ }
+
+ public void writeTo(DexBuffer.Section out) {
+ out.writeByte(visibility);
+ out.writeUleb128(typeIndex);
+ out.writeUleb128(names.length);
+ for (int i = 0; i < names.length; i++) {
+ out.writeUleb128(names[i]);
+ values[i].writeTo(out);
+ }
+ }
+
+ @Override
+ public int compareTo(Annotation other) {
+ if (typeIndex != other.typeIndex) {
+ return Unsigned.compare(typeIndex, other.typeIndex);
+ }
+ int size = Math.min(names.length, other.names.length);
+ for (int i = 0; i < size; i++) {
+ if (names[i] != other.names[i]) {
+ return Unsigned.compare(names[i], other.names[i]);
+ }
+ int compare = values[i].compareTo(other.values[i]);
+ if (compare != 0) {
+ return compare;
+ }
+ }
+ return names.length - other.names.length;
+ }
+
+ @Override
+ public String toString() {
+ if (buffer == null) {
+ return visibility + " " + typeIndex;
}
- public byte getVisibility() {
- return visibility;
+ StringBuilder result = new StringBuilder();
+ result.append(visibility);
+ result.append(" ");
+ result.append(buffer.typeNames().get(typeIndex));
+ result.append("[");
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) {
+ result.append(", ");
+ }
+ result.append(buffer.strings().get(names[i]));
+ result.append("=");
+ result.append(values[i]);
}
-
- public int getTypeIndex() {
- return typeIndex;
- }
-
- public int[] getNames() {
- return names;
- }
-
- public EncodedValue[] getValues() {
- return values;
- }
-
- public void writeTo(DexBuffer.Section out) {
- out.writeByte(visibility);
- out.writeUleb128(typeIndex);
- out.writeUleb128(names.length);
- for (int i = 0; i < names.length; i++) {
- out.writeUleb128(names[i]);
- values[i].writeTo(out);
- }
- }
-
- @Override public int compareTo(Annotation other) {
- if (typeIndex != other.typeIndex) {
- return Unsigned.compare(typeIndex, other.typeIndex);
- }
- int size = Math.min(names.length, other.names.length);
- for (int i = 0; i < size; i++) {
- if (names[i] != other.names[i]) {
- return Unsigned.compare(names[i], other.names[i]);
- }
- int compare = values[i].compareTo(other.values[i]);
- if (compare != 0) {
- return compare;
- }
- }
- return names.length - other.names.length;
- }
-
- @Override public String toString() {
- if (buffer == null) {
- return visibility + " " + typeIndex;
- }
-
- StringBuilder result = new StringBuilder();
- result.append(visibility);
- result.append(" ");
- result.append(buffer.typeNames().get(typeIndex));
- result.append("[");
- for (int i = 0; i < names.length; i++) {
- if (i > 0) {
- result.append(", ");
- }
- result.append(buffer.strings().get(names[i]));
- result.append("=");
- result.append(values[i]);
- }
- result.append("]");
- return result.toString();
- }
+ result.append("]");
+ return result.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/ClassData.java b/dx/src/com/android/jack/dx/io/ClassData.java
index c51a651..ee9d133 100644
--- a/dx/src/com/android/jack/dx/io/ClassData.java
+++ b/dx/src/com/android/jack/dx/io/ClassData.java
@@ -16,89 +16,98 @@
package com.android.jack.dx.io;
+/**
+ * TODO(jack team)
+ */
public final class ClassData {
- private final Field[] staticFields;
- private final Field[] instanceFields;
- private final Method[] directMethods;
- private final Method[] virtualMethods;
+ private final Field[] staticFields;
+ private final Field[] instanceFields;
+ private final Method[] directMethods;
+ private final Method[] virtualMethods;
- public ClassData(Field[] staticFields, Field[] instanceFields,
- Method[] directMethods, Method[] virtualMethods) {
- this.staticFields = staticFields;
- this.instanceFields = instanceFields;
- this.directMethods = directMethods;
- this.virtualMethods = virtualMethods;
+ public ClassData(Field[] staticFields, Field[] instanceFields, Method[] directMethods,
+ Method[] virtualMethods) {
+ this.staticFields = staticFields;
+ this.instanceFields = instanceFields;
+ this.directMethods = directMethods;
+ this.virtualMethods = virtualMethods;
+ }
+
+ public Field[] getStaticFields() {
+ return staticFields;
+ }
+
+ public Field[] getInstanceFields() {
+ return instanceFields;
+ }
+
+ public Method[] getDirectMethods() {
+ return directMethods;
+ }
+
+ public Method[] getVirtualMethods() {
+ return virtualMethods;
+ }
+
+ public Field[] allFields() {
+ Field[] result = new Field[staticFields.length + instanceFields.length];
+ System.arraycopy(staticFields, 0, result, 0, staticFields.length);
+ System.arraycopy(instanceFields, 0, result, staticFields.length, instanceFields.length);
+ return result;
+ }
+
+ public Method[] allMethods() {
+ Method[] result = new Method[directMethods.length + virtualMethods.length];
+ System.arraycopy(directMethods, 0, result, 0, directMethods.length);
+ System.arraycopy(virtualMethods, 0, result, directMethods.length, virtualMethods.length);
+ return result;
+ }
+
+ /**
+ * TODO(jack team)
+ */
+ public static class Field {
+ private final int fieldIndex;
+ private final int accessFlags;
+
+ public Field(int fieldIndex, int accessFlags) {
+ this.fieldIndex = fieldIndex;
+ this.accessFlags = accessFlags;
}
- public Field[] getStaticFields() {
- return staticFields;
+ public int getFieldIndex() {
+ return fieldIndex;
}
- public Field[] getInstanceFields() {
- return instanceFields;
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+ }
+
+ /**
+ * TODO(jack team)
+ */
+ public static class Method {
+ private final int methodIndex;
+ private final int accessFlags;
+ private final int codeOffset;
+
+ public Method(int methodIndex, int accessFlags, int codeOffset) {
+ this.methodIndex = methodIndex;
+ this.accessFlags = accessFlags;
+ this.codeOffset = codeOffset;
}
- public Method[] getDirectMethods() {
- return directMethods;
+ public int getMethodIndex() {
+ return methodIndex;
}
- public Method[] getVirtualMethods() {
- return virtualMethods;
+ public int getAccessFlags() {
+ return accessFlags;
}
- public Field[] allFields() {
- Field[] result = new Field[staticFields.length + instanceFields.length];
- System.arraycopy(staticFields, 0, result, 0, staticFields.length);
- System.arraycopy(instanceFields, 0, result, staticFields.length, instanceFields.length);
- return result;
+ public int getCodeOffset() {
+ return codeOffset;
}
-
- public Method[] allMethods() {
- Method[] result = new Method[directMethods.length + virtualMethods.length];
- System.arraycopy(directMethods, 0, result, 0, directMethods.length);
- System.arraycopy(virtualMethods, 0, result, directMethods.length, virtualMethods.length);
- return result;
- }
-
- public static class Field {
- private final int fieldIndex;
- private final int accessFlags;
-
- public Field(int fieldIndex, int accessFlags) {
- this.fieldIndex = fieldIndex;
- this.accessFlags = accessFlags;
- }
-
- public int getFieldIndex() {
- return fieldIndex;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
- }
-
- public static class Method {
- private final int methodIndex;
- private final int accessFlags;
- private final int codeOffset;
-
- public Method(int methodIndex, int accessFlags, int codeOffset) {
- this.methodIndex = methodIndex;
- this.accessFlags = accessFlags;
- this.codeOffset = codeOffset;
- }
-
- public int getMethodIndex() {
- return methodIndex;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- public int getCodeOffset() {
- return codeOffset;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/ClassDef.java b/dx/src/com/android/jack/dx/io/ClassDef.java
index 60f15e3..7128905 100644
--- a/dx/src/com/android/jack/dx/io/ClassDef.java
+++ b/dx/src/com/android/jack/dx/io/ClassDef.java
@@ -20,83 +20,91 @@
* A type definition.
*/
public final class ClassDef {
- public static final int NO_INDEX = -1;
- private final DexBuffer buffer;
- private final int offset;
- private final int typeIndex;
- private final int accessFlags;
- private final int supertypeIndex;
- private final int interfacesOffset;
- private final int sourceFileIndex;
- private final int annotationsOffset;
- private final int classDataOffset;
- private final int staticValuesOffset;
+ public static final int NO_INDEX = -1;
+ private final DexBuffer buffer;
+ private final int offset;
+ private final int typeIndex;
+ private final int accessFlags;
+ private final int supertypeIndex;
+ private final int interfacesOffset;
+ private final int sourceFileIndex;
+ private final int annotationsOffset;
+ private final int classDataOffset;
+ private final int staticValuesOffset;
- public ClassDef(DexBuffer buffer, int offset, int typeIndex, int accessFlags,
- int supertypeIndex, int interfacesOffset, int sourceFileIndex,
- int annotationsOffset, int classDataOffset, int staticValuesOffset) {
- this.buffer = buffer;
- this.offset = offset;
- this.typeIndex = typeIndex;
- this.accessFlags = accessFlags;
- this.supertypeIndex = supertypeIndex;
- this.interfacesOffset = interfacesOffset;
- this.sourceFileIndex = sourceFileIndex;
- this.annotationsOffset = annotationsOffset;
- this.classDataOffset = classDataOffset;
- this.staticValuesOffset = staticValuesOffset;
+ public ClassDef(DexBuffer buffer,
+ int offset,
+ int typeIndex,
+ int accessFlags,
+ int supertypeIndex,
+ int interfacesOffset,
+ int sourceFileIndex,
+ int annotationsOffset,
+ int classDataOffset,
+ int staticValuesOffset) {
+ this.buffer = buffer;
+ this.offset = offset;
+ this.typeIndex = typeIndex;
+ this.accessFlags = accessFlags;
+ this.supertypeIndex = supertypeIndex;
+ this.interfacesOffset = interfacesOffset;
+ this.sourceFileIndex = sourceFileIndex;
+ this.annotationsOffset = annotationsOffset;
+ this.classDataOffset = classDataOffset;
+ this.staticValuesOffset = staticValuesOffset;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public int getTypeIndex() {
+ return typeIndex;
+ }
+
+ public int getSupertypeIndex() {
+ return supertypeIndex;
+ }
+
+ public int getInterfacesOffset() {
+ return interfacesOffset;
+ }
+
+ public short[] getInterfaces() {
+ return buffer.readTypeList(interfacesOffset).getTypes();
+ }
+
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ public int getSourceFileIndex() {
+ return sourceFileIndex;
+ }
+
+ public int getAnnotationsOffset() {
+ return annotationsOffset;
+ }
+
+ public int getClassDataOffset() {
+ return classDataOffset;
+ }
+
+ public int getStaticValuesOffset() {
+ return staticValuesOffset;
+ }
+
+ @Override
+ public String toString() {
+ if (buffer == null) {
+ return typeIndex + " " + supertypeIndex;
}
- public int getOffset() {
- return offset;
+ StringBuilder result = new StringBuilder();
+ result.append(buffer.typeNames().get(typeIndex));
+ if (supertypeIndex != NO_INDEX) {
+ result.append(" extends ").append(buffer.typeNames().get(supertypeIndex));
}
-
- public int getTypeIndex() {
- return typeIndex;
- }
-
- public int getSupertypeIndex() {
- return supertypeIndex;
- }
-
- public int getInterfacesOffset() {
- return interfacesOffset;
- }
-
- public short[] getInterfaces() {
- return buffer.readTypeList(interfacesOffset).getTypes();
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- public int getSourceFileIndex() {
- return sourceFileIndex;
- }
-
- public int getAnnotationsOffset() {
- return annotationsOffset;
- }
-
- public int getClassDataOffset() {
- return classDataOffset;
- }
-
- public int getStaticValuesOffset() {
- return staticValuesOffset;
- }
-
- @Override public String toString() {
- if (buffer == null) {
- return typeIndex + " " + supertypeIndex;
- }
-
- StringBuilder result = new StringBuilder();
- result.append(buffer.typeNames().get(typeIndex));
- if (supertypeIndex != NO_INDEX) {
- result.append(" extends ").append(buffer.typeNames().get(supertypeIndex));
- }
- return result.toString();
- }
+ return result.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/Code.java b/dx/src/com/android/jack/dx/io/Code.java
index 865369b..376d72e 100644
--- a/dx/src/com/android/jack/dx/io/Code.java
+++ b/dx/src/com/android/jack/dx/io/Code.java
@@ -16,109 +16,123 @@
package com.android.jack.dx.io;
+/**
+ * TODO(jack team)
+ */
public final class Code {
- private final int registersSize;
- private final int insSize;
- private final int outsSize;
- private final int debugInfoOffset;
- private final short[] instructions;
- private final Try[] tries;
- private final CatchHandler[] catchHandlers;
+ private final int registersSize;
+ private final int insSize;
+ private final int outsSize;
+ private final int debugInfoOffset;
+ private final short[] instructions;
+ private final Try[] tries;
+ private final CatchHandler[] catchHandlers;
- public Code(int registersSize, int insSize, int outsSize, int debugInfoOffset,
- short[] instructions, Try[] tries, CatchHandler[] catchHandlers) {
- this.registersSize = registersSize;
- this.insSize = insSize;
- this.outsSize = outsSize;
- this.debugInfoOffset = debugInfoOffset;
- this.instructions = instructions;
- this.tries = tries;
- this.catchHandlers = catchHandlers;
+ public Code(int registersSize,
+ int insSize,
+ int outsSize,
+ int debugInfoOffset,
+ short[] instructions,
+ Try[] tries,
+ CatchHandler[] catchHandlers) {
+ this.registersSize = registersSize;
+ this.insSize = insSize;
+ this.outsSize = outsSize;
+ this.debugInfoOffset = debugInfoOffset;
+ this.instructions = instructions;
+ this.tries = tries;
+ this.catchHandlers = catchHandlers;
+ }
+
+ public int getRegistersSize() {
+ return registersSize;
+ }
+
+ public int getInsSize() {
+ return insSize;
+ }
+
+ public int getOutsSize() {
+ return outsSize;
+ }
+
+ public int getDebugInfoOffset() {
+ return debugInfoOffset;
+ }
+
+ public short[] getInstructions() {
+ return instructions;
+ }
+
+ public Try[] getTries() {
+ return tries;
+ }
+
+ public CatchHandler[] getCatchHandlers() {
+ return catchHandlers;
+ }
+
+ /**
+ * TODO(jack team)
+ */
+ public static class Try {
+ final int startAddress;
+ final int instructionCount;
+ final int catchHandlerIndex;
+
+ Try(int startAddress, int instructionCount, int catchHandlerIndex) {
+ this.startAddress = startAddress;
+ this.instructionCount = instructionCount;
+ this.catchHandlerIndex = catchHandlerIndex;
}
- public int getRegistersSize() {
- return registersSize;
+ public int getStartAddress() {
+ return startAddress;
}
- public int getInsSize() {
- return insSize;
+ public int getInstructionCount() {
+ return instructionCount;
}
- public int getOutsSize() {
- return outsSize;
+ /**
+ * Returns this try's catch handler <strong>index</strong>. Note that
+ * this is distinct from the its catch handler <strong>offset</strong>.
+ */
+ public int getCatchHandlerIndex() {
+ return catchHandlerIndex;
+ }
+ }
+
+ /**
+ * TODO(jack team)
+ */
+ public static class CatchHandler {
+ final int[] typeIndexes;
+ final int[] addresses;
+ final int catchAllAddress;
+ final int offset;
+
+ public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress, int offset) {
+ this.typeIndexes = typeIndexes;
+ this.addresses = addresses;
+ this.catchAllAddress = catchAllAddress;
+ this.offset = offset;
}
- public int getDebugInfoOffset() {
- return debugInfoOffset;
+ public int[] getTypeIndexes() {
+ return typeIndexes;
}
- public short[] getInstructions() {
- return instructions;
+ public int[] getAddresses() {
+ return addresses;
}
- public Try[] getTries() {
- return tries;
+ public int getCatchAllAddress() {
+ return catchAllAddress;
}
- public CatchHandler[] getCatchHandlers() {
- return catchHandlers;
+ public int getOffset() {
+ return offset;
}
-
- public static class Try {
- final int startAddress;
- final int instructionCount;
- final int catchHandlerIndex;
-
- Try(int startAddress, int instructionCount, int catchHandlerIndex) {
- this.startAddress = startAddress;
- this.instructionCount = instructionCount;
- this.catchHandlerIndex = catchHandlerIndex;
- }
-
- public int getStartAddress() {
- return startAddress;
- }
-
- public int getInstructionCount() {
- return instructionCount;
- }
-
- /**
- * Returns this try's catch handler <strong>index</strong>. Note that
- * this is distinct from the its catch handler <strong>offset</strong>.
- */
- public int getCatchHandlerIndex() {
- return catchHandlerIndex;
- }
- }
-
- public static class CatchHandler {
- final int[] typeIndexes;
- final int[] addresses;
- final int catchAllAddress;
- final int offset;
-
- public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress, int offset) {
- this.typeIndexes = typeIndexes;
- this.addresses = addresses;
- this.catchAllAddress = catchAllAddress;
- this.offset = offset;
- }
-
- public int[] getTypeIndexes() {
- return typeIndexes;
- }
-
- public int[] getAddresses() {
- return addresses;
- }
-
- public int getCatchAllAddress() {
- return catchAllAddress;
- }
-
- public int getOffset() {
- return offset;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/CodeReader.java b/dx/src/com/android/jack/dx/io/CodeReader.java
index 0b791b1..b1c1d4d 100644
--- a/dx/src/com/android/jack/dx/io/CodeReader.java
+++ b/dx/src/com/android/jack/dx/io/CodeReader.java
@@ -23,99 +23,110 @@
* Walks through a block of code and calls visitor call backs.
*/
public final class CodeReader {
- private Visitor fallbackVisitor = null;
- private Visitor stringVisitor = null;
- private Visitor typeVisitor = null;
- private Visitor fieldVisitor = null;
- private Visitor methodVisitor = null;
+ private Visitor fallbackVisitor = null;
+ private Visitor stringVisitor = null;
+ private Visitor typeVisitor = null;
+ private Visitor fieldVisitor = null;
+ private Visitor methodVisitor = null;
- /**
- * Sets {@code visitor} as the visitor for all instructions.
- */
- public void setAllVisitors(Visitor visitor) {
- fallbackVisitor = visitor;
- stringVisitor = visitor;
- typeVisitor = visitor;
- fieldVisitor = visitor;
- methodVisitor = visitor;
+ /**
+ * Sets {@code visitor} as the visitor for all instructions.
+ */
+ public void setAllVisitors(Visitor visitor) {
+ fallbackVisitor = visitor;
+ stringVisitor = visitor;
+ typeVisitor = visitor;
+ fieldVisitor = visitor;
+ methodVisitor = visitor;
+ }
+
+ /**
+ * Sets {@code visitor} as the visitor for all instructions not
+ * otherwise handled.
+ */
+ public void setFallbackVisitor(Visitor visitor) {
+ fallbackVisitor = visitor;
+ }
+
+ /**
+ * Sets {@code visitor} as the visitor for all string instructions.
+ */
+ public void setStringVisitor(Visitor visitor) {
+ stringVisitor = visitor;
+ }
+
+ /**
+ * Sets {@code visitor} as the visitor for all type instructions.
+ */
+ public void setTypeVisitor(Visitor visitor) {
+ typeVisitor = visitor;
+ }
+
+ /**
+ * Sets {@code visitor} as the visitor for all field instructions.
+ */
+ public void setFieldVisitor(Visitor visitor) {
+ fieldVisitor = visitor;
+ }
+
+ /**
+ * Sets {@code visitor} as the visitor for all method instructions.
+ */
+ public void setMethodVisitor(Visitor visitor) {
+ methodVisitor = visitor;
+ }
+
+ public void visitAll(DecodedInstruction[] decodedInstructions) throws DexException {
+ int size = decodedInstructions.length;
+
+ for (int i = 0; i < size; i++) {
+ DecodedInstruction one = decodedInstructions[i];
+ if (one == null) {
+ continue;
+ }
+
+ callVisit(decodedInstructions, one);
+ }
+ }
+
+ public void visitAll(short[] encodedInstructions) throws DexException {
+ DecodedInstruction[] decodedInstructions = DecodedInstruction.decodeAll(encodedInstructions);
+ visitAll(decodedInstructions);
+ }
+
+ private void callVisit(DecodedInstruction[] all, DecodedInstruction one) {
+ Visitor visitor = null;
+
+ switch (OpcodeInfo.getIndexType(one.getOpcode())) {
+ case STRING_REF:
+ visitor = stringVisitor;
+ break;
+ case TYPE_REF:
+ visitor = typeVisitor;
+ break;
+ case FIELD_REF:
+ visitor = fieldVisitor;
+ break;
+ case METHOD_REF:
+ visitor = methodVisitor;
+ break;
+ default:
+ /* continue */
}
- /**
- * Sets {@code visitor} as the visitor for all instructions not
- * otherwise handled.
- */
- public void setFallbackVisitor(Visitor visitor) {
- fallbackVisitor = visitor;
+ if (visitor == null) {
+ visitor = fallbackVisitor;
}
- /**
- * Sets {@code visitor} as the visitor for all string instructions.
- */
- public void setStringVisitor(Visitor visitor) {
- stringVisitor = visitor;
+ if (visitor != null) {
+ visitor.visit(all, one);
}
+ }
- /**
- * Sets {@code visitor} as the visitor for all type instructions.
- */
- public void setTypeVisitor(Visitor visitor) {
- typeVisitor = visitor;
- }
-
- /**
- * Sets {@code visitor} as the visitor for all field instructions.
- */
- public void setFieldVisitor(Visitor visitor) {
- fieldVisitor = visitor;
- }
-
- /**
- * Sets {@code visitor} as the visitor for all method instructions.
- */
- public void setMethodVisitor(Visitor visitor) {
- methodVisitor = visitor;
- }
-
- public void visitAll(DecodedInstruction[] decodedInstructions)
- throws DexException {
- int size = decodedInstructions.length;
-
- for (int i = 0; i < size; i++) {
- DecodedInstruction one = decodedInstructions[i];
- if (one == null) {
- continue;
- }
-
- callVisit(decodedInstructions, one);
- }
- }
-
- public void visitAll(short[] encodedInstructions) throws DexException {
- DecodedInstruction[] decodedInstructions =
- DecodedInstruction.decodeAll(encodedInstructions);
- visitAll(decodedInstructions);
- }
-
- private void callVisit(DecodedInstruction[] all, DecodedInstruction one) {
- Visitor visitor = null;
-
- switch (OpcodeInfo.getIndexType(one.getOpcode())) {
- case STRING_REF: visitor = stringVisitor; break;
- case TYPE_REF: visitor = typeVisitor; break;
- case FIELD_REF: visitor = fieldVisitor; break;
- case METHOD_REF: visitor = methodVisitor; break;
- }
-
- if (visitor == null) {
- visitor = fallbackVisitor;
- }
-
- if (visitor != null) {
- visitor.visit(all, one);
- }
- }
-
- public interface Visitor {
- void visit(DecodedInstruction[] all, DecodedInstruction one);
- }
+ /**
+ * TODO(jack team)
+ */
+ public interface Visitor {
+ void visit(DecodedInstruction[] all, DecodedInstruction one);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/DexBuffer.java b/dx/src/com/android/jack/dx/io/DexBuffer.java
index 2e8299c..e273f4b 100644
--- a/dx/src/com/android/jack/dx/io/DexBuffer.java
+++ b/dx/src/com/android/jack/dx/io/DexBuffer.java
@@ -51,660 +51,694 @@
* are unsigned.
*/
public final class DexBuffer {
- private byte[] data;
- private final TableOfContents tableOfContents = new TableOfContents();
- private int length = 0;
+ private byte[] data;
+ private final TableOfContents tableOfContents = new TableOfContents();
+ private int length = 0;
- private final List<String> strings = new AbstractList<String>() {
- @Override public String get(int index) {
- checkBounds(index, tableOfContents.stringIds.size);
- return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM))
- .readString();
- }
- @Override public int size() {
- return tableOfContents.stringIds.size;
- }
- };
-
- private final List<Integer> typeIds = new AbstractList<Integer>() {
- @Override public Integer get(int index) {
- checkBounds(index, tableOfContents.typeIds.size);
- return open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();
- }
- @Override public int size() {
- return tableOfContents.typeIds.size;
- }
- };
-
- private final List<String> typeNames = new AbstractList<String>() {
- @Override public String get(int index) {
- checkBounds(index, tableOfContents.typeIds.size);
- return strings.get(typeIds.get(index));
- }
- @Override public int size() {
- return tableOfContents.typeIds.size;
- }
- };
-
- private final List<ProtoId> protoIds = new AbstractList<ProtoId>() {
- @Override public ProtoId get(int index) {
- checkBounds(index, tableOfContents.protoIds.size);
- return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index))
- .readProtoId();
- }
- @Override public int size() {
- return tableOfContents.protoIds.size;
- }
- };
-
- private final List<FieldId> fieldIds = new AbstractList<FieldId>() {
- @Override public FieldId get(int index) {
- checkBounds(index, tableOfContents.fieldIds.size);
- return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index))
- .readFieldId();
- }
- @Override public int size() {
- return tableOfContents.fieldIds.size;
- }
- };
-
- private final List<MethodId> methodIds = new AbstractList<MethodId>() {
- @Override public MethodId get(int index) {
- checkBounds(index, tableOfContents.methodIds.size);
- return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index))
- .readMethodId();
- }
- @Override public int size() {
- return tableOfContents.methodIds.size;
- }
- };
-
- /**
- * Creates a new dex buffer defining no classes.
- */
- public DexBuffer() {
- this.data = new byte[0];
+ private final List<String> strings = new AbstractList<String>() {
+ @Override
+ public String get(int index) {
+ checkBounds(index, tableOfContents.stringIds.size);
+ return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM)).readString();
}
- /**
- * Creates a new dex buffer that reads from {@code data}. It is an error to
- * modify {@code data} after using it to create a dex buffer.
- */
- public DexBuffer(byte[] data) throws IOException {
- this.data = data;
- this.length = data.length;
- this.tableOfContents.readFrom(this);
+ @Override
+ public int size() {
+ return tableOfContents.stringIds.size;
+ }
+ };
+
+ private final List<Integer> typeIds = new AbstractList<Integer>() {
+ @Override
+ public Integer get(int index) {
+ checkBounds(index, tableOfContents.typeIds.size);
+ return open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();
}
- /**
- * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
- */
- public DexBuffer(InputStream in) throws IOException {
- loadFrom(in);
+ @Override
+ public int size() {
+ return tableOfContents.typeIds.size;
+ }
+ };
+
+ private final List<String> typeNames = new AbstractList<String>() {
+ @Override
+ public String get(int index) {
+ checkBounds(index, tableOfContents.typeIds.size);
+ return strings.get(typeIds.get(index));
}
- /**
- * Creates a new dex buffer from the dex file {@code file}.
- */
- public DexBuffer(File file) throws IOException {
- if (FileUtils.hasArchiveSuffix(file.getName())) {
- ZipFile zipFile = new ZipFile(file);
- ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
- if (entry != null) {
- loadFrom(zipFile.getInputStream(entry));
- zipFile.close();
- } else {
- throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
+ @Override
+ public int size() {
+ return tableOfContents.typeIds.size;
+ }
+ };
+
+ private final List<ProtoId> protoIds = new AbstractList<ProtoId>() {
+ @Override
+ public ProtoId get(int index) {
+ checkBounds(index, tableOfContents.protoIds.size);
+ return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index)).readProtoId();
+ }
+
+ @Override
+ public int size() {
+ return tableOfContents.protoIds.size;
+ }
+ };
+
+ private final List<FieldId> fieldIds = new AbstractList<FieldId>() {
+ @Override
+ public FieldId get(int index) {
+ checkBounds(index, tableOfContents.fieldIds.size);
+ return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index)).readFieldId();
+ }
+
+ @Override
+ public int size() {
+ return tableOfContents.fieldIds.size;
+ }
+ };
+
+ private final List<MethodId> methodIds = new AbstractList<MethodId>() {
+ @Override
+ public MethodId get(int index) {
+ checkBounds(index, tableOfContents.methodIds.size);
+ return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index)).readMethodId();
+ }
+
+ @Override
+ public int size() {
+ return tableOfContents.methodIds.size;
+ }
+ };
+
+ /**
+ * Creates a new dex buffer defining no classes.
+ */
+ public DexBuffer() {
+ this.data = new byte[0];
+ }
+
+ /**
+ * Creates a new dex buffer that reads from {@code data}. It is an error to
+ * modify {@code data} after using it to create a dex buffer.
+ */
+ public DexBuffer(byte[] data) throws IOException {
+ this.data = data;
+ this.length = data.length;
+ this.tableOfContents.readFrom(this);
+ }
+
+ /**
+ * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
+ */
+ public DexBuffer(InputStream in) throws IOException {
+ loadFrom(in);
+ }
+
+ /**
+ * Creates a new dex buffer from the dex file {@code file}.
+ */
+ public DexBuffer(File file) throws IOException {
+ if (FileUtils.hasArchiveSuffix(file.getName())) {
+ ZipFile zipFile = new ZipFile(file);
+ ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
+ if (entry != null) {
+ loadFrom(zipFile.getInputStream(entry));
+ zipFile.close();
+ } else {
+ throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
+ }
+ } else if (file.getName().endsWith(".dex")) {
+ loadFrom(new FileInputStream(file));
+ } else {
+ throw new DexException("unknown output extension: " + file);
+ }
+ }
+
+ private void loadFrom(InputStream in) throws IOException {
+ ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8192];
+
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytesOut.write(buffer, 0, count);
+ }
+ in.close();
+
+ this.data = bytesOut.toByteArray();
+ this.length = data.length;
+ this.tableOfContents.readFrom(this);
+ }
+
+ private static void checkBounds(int index, int length) {
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
+ }
+ }
+
+ public void writeTo(OutputStream out) throws IOException {
+ out.write(data);
+ }
+
+ public void writeTo(File dexOut) throws IOException {
+ OutputStream out = new FileOutputStream(dexOut);
+ writeTo(out);
+ out.close();
+ }
+
+ public TableOfContents getTableOfContents() {
+ return tableOfContents;
+ }
+
+ public Section open(int position) {
+ if (position < 0 || position > length) {
+ throw new IllegalArgumentException("position=" + position + " length=" + length);
+ }
+ return new Section(position);
+ }
+
+ public Section appendSection(int maxByteCount, String name) {
+ int limit = fourByteAlign(length + maxByteCount);
+ Section result = new Section(name, length, limit);
+ length = limit;
+ return result;
+ }
+
+ public void noMoreSections() {
+ data = new byte[length];
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public static int fourByteAlign(int position) {
+ return (position + 3) & ~3;
+ }
+
+ public byte[] getBytes() {
+ return data;
+ }
+
+ public List<String> strings() {
+ return strings;
+ }
+
+ public List<Integer> typeIds() {
+ return typeIds;
+ }
+
+ public List<String> typeNames() {
+ return typeNames;
+ }
+
+ public List<ProtoId> protoIds() {
+ return protoIds;
+ }
+
+ public List<FieldId> fieldIds() {
+ return fieldIds;
+ }
+
+ public List<MethodId> methodIds() {
+ return methodIds;
+ }
+
+ public Iterable<ClassDef> classDefs() {
+ return new Iterable<ClassDef>() {
+ @Override
+ public Iterator<ClassDef> iterator() {
+ if (!tableOfContents.classDefs.exists()) {
+ return Collections.<ClassDef>emptySet().iterator();
+ }
+ return new Iterator<ClassDef>() {
+ private DexBuffer.Section in = open(tableOfContents.classDefs.off);
+ private int count = 0;
+
+ @Override
+ public boolean hasNext() {
+ return count < tableOfContents.classDefs.size;
+ }
+
+ @Override
+ public ClassDef next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
}
- } else if (file.getName().endsWith(".dex")) {
- loadFrom(new FileInputStream(file));
- } else {
- throw new DexException("unknown output extension: " + file);
- }
- }
+ count++;
+ return in.readClassDef();
+ }
- private void loadFrom(InputStream in) throws IOException {
- ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
- byte[] buffer = new byte[8192];
-
- int count;
- while ((count = in.read(buffer)) != -1) {
- bytesOut.write(buffer, 0, count);
- }
- in.close();
-
- this.data = bytesOut.toByteArray();
- this.length = data.length;
- this.tableOfContents.readFrom(this);
- }
-
- private static void checkBounds(int index, int length) {
- if (index < 0 || index >= length) {
- throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
- }
- }
-
- public void writeTo(OutputStream out) throws IOException {
- out.write(data);
- }
-
- public void writeTo(File dexOut) throws IOException {
- OutputStream out = new FileOutputStream(dexOut);
- writeTo(out);
- out.close();
- }
-
- public TableOfContents getTableOfContents() {
- return tableOfContents;
- }
-
- public Section open(int position) {
- if (position < 0 || position > length) {
- throw new IllegalArgumentException("position=" + position + " length=" + length);
- }
- return new Section(position);
- }
-
- public Section appendSection(int maxByteCount, String name) {
- int limit = fourByteAlign(length + maxByteCount);
- Section result = new Section(name, length, limit);
- length = limit;
- return result;
- }
-
- public void noMoreSections() {
- data = new byte[length];
- }
-
- public int getLength() {
- return length;
- }
-
- public static int fourByteAlign(int position) {
- return (position + 3) & ~3;
- }
-
- public byte[] getBytes() {
- return data;
- }
-
- public List<String> strings() {
- return strings;
- }
-
- public List<Integer> typeIds() {
- return typeIds;
- }
-
- public List<String> typeNames() {
- return typeNames;
- }
-
- public List<ProtoId> protoIds() {
- return protoIds;
- }
-
- public List<FieldId> fieldIds() {
- return fieldIds;
- }
-
- public List<MethodId> methodIds() {
- return methodIds;
- }
-
- public Iterable<ClassDef> classDefs() {
- return new Iterable<ClassDef>() {
- public Iterator<ClassDef> iterator() {
- if (!tableOfContents.classDefs.exists()) {
- return Collections.<ClassDef>emptySet().iterator();
- }
- return new Iterator<ClassDef>() {
- private DexBuffer.Section in = open(tableOfContents.classDefs.off);
- private int count = 0;
-
- public boolean hasNext() {
- return count < tableOfContents.classDefs.size;
- }
- public ClassDef next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- count++;
- return in.readClassDef();
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
};
+ }
+ };
+ }
+
+ public TypeList readTypeList(int offset) {
+ if (offset == 0) {
+ return TypeList.EMPTY;
+ }
+ return open(offset).readTypeList();
+ }
+
+ public ClassData readClassData(ClassDef classDef) {
+ int offset = classDef.getClassDataOffset();
+ if (offset == 0) {
+ throw new IllegalArgumentException("offset == 0");
+ }
+ return open(offset).readClassData();
+ }
+
+ public Code readCode(ClassData.Method method) {
+ int offset = method.getCodeOffset();
+ if (offset == 0) {
+ throw new IllegalArgumentException("offset == 0");
+ }
+ return open(offset).readCode();
+ }
+
+ /**
+ * TODO(jack team)
+ */
+ public final class Section implements ByteInput, ByteOutput {
+ private final String name;
+ private int position;
+ private final int limit;
+ private final int initialPosition;
+
+ private Section(String name, int position, int limit) {
+ this.name = name;
+ this.position = this.initialPosition = position;
+ this.limit = limit;
}
- public TypeList readTypeList(int offset) {
- if (offset == 0) {
- return TypeList.EMPTY;
- }
- return open(offset).readTypeList();
+ private Section(int position) {
+ this("section", position, data.length);
}
- public ClassData readClassData(ClassDef classDef) {
- int offset = classDef.getClassDataOffset();
- if (offset == 0) {
- throw new IllegalArgumentException("offset == 0");
- }
- return open(offset).readClassData();
+ public int getPosition() {
+ return position;
}
- public Code readCode(ClassData.Method method) {
- int offset = method.getCodeOffset();
- if (offset == 0) {
- throw new IllegalArgumentException("offset == 0");
- }
- return open(offset).readCode();
+ public int readInt() {
+ int result = (data[position] & 0xff) | (data[position + 1] & 0xff) << 8
+ | (data[position + 2] & 0xff) << 16 | (data[position + 3] & 0xff) << 24;
+ position += 4;
+ return result;
}
- public final class Section implements ByteInput, ByteOutput {
- private final String name;
- private int position;
- private final int limit;
- private final int initialPosition;
+ public short readShort() {
+ int result = (data[position] & 0xff) | (data[position + 1] & 0xff) << 8;
+ position += 2;
+ return (short) result;
+ }
- private Section(String name, int position, int limit) {
- this.name = name;
- this.position = this.initialPosition = position;
- this.limit = limit;
+ public int readUnsignedShort() {
+ return readShort() & 0xffff;
+ }
+
+ @Override
+ public byte readByte() {
+ return (byte) (data[position++] & 0xff);
+ }
+
+ public byte[] readByteArray(int length) {
+ byte[] result = Arrays.copyOfRange(data, position, position + length);
+ position += length;
+ return result;
+ }
+
+ public short[] readShortArray(int length) {
+ short[] result = new short[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = readShort();
+ }
+ return result;
+ }
+
+ public int readUleb128() {
+ return Leb128Utils.readUnsignedLeb128(this);
+ }
+
+ public int readUleb128p1() {
+ return Leb128Utils.readUnsignedLeb128(this) - 1;
+ }
+
+ public int readSleb128() {
+ return Leb128Utils.readSignedLeb128(this);
+ }
+
+ public TypeList readTypeList() {
+ assertFourByteAligned();
+ int size = readInt();
+ short[] types = new short[size];
+ for (int i = 0; i < size; i++) {
+ types[i] = readShort();
+ }
+ position = DexBuffer.fourByteAlign(position);
+ return new TypeList(DexBuffer.this, types);
+ }
+
+ public String readString() {
+ int offset = readInt();
+ int savedPosition = position;
+ position = offset;
+ try {
+ int expectedLength = readUleb128();
+ String result = Mutf8.decode(this, new char[expectedLength]);
+ if (result.length() != expectedLength) {
+ throw new DexException("Declared length " + expectedLength
+ + " doesn't match decoded length of " + result.length());
+ }
+ return result;
+ } catch (UTFDataFormatException e) {
+ throw new DexException(e);
+ } finally {
+ position = savedPosition;
+ }
+ }
+
+ public FieldId readFieldId() {
+ int declaringClassIndex = readUnsignedShort();
+ int typeIndex = readUnsignedShort();
+ int nameIndex = readInt();
+ return new FieldId(DexBuffer.this, declaringClassIndex, typeIndex, nameIndex);
+ }
+
+ public MethodId readMethodId() {
+ int declaringClassIndex = readUnsignedShort();
+ int protoIndex = readUnsignedShort();
+ int nameIndex = readInt();
+ return new MethodId(DexBuffer.this, declaringClassIndex, protoIndex, nameIndex);
+ }
+
+ public ProtoId readProtoId() {
+ int shortyIndex = readInt();
+ int returnTypeIndex = readInt();
+ int parametersOffset = readInt();
+ return new ProtoId(DexBuffer.this, shortyIndex, returnTypeIndex, parametersOffset);
+ }
+
+ public ClassDef readClassDef() {
+ int offset = getPosition();
+ int type = readInt();
+ int accessFlags = readInt();
+ int supertype = readInt();
+ int interfacesOffset = readInt();
+ int sourceFileIndex = readInt();
+ int annotationsOffset = readInt();
+ int classDataOffset = readInt();
+ int staticValuesOffset = readInt();
+ return new ClassDef(DexBuffer.this,
+ offset,
+ type,
+ accessFlags,
+ supertype,
+ interfacesOffset,
+ sourceFileIndex,
+ annotationsOffset,
+ classDataOffset,
+ staticValuesOffset);
+ }
+
+ private Code readCode() {
+ int registersSize = readUnsignedShort();
+ int insSize = readUnsignedShort();
+ int outsSize = readUnsignedShort();
+ int triesSize = readUnsignedShort();
+ int debugInfoOffset = readInt();
+ int instructionsSize = readInt();
+ short[] instructions = readShortArray(instructionsSize);
+ Try[] tries;
+ CatchHandler[] catchHandlers;
+ if (triesSize > 0) {
+ if (instructions.length % 2 == 1) {
+ readShort(); // padding
}
- private Section(int position) {
- this("section", position, data.length);
- }
-
- public int getPosition() {
- return position;
- }
-
- public int readInt() {
- int result = (data[position] & 0xff)
- | (data[position + 1] & 0xff) << 8
- | (data[position + 2] & 0xff) << 16
- | (data[position + 3] & 0xff) << 24;
- position += 4;
- return result;
- }
-
- public short readShort() {
- int result = (data[position] & 0xff)
- | (data[position + 1] & 0xff) << 8;
- position += 2;
- return (short) result;
- }
-
- public int readUnsignedShort() {
- return readShort() & 0xffff;
- }
-
- public byte readByte() {
- return (byte) (data[position++] & 0xff);
- }
-
- public byte[] readByteArray(int length) {
- byte[] result = Arrays.copyOfRange(data, position, position + length);
- position += length;
- return result;
- }
-
- public short[] readShortArray(int length) {
- short[] result = new short[length];
- for (int i = 0; i < length; i++) {
- result[i] = readShort();
- }
- return result;
- }
-
- public int readUleb128() {
- return Leb128Utils.readUnsignedLeb128(this);
- }
-
- public int readUleb128p1() {
- return Leb128Utils.readUnsignedLeb128(this) - 1;
- }
-
- public int readSleb128() {
- return Leb128Utils.readSignedLeb128(this);
- }
-
- public TypeList readTypeList() {
- assertFourByteAligned();
- int size = readInt();
- short[] types = new short[size];
- for (int i = 0; i < size; i++) {
- types[i] = readShort();
- }
- position = DexBuffer.fourByteAlign(position);
- return new TypeList(DexBuffer.this, types);
- }
-
- public String readString() {
- int offset = readInt();
- int savedPosition = position;
- position = offset;
- try {
- int expectedLength = readUleb128();
- String result = Mutf8.decode(this, new char[expectedLength]);
- if (result.length() != expectedLength) {
- throw new DexException("Declared length " + expectedLength
- + " doesn't match decoded length of " + result.length());
- }
- return result;
- } catch (UTFDataFormatException e) {
- throw new DexException(e);
- } finally {
- position = savedPosition;
- }
- }
-
- public FieldId readFieldId() {
- int declaringClassIndex = readUnsignedShort();
- int typeIndex = readUnsignedShort();
- int nameIndex = readInt();
- return new FieldId(DexBuffer.this, declaringClassIndex, typeIndex, nameIndex);
- }
-
- public MethodId readMethodId() {
- int declaringClassIndex = readUnsignedShort();
- int protoIndex = readUnsignedShort();
- int nameIndex = readInt();
- return new MethodId(DexBuffer.this, declaringClassIndex, protoIndex, nameIndex);
- }
-
- public ProtoId readProtoId() {
- int shortyIndex = readInt();
- int returnTypeIndex = readInt();
- int parametersOffset = readInt();
- return new ProtoId(DexBuffer.this, shortyIndex, returnTypeIndex, parametersOffset);
- }
-
- public ClassDef readClassDef() {
- int offset = getPosition();
- int type = readInt();
- int accessFlags = readInt();
- int supertype = readInt();
- int interfacesOffset = readInt();
- int sourceFileIndex = readInt();
- int annotationsOffset = readInt();
- int classDataOffset = readInt();
- int staticValuesOffset = readInt();
- return new ClassDef(DexBuffer.this, offset, type, accessFlags, supertype,
- interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset,
- staticValuesOffset);
- }
-
- private Code readCode() {
- int registersSize = readUnsignedShort();
- int insSize = readUnsignedShort();
- int outsSize = readUnsignedShort();
- int triesSize = readUnsignedShort();
- int debugInfoOffset = readInt();
- int instructionsSize = readInt();
- short[] instructions = readShortArray(instructionsSize);
- Try[] tries;
- CatchHandler[] catchHandlers;
- if (triesSize > 0) {
- if (instructions.length % 2 == 1) {
- readShort(); // padding
- }
-
- /*
- * We can't read the tries until we've read the catch handlers.
- * Unfortunately they're in the opposite order in the dex file
- * so we need to read them out-of-order.
- */
- Section triesSection = open(position);
- skip(triesSize * SizeOf.TRY_ITEM);
- catchHandlers = readCatchHandlers();
- tries = triesSection.readTries(triesSize, catchHandlers);
- } else {
- tries = new Try[0];
- catchHandlers = new CatchHandler[0];
- }
- return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
- tries, catchHandlers);
- }
-
- private CatchHandler[] readCatchHandlers() {
- int baseOffset = position;
- int catchHandlersSize = readUleb128();
- CatchHandler[] result = new CatchHandler[catchHandlersSize];
- for (int i = 0; i < catchHandlersSize; i++) {
- int offset = position - baseOffset;
- result[i] = readCatchHandler(offset);
- }
- return result;
- }
-
- private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
- Try[] result = new Try[triesSize];
- for (int i = 0; i < triesSize; i++) {
- int startAddress = readInt();
- int instructionCount = readUnsignedShort();
- int handlerOffset = readUnsignedShort();
- int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
- result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
- }
- return result;
- }
-
- private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
- for (int i = 0; i < catchHandlers.length; i++) {
- CatchHandler catchHandler = catchHandlers[i];
- if (catchHandler.getOffset() == offset) {
- return i;
- }
- }
- throw new IllegalArgumentException();
- }
-
- private CatchHandler readCatchHandler(int offset) {
- int size = readSleb128();
- int handlersCount = Math.abs(size);
- int[] typeIndexes = new int[handlersCount];
- int[] addresses = new int[handlersCount];
- for (int i = 0; i < handlersCount; i++) {
- typeIndexes[i] = readUleb128();
- addresses[i] = readUleb128();
- }
- int catchAllAddress = size <= 0 ? readUleb128() : -1;
- return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
- }
-
- private ClassData readClassData() {
- int staticFieldsSize = readUleb128();
- int instanceFieldsSize = readUleb128();
- int directMethodsSize = readUleb128();
- int virtualMethodsSize = readUleb128();
- ClassData.Field[] staticFields = readFields(staticFieldsSize);
- ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
- ClassData.Method[] directMethods = readMethods(directMethodsSize);
- ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
- return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
- }
-
- private ClassData.Field[] readFields(int count) {
- ClassData.Field[] result = new ClassData.Field[count];
- int fieldIndex = 0;
- for (int i = 0; i < count; i++) {
- fieldIndex += readUleb128(); // field index diff
- int accessFlags = readUleb128();
- result[i] = new ClassData.Field(fieldIndex, accessFlags);
- }
- return result;
- }
-
- private ClassData.Method[] readMethods(int count) {
- ClassData.Method[] result = new ClassData.Method[count];
- int methodIndex = 0;
- for (int i = 0; i < count; i++) {
- methodIndex += readUleb128(); // method index diff
- int accessFlags = readUleb128();
- int codeOff = readUleb128();
- result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
- }
- return result;
- }
-
- public Annotation readAnnotation() {
- byte visibility = readByte();
- int typeIndex = readUleb128();
- int size = readUleb128();
- int[] names = new int[size];
- EncodedValue[] values = new EncodedValue[size];
- for (int i = 0; i < size; i++) {
- names[i] = readUleb128();
- values[i] = readEncodedValue();
- }
- return new Annotation(DexBuffer.this, visibility, typeIndex, names, values);
- }
-
- public EncodedValue readEncodedValue() {
- int start = position;
- new EncodedValueReader(this).readValue();
- int end = position;
- return new EncodedValue(Arrays.copyOfRange(data, start, end));
- }
-
- public EncodedValue readEncodedArray() {
- int start = position;
- new EncodedValueReader(this).readArray();
- int end = position;
- return new EncodedValue(Arrays.copyOfRange(data, start, end));
- }
-
- private void ensureCapacity(int size) {
- if (position + size > limit) {
- throw new DexException("Section limit " + limit + " exceeded by " + name);
- }
- }
-
- public void skip(int count) {
- if (count < 0) {
- throw new IllegalArgumentException();
- }
- ensureCapacity(count);
- position += count;
- }
-
- /**
- * Writes 0x00 until the position is aligned to a multiple of 4.
+ /*
+ * We can't read the tries until we've read the catch handlers.
+ * Unfortunately they're in the opposite order in the dex file
+ * so we need to read them out-of-order.
*/
- public void alignToFourBytes() {
- int unalignedCount = position;
- position = DexBuffer.fourByteAlign(position);
- for (int i = unalignedCount; i < position; i++) {
- data[i] = 0;
- }
- }
-
- public void assertFourByteAligned() {
- if ((position & 3) != 0) {
- throw new IllegalStateException("Not four byte aligned!");
- }
- }
-
- public void write(byte[] bytes) {
- ensureCapacity(bytes.length);
- System.arraycopy(bytes, 0, data, position, bytes.length);
- position += bytes.length;
- }
-
- public void writeByte(int b) {
- ensureCapacity(1);
- data[position++] = (byte) b;
- }
-
- public void writeShort(short i) {
- ensureCapacity(2);
- data[position ] = (byte) i;
- data[position + 1] = (byte) (i >>> 8);
- position += 2;
- }
-
- public void writeUnsignedShort(int i) {
- short s = (short) i;
- if (i != (s & 0xffff)) {
- throw new IllegalArgumentException("Expected an unsigned short: " + i);
- }
- writeShort(s);
- }
-
- public void write(short[] shorts) {
- for (short s : shorts) {
- writeShort(s);
- }
- }
-
- public void writeInt(int i) {
- ensureCapacity(4);
- data[position ] = (byte) i;
- data[position + 1] = (byte) (i >>> 8);
- data[position + 2] = (byte) (i >>> 16);
- data[position + 3] = (byte) (i >>> 24);
- position += 4;
- }
-
- public void writeUleb128(int i) {
- try {
- Leb128Utils.writeUnsignedLeb128(this, i);
- ensureCapacity(0);
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new DexException("Section limit " + limit + " exceeded by " + name);
- }
- }
-
- public void writeUleb128p1(int i) {
- writeUleb128(i + 1);
- }
-
- public void writeSleb128(int i) {
- try {
- Leb128Utils.writeSignedLeb128(this, i);
- ensureCapacity(0);
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new DexException("Section limit " + limit + " exceeded by " + name);
- }
- }
-
- public void writeStringData(String value) {
- try {
- int length = value.length();
- writeUleb128(length);
- write(Mutf8.encode(value));
- writeByte(0);
- } catch (UTFDataFormatException e) {
- throw new AssertionError();
- }
- }
-
- public void writeTypeList(TypeList typeList) {
- short[] types = typeList.getTypes();
- writeInt(types.length);
- for (short type : types) {
- writeShort(type);
- }
- alignToFourBytes();
- }
-
- /**
- * Returns the number of bytes remaining in this section.
- */
- public int remaining() {
- return limit - position;
- }
-
- /**
- * Returns the number of bytes used by this section.
- */
- public int used () {
- return position - initialPosition;
- }
+ Section triesSection = open(position);
+ skip(triesSize * SizeOf.TRY_ITEM);
+ catchHandlers = readCatchHandlers();
+ tries = triesSection.readTries(triesSize, catchHandlers);
+ } else {
+ tries = new Try[0];
+ catchHandlers = new CatchHandler[0];
+ }
+ return new Code(registersSize,
+ insSize,
+ outsSize,
+ debugInfoOffset,
+ instructions,
+ tries,
+ catchHandlers);
}
+
+ private CatchHandler[] readCatchHandlers() {
+ int baseOffset = position;
+ int catchHandlersSize = readUleb128();
+ CatchHandler[] result = new CatchHandler[catchHandlersSize];
+ for (int i = 0; i < catchHandlersSize; i++) {
+ int offset = position - baseOffset;
+ result[i] = readCatchHandler(offset);
+ }
+ return result;
+ }
+
+ private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
+ Try[] result = new Try[triesSize];
+ for (int i = 0; i < triesSize; i++) {
+ int startAddress = readInt();
+ int instructionCount = readUnsignedShort();
+ int handlerOffset = readUnsignedShort();
+ int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
+ result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
+ }
+ return result;
+ }
+
+ private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
+ for (int i = 0; i < catchHandlers.length; i++) {
+ CatchHandler catchHandler = catchHandlers[i];
+ if (catchHandler.getOffset() == offset) {
+ return i;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+
+ private CatchHandler readCatchHandler(int offset) {
+ int size = readSleb128();
+ int handlersCount = Math.abs(size);
+ int[] typeIndexes = new int[handlersCount];
+ int[] addresses = new int[handlersCount];
+ for (int i = 0; i < handlersCount; i++) {
+ typeIndexes[i] = readUleb128();
+ addresses[i] = readUleb128();
+ }
+ int catchAllAddress = size <= 0 ? readUleb128() : -1;
+ return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
+ }
+
+ private ClassData readClassData() {
+ int staticFieldsSize = readUleb128();
+ int instanceFieldsSize = readUleb128();
+ int directMethodsSize = readUleb128();
+ int virtualMethodsSize = readUleb128();
+ ClassData.Field[] staticFields = readFields(staticFieldsSize);
+ ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
+ ClassData.Method[] directMethods = readMethods(directMethodsSize);
+ ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
+ return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
+ }
+
+ private ClassData.Field[] readFields(int count) {
+ ClassData.Field[] result = new ClassData.Field[count];
+ int fieldIndex = 0;
+ for (int i = 0; i < count; i++) {
+ fieldIndex += readUleb128(); // field index diff
+ int accessFlags = readUleb128();
+ result[i] = new ClassData.Field(fieldIndex, accessFlags);
+ }
+ return result;
+ }
+
+ private ClassData.Method[] readMethods(int count) {
+ ClassData.Method[] result = new ClassData.Method[count];
+ int methodIndex = 0;
+ for (int i = 0; i < count; i++) {
+ methodIndex += readUleb128(); // method index diff
+ int accessFlags = readUleb128();
+ int codeOff = readUleb128();
+ result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
+ }
+ return result;
+ }
+
+ public Annotation readAnnotation() {
+ byte visibility = readByte();
+ int typeIndex = readUleb128();
+ int size = readUleb128();
+ int[] names = new int[size];
+ EncodedValue[] values = new EncodedValue[size];
+ for (int i = 0; i < size; i++) {
+ names[i] = readUleb128();
+ values[i] = readEncodedValue();
+ }
+ return new Annotation(DexBuffer.this, visibility, typeIndex, names, values);
+ }
+
+ public EncodedValue readEncodedValue() {
+ int start = position;
+ new EncodedValueReader(this).readValue();
+ int end = position;
+ return new EncodedValue(Arrays.copyOfRange(data, start, end));
+ }
+
+ public EncodedValue readEncodedArray() {
+ int start = position;
+ new EncodedValueReader(this).readArray();
+ int end = position;
+ return new EncodedValue(Arrays.copyOfRange(data, start, end));
+ }
+
+ private void ensureCapacity(int size) {
+ if (position + size > limit) {
+ throw new DexException("Section limit " + limit + " exceeded by " + name);
+ }
+ }
+
+ public void skip(int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException();
+ }
+ ensureCapacity(count);
+ position += count;
+ }
+
+ /**
+ * Writes 0x00 until the position is aligned to a multiple of 4.
+ */
+ public void alignToFourBytes() {
+ int unalignedCount = position;
+ position = DexBuffer.fourByteAlign(position);
+ for (int i = unalignedCount; i < position; i++) {
+ data[i] = 0;
+ }
+ }
+
+ public void assertFourByteAligned() {
+ if ((position & 3) != 0) {
+ throw new IllegalStateException("Not four byte aligned!");
+ }
+ }
+
+ public void write(byte[] bytes) {
+ ensureCapacity(bytes.length);
+ System.arraycopy(bytes, 0, data, position, bytes.length);
+ position += bytes.length;
+ }
+
+ @Override
+ public void writeByte(int b) {
+ ensureCapacity(1);
+ data[position++] = (byte) b;
+ }
+
+ public void writeShort(short i) {
+ ensureCapacity(2);
+ data[position] = (byte) i;
+ data[position + 1] = (byte) (i >>> 8);
+ position += 2;
+ }
+
+ public void writeUnsignedShort(int i) {
+ short s = (short) i;
+ if (i != (s & 0xffff)) {
+ throw new IllegalArgumentException("Expected an unsigned short: " + i);
+ }
+ writeShort(s);
+ }
+
+ public void write(short[] shorts) {
+ for (short s : shorts) {
+ writeShort(s);
+ }
+ }
+
+ public void writeInt(int i) {
+ ensureCapacity(4);
+ data[position] = (byte) i;
+ data[position + 1] = (byte) (i >>> 8);
+ data[position + 2] = (byte) (i >>> 16);
+ data[position + 3] = (byte) (i >>> 24);
+ position += 4;
+ }
+
+ public void writeUleb128(int i) {
+ try {
+ Leb128Utils.writeUnsignedLeb128(this, i);
+ ensureCapacity(0);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new DexException("Section limit " + limit + " exceeded by " + name);
+ }
+ }
+
+ public void writeUleb128p1(int i) {
+ writeUleb128(i + 1);
+ }
+
+ public void writeSleb128(int i) {
+ try {
+ Leb128Utils.writeSignedLeb128(this, i);
+ ensureCapacity(0);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new DexException("Section limit " + limit + " exceeded by " + name);
+ }
+ }
+
+ public void writeStringData(String value) {
+ try {
+ int length = value.length();
+ writeUleb128(length);
+ write(Mutf8.encode(value));
+ writeByte(0);
+ } catch (UTFDataFormatException e) {
+ throw new AssertionError();
+ }
+ }
+
+ public void writeTypeList(TypeList typeList) {
+ short[] types = typeList.getTypes();
+ writeInt(types.length);
+ for (short type : types) {
+ writeShort(type);
+ }
+ alignToFourBytes();
+ }
+
+ /**
+ * Returns the number of bytes remaining in this section.
+ */
+ public int remaining() {
+ return limit - position;
+ }
+
+ /**
+ * Returns the number of bytes used by this section.
+ */
+ public int used() {
+ return position - initialPosition;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/DexHasher.java b/dx/src/com/android/jack/dx/io/DexHasher.java
index 301dd37..3a9b3ba 100644
--- a/dx/src/com/android/jack/dx/io/DexHasher.java
+++ b/dx/src/com/android/jack/dx/io/DexHasher.java
@@ -25,51 +25,51 @@
* Generates and stores the checksum and signature of a dex file.
*/
public final class DexHasher {
- private static final int CHECKSUM_OFFSET = 8;
- private static final int CHECKSUM_SIZE = 4;
- private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
- private static final int SIGNATURE_SIZE = 20;
+ private static final int CHECKSUM_OFFSET = 8;
+ private static final int CHECKSUM_SIZE = 4;
+ private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+ private static final int SIGNATURE_SIZE = 20;
- /**
- * Returns the signature of all but the first 32 bytes of {@code dex}. The
- * first 32 bytes of dex files are not specified to be included in the
- * signature.
- */
- public byte[] computeSignature(DexBuffer dex) throws IOException {
- MessageDigest digest;
- try {
- digest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError();
- }
- int offset = SIGNATURE_OFFSET + SIGNATURE_SIZE;
-
- byte[] bytes = dex.getBytes();
- digest.update(bytes, offset, bytes.length - offset);
- return digest.digest();
+ /**
+ * Returns the signature of all but the first 32 bytes of {@code dex}. The
+ * first 32 bytes of dex files are not specified to be included in the
+ * signature.
+ */
+ public byte[] computeSignature(DexBuffer dex) throws IOException {
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError();
}
+ int offset = SIGNATURE_OFFSET + SIGNATURE_SIZE;
- /**
- * Returns the checksum of all but the first 12 bytes of {@code dex}.
- */
- public int computeChecksum(DexBuffer dex) throws IOException {
- Adler32 adler32 = new Adler32();
- int offset = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+ byte[] bytes = dex.getBytes();
+ digest.update(bytes, offset, bytes.length - offset);
+ return digest.digest();
+ }
- byte[] bytes = dex.getBytes();
- adler32.update(bytes, offset, bytes.length - offset);
- return (int) adler32.getValue();
- }
+ /**
+ * Returns the checksum of all but the first 12 bytes of {@code dex}.
+ */
+ public int computeChecksum(DexBuffer dex) throws IOException {
+ Adler32 adler32 = new Adler32();
+ int offset = CHECKSUM_OFFSET + CHECKSUM_SIZE;
- /**
- * Generates the signature and checksum of the dex file {@code out} and
- * writes them to the file.
- */
- public void writeHashes(DexBuffer dex) throws IOException {
- byte[] signature = computeSignature(dex);
- dex.open(SIGNATURE_OFFSET).write(signature);
+ byte[] bytes = dex.getBytes();
+ adler32.update(bytes, offset, bytes.length - offset);
+ return (int) adler32.getValue();
+ }
- int checksum = computeChecksum(dex);
- dex.open(CHECKSUM_OFFSET).writeInt(checksum);
- }
+ /**
+ * Generates the signature and checksum of the dex file {@code out} and
+ * writes them to the file.
+ */
+ public void writeHashes(DexBuffer dex) throws IOException {
+ byte[] signature = computeSignature(dex);
+ dex.open(SIGNATURE_OFFSET).write(signature);
+
+ int checksum = computeChecksum(dex);
+ dex.open(CHECKSUM_OFFSET).writeInt(checksum);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/DexIndexPrinter.java b/dx/src/com/android/jack/dx/io/DexIndexPrinter.java
index 952649c..89dc385 100644
--- a/dx/src/com/android/jack/dx/io/DexIndexPrinter.java
+++ b/dx/src/com/android/jack/dx/io/DexIndexPrinter.java
@@ -25,101 +25,100 @@
* Executable that prints all indices of a dex file.
*/
public final class DexIndexPrinter {
- private final DexBuffer dexBuffer;
- private final TableOfContents tableOfContents;
+ private final DexBuffer dexBuffer;
+ private final TableOfContents tableOfContents;
- public DexIndexPrinter(File file) throws IOException {
- this.dexBuffer = new DexBuffer(file);
- this.tableOfContents = dexBuffer.getTableOfContents();
- }
+ public DexIndexPrinter(File file) throws IOException {
+ this.dexBuffer = new DexBuffer(file);
+ this.tableOfContents = dexBuffer.getTableOfContents();
+ }
- private void printMap() {
- for (TableOfContents.Section section : tableOfContents.sections) {
- if (section.off != -1) {
- System.out.println("section " + Integer.toHexString(section.type)
- + " off=" + Integer.toHexString(section.off)
- + " size=" + Integer.toHexString(section.size)
- + " byteCount=" + Integer.toHexString(section.byteCount));
- }
- }
+ private void printMap() {
+ for (TableOfContents.Section section : tableOfContents.sections) {
+ if (section.off != -1) {
+ System.out.println("section " + Integer.toHexString(section.type) + " off="
+ + Integer.toHexString(section.off) + " size=" + Integer.toHexString(section.size)
+ + " byteCount=" + Integer.toHexString(section.byteCount));
+ }
}
+ }
- private void printStrings() throws IOException {
- int index = 0;
- for (String string : dexBuffer.strings()) {
- System.out.println("string " + index + ": " + string);
- index++;
- }
+ private void printStrings() throws IOException {
+ int index = 0;
+ for (String string : dexBuffer.strings()) {
+ System.out.println("string " + index + ": " + string);
+ index++;
}
+ }
- private void printTypeIds() throws IOException {
- int index = 0;
- for (Integer type : dexBuffer.typeIds()) {
- System.out.println("type " + index + ": " + dexBuffer.strings().get(type));
- index++;
- }
+ private void printTypeIds() throws IOException {
+ int index = 0;
+ for (Integer type : dexBuffer.typeIds()) {
+ System.out.println("type " + index + ": " + dexBuffer.strings().get(type));
+ index++;
}
+ }
- private void printProtoIds() throws IOException {
- int index = 0;
- for (ProtoId protoId : dexBuffer.protoIds()) {
- System.out.println("proto " + index + ": " + protoId);
- index++;
- }
+ private void printProtoIds() throws IOException {
+ int index = 0;
+ for (ProtoId protoId : dexBuffer.protoIds()) {
+ System.out.println("proto " + index + ": " + protoId);
+ index++;
}
+ }
- private void printFieldIds() throws IOException {
- int index = 0;
- for (FieldId fieldId : dexBuffer.fieldIds()) {
- System.out.println("field " + index + ": " + fieldId);
- index++;
- }
+ private void printFieldIds() throws IOException {
+ int index = 0;
+ for (FieldId fieldId : dexBuffer.fieldIds()) {
+ System.out.println("field " + index + ": " + fieldId);
+ index++;
}
+ }
- private void printMethodIds() throws IOException {
- int index = 0;
- for (MethodId methodId : dexBuffer.methodIds()) {
- System.out.println("methodId " + index + ": " + methodId);
- index++;
- }
+ private void printMethodIds() throws IOException {
+ int index = 0;
+ for (MethodId methodId : dexBuffer.methodIds()) {
+ System.out.println("methodId " + index + ": " + methodId);
+ index++;
}
+ }
- private void printTypeLists() throws IOException {
- if (tableOfContents.typeLists.off == -1) {
- System.out.println("No type lists");
- return;
- }
- DexBuffer.Section in = dexBuffer.open(tableOfContents.typeLists.off);
- for (int i = 0; i < tableOfContents.typeLists.size; i++) {
- int size = in.readInt();
- System.out.print("Type list i=" + i + ", size=" + size + ", elements=");
- for (int t = 0; t < size; t++) {
- System.out.print(" " + dexBuffer.typeNames().get((int) in.readShort()));
- }
- if (size % 2 == 1) {
- in.readShort(); // retain alignment
- }
- System.out.println();
- }
+ private void printTypeLists() throws IOException {
+ if (tableOfContents.typeLists.off == -1) {
+ System.out.println("No type lists");
+ return;
}
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.typeLists.off);
+ for (int i = 0; i < tableOfContents.typeLists.size; i++) {
+ int size = in.readInt();
+ System.out.print("Type list i=" + i + ", size=" + size + ", elements=");
+ for (int t = 0; t < size; t++) {
+ System.out.print(" " + dexBuffer.typeNames().get(in.readShort()));
+ }
+ if (size % 2 == 1) {
+ in.readShort(); // retain alignment
+ }
+ System.out.println();
+ }
+ }
- private void printClassDefs() {
- int index = 0;
- for (ClassDef classDef : dexBuffer.classDefs()) {
- System.out.println("class def " + index + ": " + classDef);
- index++;
- }
+ private void printClassDefs() {
+ int index = 0;
+ for (ClassDef classDef : dexBuffer.classDefs()) {
+ System.out.println("class def " + index + ": " + classDef);
+ index++;
}
+ }
- public static void main(String[] args) throws IOException {
- DexIndexPrinter indexPrinter = new DexIndexPrinter(new File(args[0]));
- indexPrinter.printMap();
- indexPrinter.printStrings();
- indexPrinter.printTypeIds();
- indexPrinter.printProtoIds();
- indexPrinter.printFieldIds();
- indexPrinter.printMethodIds();
- indexPrinter.printTypeLists();
- indexPrinter.printClassDefs();
- }
+ public static void main(String[] args) throws IOException {
+ DexIndexPrinter indexPrinter = new DexIndexPrinter(new File(args[0]));
+ indexPrinter.printMap();
+ indexPrinter.printStrings();
+ indexPrinter.printTypeIds();
+ indexPrinter.printProtoIds();
+ indexPrinter.printFieldIds();
+ indexPrinter.printMethodIds();
+ indexPrinter.printTypeLists();
+ indexPrinter.printClassDefs();
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/EncodedValue.java b/dx/src/com/android/jack/dx/io/EncodedValue.java
index 861dfcf..604c80c 100644
--- a/dx/src/com/android/jack/dx/io/EncodedValue.java
+++ b/dx/src/com/android/jack/dx/io/EncodedValue.java
@@ -23,35 +23,37 @@
* An encoded value or array.
*/
public final class EncodedValue implements Comparable<EncodedValue> {
- private final byte[] data;
+ private final byte[] data;
- public EncodedValue(byte[] data) {
- this.data = data;
- }
+ public EncodedValue(byte[] data) {
+ this.data = data;
+ }
- public ByteInput asByteInput() {
- return new ByteArrayByteInput(data);
- }
+ public ByteInput asByteInput() {
+ return new ByteArrayByteInput(data);
+ }
- public byte[] getBytes() {
- return data;
- }
+ public byte[] getBytes() {
+ return data;
+ }
- public void writeTo(DexBuffer.Section out) {
- out.write(data);
- }
+ public void writeTo(DexBuffer.Section out) {
+ out.write(data);
+ }
- @Override public int compareTo(EncodedValue other) {
- int size = Math.min(data.length, other.data.length);
- for (int i = 0; i < size; i++) {
- if (data[i] != other.data[i]) {
- return (data[i] & 0xff) - (other.data[i] & 0xff);
- }
- }
- return data.length - other.data.length;
+ @Override
+ public int compareTo(EncodedValue other) {
+ int size = Math.min(data.length, other.data.length);
+ for (int i = 0; i < size; i++) {
+ if (data[i] != other.data[i]) {
+ return (data[i] & 0xff) - (other.data[i] & 0xff);
+ }
}
+ return data.length - other.data.length;
+ }
- @Override public String toString() {
- return Integer.toHexString(data[0] & 0xff) + "...(" + data.length + ")";
- }
+ @Override
+ public String toString() {
+ return Integer.toHexString(data[0] & 0xff) + "...(" + data.length + ")";
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/EncodedValueReader.java b/dx/src/com/android/jack/dx/io/EncodedValueReader.java
index 694d736..d7eade0 100644
--- a/dx/src/com/android/jack/dx/io/EncodedValueReader.java
+++ b/dx/src/com/android/jack/dx/io/EncodedValueReader.java
@@ -21,126 +21,137 @@
/**
* SAX-style reader for encoded values.
- * TODO: convert this to a pull-style reader
+ * TODO(dx team): convert this to a pull-style reader
*/
public class EncodedValueReader {
- public static final int ENCODED_BYTE = 0x00;
- public static final int ENCODED_SHORT = 0x02;
- public static final int ENCODED_CHAR = 0x03;
- public static final int ENCODED_INT = 0x04;
- public static final int ENCODED_LONG = 0x06;
- public static final int ENCODED_FLOAT = 0x10;
- public static final int ENCODED_DOUBLE = 0x11;
- public static final int ENCODED_STRING = 0x17;
- public static final int ENCODED_TYPE = 0x18;
- public static final int ENCODED_FIELD = 0x19;
- public static final int ENCODED_ENUM = 0x1b;
- public static final int ENCODED_METHOD = 0x1a;
- public static final int ENCODED_ARRAY = 0x1c;
- public static final int ENCODED_ANNOTATION = 0x1d;
- public static final int ENCODED_NULL = 0x1e;
- public static final int ENCODED_BOOLEAN = 0x1f;
+ public static final int ENCODED_BYTE = 0x00;
+ public static final int ENCODED_SHORT = 0x02;
+ public static final int ENCODED_CHAR = 0x03;
+ public static final int ENCODED_INT = 0x04;
+ public static final int ENCODED_LONG = 0x06;
+ public static final int ENCODED_FLOAT = 0x10;
+ public static final int ENCODED_DOUBLE = 0x11;
+ public static final int ENCODED_STRING = 0x17;
+ public static final int ENCODED_TYPE = 0x18;
+ public static final int ENCODED_FIELD = 0x19;
+ public static final int ENCODED_ENUM = 0x1b;
+ public static final int ENCODED_METHOD = 0x1a;
+ public static final int ENCODED_ARRAY = 0x1c;
+ public static final int ENCODED_ANNOTATION = 0x1d;
+ public static final int ENCODED_NULL = 0x1e;
+ public static final int ENCODED_BOOLEAN = 0x1f;
- protected final ByteInput in;
+ protected final ByteInput in;
- public EncodedValueReader(ByteInput in) {
- this.in = in;
+ public EncodedValueReader(ByteInput in) {
+ this.in = in;
+ }
+
+ public EncodedValueReader(EncodedValue in) {
+ this(in.asByteInput());
+ }
+
+ public final void readArray() {
+ int size = Leb128Utils.readUnsignedLeb128(in);
+ visitArray(size);
+
+ for (int i = 0; i < size; i++) {
+ readValue();
}
+ }
- public EncodedValueReader(EncodedValue in) {
- this(in.asByteInput());
+ public final void readAnnotation() {
+ int typeIndex = Leb128Utils.readUnsignedLeb128(in);
+ int size = Leb128Utils.readUnsignedLeb128(in);
+ visitAnnotation(typeIndex, size);
+
+ for (int i = 0; i < size; i++) {
+ visitAnnotationName(Leb128Utils.readUnsignedLeb128(in));
+ readValue();
}
+ }
- public final void readArray() {
- int size = Leb128Utils.readUnsignedLeb128(in);
- visitArray(size);
+ public final void readValue() {
+ int argAndType = in.readByte() & 0xff;
+ int type = argAndType & 0x1f;
+ int arg = (argAndType & 0xe0) >> 5;
+ int size = arg + 1;
- for (int i = 0; i < size; i++) {
- readValue();
- }
+ switch (type) {
+ case ENCODED_BYTE:
+ case ENCODED_SHORT:
+ case ENCODED_CHAR:
+ case ENCODED_INT:
+ case ENCODED_LONG:
+ case ENCODED_FLOAT:
+ case ENCODED_DOUBLE:
+ visitPrimitive(argAndType, type, arg, size);
+ break;
+ case ENCODED_STRING:
+ visitString(type, readIndex(in, size));
+ break;
+ case ENCODED_TYPE:
+ visitType(type, readIndex(in, size));
+ break;
+ case ENCODED_FIELD:
+ case ENCODED_ENUM:
+ visitField(type, readIndex(in, size));
+ break;
+ case ENCODED_METHOD:
+ visitMethod(type, readIndex(in, size));
+ break;
+ case ENCODED_ARRAY:
+ visitArrayValue(argAndType);
+ readArray();
+ break;
+ case ENCODED_ANNOTATION:
+ visitAnnotationValue(argAndType);
+ readAnnotation();
+ break;
+ case ENCODED_NULL:
+ visitEncodedNull(argAndType);
+ break;
+ case ENCODED_BOOLEAN:
+ visitEncodedBoolean(argAndType);
+ break;
}
+ }
- public final void readAnnotation() {
- int typeIndex = Leb128Utils.readUnsignedLeb128(in);
- int size = Leb128Utils.readUnsignedLeb128(in);
- visitAnnotation(typeIndex, size);
+ protected void visitArray(int size) {}
- for (int i = 0; i < size; i++) {
- visitAnnotationName(Leb128Utils.readUnsignedLeb128(in));
- readValue();
- }
+ protected void visitAnnotation(int typeIndex, int size) {}
+
+ protected void visitAnnotationName(int nameIndex) {}
+
+ protected void visitPrimitive(int argAndType, int type, int arg, int size) {
+ for (int i = 0; i < size; i++) {
+ in.readByte();
}
+ }
- public final void readValue() {
- int argAndType = in.readByte() & 0xff;
- int type = argAndType & 0x1f;
- int arg = (argAndType & 0xe0) >> 5;
- int size = arg + 1;
+ protected void visitString(int type, int index) {}
- switch (type) {
- case ENCODED_BYTE:
- case ENCODED_SHORT:
- case ENCODED_CHAR:
- case ENCODED_INT:
- case ENCODED_LONG:
- case ENCODED_FLOAT:
- case ENCODED_DOUBLE:
- visitPrimitive(argAndType, type, arg, size);
- break;
- case ENCODED_STRING:
- visitString(type, readIndex(in, size));
- break;
- case ENCODED_TYPE:
- visitType(type, readIndex(in, size));
- break;
- case ENCODED_FIELD:
- case ENCODED_ENUM:
- visitField(type, readIndex(in, size));
- break;
- case ENCODED_METHOD:
- visitMethod(type, readIndex(in, size));
- break;
- case ENCODED_ARRAY:
- visitArrayValue(argAndType);
- readArray();
- break;
- case ENCODED_ANNOTATION:
- visitAnnotationValue(argAndType);
- readAnnotation();
- break;
- case ENCODED_NULL:
- visitEncodedNull(argAndType);
- break;
- case ENCODED_BOOLEAN:
- visitEncodedBoolean(argAndType);
- break;
- }
+ protected void visitType(int type, int index) {}
+
+ protected void visitField(int type, int index) {}
+
+ protected void visitMethod(int type, int index) {}
+
+ protected void visitArrayValue(int argAndType) {}
+
+ protected void visitAnnotationValue(int argAndType) {}
+
+ protected void visitEncodedBoolean(int argAndType) {}
+
+ protected void visitEncodedNull(int argAndType) {}
+
+ private int readIndex(ByteInput in, int byteCount) {
+ int result = 0;
+ int shift = 0;
+ for (int i = 0; i < byteCount; i++) {
+ result += (in.readByte() & 0xff) << shift;
+ shift += 8;
}
-
- protected void visitArray(int size) {}
- protected void visitAnnotation(int typeIndex, int size) {}
- protected void visitAnnotationName(int nameIndex) {}
- protected void visitPrimitive(int argAndType, int type, int arg, int size) {
- for (int i = 0; i < size; i++) {
- in.readByte();
- }
- }
- protected void visitString(int type, int index) {}
- protected void visitType(int type, int index) {}
- protected void visitField(int type, int index) {}
- protected void visitMethod(int type, int index) {}
- protected void visitArrayValue(int argAndType) {}
- protected void visitAnnotationValue(int argAndType) {}
- protected void visitEncodedBoolean(int argAndType) {}
- protected void visitEncodedNull(int argAndType) {}
-
- private int readIndex(ByteInput in, int byteCount) {
- int result = 0;
- int shift = 0;
- for (int i = 0; i < byteCount; i++) {
- result += (in.readByte() & 0xff) << shift;
- shift += 8;
- }
- return result;
- }
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/FieldId.java b/dx/src/com/android/jack/dx/io/FieldId.java
index 73c749c..a0802a3 100644
--- a/dx/src/com/android/jack/dx/io/FieldId.java
+++ b/dx/src/com/android/jack/dx/io/FieldId.java
@@ -18,51 +18,56 @@
import com.android.jack.dx.util.Unsigned;
+/**
+ * TODO(jack team)
+ */
public final class FieldId implements Comparable<FieldId> {
- private final DexBuffer buffer;
- private final int declaringClassIndex;
- private final int typeIndex;
- private final int nameIndex;
+ private final DexBuffer buffer;
+ private final int declaringClassIndex;
+ private final int typeIndex;
+ private final int nameIndex;
- public FieldId(DexBuffer buffer, int declaringClassIndex, int typeIndex, int nameIndex) {
- this.buffer = buffer;
- this.declaringClassIndex = declaringClassIndex;
- this.typeIndex = typeIndex;
- this.nameIndex = nameIndex;
- }
+ public FieldId(DexBuffer buffer, int declaringClassIndex, int typeIndex, int nameIndex) {
+ this.buffer = buffer;
+ this.declaringClassIndex = declaringClassIndex;
+ this.typeIndex = typeIndex;
+ this.nameIndex = nameIndex;
+ }
- public int getDeclaringClassIndex() {
- return declaringClassIndex;
- }
+ public int getDeclaringClassIndex() {
+ return declaringClassIndex;
+ }
- public int getTypeIndex() {
- return typeIndex;
- }
+ public int getTypeIndex() {
+ return typeIndex;
+ }
- public int getNameIndex() {
- return nameIndex;
- }
+ public int getNameIndex() {
+ return nameIndex;
+ }
- public int compareTo(FieldId other) {
- if (declaringClassIndex != other.declaringClassIndex) {
- return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
+ @Override
+ public int compareTo(FieldId other) {
+ if (declaringClassIndex != other.declaringClassIndex) {
+ return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
}
+ if (nameIndex != other.nameIndex) {
+ return Unsigned.compare(nameIndex, other.nameIndex);
+ }
+ return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
+ }
- public void writeTo(DexBuffer.Section out) {
- out.writeUnsignedShort(declaringClassIndex);
- out.writeUnsignedShort(typeIndex);
- out.writeInt(nameIndex);
- }
+ public void writeTo(DexBuffer.Section out) {
+ out.writeUnsignedShort(declaringClassIndex);
+ out.writeUnsignedShort(typeIndex);
+ out.writeInt(nameIndex);
+ }
- @Override public String toString() {
- if (buffer == null) {
- return declaringClassIndex + " " + typeIndex + " " + nameIndex;
- }
- return buffer.typeNames().get(typeIndex) + "." + buffer.strings().get(nameIndex);
+ @Override
+ public String toString() {
+ if (buffer == null) {
+ return declaringClassIndex + " " + typeIndex + " " + nameIndex;
}
+ return buffer.typeNames().get(typeIndex) + "." + buffer.strings().get(nameIndex);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/IndexType.java b/dx/src/com/android/jack/dx/io/IndexType.java
index 0538966..515af59 100644
--- a/dx/src/com/android/jack/dx/io/IndexType.java
+++ b/dx/src/com/android/jack/dx/io/IndexType.java
@@ -20,33 +20,33 @@
* The various types that an index in a Dalvik instruction might refer to.
*/
public enum IndexType {
- /** "Unknown." Used for undefined opcodes. */
- UNKNOWN,
+ /** "Unknown." Used for undefined opcodes. */
+ UNKNOWN,
- /** no index used */
- NONE,
+ /** no index used */
+ NONE,
- /** "It depends." Used for {@code throw-verification-error}. */
- VARIES,
+ /** "It depends." Used for {@code throw-verification-error}. */
+ VARIES,
- /** type reference index */
- TYPE_REF,
+ /** type reference index */
+ TYPE_REF,
- /** string reference index */
- STRING_REF,
+ /** string reference index */
+ STRING_REF,
- /** method reference index */
- METHOD_REF,
+ /** method reference index */
+ METHOD_REF,
- /** field reference index */
- FIELD_REF,
+ /** field reference index */
+ FIELD_REF,
- /** inline method index (for inline linked method invocations) */
- INLINE_METHOD,
+ /** inline method index (for inline linked method invocations) */
+ INLINE_METHOD,
- /** direct vtable offset (for static linked method invocations) */
- VTABLE_OFFSET,
+ /** direct vtable offset (for static linked method invocations) */
+ VTABLE_OFFSET,
- /** direct field offset (for static linked field accesses) */
- FIELD_OFFSET;
+ /** direct field offset (for static linked field accesses) */
+ FIELD_OFFSET;
}
diff --git a/dx/src/com/android/jack/dx/io/MethodId.java b/dx/src/com/android/jack/dx/io/MethodId.java
index 172c02f..da2a683 100644
--- a/dx/src/com/android/jack/dx/io/MethodId.java
+++ b/dx/src/com/android/jack/dx/io/MethodId.java
@@ -18,53 +18,57 @@
import com.android.jack.dx.util.Unsigned;
+/**
+ * TODO(jack team)
+ */
public final class MethodId implements Comparable<MethodId> {
- private final DexBuffer buffer;
- private final int declaringClassIndex;
- private final int protoIndex;
- private final int nameIndex;
+ private final DexBuffer buffer;
+ private final int declaringClassIndex;
+ private final int protoIndex;
+ private final int nameIndex;
- public MethodId(DexBuffer buffer, int declaringClassIndex, int protoIndex, int nameIndex) {
- this.buffer = buffer;
- this.declaringClassIndex = declaringClassIndex;
- this.protoIndex = protoIndex;
- this.nameIndex = nameIndex;
- }
+ public MethodId(DexBuffer buffer, int declaringClassIndex, int protoIndex, int nameIndex) {
+ this.buffer = buffer;
+ this.declaringClassIndex = declaringClassIndex;
+ this.protoIndex = protoIndex;
+ this.nameIndex = nameIndex;
+ }
- public int getDeclaringClassIndex() {
- return declaringClassIndex;
- }
+ public int getDeclaringClassIndex() {
+ return declaringClassIndex;
+ }
- public int getProtoIndex() {
- return protoIndex;
- }
+ public int getProtoIndex() {
+ return protoIndex;
+ }
- public int getNameIndex() {
- return nameIndex;
- }
+ public int getNameIndex() {
+ return nameIndex;
+ }
- public int compareTo(MethodId other) {
- if (declaringClassIndex != other.declaringClassIndex) {
- return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(protoIndex, other.protoIndex);
+ @Override
+ public int compareTo(MethodId other) {
+ if (declaringClassIndex != other.declaringClassIndex) {
+ return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
}
+ if (nameIndex != other.nameIndex) {
+ return Unsigned.compare(nameIndex, other.nameIndex);
+ }
+ return Unsigned.compare(protoIndex, other.protoIndex);
+ }
- public void writeTo(DexBuffer.Section out) {
- out.writeUnsignedShort(declaringClassIndex);
- out.writeUnsignedShort(protoIndex);
- out.writeInt(nameIndex);
- }
+ public void writeTo(DexBuffer.Section out) {
+ out.writeUnsignedShort(declaringClassIndex);
+ out.writeUnsignedShort(protoIndex);
+ out.writeInt(nameIndex);
+ }
- @Override public String toString() {
- if (buffer == null) {
- return declaringClassIndex + " " + protoIndex + " " + nameIndex;
- }
- return buffer.typeNames().get(declaringClassIndex)
- + "." + buffer.strings().get(nameIndex)
- + buffer.readTypeList(buffer.protoIds().get(protoIndex).getParametersOffset());
+ @Override
+ public String toString() {
+ if (buffer == null) {
+ return declaringClassIndex + " " + protoIndex + " " + nameIndex;
}
+ return buffer.typeNames().get(declaringClassIndex) + "." + buffer.strings().get(nameIndex)
+ + buffer.readTypeList(buffer.protoIds().get(protoIndex).getParametersOffset());
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/OpcodeInfo.java b/dx/src/com/android/jack/dx/io/OpcodeInfo.java
index 069784a..655e528 100644
--- a/dx/src/com/android/jack/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/jack/dx/io/OpcodeInfo.java
@@ -23,1243 +23,1016 @@
* Information about each Dalvik opcode.
*/
public final class OpcodeInfo {
- /*
- * TODO: Merge at least most of the info from the Dops class into
- * this one.
- */
+ /*
+ * TODO(dx team): Merge at least most of the info from the Dops class into
+ * this one.
+ */
- /** non-null; array containing all the information */
- private static final Info[] INFO;
+ /** non-null; array containing all the information */
+ private static final Info[] INFO;
- /**
- * pseudo-opcode used for nonstandard formatted "instructions"
- * (which are mostly not actually instructions, though they do
- * appear in instruction lists). TODO: Retire the usage of this
- * constant.
- */
- public static final Info SPECIAL_FORMAT =
- new Info(Opcodes.SPECIAL_FORMAT, "<special>",
- InstructionCodec.FORMAT_00X, IndexType.NONE);
+ /**
+ * pseudo-opcode used for nonstandard formatted "instructions"
+ * (which are mostly not actually instructions, though they do
+ * appear in instruction lists). TODO(dx team): Retire the usage of this
+ * constant.
+ */
+ public static final Info SPECIAL_FORMAT =
+ new Info(Opcodes.SPECIAL_FORMAT, "<special>", InstructionCodec.FORMAT_00X, IndexType.NONE);
- // TODO: These payload opcodes should be generated by opcode-gen.
+ // TODO(dx team): These payload opcodes should be generated by opcode-gen.
- public static final Info PACKED_SWITCH_PAYLOAD =
- new Info(Opcodes.PACKED_SWITCH_PAYLOAD, "packed-switch-payload",
- InstructionCodec.FORMAT_PACKED_SWITCH_PAYLOAD,
- IndexType.NONE);
+ public static final Info PACKED_SWITCH_PAYLOAD = new Info(Opcodes.PACKED_SWITCH_PAYLOAD,
+ "packed-switch-payload", InstructionCodec.FORMAT_PACKED_SWITCH_PAYLOAD, IndexType.NONE);
- public static final Info SPARSE_SWITCH_PAYLOAD =
- new Info(Opcodes.SPARSE_SWITCH_PAYLOAD, "sparse-switch-payload",
- InstructionCodec.FORMAT_SPARSE_SWITCH_PAYLOAD,
- IndexType.NONE);
+ public static final Info SPARSE_SWITCH_PAYLOAD = new Info(Opcodes.SPARSE_SWITCH_PAYLOAD,
+ "sparse-switch-payload", InstructionCodec.FORMAT_SPARSE_SWITCH_PAYLOAD, IndexType.NONE);
- public static final Info FILL_ARRAY_DATA_PAYLOAD =
- new Info(Opcodes.FILL_ARRAY_DATA_PAYLOAD, "fill-array-data-payload",
- InstructionCodec.FORMAT_FILL_ARRAY_DATA_PAYLOAD,
- IndexType.NONE);
+ public static final Info FILL_ARRAY_DATA_PAYLOAD = new Info(Opcodes.FILL_ARRAY_DATA_PAYLOAD,
+ "fill-array-data-payload", InstructionCodec.FORMAT_FILL_ARRAY_DATA_PAYLOAD, IndexType.NONE);
- // BEGIN(opcode-info-defs); GENERATED AUTOMATICALLY BY opcode-gen
- public static final Info NOP =
- new Info(Opcodes.NOP, "nop",
- InstructionCodec.FORMAT_10X, IndexType.NONE);
+ // BEGIN(opcode-info-defs); GENERATED AUTOMATICALLY BY opcode-gen
+ public static final Info NOP =
+ new Info(Opcodes.NOP, "nop", InstructionCodec.FORMAT_10X, IndexType.NONE);
- public static final Info MOVE =
- new Info(Opcodes.MOVE, "move",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MOVE =
+ new Info(Opcodes.MOVE, "move", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MOVE_FROM16 =
- new Info(Opcodes.MOVE_FROM16, "move/from16",
- InstructionCodec.FORMAT_22X, IndexType.NONE);
+ public static final Info MOVE_FROM16 =
+ new Info(Opcodes.MOVE_FROM16, "move/from16", InstructionCodec.FORMAT_22X, IndexType.NONE);
- public static final Info MOVE_16 =
- new Info(Opcodes.MOVE_16, "move/16",
- InstructionCodec.FORMAT_32X, IndexType.NONE);
+ public static final Info MOVE_16 =
+ new Info(Opcodes.MOVE_16, "move/16", InstructionCodec.FORMAT_32X, IndexType.NONE);
- public static final Info MOVE_WIDE =
- new Info(Opcodes.MOVE_WIDE, "move-wide",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MOVE_WIDE =
+ new Info(Opcodes.MOVE_WIDE, "move-wide", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MOVE_WIDE_FROM16 =
- new Info(Opcodes.MOVE_WIDE_FROM16, "move-wide/from16",
- InstructionCodec.FORMAT_22X, IndexType.NONE);
+ public static final Info MOVE_WIDE_FROM16 = new Info(Opcodes.MOVE_WIDE_FROM16, "move-wide/from16",
+ InstructionCodec.FORMAT_22X, IndexType.NONE);
- public static final Info MOVE_WIDE_16 =
- new Info(Opcodes.MOVE_WIDE_16, "move-wide/16",
- InstructionCodec.FORMAT_32X, IndexType.NONE);
+ public static final Info MOVE_WIDE_16 =
+ new Info(Opcodes.MOVE_WIDE_16, "move-wide/16", InstructionCodec.FORMAT_32X, IndexType.NONE);
- public static final Info MOVE_OBJECT =
- new Info(Opcodes.MOVE_OBJECT, "move-object",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MOVE_OBJECT =
+ new Info(Opcodes.MOVE_OBJECT, "move-object", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MOVE_OBJECT_FROM16 =
- new Info(Opcodes.MOVE_OBJECT_FROM16, "move-object/from16",
- InstructionCodec.FORMAT_22X, IndexType.NONE);
+ public static final Info MOVE_OBJECT_FROM16 = new Info(Opcodes.MOVE_OBJECT_FROM16,
+ "move-object/from16", InstructionCodec.FORMAT_22X, IndexType.NONE);
- public static final Info MOVE_OBJECT_16 =
- new Info(Opcodes.MOVE_OBJECT_16, "move-object/16",
- InstructionCodec.FORMAT_32X, IndexType.NONE);
+ public static final Info MOVE_OBJECT_16 = new Info(Opcodes.MOVE_OBJECT_16, "move-object/16",
+ InstructionCodec.FORMAT_32X, IndexType.NONE);
- public static final Info MOVE_RESULT =
- new Info(Opcodes.MOVE_RESULT, "move-result",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MOVE_RESULT =
+ new Info(Opcodes.MOVE_RESULT, "move-result", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info MOVE_RESULT_WIDE =
- new Info(Opcodes.MOVE_RESULT_WIDE, "move-result-wide",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MOVE_RESULT_WIDE = new Info(Opcodes.MOVE_RESULT_WIDE, "move-result-wide",
+ InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info MOVE_RESULT_OBJECT =
- new Info(Opcodes.MOVE_RESULT_OBJECT, "move-result-object",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MOVE_RESULT_OBJECT = new Info(Opcodes.MOVE_RESULT_OBJECT,
+ "move-result-object", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info MOVE_EXCEPTION =
- new Info(Opcodes.MOVE_EXCEPTION, "move-exception",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MOVE_EXCEPTION = new Info(Opcodes.MOVE_EXCEPTION, "move-exception",
+ InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info RETURN_VOID =
- new Info(Opcodes.RETURN_VOID, "return-void",
- InstructionCodec.FORMAT_10X, IndexType.NONE);
+ public static final Info RETURN_VOID =
+ new Info(Opcodes.RETURN_VOID, "return-void", InstructionCodec.FORMAT_10X, IndexType.NONE);
- public static final Info RETURN =
- new Info(Opcodes.RETURN, "return",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info RETURN =
+ new Info(Opcodes.RETURN, "return", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info RETURN_WIDE =
- new Info(Opcodes.RETURN_WIDE, "return-wide",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info RETURN_WIDE =
+ new Info(Opcodes.RETURN_WIDE, "return-wide", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info RETURN_OBJECT =
- new Info(Opcodes.RETURN_OBJECT, "return-object",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info RETURN_OBJECT =
+ new Info(Opcodes.RETURN_OBJECT, "return-object", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info CONST_4 =
- new Info(Opcodes.CONST_4, "const/4",
- InstructionCodec.FORMAT_11N, IndexType.NONE);
+ public static final Info CONST_4 =
+ new Info(Opcodes.CONST_4, "const/4", InstructionCodec.FORMAT_11N, IndexType.NONE);
- public static final Info CONST_16 =
- new Info(Opcodes.CONST_16, "const/16",
- InstructionCodec.FORMAT_21S, IndexType.NONE);
+ public static final Info CONST_16 =
+ new Info(Opcodes.CONST_16, "const/16", InstructionCodec.FORMAT_21S, IndexType.NONE);
- public static final Info CONST =
- new Info(Opcodes.CONST, "const",
- InstructionCodec.FORMAT_31I, IndexType.NONE);
+ public static final Info CONST =
+ new Info(Opcodes.CONST, "const", InstructionCodec.FORMAT_31I, IndexType.NONE);
- public static final Info CONST_HIGH16 =
- new Info(Opcodes.CONST_HIGH16, "const/high16",
- InstructionCodec.FORMAT_21H, IndexType.NONE);
+ public static final Info CONST_HIGH16 =
+ new Info(Opcodes.CONST_HIGH16, "const/high16", InstructionCodec.FORMAT_21H, IndexType.NONE);
- public static final Info CONST_WIDE_16 =
- new Info(Opcodes.CONST_WIDE_16, "const-wide/16",
- InstructionCodec.FORMAT_21S, IndexType.NONE);
+ public static final Info CONST_WIDE_16 =
+ new Info(Opcodes.CONST_WIDE_16, "const-wide/16", InstructionCodec.FORMAT_21S, IndexType.NONE);
- public static final Info CONST_WIDE_32 =
- new Info(Opcodes.CONST_WIDE_32, "const-wide/32",
- InstructionCodec.FORMAT_31I, IndexType.NONE);
+ public static final Info CONST_WIDE_32 =
+ new Info(Opcodes.CONST_WIDE_32, "const-wide/32", InstructionCodec.FORMAT_31I, IndexType.NONE);
- public static final Info CONST_WIDE =
- new Info(Opcodes.CONST_WIDE, "const-wide",
- InstructionCodec.FORMAT_51L, IndexType.NONE);
+ public static final Info CONST_WIDE =
+ new Info(Opcodes.CONST_WIDE, "const-wide", InstructionCodec.FORMAT_51L, IndexType.NONE);
- public static final Info CONST_WIDE_HIGH16 =
- new Info(Opcodes.CONST_WIDE_HIGH16, "const-wide/high16",
- InstructionCodec.FORMAT_21H, IndexType.NONE);
+ public static final Info CONST_WIDE_HIGH16 = new Info(Opcodes.CONST_WIDE_HIGH16,
+ "const-wide/high16", InstructionCodec.FORMAT_21H, IndexType.NONE);
- public static final Info CONST_STRING =
- new Info(Opcodes.CONST_STRING, "const-string",
- InstructionCodec.FORMAT_21C, IndexType.STRING_REF);
+ public static final Info CONST_STRING = new Info(Opcodes.CONST_STRING, "const-string",
+ InstructionCodec.FORMAT_21C, IndexType.STRING_REF);
- public static final Info CONST_STRING_JUMBO =
- new Info(Opcodes.CONST_STRING_JUMBO, "const-string/jumbo",
- InstructionCodec.FORMAT_31C, IndexType.STRING_REF);
+ public static final Info CONST_STRING_JUMBO = new Info(Opcodes.CONST_STRING_JUMBO,
+ "const-string/jumbo", InstructionCodec.FORMAT_31C, IndexType.STRING_REF);
- public static final Info CONST_CLASS =
- new Info(Opcodes.CONST_CLASS, "const-class",
- InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+ public static final Info CONST_CLASS =
+ new Info(Opcodes.CONST_CLASS, "const-class", InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
- public static final Info MONITOR_ENTER =
- new Info(Opcodes.MONITOR_ENTER, "monitor-enter",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MONITOR_ENTER =
+ new Info(Opcodes.MONITOR_ENTER, "monitor-enter", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info MONITOR_EXIT =
- new Info(Opcodes.MONITOR_EXIT, "monitor-exit",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info MONITOR_EXIT =
+ new Info(Opcodes.MONITOR_EXIT, "monitor-exit", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info CHECK_CAST =
- new Info(Opcodes.CHECK_CAST, "check-cast",
- InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+ public static final Info CHECK_CAST =
+ new Info(Opcodes.CHECK_CAST, "check-cast", InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
- public static final Info INSTANCE_OF =
- new Info(Opcodes.INSTANCE_OF, "instance-of",
- InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
+ public static final Info INSTANCE_OF =
+ new Info(Opcodes.INSTANCE_OF, "instance-of", InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
- public static final Info ARRAY_LENGTH =
- new Info(Opcodes.ARRAY_LENGTH, "array-length",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info ARRAY_LENGTH =
+ new Info(Opcodes.ARRAY_LENGTH, "array-length", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NEW_INSTANCE =
- new Info(Opcodes.NEW_INSTANCE, "new-instance",
- InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+ public static final Info NEW_INSTANCE = new Info(Opcodes.NEW_INSTANCE, "new-instance",
+ InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
- public static final Info NEW_ARRAY =
- new Info(Opcodes.NEW_ARRAY, "new-array",
- InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
+ public static final Info NEW_ARRAY =
+ new Info(Opcodes.NEW_ARRAY, "new-array", InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
- public static final Info FILLED_NEW_ARRAY =
- new Info(Opcodes.FILLED_NEW_ARRAY, "filled-new-array",
- InstructionCodec.FORMAT_35C, IndexType.TYPE_REF);
+ public static final Info FILLED_NEW_ARRAY = new Info(Opcodes.FILLED_NEW_ARRAY, "filled-new-array",
+ InstructionCodec.FORMAT_35C, IndexType.TYPE_REF);
- public static final Info FILLED_NEW_ARRAY_RANGE =
- new Info(Opcodes.FILLED_NEW_ARRAY_RANGE, "filled-new-array/range",
- InstructionCodec.FORMAT_3RC, IndexType.TYPE_REF);
+ public static final Info FILLED_NEW_ARRAY_RANGE = new Info(Opcodes.FILLED_NEW_ARRAY_RANGE,
+ "filled-new-array/range", InstructionCodec.FORMAT_3RC, IndexType.TYPE_REF);
- public static final Info FILL_ARRAY_DATA =
- new Info(Opcodes.FILL_ARRAY_DATA, "fill-array-data",
- InstructionCodec.FORMAT_31T, IndexType.NONE);
+ public static final Info FILL_ARRAY_DATA = new Info(Opcodes.FILL_ARRAY_DATA, "fill-array-data",
+ InstructionCodec.FORMAT_31T, IndexType.NONE);
- public static final Info THROW =
- new Info(Opcodes.THROW, "throw",
- InstructionCodec.FORMAT_11X, IndexType.NONE);
+ public static final Info THROW =
+ new Info(Opcodes.THROW, "throw", InstructionCodec.FORMAT_11X, IndexType.NONE);
- public static final Info GOTO =
- new Info(Opcodes.GOTO, "goto",
- InstructionCodec.FORMAT_10T, IndexType.NONE);
+ public static final Info GOTO =
+ new Info(Opcodes.GOTO, "goto", InstructionCodec.FORMAT_10T, IndexType.NONE);
- public static final Info GOTO_16 =
- new Info(Opcodes.GOTO_16, "goto/16",
- InstructionCodec.FORMAT_20T, IndexType.NONE);
+ public static final Info GOTO_16 =
+ new Info(Opcodes.GOTO_16, "goto/16", InstructionCodec.FORMAT_20T, IndexType.NONE);
- public static final Info GOTO_32 =
- new Info(Opcodes.GOTO_32, "goto/32",
- InstructionCodec.FORMAT_30T, IndexType.NONE);
+ public static final Info GOTO_32 =
+ new Info(Opcodes.GOTO_32, "goto/32", InstructionCodec.FORMAT_30T, IndexType.NONE);
- public static final Info PACKED_SWITCH =
- new Info(Opcodes.PACKED_SWITCH, "packed-switch",
- InstructionCodec.FORMAT_31T, IndexType.NONE);
+ public static final Info PACKED_SWITCH =
+ new Info(Opcodes.PACKED_SWITCH, "packed-switch", InstructionCodec.FORMAT_31T, IndexType.NONE);
- public static final Info SPARSE_SWITCH =
- new Info(Opcodes.SPARSE_SWITCH, "sparse-switch",
- InstructionCodec.FORMAT_31T, IndexType.NONE);
+ public static final Info SPARSE_SWITCH =
+ new Info(Opcodes.SPARSE_SWITCH, "sparse-switch", InstructionCodec.FORMAT_31T, IndexType.NONE);
- public static final Info CMPL_FLOAT =
- new Info(Opcodes.CMPL_FLOAT, "cmpl-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info CMPL_FLOAT =
+ new Info(Opcodes.CMPL_FLOAT, "cmpl-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info CMPG_FLOAT =
- new Info(Opcodes.CMPG_FLOAT, "cmpg-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info CMPG_FLOAT =
+ new Info(Opcodes.CMPG_FLOAT, "cmpg-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info CMPL_DOUBLE =
- new Info(Opcodes.CMPL_DOUBLE, "cmpl-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info CMPL_DOUBLE =
+ new Info(Opcodes.CMPL_DOUBLE, "cmpl-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info CMPG_DOUBLE =
- new Info(Opcodes.CMPG_DOUBLE, "cmpg-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info CMPG_DOUBLE =
+ new Info(Opcodes.CMPG_DOUBLE, "cmpg-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info CMP_LONG =
- new Info(Opcodes.CMP_LONG, "cmp-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info CMP_LONG =
+ new Info(Opcodes.CMP_LONG, "cmp-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info IF_EQ =
- new Info(Opcodes.IF_EQ, "if-eq",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_EQ =
+ new Info(Opcodes.IF_EQ, "if-eq", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_NE =
- new Info(Opcodes.IF_NE, "if-ne",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_NE =
+ new Info(Opcodes.IF_NE, "if-ne", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_LT =
- new Info(Opcodes.IF_LT, "if-lt",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_LT =
+ new Info(Opcodes.IF_LT, "if-lt", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_GE =
- new Info(Opcodes.IF_GE, "if-ge",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_GE =
+ new Info(Opcodes.IF_GE, "if-ge", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_GT =
- new Info(Opcodes.IF_GT, "if-gt",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_GT =
+ new Info(Opcodes.IF_GT, "if-gt", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_LE =
- new Info(Opcodes.IF_LE, "if-le",
- InstructionCodec.FORMAT_22T, IndexType.NONE);
+ public static final Info IF_LE =
+ new Info(Opcodes.IF_LE, "if-le", InstructionCodec.FORMAT_22T, IndexType.NONE);
- public static final Info IF_EQZ =
- new Info(Opcodes.IF_EQZ, "if-eqz",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_EQZ =
+ new Info(Opcodes.IF_EQZ, "if-eqz", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info IF_NEZ =
- new Info(Opcodes.IF_NEZ, "if-nez",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_NEZ =
+ new Info(Opcodes.IF_NEZ, "if-nez", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info IF_LTZ =
- new Info(Opcodes.IF_LTZ, "if-ltz",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_LTZ =
+ new Info(Opcodes.IF_LTZ, "if-ltz", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info IF_GEZ =
- new Info(Opcodes.IF_GEZ, "if-gez",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_GEZ =
+ new Info(Opcodes.IF_GEZ, "if-gez", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info IF_GTZ =
- new Info(Opcodes.IF_GTZ, "if-gtz",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_GTZ =
+ new Info(Opcodes.IF_GTZ, "if-gtz", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info IF_LEZ =
- new Info(Opcodes.IF_LEZ, "if-lez",
- InstructionCodec.FORMAT_21T, IndexType.NONE);
+ public static final Info IF_LEZ =
+ new Info(Opcodes.IF_LEZ, "if-lez", InstructionCodec.FORMAT_21T, IndexType.NONE);
- public static final Info AGET =
- new Info(Opcodes.AGET, "aget",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET =
+ new Info(Opcodes.AGET, "aget", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_WIDE =
- new Info(Opcodes.AGET_WIDE, "aget-wide",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_WIDE =
+ new Info(Opcodes.AGET_WIDE, "aget-wide", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_OBJECT =
- new Info(Opcodes.AGET_OBJECT, "aget-object",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_OBJECT =
+ new Info(Opcodes.AGET_OBJECT, "aget-object", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_BOOLEAN =
- new Info(Opcodes.AGET_BOOLEAN, "aget-boolean",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_BOOLEAN =
+ new Info(Opcodes.AGET_BOOLEAN, "aget-boolean", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_BYTE =
- new Info(Opcodes.AGET_BYTE, "aget-byte",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_BYTE =
+ new Info(Opcodes.AGET_BYTE, "aget-byte", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_CHAR =
- new Info(Opcodes.AGET_CHAR, "aget-char",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_CHAR =
+ new Info(Opcodes.AGET_CHAR, "aget-char", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AGET_SHORT =
- new Info(Opcodes.AGET_SHORT, "aget-short",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AGET_SHORT =
+ new Info(Opcodes.AGET_SHORT, "aget-short", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT =
- new Info(Opcodes.APUT, "aput",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT =
+ new Info(Opcodes.APUT, "aput", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_WIDE =
- new Info(Opcodes.APUT_WIDE, "aput-wide",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_WIDE =
+ new Info(Opcodes.APUT_WIDE, "aput-wide", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_OBJECT =
- new Info(Opcodes.APUT_OBJECT, "aput-object",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_OBJECT =
+ new Info(Opcodes.APUT_OBJECT, "aput-object", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_BOOLEAN =
- new Info(Opcodes.APUT_BOOLEAN, "aput-boolean",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_BOOLEAN =
+ new Info(Opcodes.APUT_BOOLEAN, "aput-boolean", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_BYTE =
- new Info(Opcodes.APUT_BYTE, "aput-byte",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_BYTE =
+ new Info(Opcodes.APUT_BYTE, "aput-byte", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_CHAR =
- new Info(Opcodes.APUT_CHAR, "aput-char",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_CHAR =
+ new Info(Opcodes.APUT_CHAR, "aput-char", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info APUT_SHORT =
- new Info(Opcodes.APUT_SHORT, "aput-short",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info APUT_SHORT =
+ new Info(Opcodes.APUT_SHORT, "aput-short", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info IGET =
- new Info(Opcodes.IGET, "iget",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET =
+ new Info(Opcodes.IGET, "iget", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_WIDE =
- new Info(Opcodes.IGET_WIDE, "iget-wide",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_WIDE =
+ new Info(Opcodes.IGET_WIDE, "iget-wide", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_OBJECT =
- new Info(Opcodes.IGET_OBJECT, "iget-object",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_OBJECT = new Info(Opcodes.IGET_OBJECT, "iget-object",
+ InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_BOOLEAN =
- new Info(Opcodes.IGET_BOOLEAN, "iget-boolean",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_BOOLEAN = new Info(Opcodes.IGET_BOOLEAN, "iget-boolean",
+ InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_BYTE =
- new Info(Opcodes.IGET_BYTE, "iget-byte",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_BYTE =
+ new Info(Opcodes.IGET_BYTE, "iget-byte", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_CHAR =
- new Info(Opcodes.IGET_CHAR, "iget-char",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_CHAR =
+ new Info(Opcodes.IGET_CHAR, "iget-char", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IGET_SHORT =
- new Info(Opcodes.IGET_SHORT, "iget-short",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IGET_SHORT =
+ new Info(Opcodes.IGET_SHORT, "iget-short", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT =
- new Info(Opcodes.IPUT, "iput",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT =
+ new Info(Opcodes.IPUT, "iput", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_WIDE =
- new Info(Opcodes.IPUT_WIDE, "iput-wide",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_WIDE =
+ new Info(Opcodes.IPUT_WIDE, "iput-wide", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_OBJECT =
- new Info(Opcodes.IPUT_OBJECT, "iput-object",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_OBJECT = new Info(Opcodes.IPUT_OBJECT, "iput-object",
+ InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_BOOLEAN =
- new Info(Opcodes.IPUT_BOOLEAN, "iput-boolean",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_BOOLEAN = new Info(Opcodes.IPUT_BOOLEAN, "iput-boolean",
+ InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_BYTE =
- new Info(Opcodes.IPUT_BYTE, "iput-byte",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_BYTE =
+ new Info(Opcodes.IPUT_BYTE, "iput-byte", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_CHAR =
- new Info(Opcodes.IPUT_CHAR, "iput-char",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_CHAR =
+ new Info(Opcodes.IPUT_CHAR, "iput-char", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info IPUT_SHORT =
- new Info(Opcodes.IPUT_SHORT, "iput-short",
- InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+ public static final Info IPUT_SHORT =
+ new Info(Opcodes.IPUT_SHORT, "iput-short", InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
- public static final Info SGET =
- new Info(Opcodes.SGET, "sget",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET =
+ new Info(Opcodes.SGET, "sget", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_WIDE =
- new Info(Opcodes.SGET_WIDE, "sget-wide",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_WIDE =
+ new Info(Opcodes.SGET_WIDE, "sget-wide", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_OBJECT =
- new Info(Opcodes.SGET_OBJECT, "sget-object",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_OBJECT = new Info(Opcodes.SGET_OBJECT, "sget-object",
+ InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_BOOLEAN =
- new Info(Opcodes.SGET_BOOLEAN, "sget-boolean",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_BOOLEAN = new Info(Opcodes.SGET_BOOLEAN, "sget-boolean",
+ InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_BYTE =
- new Info(Opcodes.SGET_BYTE, "sget-byte",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_BYTE =
+ new Info(Opcodes.SGET_BYTE, "sget-byte", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_CHAR =
- new Info(Opcodes.SGET_CHAR, "sget-char",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_CHAR =
+ new Info(Opcodes.SGET_CHAR, "sget-char", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SGET_SHORT =
- new Info(Opcodes.SGET_SHORT, "sget-short",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SGET_SHORT =
+ new Info(Opcodes.SGET_SHORT, "sget-short", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT =
- new Info(Opcodes.SPUT, "sput",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT =
+ new Info(Opcodes.SPUT, "sput", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_WIDE =
- new Info(Opcodes.SPUT_WIDE, "sput-wide",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_WIDE =
+ new Info(Opcodes.SPUT_WIDE, "sput-wide", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_OBJECT =
- new Info(Opcodes.SPUT_OBJECT, "sput-object",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_OBJECT = new Info(Opcodes.SPUT_OBJECT, "sput-object",
+ InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_BOOLEAN =
- new Info(Opcodes.SPUT_BOOLEAN, "sput-boolean",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_BOOLEAN = new Info(Opcodes.SPUT_BOOLEAN, "sput-boolean",
+ InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_BYTE =
- new Info(Opcodes.SPUT_BYTE, "sput-byte",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_BYTE =
+ new Info(Opcodes.SPUT_BYTE, "sput-byte", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_CHAR =
- new Info(Opcodes.SPUT_CHAR, "sput-char",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_CHAR =
+ new Info(Opcodes.SPUT_CHAR, "sput-char", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info SPUT_SHORT =
- new Info(Opcodes.SPUT_SHORT, "sput-short",
- InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+ public static final Info SPUT_SHORT =
+ new Info(Opcodes.SPUT_SHORT, "sput-short", InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
- public static final Info INVOKE_VIRTUAL =
- new Info(Opcodes.INVOKE_VIRTUAL, "invoke-virtual",
- InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+ public static final Info INVOKE_VIRTUAL = new Info(Opcodes.INVOKE_VIRTUAL, "invoke-virtual",
+ InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
- public static final Info INVOKE_SUPER =
- new Info(Opcodes.INVOKE_SUPER, "invoke-super",
- InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+ public static final Info INVOKE_SUPER = new Info(Opcodes.INVOKE_SUPER, "invoke-super",
+ InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
- public static final Info INVOKE_DIRECT =
- new Info(Opcodes.INVOKE_DIRECT, "invoke-direct",
- InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+ public static final Info INVOKE_DIRECT = new Info(Opcodes.INVOKE_DIRECT, "invoke-direct",
+ InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
- public static final Info INVOKE_STATIC =
- new Info(Opcodes.INVOKE_STATIC, "invoke-static",
- InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+ public static final Info INVOKE_STATIC = new Info(Opcodes.INVOKE_STATIC, "invoke-static",
+ InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
- public static final Info INVOKE_INTERFACE =
- new Info(Opcodes.INVOKE_INTERFACE, "invoke-interface",
- InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+ public static final Info INVOKE_INTERFACE = new Info(Opcodes.INVOKE_INTERFACE, "invoke-interface",
+ InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
- public static final Info INVOKE_VIRTUAL_RANGE =
- new Info(Opcodes.INVOKE_VIRTUAL_RANGE, "invoke-virtual/range",
- InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+ public static final Info INVOKE_VIRTUAL_RANGE = new Info(Opcodes.INVOKE_VIRTUAL_RANGE,
+ "invoke-virtual/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
- public static final Info INVOKE_SUPER_RANGE =
- new Info(Opcodes.INVOKE_SUPER_RANGE, "invoke-super/range",
- InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+ public static final Info INVOKE_SUPER_RANGE = new Info(Opcodes.INVOKE_SUPER_RANGE,
+ "invoke-super/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
- public static final Info INVOKE_DIRECT_RANGE =
- new Info(Opcodes.INVOKE_DIRECT_RANGE, "invoke-direct/range",
- InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+ public static final Info INVOKE_DIRECT_RANGE = new Info(Opcodes.INVOKE_DIRECT_RANGE,
+ "invoke-direct/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
- public static final Info INVOKE_STATIC_RANGE =
- new Info(Opcodes.INVOKE_STATIC_RANGE, "invoke-static/range",
- InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+ public static final Info INVOKE_STATIC_RANGE = new Info(Opcodes.INVOKE_STATIC_RANGE,
+ "invoke-static/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
- public static final Info INVOKE_INTERFACE_RANGE =
- new Info(Opcodes.INVOKE_INTERFACE_RANGE, "invoke-interface/range",
- InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+ public static final Info INVOKE_INTERFACE_RANGE = new Info(Opcodes.INVOKE_INTERFACE_RANGE,
+ "invoke-interface/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
- public static final Info NEG_INT =
- new Info(Opcodes.NEG_INT, "neg-int",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NEG_INT =
+ new Info(Opcodes.NEG_INT, "neg-int", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NOT_INT =
- new Info(Opcodes.NOT_INT, "not-int",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NOT_INT =
+ new Info(Opcodes.NOT_INT, "not-int", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NEG_LONG =
- new Info(Opcodes.NEG_LONG, "neg-long",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NEG_LONG =
+ new Info(Opcodes.NEG_LONG, "neg-long", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NOT_LONG =
- new Info(Opcodes.NOT_LONG, "not-long",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NOT_LONG =
+ new Info(Opcodes.NOT_LONG, "not-long", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NEG_FLOAT =
- new Info(Opcodes.NEG_FLOAT, "neg-float",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NEG_FLOAT =
+ new Info(Opcodes.NEG_FLOAT, "neg-float", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info NEG_DOUBLE =
- new Info(Opcodes.NEG_DOUBLE, "neg-double",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info NEG_DOUBLE =
+ new Info(Opcodes.NEG_DOUBLE, "neg-double", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_LONG =
- new Info(Opcodes.INT_TO_LONG, "int-to-long",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_LONG =
+ new Info(Opcodes.INT_TO_LONG, "int-to-long", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_FLOAT =
- new Info(Opcodes.INT_TO_FLOAT, "int-to-float",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_FLOAT =
+ new Info(Opcodes.INT_TO_FLOAT, "int-to-float", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_DOUBLE =
- new Info(Opcodes.INT_TO_DOUBLE, "int-to-double",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_DOUBLE =
+ new Info(Opcodes.INT_TO_DOUBLE, "int-to-double", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info LONG_TO_INT =
- new Info(Opcodes.LONG_TO_INT, "long-to-int",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info LONG_TO_INT =
+ new Info(Opcodes.LONG_TO_INT, "long-to-int", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info LONG_TO_FLOAT =
- new Info(Opcodes.LONG_TO_FLOAT, "long-to-float",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info LONG_TO_FLOAT =
+ new Info(Opcodes.LONG_TO_FLOAT, "long-to-float", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info LONG_TO_DOUBLE =
- new Info(Opcodes.LONG_TO_DOUBLE, "long-to-double",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info LONG_TO_DOUBLE = new Info(Opcodes.LONG_TO_DOUBLE, "long-to-double",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info FLOAT_TO_INT =
- new Info(Opcodes.FLOAT_TO_INT, "float-to-int",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info FLOAT_TO_INT =
+ new Info(Opcodes.FLOAT_TO_INT, "float-to-int", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info FLOAT_TO_LONG =
- new Info(Opcodes.FLOAT_TO_LONG, "float-to-long",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info FLOAT_TO_LONG =
+ new Info(Opcodes.FLOAT_TO_LONG, "float-to-long", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info FLOAT_TO_DOUBLE =
- new Info(Opcodes.FLOAT_TO_DOUBLE, "float-to-double",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info FLOAT_TO_DOUBLE = new Info(Opcodes.FLOAT_TO_DOUBLE, "float-to-double",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DOUBLE_TO_INT =
- new Info(Opcodes.DOUBLE_TO_INT, "double-to-int",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DOUBLE_TO_INT =
+ new Info(Opcodes.DOUBLE_TO_INT, "double-to-int", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DOUBLE_TO_LONG =
- new Info(Opcodes.DOUBLE_TO_LONG, "double-to-long",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DOUBLE_TO_LONG = new Info(Opcodes.DOUBLE_TO_LONG, "double-to-long",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DOUBLE_TO_FLOAT =
- new Info(Opcodes.DOUBLE_TO_FLOAT, "double-to-float",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DOUBLE_TO_FLOAT = new Info(Opcodes.DOUBLE_TO_FLOAT, "double-to-float",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_BYTE =
- new Info(Opcodes.INT_TO_BYTE, "int-to-byte",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_BYTE =
+ new Info(Opcodes.INT_TO_BYTE, "int-to-byte", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_CHAR =
- new Info(Opcodes.INT_TO_CHAR, "int-to-char",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_CHAR =
+ new Info(Opcodes.INT_TO_CHAR, "int-to-char", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info INT_TO_SHORT =
- new Info(Opcodes.INT_TO_SHORT, "int-to-short",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info INT_TO_SHORT =
+ new Info(Opcodes.INT_TO_SHORT, "int-to-short", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info ADD_INT =
- new Info(Opcodes.ADD_INT, "add-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info ADD_INT =
+ new Info(Opcodes.ADD_INT, "add-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SUB_INT =
- new Info(Opcodes.SUB_INT, "sub-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SUB_INT =
+ new Info(Opcodes.SUB_INT, "sub-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info MUL_INT =
- new Info(Opcodes.MUL_INT, "mul-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info MUL_INT =
+ new Info(Opcodes.MUL_INT, "mul-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info DIV_INT =
- new Info(Opcodes.DIV_INT, "div-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info DIV_INT =
+ new Info(Opcodes.DIV_INT, "div-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info REM_INT =
- new Info(Opcodes.REM_INT, "rem-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info REM_INT =
+ new Info(Opcodes.REM_INT, "rem-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AND_INT =
- new Info(Opcodes.AND_INT, "and-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info AND_INT =
+ new Info(Opcodes.AND_INT, "and-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info OR_INT =
- new Info(Opcodes.OR_INT, "or-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info OR_INT =
+ new Info(Opcodes.OR_INT, "or-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info XOR_INT =
- new Info(Opcodes.XOR_INT, "xor-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info XOR_INT =
+ new Info(Opcodes.XOR_INT, "xor-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SHL_INT =
- new Info(Opcodes.SHL_INT, "shl-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SHL_INT =
+ new Info(Opcodes.SHL_INT, "shl-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SHR_INT =
- new Info(Opcodes.SHR_INT, "shr-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SHR_INT =
+ new Info(Opcodes.SHR_INT, "shr-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info USHR_INT =
- new Info(Opcodes.USHR_INT, "ushr-int",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info USHR_INT =
+ new Info(Opcodes.USHR_INT, "ushr-int", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info ADD_LONG =
- new Info(Opcodes.ADD_LONG, "add-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info ADD_LONG =
+ new Info(Opcodes.ADD_LONG, "add-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SUB_LONG =
- new Info(Opcodes.SUB_LONG, "sub-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SUB_LONG =
+ new Info(Opcodes.SUB_LONG, "sub-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info MUL_LONG =
- new Info(Opcodes.MUL_LONG, "mul-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info MUL_LONG =
+ new Info(Opcodes.MUL_LONG, "mul-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info DIV_LONG =
- new Info(Opcodes.DIV_LONG, "div-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info DIV_LONG =
+ new Info(Opcodes.DIV_LONG, "div-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info REM_LONG =
- new Info(Opcodes.REM_LONG, "rem-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info REM_LONG =
+ new Info(Opcodes.REM_LONG, "rem-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+ public static final Info AND_LONG =
+ new Info(Opcodes.AND_LONG, "and-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+ public static final Info OR_LONG =
+ new Info(Opcodes.OR_LONG, "or-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+ public static final Info XOR_LONG =
+ new Info(Opcodes.XOR_LONG, "xor-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info AND_LONG =
- new Info(Opcodes.AND_LONG, "and-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SHL_LONG =
+ new Info(Opcodes.SHL_LONG, "shl-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info OR_LONG =
- new Info(Opcodes.OR_LONG, "or-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SHR_LONG =
+ new Info(Opcodes.SHR_LONG, "shr-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info XOR_LONG =
- new Info(Opcodes.XOR_LONG, "xor-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info USHR_LONG =
+ new Info(Opcodes.USHR_LONG, "ushr-long", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SHL_LONG =
- new Info(Opcodes.SHL_LONG, "shl-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info ADD_FLOAT =
+ new Info(Opcodes.ADD_FLOAT, "add-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SHR_LONG =
- new Info(Opcodes.SHR_LONG, "shr-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SUB_FLOAT =
+ new Info(Opcodes.SUB_FLOAT, "sub-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info USHR_LONG =
- new Info(Opcodes.USHR_LONG, "ushr-long",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info MUL_FLOAT =
+ new Info(Opcodes.MUL_FLOAT, "mul-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info ADD_FLOAT =
- new Info(Opcodes.ADD_FLOAT, "add-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info DIV_FLOAT =
+ new Info(Opcodes.DIV_FLOAT, "div-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SUB_FLOAT =
- new Info(Opcodes.SUB_FLOAT, "sub-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info REM_FLOAT =
+ new Info(Opcodes.REM_FLOAT, "rem-float", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info MUL_FLOAT =
- new Info(Opcodes.MUL_FLOAT, "mul-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info ADD_DOUBLE =
+ new Info(Opcodes.ADD_DOUBLE, "add-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info DIV_FLOAT =
- new Info(Opcodes.DIV_FLOAT, "div-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SUB_DOUBLE =
+ new Info(Opcodes.SUB_DOUBLE, "sub-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info REM_FLOAT =
- new Info(Opcodes.REM_FLOAT, "rem-float",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info MUL_DOUBLE =
+ new Info(Opcodes.MUL_DOUBLE, "mul-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info ADD_DOUBLE =
- new Info(Opcodes.ADD_DOUBLE, "add-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info DIV_DOUBLE =
+ new Info(Opcodes.DIV_DOUBLE, "div-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info SUB_DOUBLE =
- new Info(Opcodes.SUB_DOUBLE, "sub-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info REM_DOUBLE =
+ new Info(Opcodes.REM_DOUBLE, "rem-double", InstructionCodec.FORMAT_23X, IndexType.NONE);
- public static final Info MUL_DOUBLE =
- new Info(Opcodes.MUL_DOUBLE, "mul-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info ADD_INT_2ADDR =
+ new Info(Opcodes.ADD_INT_2ADDR, "add-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DIV_DOUBLE =
- new Info(Opcodes.DIV_DOUBLE, "div-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info SUB_INT_2ADDR =
+ new Info(Opcodes.SUB_INT_2ADDR, "sub-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info REM_DOUBLE =
- new Info(Opcodes.REM_DOUBLE, "rem-double",
- InstructionCodec.FORMAT_23X, IndexType.NONE);
+ public static final Info MUL_INT_2ADDR =
+ new Info(Opcodes.MUL_INT_2ADDR, "mul-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info ADD_INT_2ADDR =
- new Info(Opcodes.ADD_INT_2ADDR, "add-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DIV_INT_2ADDR =
+ new Info(Opcodes.DIV_INT_2ADDR, "div-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SUB_INT_2ADDR =
- new Info(Opcodes.SUB_INT_2ADDR, "sub-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info REM_INT_2ADDR =
+ new Info(Opcodes.REM_INT_2ADDR, "rem-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MUL_INT_2ADDR =
- new Info(Opcodes.MUL_INT_2ADDR, "mul-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info AND_INT_2ADDR =
+ new Info(Opcodes.AND_INT_2ADDR, "and-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DIV_INT_2ADDR =
- new Info(Opcodes.DIV_INT_2ADDR, "div-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info OR_INT_2ADDR =
+ new Info(Opcodes.OR_INT_2ADDR, "or-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info REM_INT_2ADDR =
- new Info(Opcodes.REM_INT_2ADDR, "rem-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info XOR_INT_2ADDR =
+ new Info(Opcodes.XOR_INT_2ADDR, "xor-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info AND_INT_2ADDR =
- new Info(Opcodes.AND_INT_2ADDR, "and-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SHL_INT_2ADDR =
+ new Info(Opcodes.SHL_INT_2ADDR, "shl-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info OR_INT_2ADDR =
- new Info(Opcodes.OR_INT_2ADDR, "or-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SHR_INT_2ADDR =
+ new Info(Opcodes.SHR_INT_2ADDR, "shr-int/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info XOR_INT_2ADDR =
- new Info(Opcodes.XOR_INT_2ADDR, "xor-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info USHR_INT_2ADDR = new Info(Opcodes.USHR_INT_2ADDR, "ushr-int/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SHL_INT_2ADDR =
- new Info(Opcodes.SHL_INT_2ADDR, "shl-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info ADD_LONG_2ADDR = new Info(Opcodes.ADD_LONG_2ADDR, "add-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SHR_INT_2ADDR =
- new Info(Opcodes.SHR_INT_2ADDR, "shr-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SUB_LONG_2ADDR = new Info(Opcodes.SUB_LONG_2ADDR, "sub-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info USHR_INT_2ADDR =
- new Info(Opcodes.USHR_INT_2ADDR, "ushr-int/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MUL_LONG_2ADDR = new Info(Opcodes.MUL_LONG_2ADDR, "mul-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info ADD_LONG_2ADDR =
- new Info(Opcodes.ADD_LONG_2ADDR, "add-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DIV_LONG_2ADDR = new Info(Opcodes.DIV_LONG_2ADDR, "div-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SUB_LONG_2ADDR =
- new Info(Opcodes.SUB_LONG_2ADDR, "sub-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info REM_LONG_2ADDR = new Info(Opcodes.REM_LONG_2ADDR, "rem-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MUL_LONG_2ADDR =
- new Info(Opcodes.MUL_LONG_2ADDR, "mul-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info AND_LONG_2ADDR = new Info(Opcodes.AND_LONG_2ADDR, "and-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DIV_LONG_2ADDR =
- new Info(Opcodes.DIV_LONG_2ADDR, "div-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info OR_LONG_2ADDR =
+ new Info(Opcodes.OR_LONG_2ADDR, "or-long/2addr", InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info REM_LONG_2ADDR =
- new Info(Opcodes.REM_LONG_2ADDR, "rem-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info XOR_LONG_2ADDR = new Info(Opcodes.XOR_LONG_2ADDR, "xor-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info AND_LONG_2ADDR =
- new Info(Opcodes.AND_LONG_2ADDR, "and-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SHL_LONG_2ADDR = new Info(Opcodes.SHL_LONG_2ADDR, "shl-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info OR_LONG_2ADDR =
- new Info(Opcodes.OR_LONG_2ADDR, "or-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SHR_LONG_2ADDR = new Info(Opcodes.SHR_LONG_2ADDR, "shr-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info XOR_LONG_2ADDR =
- new Info(Opcodes.XOR_LONG_2ADDR, "xor-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info USHR_LONG_2ADDR = new Info(Opcodes.USHR_LONG_2ADDR, "ushr-long/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SHL_LONG_2ADDR =
- new Info(Opcodes.SHL_LONG_2ADDR, "shl-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info ADD_FLOAT_2ADDR = new Info(Opcodes.ADD_FLOAT_2ADDR, "add-float/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SHR_LONG_2ADDR =
- new Info(Opcodes.SHR_LONG_2ADDR, "shr-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SUB_FLOAT_2ADDR = new Info(Opcodes.SUB_FLOAT_2ADDR, "sub-float/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info USHR_LONG_2ADDR =
- new Info(Opcodes.USHR_LONG_2ADDR, "ushr-long/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MUL_FLOAT_2ADDR = new Info(Opcodes.MUL_FLOAT_2ADDR, "mul-float/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info ADD_FLOAT_2ADDR =
- new Info(Opcodes.ADD_FLOAT_2ADDR, "add-float/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DIV_FLOAT_2ADDR = new Info(Opcodes.DIV_FLOAT_2ADDR, "div-float/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SUB_FLOAT_2ADDR =
- new Info(Opcodes.SUB_FLOAT_2ADDR, "sub-float/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info REM_FLOAT_2ADDR = new Info(Opcodes.REM_FLOAT_2ADDR, "rem-float/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MUL_FLOAT_2ADDR =
- new Info(Opcodes.MUL_FLOAT_2ADDR, "mul-float/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info ADD_DOUBLE_2ADDR = new Info(Opcodes.ADD_DOUBLE_2ADDR, "add-double/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info DIV_FLOAT_2ADDR =
- new Info(Opcodes.DIV_FLOAT_2ADDR, "div-float/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info SUB_DOUBLE_2ADDR = new Info(Opcodes.SUB_DOUBLE_2ADDR, "sub-double/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info REM_FLOAT_2ADDR =
- new Info(Opcodes.REM_FLOAT_2ADDR, "rem-float/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MUL_DOUBLE_2ADDR = new Info(Opcodes.MUL_DOUBLE_2ADDR, "mul-double/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info ADD_DOUBLE_2ADDR =
- new Info(Opcodes.ADD_DOUBLE_2ADDR, "add-double/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info DIV_DOUBLE_2ADDR = new Info(Opcodes.DIV_DOUBLE_2ADDR, "div-double/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info SUB_DOUBLE_2ADDR =
- new Info(Opcodes.SUB_DOUBLE_2ADDR, "sub-double/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info REM_DOUBLE_2ADDR = new Info(Opcodes.REM_DOUBLE_2ADDR, "rem-double/2addr",
+ InstructionCodec.FORMAT_12X, IndexType.NONE);
- public static final Info MUL_DOUBLE_2ADDR =
- new Info(Opcodes.MUL_DOUBLE_2ADDR, "mul-double/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info ADD_INT_LIT16 =
+ new Info(Opcodes.ADD_INT_LIT16, "add-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info DIV_DOUBLE_2ADDR =
- new Info(Opcodes.DIV_DOUBLE_2ADDR, "div-double/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info RSUB_INT =
+ new Info(Opcodes.RSUB_INT, "rsub-int", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info REM_DOUBLE_2ADDR =
- new Info(Opcodes.REM_DOUBLE_2ADDR, "rem-double/2addr",
- InstructionCodec.FORMAT_12X, IndexType.NONE);
+ public static final Info MUL_INT_LIT16 =
+ new Info(Opcodes.MUL_INT_LIT16, "mul-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info ADD_INT_LIT16 =
- new Info(Opcodes.ADD_INT_LIT16, "add-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info DIV_INT_LIT16 =
+ new Info(Opcodes.DIV_INT_LIT16, "div-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info RSUB_INT =
- new Info(Opcodes.RSUB_INT, "rsub-int",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info REM_INT_LIT16 =
+ new Info(Opcodes.REM_INT_LIT16, "rem-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info MUL_INT_LIT16 =
- new Info(Opcodes.MUL_INT_LIT16, "mul-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info AND_INT_LIT16 =
+ new Info(Opcodes.AND_INT_LIT16, "and-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info DIV_INT_LIT16 =
- new Info(Opcodes.DIV_INT_LIT16, "div-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info OR_INT_LIT16 =
+ new Info(Opcodes.OR_INT_LIT16, "or-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info REM_INT_LIT16 =
- new Info(Opcodes.REM_INT_LIT16, "rem-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info XOR_INT_LIT16 =
+ new Info(Opcodes.XOR_INT_LIT16, "xor-int/lit16", InstructionCodec.FORMAT_22S, IndexType.NONE);
- public static final Info AND_INT_LIT16 =
- new Info(Opcodes.AND_INT_LIT16, "and-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info ADD_INT_LIT8 =
+ new Info(Opcodes.ADD_INT_LIT8, "add-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info OR_INT_LIT16 =
- new Info(Opcodes.OR_INT_LIT16, "or-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info RSUB_INT_LIT8 =
+ new Info(Opcodes.RSUB_INT_LIT8, "rsub-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info XOR_INT_LIT16 =
- new Info(Opcodes.XOR_INT_LIT16, "xor-int/lit16",
- InstructionCodec.FORMAT_22S, IndexType.NONE);
+ public static final Info MUL_INT_LIT8 =
+ new Info(Opcodes.MUL_INT_LIT8, "mul-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info ADD_INT_LIT8 =
- new Info(Opcodes.ADD_INT_LIT8, "add-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info DIV_INT_LIT8 =
+ new Info(Opcodes.DIV_INT_LIT8, "div-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info RSUB_INT_LIT8 =
- new Info(Opcodes.RSUB_INT_LIT8, "rsub-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info REM_INT_LIT8 =
+ new Info(Opcodes.REM_INT_LIT8, "rem-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info MUL_INT_LIT8 =
- new Info(Opcodes.MUL_INT_LIT8, "mul-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info AND_INT_LIT8 =
+ new Info(Opcodes.AND_INT_LIT8, "and-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info DIV_INT_LIT8 =
- new Info(Opcodes.DIV_INT_LIT8, "div-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info OR_INT_LIT8 =
+ new Info(Opcodes.OR_INT_LIT8, "or-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info REM_INT_LIT8 =
- new Info(Opcodes.REM_INT_LIT8, "rem-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info XOR_INT_LIT8 =
+ new Info(Opcodes.XOR_INT_LIT8, "xor-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info AND_INT_LIT8 =
- new Info(Opcodes.AND_INT_LIT8, "and-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info SHL_INT_LIT8 =
+ new Info(Opcodes.SHL_INT_LIT8, "shl-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info OR_INT_LIT8 =
- new Info(Opcodes.OR_INT_LIT8, "or-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info SHR_INT_LIT8 =
+ new Info(Opcodes.SHR_INT_LIT8, "shr-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info XOR_INT_LIT8 =
- new Info(Opcodes.XOR_INT_LIT8, "xor-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ public static final Info USHR_INT_LIT8 =
+ new Info(Opcodes.USHR_INT_LIT8, "ushr-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE);
- public static final Info SHL_INT_LIT8 =
- new Info(Opcodes.SHL_INT_LIT8, "shl-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ // END(opcode-info-defs)
- public static final Info SHR_INT_LIT8 =
- new Info(Opcodes.SHR_INT_LIT8, "shr-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ // Static initialization.
+ static {
+ INFO = new Info[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
- public static final Info USHR_INT_LIT8 =
- new Info(Opcodes.USHR_INT_LIT8, "ushr-int/lit8",
- InstructionCodec.FORMAT_22B, IndexType.NONE);
+ // TODO(dx team): Stop using this constant.
+ set(SPECIAL_FORMAT);
- // END(opcode-info-defs)
+ // TODO(dx team): These payload opcodes should be generated by opcode-gen.
+ set(PACKED_SWITCH_PAYLOAD);
+ set(SPARSE_SWITCH_PAYLOAD);
+ set(FILL_ARRAY_DATA_PAYLOAD);
- // Static initialization.
- static {
- INFO = new Info[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
+ // BEGIN(opcode-info-init); GENERATED AUTOMATICALLY BY opcode-gen
+ set(NOP);
+ set(MOVE);
+ set(MOVE_FROM16);
+ set(MOVE_16);
+ set(MOVE_WIDE);
+ set(MOVE_WIDE_FROM16);
+ set(MOVE_WIDE_16);
+ set(MOVE_OBJECT);
+ set(MOVE_OBJECT_FROM16);
+ set(MOVE_OBJECT_16);
+ set(MOVE_RESULT);
+ set(MOVE_RESULT_WIDE);
+ set(MOVE_RESULT_OBJECT);
+ set(MOVE_EXCEPTION);
+ set(RETURN_VOID);
+ set(RETURN);
+ set(RETURN_WIDE);
+ set(RETURN_OBJECT);
+ set(CONST_4);
+ set(CONST_16);
+ set(CONST);
+ set(CONST_HIGH16);
+ set(CONST_WIDE_16);
+ set(CONST_WIDE_32);
+ set(CONST_WIDE);
+ set(CONST_WIDE_HIGH16);
+ set(CONST_STRING);
+ set(CONST_STRING_JUMBO);
+ set(CONST_CLASS);
+ set(MONITOR_ENTER);
+ set(MONITOR_EXIT);
+ set(CHECK_CAST);
+ set(INSTANCE_OF);
+ set(ARRAY_LENGTH);
+ set(NEW_INSTANCE);
+ set(NEW_ARRAY);
+ set(FILLED_NEW_ARRAY);
+ set(FILLED_NEW_ARRAY_RANGE);
+ set(FILL_ARRAY_DATA);
+ set(THROW);
+ set(GOTO);
+ set(GOTO_16);
+ set(GOTO_32);
+ set(PACKED_SWITCH);
+ set(SPARSE_SWITCH);
+ set(CMPL_FLOAT);
+ set(CMPG_FLOAT);
+ set(CMPL_DOUBLE);
+ set(CMPG_DOUBLE);
+ set(CMP_LONG);
+ set(IF_EQ);
+ set(IF_NE);
+ set(IF_LT);
+ set(IF_GE);
+ set(IF_GT);
+ set(IF_LE);
+ set(IF_EQZ);
+ set(IF_NEZ);
+ set(IF_LTZ);
+ set(IF_GEZ);
+ set(IF_GTZ);
+ set(IF_LEZ);
+ set(AGET);
+ set(AGET_WIDE);
+ set(AGET_OBJECT);
+ set(AGET_BOOLEAN);
+ set(AGET_BYTE);
+ set(AGET_CHAR);
+ set(AGET_SHORT);
+ set(APUT);
+ set(APUT_WIDE);
+ set(APUT_OBJECT);
+ set(APUT_BOOLEAN);
+ set(APUT_BYTE);
+ set(APUT_CHAR);
+ set(APUT_SHORT);
+ set(IGET);
+ set(IGET_WIDE);
+ set(IGET_OBJECT);
+ set(IGET_BOOLEAN);
+ set(IGET_BYTE);
+ set(IGET_CHAR);
+ set(IGET_SHORT);
+ set(IPUT);
+ set(IPUT_WIDE);
+ set(IPUT_OBJECT);
+ set(IPUT_BOOLEAN);
+ set(IPUT_BYTE);
+ set(IPUT_CHAR);
+ set(IPUT_SHORT);
+ set(SGET);
+ set(SGET_WIDE);
+ set(SGET_OBJECT);
+ set(SGET_BOOLEAN);
+ set(SGET_BYTE);
+ set(SGET_CHAR);
+ set(SGET_SHORT);
+ set(SPUT);
+ set(SPUT_WIDE);
+ set(SPUT_OBJECT);
+ set(SPUT_BOOLEAN);
+ set(SPUT_BYTE);
+ set(SPUT_CHAR);
+ set(SPUT_SHORT);
+ set(INVOKE_VIRTUAL);
+ set(INVOKE_SUPER);
+ set(INVOKE_DIRECT);
+ set(INVOKE_STATIC);
+ set(INVOKE_INTERFACE);
+ set(INVOKE_VIRTUAL_RANGE);
+ set(INVOKE_SUPER_RANGE);
+ set(INVOKE_DIRECT_RANGE);
+ set(INVOKE_STATIC_RANGE);
+ set(INVOKE_INTERFACE_RANGE);
+ set(NEG_INT);
+ set(NOT_INT);
+ set(NEG_LONG);
+ set(NOT_LONG);
+ set(NEG_FLOAT);
+ set(NEG_DOUBLE);
+ set(INT_TO_LONG);
+ set(INT_TO_FLOAT);
+ set(INT_TO_DOUBLE);
+ set(LONG_TO_INT);
+ set(LONG_TO_FLOAT);
+ set(LONG_TO_DOUBLE);
+ set(FLOAT_TO_INT);
+ set(FLOAT_TO_LONG);
+ set(FLOAT_TO_DOUBLE);
+ set(DOUBLE_TO_INT);
+ set(DOUBLE_TO_LONG);
+ set(DOUBLE_TO_FLOAT);
+ set(INT_TO_BYTE);
+ set(INT_TO_CHAR);
+ set(INT_TO_SHORT);
+ set(ADD_INT);
+ set(SUB_INT);
+ set(MUL_INT);
+ set(DIV_INT);
+ set(REM_INT);
+ set(AND_INT);
+ set(OR_INT);
+ set(XOR_INT);
+ set(SHL_INT);
+ set(SHR_INT);
+ set(USHR_INT);
+ set(ADD_LONG);
+ set(SUB_LONG);
+ set(MUL_LONG);
+ set(DIV_LONG);
+ set(REM_LONG);
+ set(AND_LONG);
+ set(OR_LONG);
+ set(XOR_LONG);
+ set(SHL_LONG);
+ set(SHR_LONG);
+ set(USHR_LONG);
+ set(ADD_FLOAT);
+ set(SUB_FLOAT);
+ set(MUL_FLOAT);
+ set(DIV_FLOAT);
+ set(REM_FLOAT);
+ set(ADD_DOUBLE);
+ set(SUB_DOUBLE);
+ set(MUL_DOUBLE);
+ set(DIV_DOUBLE);
+ set(REM_DOUBLE);
+ set(ADD_INT_2ADDR);
+ set(SUB_INT_2ADDR);
+ set(MUL_INT_2ADDR);
+ set(DIV_INT_2ADDR);
+ set(REM_INT_2ADDR);
+ set(AND_INT_2ADDR);
+ set(OR_INT_2ADDR);
+ set(XOR_INT_2ADDR);
+ set(SHL_INT_2ADDR);
+ set(SHR_INT_2ADDR);
+ set(USHR_INT_2ADDR);
+ set(ADD_LONG_2ADDR);
+ set(SUB_LONG_2ADDR);
+ set(MUL_LONG_2ADDR);
+ set(DIV_LONG_2ADDR);
+ set(REM_LONG_2ADDR);
+ set(AND_LONG_2ADDR);
+ set(OR_LONG_2ADDR);
+ set(XOR_LONG_2ADDR);
+ set(SHL_LONG_2ADDR);
+ set(SHR_LONG_2ADDR);
+ set(USHR_LONG_2ADDR);
+ set(ADD_FLOAT_2ADDR);
+ set(SUB_FLOAT_2ADDR);
+ set(MUL_FLOAT_2ADDR);
+ set(DIV_FLOAT_2ADDR);
+ set(REM_FLOAT_2ADDR);
+ set(ADD_DOUBLE_2ADDR);
+ set(SUB_DOUBLE_2ADDR);
+ set(MUL_DOUBLE_2ADDR);
+ set(DIV_DOUBLE_2ADDR);
+ set(REM_DOUBLE_2ADDR);
+ set(ADD_INT_LIT16);
+ set(RSUB_INT);
+ set(MUL_INT_LIT16);
+ set(DIV_INT_LIT16);
+ set(REM_INT_LIT16);
+ set(AND_INT_LIT16);
+ set(OR_INT_LIT16);
+ set(XOR_INT_LIT16);
+ set(ADD_INT_LIT8);
+ set(RSUB_INT_LIT8);
+ set(MUL_INT_LIT8);
+ set(DIV_INT_LIT8);
+ set(REM_INT_LIT8);
+ set(AND_INT_LIT8);
+ set(OR_INT_LIT8);
+ set(XOR_INT_LIT8);
+ set(SHL_INT_LIT8);
+ set(SHR_INT_LIT8);
+ set(USHR_INT_LIT8);
+ // END(opcode-info-init)
+ }
- // TODO: Stop using this constant.
- set(SPECIAL_FORMAT);
+ /**
+ * This class is uninstantiable.
+ */
+ private OpcodeInfo() {
+ // This space intentionally left blank.
+ }
- // TODO: These payload opcodes should be generated by opcode-gen.
- set(PACKED_SWITCH_PAYLOAD);
- set(SPARSE_SWITCH_PAYLOAD);
- set(FILL_ARRAY_DATA_PAYLOAD);
+ /**
+ * Gets the {@link @Info} for the given opcode value.
+ *
+ * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
+ * opcode value
+ * @return non-null; the associated opcode information instance
+ */
+ public static Info get(int opcode) {
+ int idx = opcode - Opcodes.MIN_VALUE;
- // BEGIN(opcode-info-init); GENERATED AUTOMATICALLY BY opcode-gen
- set(NOP);
- set(MOVE);
- set(MOVE_FROM16);
- set(MOVE_16);
- set(MOVE_WIDE);
- set(MOVE_WIDE_FROM16);
- set(MOVE_WIDE_16);
- set(MOVE_OBJECT);
- set(MOVE_OBJECT_FROM16);
- set(MOVE_OBJECT_16);
- set(MOVE_RESULT);
- set(MOVE_RESULT_WIDE);
- set(MOVE_RESULT_OBJECT);
- set(MOVE_EXCEPTION);
- set(RETURN_VOID);
- set(RETURN);
- set(RETURN_WIDE);
- set(RETURN_OBJECT);
- set(CONST_4);
- set(CONST_16);
- set(CONST);
- set(CONST_HIGH16);
- set(CONST_WIDE_16);
- set(CONST_WIDE_32);
- set(CONST_WIDE);
- set(CONST_WIDE_HIGH16);
- set(CONST_STRING);
- set(CONST_STRING_JUMBO);
- set(CONST_CLASS);
- set(MONITOR_ENTER);
- set(MONITOR_EXIT);
- set(CHECK_CAST);
- set(INSTANCE_OF);
- set(ARRAY_LENGTH);
- set(NEW_INSTANCE);
- set(NEW_ARRAY);
- set(FILLED_NEW_ARRAY);
- set(FILLED_NEW_ARRAY_RANGE);
- set(FILL_ARRAY_DATA);
- set(THROW);
- set(GOTO);
- set(GOTO_16);
- set(GOTO_32);
- set(PACKED_SWITCH);
- set(SPARSE_SWITCH);
- set(CMPL_FLOAT);
- set(CMPG_FLOAT);
- set(CMPL_DOUBLE);
- set(CMPG_DOUBLE);
- set(CMP_LONG);
- set(IF_EQ);
- set(IF_NE);
- set(IF_LT);
- set(IF_GE);
- set(IF_GT);
- set(IF_LE);
- set(IF_EQZ);
- set(IF_NEZ);
- set(IF_LTZ);
- set(IF_GEZ);
- set(IF_GTZ);
- set(IF_LEZ);
- set(AGET);
- set(AGET_WIDE);
- set(AGET_OBJECT);
- set(AGET_BOOLEAN);
- set(AGET_BYTE);
- set(AGET_CHAR);
- set(AGET_SHORT);
- set(APUT);
- set(APUT_WIDE);
- set(APUT_OBJECT);
- set(APUT_BOOLEAN);
- set(APUT_BYTE);
- set(APUT_CHAR);
- set(APUT_SHORT);
- set(IGET);
- set(IGET_WIDE);
- set(IGET_OBJECT);
- set(IGET_BOOLEAN);
- set(IGET_BYTE);
- set(IGET_CHAR);
- set(IGET_SHORT);
- set(IPUT);
- set(IPUT_WIDE);
- set(IPUT_OBJECT);
- set(IPUT_BOOLEAN);
- set(IPUT_BYTE);
- set(IPUT_CHAR);
- set(IPUT_SHORT);
- set(SGET);
- set(SGET_WIDE);
- set(SGET_OBJECT);
- set(SGET_BOOLEAN);
- set(SGET_BYTE);
- set(SGET_CHAR);
- set(SGET_SHORT);
- set(SPUT);
- set(SPUT_WIDE);
- set(SPUT_OBJECT);
- set(SPUT_BOOLEAN);
- set(SPUT_BYTE);
- set(SPUT_CHAR);
- set(SPUT_SHORT);
- set(INVOKE_VIRTUAL);
- set(INVOKE_SUPER);
- set(INVOKE_DIRECT);
- set(INVOKE_STATIC);
- set(INVOKE_INTERFACE);
- set(INVOKE_VIRTUAL_RANGE);
- set(INVOKE_SUPER_RANGE);
- set(INVOKE_DIRECT_RANGE);
- set(INVOKE_STATIC_RANGE);
- set(INVOKE_INTERFACE_RANGE);
- set(NEG_INT);
- set(NOT_INT);
- set(NEG_LONG);
- set(NOT_LONG);
- set(NEG_FLOAT);
- set(NEG_DOUBLE);
- set(INT_TO_LONG);
- set(INT_TO_FLOAT);
- set(INT_TO_DOUBLE);
- set(LONG_TO_INT);
- set(LONG_TO_FLOAT);
- set(LONG_TO_DOUBLE);
- set(FLOAT_TO_INT);
- set(FLOAT_TO_LONG);
- set(FLOAT_TO_DOUBLE);
- set(DOUBLE_TO_INT);
- set(DOUBLE_TO_LONG);
- set(DOUBLE_TO_FLOAT);
- set(INT_TO_BYTE);
- set(INT_TO_CHAR);
- set(INT_TO_SHORT);
- set(ADD_INT);
- set(SUB_INT);
- set(MUL_INT);
- set(DIV_INT);
- set(REM_INT);
- set(AND_INT);
- set(OR_INT);
- set(XOR_INT);
- set(SHL_INT);
- set(SHR_INT);
- set(USHR_INT);
- set(ADD_LONG);
- set(SUB_LONG);
- set(MUL_LONG);
- set(DIV_LONG);
- set(REM_LONG);
- set(AND_LONG);
- set(OR_LONG);
- set(XOR_LONG);
- set(SHL_LONG);
- set(SHR_LONG);
- set(USHR_LONG);
- set(ADD_FLOAT);
- set(SUB_FLOAT);
- set(MUL_FLOAT);
- set(DIV_FLOAT);
- set(REM_FLOAT);
- set(ADD_DOUBLE);
- set(SUB_DOUBLE);
- set(MUL_DOUBLE);
- set(DIV_DOUBLE);
- set(REM_DOUBLE);
- set(ADD_INT_2ADDR);
- set(SUB_INT_2ADDR);
- set(MUL_INT_2ADDR);
- set(DIV_INT_2ADDR);
- set(REM_INT_2ADDR);
- set(AND_INT_2ADDR);
- set(OR_INT_2ADDR);
- set(XOR_INT_2ADDR);
- set(SHL_INT_2ADDR);
- set(SHR_INT_2ADDR);
- set(USHR_INT_2ADDR);
- set(ADD_LONG_2ADDR);
- set(SUB_LONG_2ADDR);
- set(MUL_LONG_2ADDR);
- set(DIV_LONG_2ADDR);
- set(REM_LONG_2ADDR);
- set(AND_LONG_2ADDR);
- set(OR_LONG_2ADDR);
- set(XOR_LONG_2ADDR);
- set(SHL_LONG_2ADDR);
- set(SHR_LONG_2ADDR);
- set(USHR_LONG_2ADDR);
- set(ADD_FLOAT_2ADDR);
- set(SUB_FLOAT_2ADDR);
- set(MUL_FLOAT_2ADDR);
- set(DIV_FLOAT_2ADDR);
- set(REM_FLOAT_2ADDR);
- set(ADD_DOUBLE_2ADDR);
- set(SUB_DOUBLE_2ADDR);
- set(MUL_DOUBLE_2ADDR);
- set(DIV_DOUBLE_2ADDR);
- set(REM_DOUBLE_2ADDR);
- set(ADD_INT_LIT16);
- set(RSUB_INT);
- set(MUL_INT_LIT16);
- set(DIV_INT_LIT16);
- set(REM_INT_LIT16);
- set(AND_INT_LIT16);
- set(OR_INT_LIT16);
- set(XOR_INT_LIT16);
- set(ADD_INT_LIT8);
- set(RSUB_INT_LIT8);
- set(MUL_INT_LIT8);
- set(DIV_INT_LIT8);
- set(REM_INT_LIT8);
- set(AND_INT_LIT8);
- set(OR_INT_LIT8);
- set(XOR_INT_LIT8);
- set(SHL_INT_LIT8);
- set(SHR_INT_LIT8);
- set(USHR_INT_LIT8);
- // END(opcode-info-init)
+ try {
+ Info result = INFO[idx];
+ if (result != null) {
+ return result;
+ }
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Fall through.
}
- /**
- * This class is uninstantiable.
- */
- private OpcodeInfo() {
- // This space intentionally left blank.
+ throw new IllegalArgumentException("bogus opcode: " + Hex.u2or4(opcode));
+ }
+
+ /**
+ * Gets the name of the given opcode.
+ */
+ public static String getName(int opcode) {
+ return get(opcode).getName();
+ }
+
+ /**
+ * Gets the format (an {@link InstructionCodec}) for the given opcode
+ * value.
+ */
+ public static InstructionCodec getFormat(int opcode) {
+ return get(opcode).getFormat();
+ }
+
+ /**
+ * Gets the {@link IndexType} for the given opcode value.
+ */
+ public static IndexType getIndexType(int opcode) {
+ return get(opcode).getIndexType();
+ }
+
+ /**
+ * Puts the given opcode into the table of all ops.
+ *
+ * @param opcode non-null; the opcode
+ */
+ private static void set(Info opcode) {
+ int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
+ INFO[idx] = opcode;
+ }
+
+ /**
+ * Information about an opcode.
+ */
+ public static class Info {
+ private final int opcode;
+ private final String name;
+ private final InstructionCodec format;
+ private final IndexType indexType;
+
+ public Info(int opcode, String name, InstructionCodec format, IndexType indexType) {
+ this.opcode = opcode;
+ this.name = name;
+ this.format = format;
+ this.indexType = indexType;
}
- /**
- * Gets the {@link @Info} for the given opcode value.
- *
- * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
- * opcode value
- * @return non-null; the associated opcode information instance
- */
- public static Info get(int opcode) {
- int idx = opcode - Opcodes.MIN_VALUE;
-
- try {
- Info result = INFO[idx];
- if (result != null) {
- return result;
- }
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Fall through.
- }
-
- throw new IllegalArgumentException("bogus opcode: "
- + Hex.u2or4(opcode));
+ public int getOpcode() {
+ return opcode;
}
- /**
- * Gets the name of the given opcode.
- */
- public static String getName(int opcode) {
- return get(opcode).getName();
+ public String getName() {
+ return name;
}
- /**
- * Gets the format (an {@link InstructionCodec}) for the given opcode
- * value.
- */
- public static InstructionCodec getFormat(int opcode) {
- return get(opcode).getFormat();
+ public InstructionCodec getFormat() {
+ return format;
}
- /**
- * Gets the {@link IndexType} for the given opcode value.
- */
- public static IndexType getIndexType(int opcode) {
- return get(opcode).getIndexType();
+ public IndexType getIndexType() {
+ return indexType;
}
-
- /**
- * Puts the given opcode into the table of all ops.
- *
- * @param opcode non-null; the opcode
- */
- private static void set(Info opcode) {
- int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
- INFO[idx] = opcode;
- }
-
- /**
- * Information about an opcode.
- */
- public static class Info {
- private final int opcode;
- private final String name;
- private final InstructionCodec format;
- private final IndexType indexType;
-
- public Info(int opcode, String name, InstructionCodec format,
- IndexType indexType) {
- this.opcode = opcode;
- this.name = name;
- this.format = format;
- this.indexType = indexType;
- }
-
- public int getOpcode() {
- return opcode;
- }
-
- public String getName() {
- return name;
- }
-
- public InstructionCodec getFormat() {
- return format;
- }
-
- public IndexType getIndexType() {
- return indexType;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/Opcodes.java b/dx/src/com/android/jack/dx/io/Opcodes.java
index 77b5d8e..4f79a31 100644
--- a/dx/src/com/android/jack/dx/io/Opcodes.java
+++ b/dx/src/com/android/jack/dx/io/Opcodes.java
@@ -21,326 +21,326 @@
* document for the meaning and instruction format of each opcode.
*/
public final class Opcodes {
- /**
- * pseudo-opcode used for nonstandard format payload "instructions". TODO:
- * Retire this concept, and start treating the payload instructions
- * more like the rest.
- */
- public static final int SPECIAL_FORMAT = -1;
+ /**
+ * pseudo-opcode used for nonstandard format payload "instructions". TODO(dx team):
+ * Retire this concept, and start treating the payload instructions
+ * more like the rest.
+ */
+ public static final int SPECIAL_FORMAT = -1;
- /**
- * pseudo-opcode used to indicate there is no next opcode; used
- * in opcode chaining lists
- */
- public static final int NO_NEXT = -1;
+ /**
+ * pseudo-opcode used to indicate there is no next opcode; used
+ * in opcode chaining lists
+ */
+ public static final int NO_NEXT = -1;
- /** minimum valid opcode value */
- public static final int MIN_VALUE = -1;
+ /** minimum valid opcode value */
+ public static final int MIN_VALUE = -1;
- /** maximum valid opcode value */
- public static final int MAX_VALUE = 0xffff;
+ /** maximum valid opcode value */
+ public static final int MAX_VALUE = 0xffff;
- // BEGIN(opcodes); GENERATED AUTOMATICALLY BY opcode-gen
- public static final int NOP = 0x00;
- public static final int MOVE = 0x01;
- public static final int MOVE_FROM16 = 0x02;
- public static final int MOVE_16 = 0x03;
- public static final int MOVE_WIDE = 0x04;
- public static final int MOVE_WIDE_FROM16 = 0x05;
- public static final int MOVE_WIDE_16 = 0x06;
- public static final int MOVE_OBJECT = 0x07;
- public static final int MOVE_OBJECT_FROM16 = 0x08;
- public static final int MOVE_OBJECT_16 = 0x09;
- public static final int MOVE_RESULT = 0x0a;
- public static final int MOVE_RESULT_WIDE = 0x0b;
- public static final int MOVE_RESULT_OBJECT = 0x0c;
- public static final int MOVE_EXCEPTION = 0x0d;
- public static final int RETURN_VOID = 0x0e;
- public static final int RETURN = 0x0f;
- public static final int RETURN_WIDE = 0x10;
- public static final int RETURN_OBJECT = 0x11;
- public static final int CONST_4 = 0x12;
- public static final int CONST_16 = 0x13;
- public static final int CONST = 0x14;
- public static final int CONST_HIGH16 = 0x15;
- public static final int CONST_WIDE_16 = 0x16;
- public static final int CONST_WIDE_32 = 0x17;
- public static final int CONST_WIDE = 0x18;
- public static final int CONST_WIDE_HIGH16 = 0x19;
- public static final int CONST_STRING = 0x1a;
- public static final int CONST_STRING_JUMBO = 0x1b;
- public static final int CONST_CLASS = 0x1c;
- public static final int MONITOR_ENTER = 0x1d;
- public static final int MONITOR_EXIT = 0x1e;
- public static final int CHECK_CAST = 0x1f;
- public static final int INSTANCE_OF = 0x20;
- public static final int ARRAY_LENGTH = 0x21;
- public static final int NEW_INSTANCE = 0x22;
- public static final int NEW_ARRAY = 0x23;
- public static final int FILLED_NEW_ARRAY = 0x24;
- public static final int FILLED_NEW_ARRAY_RANGE = 0x25;
- public static final int FILL_ARRAY_DATA = 0x26;
- public static final int THROW = 0x27;
- public static final int GOTO = 0x28;
- public static final int GOTO_16 = 0x29;
- public static final int GOTO_32 = 0x2a;
- public static final int PACKED_SWITCH = 0x2b;
- public static final int SPARSE_SWITCH = 0x2c;
- public static final int CMPL_FLOAT = 0x2d;
- public static final int CMPG_FLOAT = 0x2e;
- public static final int CMPL_DOUBLE = 0x2f;
- public static final int CMPG_DOUBLE = 0x30;
- public static final int CMP_LONG = 0x31;
- public static final int IF_EQ = 0x32;
- public static final int IF_NE = 0x33;
- public static final int IF_LT = 0x34;
- public static final int IF_GE = 0x35;
- public static final int IF_GT = 0x36;
- public static final int IF_LE = 0x37;
- public static final int IF_EQZ = 0x38;
- public static final int IF_NEZ = 0x39;
- public static final int IF_LTZ = 0x3a;
- public static final int IF_GEZ = 0x3b;
- public static final int IF_GTZ = 0x3c;
- public static final int IF_LEZ = 0x3d;
- public static final int AGET = 0x44;
- public static final int AGET_WIDE = 0x45;
- public static final int AGET_OBJECT = 0x46;
- public static final int AGET_BOOLEAN = 0x47;
- public static final int AGET_BYTE = 0x48;
- public static final int AGET_CHAR = 0x49;
- public static final int AGET_SHORT = 0x4a;
- public static final int APUT = 0x4b;
- public static final int APUT_WIDE = 0x4c;
- public static final int APUT_OBJECT = 0x4d;
- public static final int APUT_BOOLEAN = 0x4e;
- public static final int APUT_BYTE = 0x4f;
- public static final int APUT_CHAR = 0x50;
- public static final int APUT_SHORT = 0x51;
- public static final int IGET = 0x52;
- public static final int IGET_WIDE = 0x53;
- public static final int IGET_OBJECT = 0x54;
- public static final int IGET_BOOLEAN = 0x55;
- public static final int IGET_BYTE = 0x56;
- public static final int IGET_CHAR = 0x57;
- public static final int IGET_SHORT = 0x58;
- public static final int IPUT = 0x59;
- public static final int IPUT_WIDE = 0x5a;
- public static final int IPUT_OBJECT = 0x5b;
- public static final int IPUT_BOOLEAN = 0x5c;
- public static final int IPUT_BYTE = 0x5d;
- public static final int IPUT_CHAR = 0x5e;
- public static final int IPUT_SHORT = 0x5f;
- public static final int SGET = 0x60;
- public static final int SGET_WIDE = 0x61;
- public static final int SGET_OBJECT = 0x62;
- public static final int SGET_BOOLEAN = 0x63;
- public static final int SGET_BYTE = 0x64;
- public static final int SGET_CHAR = 0x65;
- public static final int SGET_SHORT = 0x66;
- public static final int SPUT = 0x67;
- public static final int SPUT_WIDE = 0x68;
- public static final int SPUT_OBJECT = 0x69;
- public static final int SPUT_BOOLEAN = 0x6a;
- public static final int SPUT_BYTE = 0x6b;
- public static final int SPUT_CHAR = 0x6c;
- public static final int SPUT_SHORT = 0x6d;
- public static final int INVOKE_VIRTUAL = 0x6e;
- public static final int INVOKE_SUPER = 0x6f;
- public static final int INVOKE_DIRECT = 0x70;
- public static final int INVOKE_STATIC = 0x71;
- public static final int INVOKE_INTERFACE = 0x72;
- public static final int INVOKE_VIRTUAL_RANGE = 0x74;
- public static final int INVOKE_SUPER_RANGE = 0x75;
- public static final int INVOKE_DIRECT_RANGE = 0x76;
- public static final int INVOKE_STATIC_RANGE = 0x77;
- public static final int INVOKE_INTERFACE_RANGE = 0x78;
- public static final int NEG_INT = 0x7b;
- public static final int NOT_INT = 0x7c;
- public static final int NEG_LONG = 0x7d;
- public static final int NOT_LONG = 0x7e;
- public static final int NEG_FLOAT = 0x7f;
- public static final int NEG_DOUBLE = 0x80;
- public static final int INT_TO_LONG = 0x81;
- public static final int INT_TO_FLOAT = 0x82;
- public static final int INT_TO_DOUBLE = 0x83;
- public static final int LONG_TO_INT = 0x84;
- public static final int LONG_TO_FLOAT = 0x85;
- public static final int LONG_TO_DOUBLE = 0x86;
- public static final int FLOAT_TO_INT = 0x87;
- public static final int FLOAT_TO_LONG = 0x88;
- public static final int FLOAT_TO_DOUBLE = 0x89;
- public static final int DOUBLE_TO_INT = 0x8a;
- public static final int DOUBLE_TO_LONG = 0x8b;
- public static final int DOUBLE_TO_FLOAT = 0x8c;
- public static final int INT_TO_BYTE = 0x8d;
- public static final int INT_TO_CHAR = 0x8e;
- public static final int INT_TO_SHORT = 0x8f;
- public static final int ADD_INT = 0x90;
- public static final int SUB_INT = 0x91;
- public static final int MUL_INT = 0x92;
- public static final int DIV_INT = 0x93;
- public static final int REM_INT = 0x94;
- public static final int AND_INT = 0x95;
- public static final int OR_INT = 0x96;
- public static final int XOR_INT = 0x97;
- public static final int SHL_INT = 0x98;
- public static final int SHR_INT = 0x99;
- public static final int USHR_INT = 0x9a;
- public static final int ADD_LONG = 0x9b;
- public static final int SUB_LONG = 0x9c;
- public static final int MUL_LONG = 0x9d;
- public static final int DIV_LONG = 0x9e;
- public static final int REM_LONG = 0x9f;
- public static final int AND_LONG = 0xa0;
- public static final int OR_LONG = 0xa1;
- public static final int XOR_LONG = 0xa2;
- public static final int SHL_LONG = 0xa3;
- public static final int SHR_LONG = 0xa4;
- public static final int USHR_LONG = 0xa5;
- public static final int ADD_FLOAT = 0xa6;
- public static final int SUB_FLOAT = 0xa7;
- public static final int MUL_FLOAT = 0xa8;
- public static final int DIV_FLOAT = 0xa9;
- public static final int REM_FLOAT = 0xaa;
- public static final int ADD_DOUBLE = 0xab;
- public static final int SUB_DOUBLE = 0xac;
- public static final int MUL_DOUBLE = 0xad;
- public static final int DIV_DOUBLE = 0xae;
- public static final int REM_DOUBLE = 0xaf;
- public static final int ADD_INT_2ADDR = 0xb0;
- public static final int SUB_INT_2ADDR = 0xb1;
- public static final int MUL_INT_2ADDR = 0xb2;
- public static final int DIV_INT_2ADDR = 0xb3;
- public static final int REM_INT_2ADDR = 0xb4;
- public static final int AND_INT_2ADDR = 0xb5;
- public static final int OR_INT_2ADDR = 0xb6;
- public static final int XOR_INT_2ADDR = 0xb7;
- public static final int SHL_INT_2ADDR = 0xb8;
- public static final int SHR_INT_2ADDR = 0xb9;
- public static final int USHR_INT_2ADDR = 0xba;
- public static final int ADD_LONG_2ADDR = 0xbb;
- public static final int SUB_LONG_2ADDR = 0xbc;
- public static final int MUL_LONG_2ADDR = 0xbd;
- public static final int DIV_LONG_2ADDR = 0xbe;
- public static final int REM_LONG_2ADDR = 0xbf;
- public static final int AND_LONG_2ADDR = 0xc0;
- public static final int OR_LONG_2ADDR = 0xc1;
- public static final int XOR_LONG_2ADDR = 0xc2;
- public static final int SHL_LONG_2ADDR = 0xc3;
- public static final int SHR_LONG_2ADDR = 0xc4;
- public static final int USHR_LONG_2ADDR = 0xc5;
- public static final int ADD_FLOAT_2ADDR = 0xc6;
- public static final int SUB_FLOAT_2ADDR = 0xc7;
- public static final int MUL_FLOAT_2ADDR = 0xc8;
- public static final int DIV_FLOAT_2ADDR = 0xc9;
- public static final int REM_FLOAT_2ADDR = 0xca;
- public static final int ADD_DOUBLE_2ADDR = 0xcb;
- public static final int SUB_DOUBLE_2ADDR = 0xcc;
- public static final int MUL_DOUBLE_2ADDR = 0xcd;
- public static final int DIV_DOUBLE_2ADDR = 0xce;
- public static final int REM_DOUBLE_2ADDR = 0xcf;
- public static final int ADD_INT_LIT16 = 0xd0;
- public static final int RSUB_INT = 0xd1;
- public static final int MUL_INT_LIT16 = 0xd2;
- public static final int DIV_INT_LIT16 = 0xd3;
- public static final int REM_INT_LIT16 = 0xd4;
- public static final int AND_INT_LIT16 = 0xd5;
- public static final int OR_INT_LIT16 = 0xd6;
- public static final int XOR_INT_LIT16 = 0xd7;
- public static final int ADD_INT_LIT8 = 0xd8;
- public static final int RSUB_INT_LIT8 = 0xd9;
- public static final int MUL_INT_LIT8 = 0xda;
- public static final int DIV_INT_LIT8 = 0xdb;
- public static final int REM_INT_LIT8 = 0xdc;
- public static final int AND_INT_LIT8 = 0xdd;
- public static final int OR_INT_LIT8 = 0xde;
- public static final int XOR_INT_LIT8 = 0xdf;
- public static final int SHL_INT_LIT8 = 0xe0;
- public static final int SHR_INT_LIT8 = 0xe1;
- public static final int USHR_INT_LIT8 = 0xe2;
- // END(opcodes)
+ // BEGIN(opcodes); GENERATED AUTOMATICALLY BY opcode-gen
+ public static final int NOP = 0x00;
+ public static final int MOVE = 0x01;
+ public static final int MOVE_FROM16 = 0x02;
+ public static final int MOVE_16 = 0x03;
+ public static final int MOVE_WIDE = 0x04;
+ public static final int MOVE_WIDE_FROM16 = 0x05;
+ public static final int MOVE_WIDE_16 = 0x06;
+ public static final int MOVE_OBJECT = 0x07;
+ public static final int MOVE_OBJECT_FROM16 = 0x08;
+ public static final int MOVE_OBJECT_16 = 0x09;
+ public static final int MOVE_RESULT = 0x0a;
+ public static final int MOVE_RESULT_WIDE = 0x0b;
+ public static final int MOVE_RESULT_OBJECT = 0x0c;
+ public static final int MOVE_EXCEPTION = 0x0d;
+ public static final int RETURN_VOID = 0x0e;
+ public static final int RETURN = 0x0f;
+ public static final int RETURN_WIDE = 0x10;
+ public static final int RETURN_OBJECT = 0x11;
+ public static final int CONST_4 = 0x12;
+ public static final int CONST_16 = 0x13;
+ public static final int CONST = 0x14;
+ public static final int CONST_HIGH16 = 0x15;
+ public static final int CONST_WIDE_16 = 0x16;
+ public static final int CONST_WIDE_32 = 0x17;
+ public static final int CONST_WIDE = 0x18;
+ public static final int CONST_WIDE_HIGH16 = 0x19;
+ public static final int CONST_STRING = 0x1a;
+ public static final int CONST_STRING_JUMBO = 0x1b;
+ public static final int CONST_CLASS = 0x1c;
+ public static final int MONITOR_ENTER = 0x1d;
+ public static final int MONITOR_EXIT = 0x1e;
+ public static final int CHECK_CAST = 0x1f;
+ public static final int INSTANCE_OF = 0x20;
+ public static final int ARRAY_LENGTH = 0x21;
+ public static final int NEW_INSTANCE = 0x22;
+ public static final int NEW_ARRAY = 0x23;
+ public static final int FILLED_NEW_ARRAY = 0x24;
+ public static final int FILLED_NEW_ARRAY_RANGE = 0x25;
+ public static final int FILL_ARRAY_DATA = 0x26;
+ public static final int THROW = 0x27;
+ public static final int GOTO = 0x28;
+ public static final int GOTO_16 = 0x29;
+ public static final int GOTO_32 = 0x2a;
+ public static final int PACKED_SWITCH = 0x2b;
+ public static final int SPARSE_SWITCH = 0x2c;
+ public static final int CMPL_FLOAT = 0x2d;
+ public static final int CMPG_FLOAT = 0x2e;
+ public static final int CMPL_DOUBLE = 0x2f;
+ public static final int CMPG_DOUBLE = 0x30;
+ public static final int CMP_LONG = 0x31;
+ public static final int IF_EQ = 0x32;
+ public static final int IF_NE = 0x33;
+ public static final int IF_LT = 0x34;
+ public static final int IF_GE = 0x35;
+ public static final int IF_GT = 0x36;
+ public static final int IF_LE = 0x37;
+ public static final int IF_EQZ = 0x38;
+ public static final int IF_NEZ = 0x39;
+ public static final int IF_LTZ = 0x3a;
+ public static final int IF_GEZ = 0x3b;
+ public static final int IF_GTZ = 0x3c;
+ public static final int IF_LEZ = 0x3d;
+ public static final int AGET = 0x44;
+ public static final int AGET_WIDE = 0x45;
+ public static final int AGET_OBJECT = 0x46;
+ public static final int AGET_BOOLEAN = 0x47;
+ public static final int AGET_BYTE = 0x48;
+ public static final int AGET_CHAR = 0x49;
+ public static final int AGET_SHORT = 0x4a;
+ public static final int APUT = 0x4b;
+ public static final int APUT_WIDE = 0x4c;
+ public static final int APUT_OBJECT = 0x4d;
+ public static final int APUT_BOOLEAN = 0x4e;
+ public static final int APUT_BYTE = 0x4f;
+ public static final int APUT_CHAR = 0x50;
+ public static final int APUT_SHORT = 0x51;
+ public static final int IGET = 0x52;
+ public static final int IGET_WIDE = 0x53;
+ public static final int IGET_OBJECT = 0x54;
+ public static final int IGET_BOOLEAN = 0x55;
+ public static final int IGET_BYTE = 0x56;
+ public static final int IGET_CHAR = 0x57;
+ public static final int IGET_SHORT = 0x58;
+ public static final int IPUT = 0x59;
+ public static final int IPUT_WIDE = 0x5a;
+ public static final int IPUT_OBJECT = 0x5b;
+ public static final int IPUT_BOOLEAN = 0x5c;
+ public static final int IPUT_BYTE = 0x5d;
+ public static final int IPUT_CHAR = 0x5e;
+ public static final int IPUT_SHORT = 0x5f;
+ public static final int SGET = 0x60;
+ public static final int SGET_WIDE = 0x61;
+ public static final int SGET_OBJECT = 0x62;
+ public static final int SGET_BOOLEAN = 0x63;
+ public static final int SGET_BYTE = 0x64;
+ public static final int SGET_CHAR = 0x65;
+ public static final int SGET_SHORT = 0x66;
+ public static final int SPUT = 0x67;
+ public static final int SPUT_WIDE = 0x68;
+ public static final int SPUT_OBJECT = 0x69;
+ public static final int SPUT_BOOLEAN = 0x6a;
+ public static final int SPUT_BYTE = 0x6b;
+ public static final int SPUT_CHAR = 0x6c;
+ public static final int SPUT_SHORT = 0x6d;
+ public static final int INVOKE_VIRTUAL = 0x6e;
+ public static final int INVOKE_SUPER = 0x6f;
+ public static final int INVOKE_DIRECT = 0x70;
+ public static final int INVOKE_STATIC = 0x71;
+ public static final int INVOKE_INTERFACE = 0x72;
+ public static final int INVOKE_VIRTUAL_RANGE = 0x74;
+ public static final int INVOKE_SUPER_RANGE = 0x75;
+ public static final int INVOKE_DIRECT_RANGE = 0x76;
+ public static final int INVOKE_STATIC_RANGE = 0x77;
+ public static final int INVOKE_INTERFACE_RANGE = 0x78;
+ public static final int NEG_INT = 0x7b;
+ public static final int NOT_INT = 0x7c;
+ public static final int NEG_LONG = 0x7d;
+ public static final int NOT_LONG = 0x7e;
+ public static final int NEG_FLOAT = 0x7f;
+ public static final int NEG_DOUBLE = 0x80;
+ public static final int INT_TO_LONG = 0x81;
+ public static final int INT_TO_FLOAT = 0x82;
+ public static final int INT_TO_DOUBLE = 0x83;
+ public static final int LONG_TO_INT = 0x84;
+ public static final int LONG_TO_FLOAT = 0x85;
+ public static final int LONG_TO_DOUBLE = 0x86;
+ public static final int FLOAT_TO_INT = 0x87;
+ public static final int FLOAT_TO_LONG = 0x88;
+ public static final int FLOAT_TO_DOUBLE = 0x89;
+ public static final int DOUBLE_TO_INT = 0x8a;
+ public static final int DOUBLE_TO_LONG = 0x8b;
+ public static final int DOUBLE_TO_FLOAT = 0x8c;
+ public static final int INT_TO_BYTE = 0x8d;
+ public static final int INT_TO_CHAR = 0x8e;
+ public static final int INT_TO_SHORT = 0x8f;
+ public static final int ADD_INT = 0x90;
+ public static final int SUB_INT = 0x91;
+ public static final int MUL_INT = 0x92;
+ public static final int DIV_INT = 0x93;
+ public static final int REM_INT = 0x94;
+ public static final int AND_INT = 0x95;
+ public static final int OR_INT = 0x96;
+ public static final int XOR_INT = 0x97;
+ public static final int SHL_INT = 0x98;
+ public static final int SHR_INT = 0x99;
+ public static final int USHR_INT = 0x9a;
+ public static final int ADD_LONG = 0x9b;
+ public static final int SUB_LONG = 0x9c;
+ public static final int MUL_LONG = 0x9d;
+ public static final int DIV_LONG = 0x9e;
+ public static final int REM_LONG = 0x9f;
+ public static final int AND_LONG = 0xa0;
+ public static final int OR_LONG = 0xa1;
+ public static final int XOR_LONG = 0xa2;
+ public static final int SHL_LONG = 0xa3;
+ public static final int SHR_LONG = 0xa4;
+ public static final int USHR_LONG = 0xa5;
+ public static final int ADD_FLOAT = 0xa6;
+ public static final int SUB_FLOAT = 0xa7;
+ public static final int MUL_FLOAT = 0xa8;
+ public static final int DIV_FLOAT = 0xa9;
+ public static final int REM_FLOAT = 0xaa;
+ public static final int ADD_DOUBLE = 0xab;
+ public static final int SUB_DOUBLE = 0xac;
+ public static final int MUL_DOUBLE = 0xad;
+ public static final int DIV_DOUBLE = 0xae;
+ public static final int REM_DOUBLE = 0xaf;
+ public static final int ADD_INT_2ADDR = 0xb0;
+ public static final int SUB_INT_2ADDR = 0xb1;
+ public static final int MUL_INT_2ADDR = 0xb2;
+ public static final int DIV_INT_2ADDR = 0xb3;
+ public static final int REM_INT_2ADDR = 0xb4;
+ public static final int AND_INT_2ADDR = 0xb5;
+ public static final int OR_INT_2ADDR = 0xb6;
+ public static final int XOR_INT_2ADDR = 0xb7;
+ public static final int SHL_INT_2ADDR = 0xb8;
+ public static final int SHR_INT_2ADDR = 0xb9;
+ public static final int USHR_INT_2ADDR = 0xba;
+ public static final int ADD_LONG_2ADDR = 0xbb;
+ public static final int SUB_LONG_2ADDR = 0xbc;
+ public static final int MUL_LONG_2ADDR = 0xbd;
+ public static final int DIV_LONG_2ADDR = 0xbe;
+ public static final int REM_LONG_2ADDR = 0xbf;
+ public static final int AND_LONG_2ADDR = 0xc0;
+ public static final int OR_LONG_2ADDR = 0xc1;
+ public static final int XOR_LONG_2ADDR = 0xc2;
+ public static final int SHL_LONG_2ADDR = 0xc3;
+ public static final int SHR_LONG_2ADDR = 0xc4;
+ public static final int USHR_LONG_2ADDR = 0xc5;
+ public static final int ADD_FLOAT_2ADDR = 0xc6;
+ public static final int SUB_FLOAT_2ADDR = 0xc7;
+ public static final int MUL_FLOAT_2ADDR = 0xc8;
+ public static final int DIV_FLOAT_2ADDR = 0xc9;
+ public static final int REM_FLOAT_2ADDR = 0xca;
+ public static final int ADD_DOUBLE_2ADDR = 0xcb;
+ public static final int SUB_DOUBLE_2ADDR = 0xcc;
+ public static final int MUL_DOUBLE_2ADDR = 0xcd;
+ public static final int DIV_DOUBLE_2ADDR = 0xce;
+ public static final int REM_DOUBLE_2ADDR = 0xcf;
+ public static final int ADD_INT_LIT16 = 0xd0;
+ public static final int RSUB_INT = 0xd1;
+ public static final int MUL_INT_LIT16 = 0xd2;
+ public static final int DIV_INT_LIT16 = 0xd3;
+ public static final int REM_INT_LIT16 = 0xd4;
+ public static final int AND_INT_LIT16 = 0xd5;
+ public static final int OR_INT_LIT16 = 0xd6;
+ public static final int XOR_INT_LIT16 = 0xd7;
+ public static final int ADD_INT_LIT8 = 0xd8;
+ public static final int RSUB_INT_LIT8 = 0xd9;
+ public static final int MUL_INT_LIT8 = 0xda;
+ public static final int DIV_INT_LIT8 = 0xdb;
+ public static final int REM_INT_LIT8 = 0xdc;
+ public static final int AND_INT_LIT8 = 0xdd;
+ public static final int OR_INT_LIT8 = 0xde;
+ public static final int XOR_INT_LIT8 = 0xdf;
+ public static final int SHL_INT_LIT8 = 0xe0;
+ public static final int SHR_INT_LIT8 = 0xe1;
+ public static final int USHR_INT_LIT8 = 0xe2;
+ // END(opcodes)
- // TODO: Generate these payload opcodes with opcode-gen.
+ // TODO(dx team): Generate these payload opcodes with opcode-gen.
- /**
- * special pseudo-opcode value for packed-switch data payload
- * instructions
- */
- public static final int PACKED_SWITCH_PAYLOAD = 0x100;
+ /**
+ * special pseudo-opcode value for packed-switch data payload
+ * instructions
+ */
+ public static final int PACKED_SWITCH_PAYLOAD = 0x100;
- /** special pseudo-opcode value for packed-switch data payload
- * instructions
- */
- public static final int SPARSE_SWITCH_PAYLOAD = 0x200;
+ /** special pseudo-opcode value for packed-switch data payload
+ * instructions
+ */
+ public static final int SPARSE_SWITCH_PAYLOAD = 0x200;
- /** special pseudo-opcode value for fill-array-data data payload
- * instructions
- */
- public static final int FILL_ARRAY_DATA_PAYLOAD = 0x300;
+ /** special pseudo-opcode value for fill-array-data data payload
+ * instructions
+ */
+ public static final int FILL_ARRAY_DATA_PAYLOAD = 0x300;
- /**
- * This class is uninstantiable.
- */
- private Opcodes() {
- // This space intentionally left blank.
- }
+ /**
+ * This class is uninstantiable.
+ */
+ private Opcodes() {
+ // This space intentionally left blank.
+ }
- /**
- * Determines if the given opcode has the right "shape" to be
- * valid. This includes the range {@code 0x01..0xfe}, the range
- * {@code 0x00ff..0xffff} where the low-order byte is either
- * {@code 0} or {@code 0xff}, and the special opcode values {@code
- * SPECIAL_FORMAT} and {@code NO_NEXT}. Note that not all of the
- * opcode values that pass this test are in fact used. This method
- * is meant to perform a quick check to reject blatantly wrong
- * values (e.g. when validating arguments).
+ /**
+ * Determines if the given opcode has the right "shape" to be
+ * valid. This includes the range {@code 0x01..0xfe}, the range
+ * {@code 0x00ff..0xffff} where the low-order byte is either
+ * {@code 0} or {@code 0xff}, and the special opcode values {@code
+ * SPECIAL_FORMAT} and {@code NO_NEXT}. Note that not all of the
+ * opcode values that pass this test are in fact used. This method
+ * is meant to perform a quick check to reject blatantly wrong
+ * values (e.g. when validating arguments).
+ *
+ * @param opcode the opcode value
+ * @return {@code true} iff the value has the right "shape" to be
+ * possibly valid
+ */
+ public static boolean isValidShape(int opcode) {
+ /*
+ * Note: This method bakes in knowledge that all opcodes are
+ * one of the forms:
*
- * @param opcode the opcode value
- * @return {@code true} iff the value has the right "shape" to be
- * possibly valid
+ * * single byte in range 0x01..0xfe -- normal opcodes
+ * * (byteValue << 8) -- nop and data payload opcodes
+ * * ((byteValue << 8) | 0xff) -- 16-bit extended opcodes
+ * * SPECIAL_FORMAT or NO_NEXT -- pseudo-opcodes
*/
- public static boolean isValidShape(int opcode) {
- /*
- * Note: This method bakes in knowledge that all opcodes are
- * one of the forms:
- *
- * * single byte in range 0x01..0xfe -- normal opcodes
- * * (byteValue << 8) -- nop and data payload opcodes
- * * ((byteValue << 8) | 0xff) -- 16-bit extended opcodes
- * * SPECIAL_FORMAT or NO_NEXT -- pseudo-opcodes
- */
- // Note: SPECIAL_FORMAT == NO_NEXT.
- if (opcode < SPECIAL_FORMAT) {
- return false;
- } else if (opcode == SPECIAL_FORMAT) {
- return true;
- }
-
- int lowByte = opcode & 0xff;
- if ((lowByte == 0) || (lowByte == 0xff)) {
- return true;
- }
-
- return (opcode & 0xff00) == 0;
+// Note: SPECIAL_FORMAT == NO_NEXT.
+ if (opcode < SPECIAL_FORMAT) {
+ return false;
+ } else if (opcode == SPECIAL_FORMAT) {
+ return true;
}
- /**
- * Gets the opcode out of an opcode unit, the latter of which may also
- * include one or more argument values.
- *
- * @param opcodeUnit the opcode-containing code unit
- * @return the extracted opcode
- */
- public static int extractOpcodeFromUnit(int opcodeUnit) {
- /*
- * Note: This method bakes in knowledge that all opcodes are
- * either single-byte or of the forms (byteValue << 8) or
- * ((byteValue << 8) | 0xff).
- */
-
- int lowByte = opcodeUnit & 0xff;
- return ((lowByte == 0) || (lowByte == 0xff)) ? opcodeUnit : lowByte;
+ int lowByte = opcode & 0xff;
+ if ((lowByte == 0) || (lowByte == 0xff)) {
+ return true;
}
+
+ return (opcode & 0xff00) == 0;
+ }
+
+ /**
+ * Gets the opcode out of an opcode unit, the latter of which may also
+ * include one or more argument values.
+ *
+ * @param opcodeUnit the opcode-containing code unit
+ * @return the extracted opcode
+ */
+ public static int extractOpcodeFromUnit(int opcodeUnit) {
+ /*
+ * Note: This method bakes in knowledge that all opcodes are
+ * either single-byte or of the forms (byteValue << 8) or
+ * ((byteValue << 8) | 0xff).
+ */
+
+int lowByte = opcodeUnit & 0xff;
+ return ((lowByte == 0) || (lowByte == 0xff)) ? opcodeUnit : lowByte;
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/ProtoId.java b/dx/src/com/android/jack/dx/io/ProtoId.java
index c1bb61a..d715720 100644
--- a/dx/src/com/android/jack/dx/io/ProtoId.java
+++ b/dx/src/com/android/jack/dx/io/ProtoId.java
@@ -18,51 +18,55 @@
import com.android.jack.dx.util.Unsigned;
+/**
+ * TODO(jack team)
+ */
public final class ProtoId implements Comparable<ProtoId> {
- private final DexBuffer buffer;
- private final int shortyIndex;
- private final int returnTypeIndex;
- private final int parametersOffset;
+ private final DexBuffer buffer;
+ private final int shortyIndex;
+ private final int returnTypeIndex;
+ private final int parametersOffset;
- public ProtoId(DexBuffer buffer, int shortyIndex, int returnTypeIndex, int parametersOffset) {
- this.buffer = buffer;
- this.shortyIndex = shortyIndex;
- this.returnTypeIndex = returnTypeIndex;
- this.parametersOffset = parametersOffset;
+ public ProtoId(DexBuffer buffer, int shortyIndex, int returnTypeIndex, int parametersOffset) {
+ this.buffer = buffer;
+ this.shortyIndex = shortyIndex;
+ this.returnTypeIndex = returnTypeIndex;
+ this.parametersOffset = parametersOffset;
+ }
+
+ @Override
+ public int compareTo(ProtoId other) {
+ if (returnTypeIndex != other.returnTypeIndex) {
+ return Unsigned.compare(returnTypeIndex, other.returnTypeIndex);
+ }
+ return Unsigned.compare(parametersOffset, other.parametersOffset);
+ }
+
+ public int getShortyIndex() {
+ return shortyIndex;
+ }
+
+ public int getReturnTypeIndex() {
+ return returnTypeIndex;
+ }
+
+ public int getParametersOffset() {
+ return parametersOffset;
+ }
+
+ public void writeTo(DexBuffer.Section out) {
+ out.writeInt(shortyIndex);
+ out.writeInt(returnTypeIndex);
+ out.writeInt(parametersOffset);
+ }
+
+ @Override
+ public String toString() {
+ if (buffer == null) {
+ return shortyIndex + " " + returnTypeIndex + " " + parametersOffset;
}
- public int compareTo(ProtoId other) {
- if (returnTypeIndex != other.returnTypeIndex) {
- return Unsigned.compare(returnTypeIndex, other.returnTypeIndex);
- }
- return Unsigned.compare(parametersOffset, other.parametersOffset);
- }
-
- public int getShortyIndex() {
- return shortyIndex;
- }
-
- public int getReturnTypeIndex() {
- return returnTypeIndex;
- }
-
- public int getParametersOffset() {
- return parametersOffset;
- }
-
- public void writeTo(DexBuffer.Section out) {
- out.writeInt(shortyIndex);
- out.writeInt(returnTypeIndex);
- out.writeInt(parametersOffset);
- }
-
- @Override public String toString() {
- if (buffer == null) {
- return shortyIndex + " " + returnTypeIndex + " " + parametersOffset;
- }
-
- return buffer.strings().get(shortyIndex)
- + ": " + buffer.typeNames().get(returnTypeIndex)
- + " " + buffer.readTypeList(parametersOffset);
- }
+ return buffer.strings().get(shortyIndex) + ": " + buffer.typeNames().get(returnTypeIndex) + " "
+ + buffer.readTypeList(parametersOffset);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/AddressMap.java b/dx/src/com/android/jack/dx/io/instructions/AddressMap.java
index 624870b..f546add 100644
--- a/dx/src/com/android/jack/dx/io/instructions/AddressMap.java
+++ b/dx/src/com/android/jack/dx/io/instructions/AddressMap.java
@@ -16,7 +16,6 @@
package com.android.jack.dx.io.instructions;
-import java.io.EOFException;
import java.util.HashMap;
/**
@@ -24,29 +23,29 @@
* {@code int}s.
*/
public final class AddressMap {
- /** underlying map. TODO: This might be too inefficient. */
- private final HashMap<Integer,Integer> map;
+ /** underlying map. TODO(dx team): This might be too inefficient. */
+ private final HashMap<Integer, Integer> map;
- /**
- * Constructs an instance.
- */
- public AddressMap() {
- map = new HashMap<Integer,Integer>();
- }
+ /**
+ * Constructs an instance.
+ */
+ public AddressMap() {
+ map = new HashMap<Integer, Integer>();
+ }
- /**
- * Gets the value address corresponding to the given key address. Returns
- * {@code -1} if there is no mapping.
- */
- public int get(int keyAddress) {
- Integer value = map.get(keyAddress);
- return (value == null) ? -1 : value;
- }
+ /**
+ * Gets the value address corresponding to the given key address. Returns
+ * {@code -1} if there is no mapping.
+ */
+ public int get(int keyAddress) {
+ Integer value = map.get(keyAddress);
+ return (value == null) ? -1 : value;
+ }
- /**
- * Sets the value address associated with the given key address.
- */
- public void put(int keyAddress, int valueAddress) {
- map.put(keyAddress, valueAddress);
- }
+ /**
+ * Sets the value address associated with the given key address.
+ */
+ public void put(int keyAddress, int valueAddress) {
+ map.put(keyAddress, valueAddress);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/BaseCodeCursor.java b/dx/src/com/android/jack/dx/io/instructions/BaseCodeCursor.java
index 8d82cae..f62c9aa 100644
--- a/dx/src/com/android/jack/dx/io/instructions/BaseCodeCursor.java
+++ b/dx/src/com/android/jack/dx/io/instructions/BaseCodeCursor.java
@@ -16,46 +16,48 @@
package com.android.jack.dx.io.instructions;
-import java.io.EOFException;
/**
* Base implementation of {@link CodeCursor}.
*/
public abstract class BaseCodeCursor implements CodeCursor {
- /** base address map */
- private final AddressMap baseAddressMap;
+ /** base address map */
+ private final AddressMap baseAddressMap;
- /** next index within {@link #array} to read from or write to */
- private int cursor;
+ /** next index within {@link #array} to read from or write to */
+ private int cursor;
- /**
- * Constructs an instance.
- */
- public BaseCodeCursor() {
- this.baseAddressMap = new AddressMap();
- this.cursor = 0;
- }
+ /**
+ * Constructs an instance.
+ */
+ public BaseCodeCursor() {
+ this.baseAddressMap = new AddressMap();
+ this.cursor = 0;
+ }
- /** @inheritDoc */
- public final int cursor() {
- return cursor;
- }
+ /** @inheritDoc */
+ @Override
+ public final int cursor() {
+ return cursor;
+ }
- /** @inheritDoc */
- public final int baseAddressForCursor() {
- int mapped = baseAddressMap.get(cursor);
- return (mapped >= 0) ? mapped : cursor;
- }
+ /** @inheritDoc */
+ @Override
+ public final int baseAddressForCursor() {
+ int mapped = baseAddressMap.get(cursor);
+ return (mapped >= 0) ? mapped : cursor;
+ }
- /** @inheritDoc */
- public final void setBaseAddress(int targetAddress, int baseAddress) {
- baseAddressMap.put(targetAddress, baseAddress);
- }
+ /** @inheritDoc */
+ @Override
+ public final void setBaseAddress(int targetAddress, int baseAddress) {
+ baseAddressMap.put(targetAddress, baseAddress);
+ }
- /**
- * Advance the cursor by the indicated amount.
- */
- protected final void advance(int amount) {
- cursor += amount;
- }
+ /**
+ * Advance the cursor by the indicated amount.
+ */
+ protected final void advance(int amount) {
+ cursor += amount;
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/CodeCursor.java b/dx/src/com/android/jack/dx/io/instructions/CodeCursor.java
index b9dbbbe..98e8eae 100644
--- a/dx/src/com/android/jack/dx/io/instructions/CodeCursor.java
+++ b/dx/src/com/android/jack/dx/io/instructions/CodeCursor.java
@@ -20,28 +20,28 @@
* Cursor over code units, for reading or writing out Dalvik bytecode.
*/
public interface CodeCursor {
- /**
- * Gets the cursor. The cursor is the offset in code units from
- * the start of the input of the next code unit to be read or
- * written, where the input generally consists of the code for a
- * single method.
- */
- public int cursor();
+ /**
+ * Gets the cursor. The cursor is the offset in code units from
+ * the start of the input of the next code unit to be read or
+ * written, where the input generally consists of the code for a
+ * single method.
+ */
+ public int cursor();
- /**
- * Gets the base address associated with the current cursor. This
- * differs from the cursor value when explicitly set (by {@link
- * #setBaseAddress). This is used, in particular, to convey base
- * addresses to switch data payload instructions, whose relative
- * addresses are relative to the address of a dependant switch
- * instruction.
- */
- public int baseAddressForCursor();
+ /**
+ * Gets the base address associated with the current cursor. This
+ * differs from the cursor value when explicitly set (by {@link
+ * #setBaseAddress). This is used, in particular, to convey base
+ * addresses to switch data payload instructions, whose relative
+ * addresses are relative to the address of a dependant switch
+ * instruction.
+ */
+ public int baseAddressForCursor();
- /**
- * Sets the base address for the given target address to be as indicated.
- *
- * @see #baseAddressForCursor
- */
- public void setBaseAddress(int targetAddress, int baseAddress);
+ /**
+ * Sets the base address for the given target address to be as indicated.
+ *
+ * @see #baseAddressForCursor
+ */
+ public void setBaseAddress(int targetAddress, int baseAddress);
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/CodeInput.java b/dx/src/com/android/jack/dx/io/instructions/CodeInput.java
index 9327dc4..cec6a48 100644
--- a/dx/src/com/android/jack/dx/io/instructions/CodeInput.java
+++ b/dx/src/com/android/jack/dx/io/instructions/CodeInput.java
@@ -22,24 +22,24 @@
* Input stream of code units, for reading in Dalvik bytecode.
*/
public interface CodeInput extends CodeCursor {
- /**
- * Returns whether there are any more code units to read. This
- * is analogous to {@code hasNext()} on an interator.
- */
- public boolean hasMore();
+ /**
+ * Returns whether there are any more code units to read. This
+ * is analogous to {@code hasNext()} on an interator.
+ */
+ public boolean hasMore();
- /**
- * Reads a code unit.
- */
- public int read() throws EOFException;
+ /**
+ * Reads a code unit.
+ */
+ public int read() throws EOFException;
- /**
- * Reads two code units, treating them as a little-endian {@code int}.
- */
- public int readInt() throws EOFException;
+ /**
+ * Reads two code units, treating them as a little-endian {@code int}.
+ */
+ public int readInt() throws EOFException;
- /**
- * Reads four code units, treating them as a little-endian {@code long}.
- */
- public long readLong() throws EOFException;
+ /**
+ * Reads four code units, treating them as a little-endian {@code long}.
+ */
+ public long readLong() throws EOFException;
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/CodeOutput.java b/dx/src/com/android/jack/dx/io/instructions/CodeOutput.java
index 76f4d14..3de07ac 100644
--- a/dx/src/com/android/jack/dx/io/instructions/CodeOutput.java
+++ b/dx/src/com/android/jack/dx/io/instructions/CodeOutput.java
@@ -20,58 +20,58 @@
* Output stream of code units, for writing out Dalvik bytecode.
*/
public interface CodeOutput extends CodeCursor {
- /**
- * Writes a code unit.
- */
- public void write(short codeUnit);
+ /**
+ * Writes a code unit.
+ */
+ public void write(short codeUnit);
- /**
- * Writes two code units.
- */
- public void write(short u0, short u1);
+ /**
+ * Writes two code units.
+ */
+ public void write(short u0, short u1);
- /**
- * Writes three code units.
- */
- public void write(short u0, short u1, short u2);
+ /**
+ * Writes three code units.
+ */
+ public void write(short u0, short u1, short u2);
- /**
- * Writes four code units.
- */
- public void write(short u0, short u1, short u2, short u3);
+ /**
+ * Writes four code units.
+ */
+ public void write(short u0, short u1, short u2, short u3);
- /**
- * Writes five code units.
- */
- public void write(short u0, short u1, short u2, short u3, short u4);
+ /**
+ * Writes five code units.
+ */
+ public void write(short u0, short u1, short u2, short u3, short u4);
- /**
- * Writes an {@code int}, little-endian.
- */
- public void writeInt(int value);
+ /**
+ * Writes an {@code int}, little-endian.
+ */
+ public void writeInt(int value);
- /**
- * Writes a {@code long}, little-endian.
- */
- public void writeLong(long value);
+ /**
+ * Writes a {@code long}, little-endian.
+ */
+ public void writeLong(long value);
- /**
- * Writes the contents of the given array.
- */
- public void write(byte[] data);
+ /**
+ * Writes the contents of the given array.
+ */
+ public void write(byte[] data);
- /**
- * Writes the contents of the given array.
- */
- public void write(short[] data);
+ /**
+ * Writes the contents of the given array.
+ */
+ public void write(short[] data);
- /**
- * Writes the contents of the given array.
- */
- public void write(int[] data);
+ /**
+ * Writes the contents of the given array.
+ */
+ public void write(int[] data);
- /**
- * Writes the contents of the given array.
- */
- public void write(long[] data);
+ /**
+ * Writes the contents of the given array.
+ */
+ public void write(long[] data);
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/DecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/DecodedInstruction.java
index efcdec6..0d71a91 100644
--- a/dx/src/com/android/jack/dx/io/instructions/DecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/DecodedInstruction.java
@@ -38,442 +38,443 @@
* consistently named alphabetically.</p>
*/
public abstract class DecodedInstruction {
- /** non-null; instruction format / codec */
- private final InstructionCodec format;
+ /** non-null; instruction format / codec */
+ private final InstructionCodec format;
- /** opcode number */
- private final int opcode;
+ /** opcode number */
+ private final int opcode;
- /** constant index argument */
- private final int index;
+ /** constant index argument */
+ private final int index;
- /** null-ok; index type */
- private final IndexType indexType;
+ /** null-ok; index type */
+ private final IndexType indexType;
- /**
- * target address argument. This is an absolute address, not just
- * a signed offset. <b>Note:</b> The address is unsigned, even
- * though it is stored in an {@code int}.
- */
- private final int target;
+ /**
+ * target address argument. This is an absolute address, not just
+ * a signed offset. <b>Note:</b> The address is unsigned, even
+ * though it is stored in an {@code int}.
+ */
+ private final int target;
- /**
- * literal value argument; also used for special verification error
- * constants (format 20bc) as well as should-be-zero values
- * (formats 10x, 20t, 30t, and 32x)
- */
- private final long literal;
+ /**
+ * literal value argument; also used for special verification error
+ * constants (format 20bc) as well as should-be-zero values
+ * (formats 10x, 20t, 30t, and 32x)
+ */
+ private final long literal;
- /**
- * Decodes an instruction from the given input source.
- */
- public static DecodedInstruction decode(CodeInput in) throws EOFException {
- int opcodeUnit = in.read();
- int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
- InstructionCodec format = OpcodeInfo.getFormat(opcode);
+ /**
+ * Decodes an instruction from the given input source.
+ */
+ public static DecodedInstruction decode(CodeInput in) throws EOFException {
+ int opcodeUnit = in.read();
+ int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
+ InstructionCodec format = OpcodeInfo.getFormat(opcode);
- return format.decode(opcodeUnit, in);
+ return format.decode(opcodeUnit, in);
+ }
+
+ /**
+ * Decodes an array of instructions. The result has non-null
+ * elements at each offset that represents the start of an
+ * instruction.
+ */
+ public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
+ int size = encodedInstructions.length;
+ DecodedInstruction[] decoded = new DecodedInstruction[size];
+ ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
+
+ try {
+ while (in.hasMore()) {
+ decoded[in.cursor()] = DecodedInstruction.decode(in);
+ }
+ } catch (EOFException ex) {
+ throw new DexException(ex);
}
- /**
- * Decodes an array of instructions. The result has non-null
- * elements at each offset that represents the start of an
- * instruction.
- */
- public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
- int size = encodedInstructions.length;
- DecodedInstruction[] decoded = new DecodedInstruction[size];
- ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
+ return decoded;
+ }
- try {
- while (in.hasMore()) {
- decoded[in.cursor()] = DecodedInstruction.decode(in);
- }
- } catch (EOFException ex) {
- throw new DexException(ex);
- }
-
- return decoded;
+ /**
+ * Constructs an instance.
+ */
+ public DecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal) {
+ if (format == null) {
+ throw new NullPointerException("format == null");
}
- /**
- * Constructs an instance.
- */
- public DecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal) {
- if (format == null) {
- throw new NullPointerException("format == null");
- }
-
- if (!Opcodes.isValidShape(opcode)) {
- throw new IllegalArgumentException("invalid opcode");
- }
-
- this.format = format;
- this.opcode = opcode;
- this.index = index;
- this.indexType = indexType;
- this.target = target;
- this.literal = literal;
+ if (!Opcodes.isValidShape(opcode)) {
+ throw new IllegalArgumentException("invalid opcode");
}
- public final InstructionCodec getFormat() {
- return format;
+ this.format = format;
+ this.opcode = opcode;
+ this.index = index;
+ this.indexType = indexType;
+ this.target = target;
+ this.literal = literal;
+ }
+
+ public final InstructionCodec getFormat() {
+ return format;
+ }
+
+ public final int getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Gets the opcode, as a code unit.
+ */
+ public final short getOpcodeUnit() {
+ return (short) opcode;
+ }
+
+ public final int getIndex() {
+ return index;
+ }
+
+ /**
+ * Gets the index, as a code unit.
+ */
+ public final short getIndexUnit() {
+ return (short) index;
+ }
+
+ public final IndexType getIndexType() {
+ return indexType;
+ }
+
+ /**
+ * Gets the raw target.
+ */
+ public final int getTarget() {
+ return target;
+ }
+
+ /**
+ * Gets the target as a relative offset from the given address.
+ */
+ public final int getTarget(int baseAddress) {
+ return target - baseAddress;
+ }
+
+ /**
+ * Gets the target as a relative offset from the given base
+ * address, as a code unit. This will throw if the value is out of
+ * the range of a signed code unit.
+ */
+ public final short getTargetUnit(int baseAddress) {
+ int relativeTarget = getTarget(baseAddress);
+
+ if (relativeTarget != (short) relativeTarget) {
+ throw new DexException("Target out of range: " + Hex.s4(relativeTarget));
}
- public final int getOpcode() {
- return opcode;
+ return (short) relativeTarget;
+ }
+
+ /**
+ * Gets the target as a relative offset from the given base
+ * address, masked to be a byte in size. This will throw if the
+ * value is out of the range of a signed byte.
+ */
+ public final int getTargetByte(int baseAddress) {
+ int relativeTarget = getTarget(baseAddress);
+
+ if (relativeTarget != (byte) relativeTarget) {
+ throw new DexException("Target out of range: " + Hex.s4(relativeTarget));
}
- /**
- * Gets the opcode, as a code unit.
- */
- public final short getOpcodeUnit() {
- return (short) opcode;
+ return relativeTarget & 0xff;
+ }
+
+ public final long getLiteral() {
+ return literal;
+ }
+
+ /**
+ * Gets the literal value, masked to be an int in size. This will
+ * throw if the value is out of the range of a signed int.
+ */
+ public final int getLiteralInt() {
+ if (literal != (int) literal) {
+ throw new DexException("Literal out of range: " + Hex.u8(literal));
}
- public final int getIndex() {
- return index;
+ return (int) literal;
+ }
+
+ /**
+ * Gets the literal value, as a code unit. This will throw if the
+ * value is out of the range of a signed code unit.
+ */
+ public final short getLiteralUnit() {
+ if (literal != (short) literal) {
+ throw new DexException("Literal out of range: " + Hex.u8(literal));
}
- /**
- * Gets the index, as a code unit.
- */
- public final short getIndexUnit() {
- return (short) index;
+ return (short) literal;
+ }
+
+ /**
+ * Gets the literal value, masked to be a byte in size. This will
+ * throw if the value is out of the range of a signed byte.
+ */
+ public final int getLiteralByte() {
+ if (literal != (byte) literal) {
+ throw new DexException("Literal out of range: " + Hex.u8(literal));
}
- public final IndexType getIndexType() {
- return indexType;
+ return (int) literal & 0xff;
+ }
+
+ /**
+ * Gets the literal value, masked to be a nibble in size. This
+ * will throw if the value is out of the range of a signed nibble.
+ */
+ public final int getLiteralNibble() {
+ if ((literal < -8) || (literal > 7)) {
+ throw new DexException("Literal out of range: " + Hex.u8(literal));
}
- /**
- * Gets the raw target.
- */
- public final int getTarget() {
- return target;
+ return (int) literal & 0xf;
+ }
+
+ public abstract int getRegisterCount();
+
+ public int getA() {
+ return 0;
+ }
+
+ public int getB() {
+ return 0;
+ }
+
+ public int getC() {
+ return 0;
+ }
+
+ public int getD() {
+ return 0;
+ }
+
+ public int getE() {
+ return 0;
+ }
+
+ /**
+ * Gets the register count, as a code unit. This will throw if the
+ * value is out of the range of an unsigned code unit.
+ */
+ public final short getRegisterCountUnit() {
+ int registerCount = getRegisterCount();
+
+ if ((registerCount & ~0xffff) != 0) {
+ throw new DexException("Register count out of range: " + Hex.u8(registerCount));
}
- /**
- * Gets the target as a relative offset from the given address.
- */
- public final int getTarget(int baseAddress) {
- return target - baseAddress;
+ return (short) registerCount;
+ }
+
+ /**
+ * Gets the A register number, as a code unit. This will throw if the
+ * value is out of the range of an unsigned code unit.
+ */
+ public final short getAUnit() {
+ int a = getA();
+
+ if ((a & ~0xffff) != 0) {
+ throw new DexException("Register A out of range: " + Hex.u8(a));
}
- /**
- * Gets the target as a relative offset from the given base
- * address, as a code unit. This will throw if the value is out of
- * the range of a signed code unit.
- */
- public final short getTargetUnit(int baseAddress) {
- int relativeTarget = getTarget(baseAddress);
+ return (short) a;
+ }
- if (relativeTarget != (short) relativeTarget) {
- throw new DexException("Target out of range: "
- + Hex.s4(relativeTarget));
- }
+ /**
+ * Gets the A register number, as a byte. This will throw if the
+ * value is out of the range of an unsigned byte.
+ */
+ public final short getAByte() {
+ int a = getA();
- return (short) relativeTarget;
+ if ((a & ~0xff) != 0) {
+ throw new DexException("Register A out of range: " + Hex.u8(a));
}
- /**
- * Gets the target as a relative offset from the given base
- * address, masked to be a byte in size. This will throw if the
- * value is out of the range of a signed byte.
- */
- public final int getTargetByte(int baseAddress) {
- int relativeTarget = getTarget(baseAddress);
+ return (short) a;
+ }
- if (relativeTarget != (byte) relativeTarget) {
- throw new DexException("Target out of range: "
- + Hex.s4(relativeTarget));
- }
+ /**
+ * Gets the A register number, as a nibble. This will throw if the
+ * value is out of the range of an unsigned nibble.
+ */
+ public final short getANibble() {
+ int a = getA();
- return relativeTarget & 0xff;
+ if ((a & ~0xf) != 0) {
+ throw new DexException("Register A out of range: " + Hex.u8(a));
}
- public final long getLiteral() {
- return literal;
+ return (short) a;
+ }
+
+ /**
+ * Gets the B register number, as a code unit. This will throw if the
+ * value is out of the range of an unsigned code unit.
+ */
+ public final short getBUnit() {
+ int b = getB();
+
+ if ((b & ~0xffff) != 0) {
+ throw new DexException("Register B out of range: " + Hex.u8(b));
}
- /**
- * Gets the literal value, masked to be an int in size. This will
- * throw if the value is out of the range of a signed int.
- */
- public final int getLiteralInt() {
- if (literal != (int) literal) {
- throw new DexException("Literal out of range: " + Hex.u8(literal));
- }
+ return (short) b;
+ }
- return (int) literal;
+ /**
+ * Gets the B register number, as a byte. This will throw if the
+ * value is out of the range of an unsigned byte.
+ */
+ public final short getBByte() {
+ int b = getB();
+
+ if ((b & ~0xff) != 0) {
+ throw new DexException("Register B out of range: " + Hex.u8(b));
}
- /**
- * Gets the literal value, as a code unit. This will throw if the
- * value is out of the range of a signed code unit.
- */
- public final short getLiteralUnit() {
- if (literal != (short) literal) {
- throw new DexException("Literal out of range: " + Hex.u8(literal));
- }
+ return (short) b;
+ }
- return (short) literal;
+ /**
+ * Gets the B register number, as a nibble. This will throw if the
+ * value is out of the range of an unsigned nibble.
+ */
+ public final short getBNibble() {
+ int b = getB();
+
+ if ((b & ~0xf) != 0) {
+ throw new DexException("Register B out of range: " + Hex.u8(b));
}
- /**
- * Gets the literal value, masked to be a byte in size. This will
- * throw if the value is out of the range of a signed byte.
- */
- public final int getLiteralByte() {
- if (literal != (byte) literal) {
- throw new DexException("Literal out of range: " + Hex.u8(literal));
- }
+ return (short) b;
+ }
- return (int) literal & 0xff;
+ /**
+ * Gets the C register number, as a code unit. This will throw if the
+ * value is out of the range of an unsigned code unit.
+ */
+ public final short getCUnit() {
+ int c = getC();
+
+ if ((c & ~0xffff) != 0) {
+ throw new DexException("Register C out of range: " + Hex.u8(c));
}
- /**
- * Gets the literal value, masked to be a nibble in size. This
- * will throw if the value is out of the range of a signed nibble.
- */
- public final int getLiteralNibble() {
- if ((literal < -8) || (literal > 7)) {
- throw new DexException("Literal out of range: " + Hex.u8(literal));
- }
+ return (short) c;
+ }
- return (int) literal & 0xf;
+ /**
+ * Gets the C register number, as a byte. This will throw if the
+ * value is out of the range of an unsigned byte.
+ */
+ public final short getCByte() {
+ int c = getC();
+
+ if ((c & ~0xff) != 0) {
+ throw new DexException("Register C out of range: " + Hex.u8(c));
}
- public abstract int getRegisterCount();
+ return (short) c;
+ }
- public int getA() {
- return 0;
+ /**
+ * Gets the C register number, as a nibble. This will throw if the
+ * value is out of the range of an unsigned nibble.
+ */
+ public final short getCNibble() {
+ int c = getC();
+
+ if ((c & ~0xf) != 0) {
+ throw new DexException("Register C out of range: " + Hex.u8(c));
}
- public int getB() {
- return 0;
+ return (short) c;
+ }
+
+ /**
+ * Gets the D register number, as a code unit. This will throw if the
+ * value is out of the range of an unsigned code unit.
+ */
+ public final short getDUnit() {
+ int d = getD();
+
+ if ((d & ~0xffff) != 0) {
+ throw new DexException("Register D out of range: " + Hex.u8(d));
}
- public int getC() {
- return 0;
+ return (short) d;
+ }
+
+ /**
+ * Gets the D register number, as a byte. This will throw if the
+ * value is out of the range of an unsigned byte.
+ */
+ public final short getDByte() {
+ int d = getD();
+
+ if ((d & ~0xff) != 0) {
+ throw new DexException("Register D out of range: " + Hex.u8(d));
}
- public int getD() {
- return 0;
+ return (short) d;
+ }
+
+ /**
+ * Gets the D register number, as a nibble. This will throw if the
+ * value is out of the range of an unsigned nibble.
+ */
+ public final short getDNibble() {
+ int d = getD();
+
+ if ((d & ~0xf) != 0) {
+ throw new DexException("Register D out of range: " + Hex.u8(d));
}
- public int getE() {
- return 0;
+ return (short) d;
+ }
+
+ /**
+ * Gets the E register number, as a nibble. This will throw if the
+ * value is out of the range of an unsigned nibble.
+ */
+ public final short getENibble() {
+ int e = getE();
+
+ if ((e & ~0xf) != 0) {
+ throw new DexException("Register E out of range: " + Hex.u8(e));
}
- /**
- * Gets the register count, as a code unit. This will throw if the
- * value is out of the range of an unsigned code unit.
- */
- public final short getRegisterCountUnit() {
- int registerCount = getRegisterCount();
+ return (short) e;
+ }
- if ((registerCount & ~0xffff) != 0) {
- throw new DexException("Register count out of range: "
- + Hex.u8(registerCount));
- }
+ /**
+ * Encodes this instance to the given output.
+ */
+ public final void encode(CodeOutput out) {
+ format.encode(this, out);
+ }
- return (short) registerCount;
- }
-
- /**
- * Gets the A register number, as a code unit. This will throw if the
- * value is out of the range of an unsigned code unit.
- */
- public final short getAUnit() {
- int a = getA();
-
- if ((a & ~0xffff) != 0) {
- throw new DexException("Register A out of range: " + Hex.u8(a));
- }
-
- return (short) a;
- }
-
- /**
- * Gets the A register number, as a byte. This will throw if the
- * value is out of the range of an unsigned byte.
- */
- public final short getAByte() {
- int a = getA();
-
- if ((a & ~0xff) != 0) {
- throw new DexException("Register A out of range: " + Hex.u8(a));
- }
-
- return (short) a;
- }
-
- /**
- * Gets the A register number, as a nibble. This will throw if the
- * value is out of the range of an unsigned nibble.
- */
- public final short getANibble() {
- int a = getA();
-
- if ((a & ~0xf) != 0) {
- throw new DexException("Register A out of range: " + Hex.u8(a));
- }
-
- return (short) a;
- }
-
- /**
- * Gets the B register number, as a code unit. This will throw if the
- * value is out of the range of an unsigned code unit.
- */
- public final short getBUnit() {
- int b = getB();
-
- if ((b & ~0xffff) != 0) {
- throw new DexException("Register B out of range: " + Hex.u8(b));
- }
-
- return (short) b;
- }
-
- /**
- * Gets the B register number, as a byte. This will throw if the
- * value is out of the range of an unsigned byte.
- */
- public final short getBByte() {
- int b = getB();
-
- if ((b & ~0xff) != 0) {
- throw new DexException("Register B out of range: " + Hex.u8(b));
- }
-
- return (short) b;
- }
-
- /**
- * Gets the B register number, as a nibble. This will throw if the
- * value is out of the range of an unsigned nibble.
- */
- public final short getBNibble() {
- int b = getB();
-
- if ((b & ~0xf) != 0) {
- throw new DexException("Register B out of range: " + Hex.u8(b));
- }
-
- return (short) b;
- }
-
- /**
- * Gets the C register number, as a code unit. This will throw if the
- * value is out of the range of an unsigned code unit.
- */
- public final short getCUnit() {
- int c = getC();
-
- if ((c & ~0xffff) != 0) {
- throw new DexException("Register C out of range: " + Hex.u8(c));
- }
-
- return (short) c;
- }
-
- /**
- * Gets the C register number, as a byte. This will throw if the
- * value is out of the range of an unsigned byte.
- */
- public final short getCByte() {
- int c = getC();
-
- if ((c & ~0xff) != 0) {
- throw new DexException("Register C out of range: " + Hex.u8(c));
- }
-
- return (short) c;
- }
-
- /**
- * Gets the C register number, as a nibble. This will throw if the
- * value is out of the range of an unsigned nibble.
- */
- public final short getCNibble() {
- int c = getC();
-
- if ((c & ~0xf) != 0) {
- throw new DexException("Register C out of range: " + Hex.u8(c));
- }
-
- return (short) c;
- }
-
- /**
- * Gets the D register number, as a code unit. This will throw if the
- * value is out of the range of an unsigned code unit.
- */
- public final short getDUnit() {
- int d = getD();
-
- if ((d & ~0xffff) != 0) {
- throw new DexException("Register D out of range: " + Hex.u8(d));
- }
-
- return (short) d;
- }
-
- /**
- * Gets the D register number, as a byte. This will throw if the
- * value is out of the range of an unsigned byte.
- */
- public final short getDByte() {
- int d = getD();
-
- if ((d & ~0xff) != 0) {
- throw new DexException("Register D out of range: " + Hex.u8(d));
- }
-
- return (short) d;
- }
-
- /**
- * Gets the D register number, as a nibble. This will throw if the
- * value is out of the range of an unsigned nibble.
- */
- public final short getDNibble() {
- int d = getD();
-
- if ((d & ~0xf) != 0) {
- throw new DexException("Register D out of range: " + Hex.u8(d));
- }
-
- return (short) d;
- }
-
- /**
- * Gets the E register number, as a nibble. This will throw if the
- * value is out of the range of an unsigned nibble.
- */
- public final short getENibble() {
- int e = getE();
-
- if ((e & ~0xf) != 0) {
- throw new DexException("Register E out of range: " + Hex.u8(e));
- }
-
- return (short) e;
- }
-
- /**
- * Encodes this instance to the given output.
- */
- public final void encode(CodeOutput out) {
- format.encode(this, out);
- }
-
- /**
- * Returns an instance just like this one, except with the index replaced
- * with the given one.
- */
- public abstract DecodedInstruction withIndex(int newIndex);
+ /**
+ * Returns an instance just like this one, except with the index replaced
+ * with the given one.
+ */
+ public abstract DecodedInstruction withIndex(int newIndex);
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java
index 4e59342..35ada3e 100644
--- a/dx/src/com/android/jack/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java
@@ -20,81 +20,78 @@
* A decoded Dalvik instruction which contains the payload for
* a {@code packed-switch} instruction.
*/
-public final class FillArrayDataPayloadDecodedInstruction
- extends DecodedInstruction {
- /** data array */
- private final Object data;
+public final class FillArrayDataPayloadDecodedInstruction extends DecodedInstruction {
+ /** data array */
+ private final Object data;
- /** number of elements */
- private final int size;
+ /** number of elements */
+ private final int size;
- /** element width */
- private final int elementWidth;
+ /** element width */
+ private final int elementWidth;
- /**
- * Constructs an instance. This private instance doesn't check the
- * type of the data array.
- */
- private FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
- int opcode, Object data, int size, int elementWidth) {
- super(format, opcode, 0, null, 0, 0L);
+ /**
+ * Constructs an instance. This private instance doesn't check the
+ * type of the data array.
+ */
+ private FillArrayDataPayloadDecodedInstruction(InstructionCodec format, int opcode, Object data,
+ int size, int elementWidth) {
+ super(format, opcode, 0, null, 0, 0L);
- this.data = data;
- this.size = size;
- this.elementWidth = elementWidth;
- }
+ this.data = data;
+ this.size = size;
+ this.elementWidth = elementWidth;
+ }
- /**
- * Constructs an instance.
- */
- public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
- int opcode, byte[] data) {
- this(format, opcode, data, data.length, 1);
- }
+ /**
+ * Constructs an instance.
+ */
+ public FillArrayDataPayloadDecodedInstruction(InstructionCodec format, int opcode, byte[] data) {
+ this(format, opcode, data, data.length, 1);
+ }
- /**
- * Constructs an instance.
- */
- public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
- int opcode, short[] data) {
- this(format, opcode, data, data.length, 2);
- }
+ /**
+ * Constructs an instance.
+ */
+ public FillArrayDataPayloadDecodedInstruction(InstructionCodec format, int opcode, short[] data) {
+ this(format, opcode, data, data.length, 2);
+ }
- /**
- * Constructs an instance.
- */
- public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
- int opcode, int[] data) {
- this(format, opcode, data, data.length, 4);
- }
+ /**
+ * Constructs an instance.
+ */
+ public FillArrayDataPayloadDecodedInstruction(InstructionCodec format, int opcode, int[] data) {
+ this(format, opcode, data, data.length, 4);
+ }
- /**
- * Constructs an instance.
- */
- public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
- int opcode, long[] data) {
- this(format, opcode, data, data.length, 8);
- }
+ /**
+ * Constructs an instance.
+ */
+ public FillArrayDataPayloadDecodedInstruction(InstructionCodec format, int opcode, long[] data) {
+ this(format, opcode, data, data.length, 8);
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 0;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 0;
+ }
- public short getElementWidthUnit() {
- return (short) elementWidth;
- }
+ public short getElementWidthUnit() {
+ return (short) elementWidth;
+ }
- public int getSize() {
- return size;
- }
+ public int getSize() {
+ return size;
+ }
- public Object getData() {
- return data;
- }
+ public Object getData() {
+ return data;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- throw new UnsupportedOperationException("no index in instruction");
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ throw new UnsupportedOperationException("no index in instruction");
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/FiveRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/FiveRegisterDecodedInstruction.java
index 0ed17b3..a7a1aea 100644
--- a/dx/src/com/android/jack/dx/io/instructions/FiveRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/FiveRegisterDecodedInstruction.java
@@ -22,70 +22,93 @@
* A decoded Dalvik instruction which has five register arguments.
*/
public final class FiveRegisterDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /** register argument "B" */
- private final int b;
+ /** register argument "B" */
+ private final int b;
- /** register argument "C" */
- private final int c;
+ /** register argument "C" */
+ private final int c;
- /** register argument "D" */
- private final int d;
+ /** register argument "D" */
+ private final int d;
- /** register argument "E" */
- private final int e;
+ /** register argument "E" */
+ private final int e;
- /**
- * Constructs an instance.
- */
- public FiveRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a, int b, int c, int d, int e) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public FiveRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a,
+ int b,
+ int c,
+ int d,
+ int e) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- this.b = b;
- this.c = c;
- this.d = d;
- this.e = e;
- }
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 5;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 5;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public int getB() {
- return b;
- }
+ /** @inheritDoc */
+ @Override
+ public int getB() {
+ return b;
+ }
- /** @inheritDoc */
- public int getC() {
- return c;
- }
+ /** @inheritDoc */
+ @Override
+ public int getC() {
+ return c;
+ }
- /** @inheritDoc */
- public int getD() {
- return d;
- }
+ /** @inheritDoc */
+ @Override
+ public int getD() {
+ return d;
+ }
- /** @inheritDoc */
- public int getE() {
- return e;
- }
+ /** @inheritDoc */
+ @Override
+ public int getE() {
+ return e;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new FiveRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a, b, c, d, e);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new FiveRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a,
+ b,
+ c,
+ d,
+ e);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/FourRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/FourRegisterDecodedInstruction.java
index 9d3e7e3..912a8eb 100644
--- a/dx/src/com/android/jack/dx/io/instructions/FourRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/FourRegisterDecodedInstruction.java
@@ -22,61 +22,81 @@
* A decoded Dalvik instruction which has five register arguments.
*/
public final class FourRegisterDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /** register argument "B" */
- private final int b;
+ /** register argument "B" */
+ private final int b;
- /** register argument "C" */
- private final int c;
+ /** register argument "C" */
+ private final int c;
- /** register argument "D" */
- private final int d;
+ /** register argument "D" */
+ private final int d;
- /**
- * Constructs an instance.
- */
- public FourRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a, int b, int c, int d) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public FourRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a,
+ int b,
+ int c,
+ int d) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- this.b = b;
- this.c = c;
- this.d = d;
- }
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 4;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 4;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public int getB() {
- return b;
- }
+ /** @inheritDoc */
+ @Override
+ public int getB() {
+ return b;
+ }
- /** @inheritDoc */
- public int getC() {
- return c;
- }
+ /** @inheritDoc */
+ @Override
+ public int getC() {
+ return c;
+ }
- /** @inheritDoc */
- public int getD() {
- return d;
- }
+ /** @inheritDoc */
+ @Override
+ public int getD() {
+ return d;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new FourRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a, b, c, d);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new FourRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a,
+ b,
+ c,
+ d);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/InstructionCodec.java b/dx/src/com/android/jack/dx/io/instructions/InstructionCodec.java
index d24d930..c913fcb 100644
--- a/dx/src/com/android/jack/dx/io/instructions/InstructionCodec.java
+++ b/dx/src/com/android/jack/dx/io/instructions/InstructionCodec.java
@@ -29,934 +29,864 @@
* and encode from instances of {@link DecodedInstruction}.
*/
public enum InstructionCodec {
- FORMAT_00X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return new ZeroRegisterDecodedInstruction(
- this, opcodeUnit, 0, null,
- 0, 0L);
- }
+ FORMAT_00X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return new ZeroRegisterDecodedInstruction(this, opcodeUnit, 0, null, 0, 0L);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(insn.getOpcodeUnit());
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit());
+ }
+ },
- FORMAT_10X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int literal = byte1(opcodeUnit); // should be zero
- return new ZeroRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal);
- }
+ FORMAT_10X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int literal = byte1(opcodeUnit); // should be zero
+ return new ZeroRegisterDecodedInstruction(this, opcode, 0, null, 0, literal);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(insn.getOpcodeUnit());
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit());
+ }
+ },
- FORMAT_12X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int b = nibble3(opcodeUnit);
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, 0L,
- a, b);
- }
+ FORMAT_12X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int b = nibble3(opcodeUnit);
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, 0, 0L, a, b);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcodeUnit(),
- makeByte(insn.getA(), insn.getB())));
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcodeUnit(), makeByte(insn.getA(), insn.getB())));
+ }
+ },
- FORMAT_11N() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int literal = (nibble3(opcodeUnit) << 28) >> 28; // sign-extend
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a);
- }
+ FORMAT_11N() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int literal = (nibble3(opcodeUnit) << 28) >> 28; // sign-extend
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcodeUnit(),
- makeByte(insn.getA(), insn.getLiteralNibble())));
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcodeUnit(), makeByte(insn.getA(), insn.getLiteralNibble())));
+ }
+ },
- FORMAT_11X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, 0L,
- a);
- }
+ FORMAT_11X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, 0L, a);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(codeUnit(insn.getOpcode(), insn.getA()));
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()));
+ }
+ },
- FORMAT_10T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int target = (byte) byte1(opcodeUnit); // sign-extend
- return new ZeroRegisterDecodedInstruction(
- this, opcode, 0, null,
- baseAddress + target, 0L);
- }
+ FORMAT_10T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int target = (byte) byte1(opcodeUnit); // sign-extend
+ return new ZeroRegisterDecodedInstruction(this, opcode, 0, null, baseAddress + target, 0L);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- int relativeTarget = insn.getTargetByte(out.cursor());
- out.write(codeUnit(insn.getOpcode(), relativeTarget));
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ int relativeTarget = insn.getTargetByte(out.cursor());
+ out.write(codeUnit(insn.getOpcode(), relativeTarget));
+ }
+ },
- FORMAT_20T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int literal = byte1(opcodeUnit); // should be zero
- int target = (short) in.read(); // sign-extend
- return new ZeroRegisterDecodedInstruction(
- this, opcode, 0, null,
- baseAddress + target, literal);
- }
+ FORMAT_20T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int literal = byte1(opcodeUnit); // should be zero
+ int target = (short) in.read(); // sign-extend
+ return new ZeroRegisterDecodedInstruction(this,
+ opcode,
+ 0,
+ null,
+ baseAddress + target,
+ literal);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- short relativeTarget = insn.getTargetUnit(out.cursor());
- out.write(insn.getOpcodeUnit(), relativeTarget);
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ short relativeTarget = insn.getTargetUnit(out.cursor());
+ out.write(insn.getOpcodeUnit(), relativeTarget);
+ }
+},
- FORMAT_20BC() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- // Note: We use the literal field to hold the decoded AA value.
- int opcode = byte0(opcodeUnit);
- int literal = byte1(opcodeUnit);
- int index = in.read();
- return new ZeroRegisterDecodedInstruction(
- this, opcode, index, IndexType.VARIES,
- 0, literal);
- }
+ FORMAT_20BC() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ // Note: We use the literal field to hold the decoded AA value.
+ int opcode = byte0(opcodeUnit);
+ int literal = byte1(opcodeUnit);
+ int index = in.read();
+ return new ZeroRegisterDecodedInstruction(this, opcode, index, IndexType.VARIES, 0, literal);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getLiteralByte()),
- insn.getIndexUnit());
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getLiteralByte()), insn.getIndexUnit());
+ }
+},
- FORMAT_22X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int b = in.read();
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, 0L,
- a, b);
- }
+ FORMAT_22X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int b = in.read();
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, 0, 0L, a, b);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- insn.getBUnit());
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), insn.getBUnit());
+ }
+},
- FORMAT_21T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int target = (short) in.read(); // sign-extend
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- baseAddress + target, 0L,
- a);
- }
+ FORMAT_21T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int target = (short) in.read(); // sign-extend
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, baseAddress + target, 0L, a);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- short relativeTarget = insn.getTargetUnit(out.cursor());
- out.write(codeUnit(insn.getOpcode(), insn.getA()), relativeTarget);
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ short relativeTarget = insn.getTargetUnit(out.cursor());
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), relativeTarget);
+ }
+},
- FORMAT_21S() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int literal = (short) in.read(); // sign-extend
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a);
- }
+ FORMAT_21S() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int literal = (short) in.read(); // sign-extend
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a);
+ }
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- insn.getLiteralUnit());
- }
- },
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), insn.getLiteralUnit());
+ }
+},
- FORMAT_21H() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- long literal = (short) in.read(); // sign-extend
+ FORMAT_21H() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ long literal = (short) in.read(); // sign-extend
- /*
- * Format 21h decodes differently depending on the opcode,
- * because the "signed hat" might represent either a 32-
- * or 64- bit value.
- */
- literal <<= (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
-
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- // See above.
- int opcode = insn.getOpcode();
- int shift = (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
- short literal = (short) (insn.getLiteral() >> shift);
-
- out.write(codeUnit(opcode, insn.getA()), literal);
- }
- },
-
- FORMAT_21C() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int index = in.read();
- IndexType indexType = OpcodeInfo.getIndexType(opcode);
- return new OneRegisterDecodedInstruction(
- this, opcode, index, indexType,
- 0, 0L,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- insn.getIndexUnit());
- }
- },
-
- FORMAT_23X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int bc = in.read();
- int b = byte0(bc);
- int c = byte1(bc);
- return new ThreeRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, 0L,
- a, b, c);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- codeUnit(insn.getB(), insn.getC()));
- }
- },
-
- FORMAT_22B() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int bc = in.read();
- int b = byte0(bc);
- int literal = (byte) byte1(bc); // sign-extend
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- codeUnit(insn.getB(),
- insn.getLiteralByte()));
- }
- },
-
- FORMAT_22T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int b = nibble3(opcodeUnit);
- int target = (short) in.read(); // sign-extend
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- baseAddress + target, 0L,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- short relativeTarget = insn.getTargetUnit(out.cursor());
- out.write(
- codeUnit(insn.getOpcode(),
- makeByte(insn.getA(), insn.getB())),
- relativeTarget);
- }
- },
-
- FORMAT_22S() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int b = nibble3(opcodeUnit);
- int literal = (short) in.read(); // sign-extend
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(),
- makeByte(insn.getA(), insn.getB())),
- insn.getLiteralUnit());
- }
- },
-
- FORMAT_22C() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int b = nibble3(opcodeUnit);
- int index = in.read();
- IndexType indexType = OpcodeInfo.getIndexType(opcode);
- return new TwoRegisterDecodedInstruction(
- this, opcode, index, indexType,
- 0, 0L,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(),
- makeByte(insn.getA(), insn.getB())),
- insn.getIndexUnit());
- }
- },
-
- FORMAT_22CS() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = nibble2(opcodeUnit);
- int b = nibble3(opcodeUnit);
- int index = in.read();
- return new TwoRegisterDecodedInstruction(
- this, opcode, index, IndexType.FIELD_OFFSET,
- 0, 0L,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(
- codeUnit(insn.getOpcode(),
- makeByte(insn.getA(), insn.getB())),
- insn.getIndexUnit());
- }
- },
-
- FORMAT_30T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int literal = byte1(opcodeUnit); // should be zero
- int target = in.readInt();
- return new ZeroRegisterDecodedInstruction(
- this, opcode, 0, null,
- baseAddress + target, literal);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- int relativeTarget = insn.getTarget(out.cursor());
- out.write(insn.getOpcodeUnit(),
- unit0(relativeTarget), unit1(relativeTarget));
- }
- },
-
- FORMAT_32X() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int literal = byte1(opcodeUnit); // should be zero
- int a = in.read();
- int b = in.read();
- return new TwoRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a, b);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- out.write(insn.getOpcodeUnit(), insn.getAUnit(), insn.getBUnit());
- }
- },
-
- FORMAT_31I() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int literal = in.readInt();
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- int literal = insn.getLiteralInt();
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- unit0(literal),
- unit1(literal));
- }
- },
-
- FORMAT_31T() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int baseAddress = in.cursor() - 1;
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int target = baseAddress + in.readInt();
-
- /*
- * Switch instructions need to "forward" their addresses to their
- * payload target instructions.
- */
- switch (opcode) {
- case Opcodes.PACKED_SWITCH:
- case Opcodes.SPARSE_SWITCH: {
- in.setBaseAddress(target, baseAddress);
- break;
- }
- }
-
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- target, 0L,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- int relativeTarget = insn.getTarget(out.cursor());
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- unit0(relativeTarget), unit1(relativeTarget));
- }
- },
-
- FORMAT_31C() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- int index = in.readInt();
- IndexType indexType = OpcodeInfo.getIndexType(opcode);
- return new OneRegisterDecodedInstruction(
- this, opcode, index, indexType,
- 0, 0L,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- int index = insn.getIndex();
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- unit0(index),
- unit1(index));
- }
- },
-
- FORMAT_35C() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterList(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterList(insn, out);
- }
- },
-
- FORMAT_35MS() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterList(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterList(insn, out);
- }
- },
-
- FORMAT_35MI() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterList(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterList(insn, out);
- }
- },
-
- FORMAT_3RC() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterRange(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterRange(insn, out);
- }
- },
-
- FORMAT_3RMS() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterRange(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterRange(insn, out);
- }
- },
-
- FORMAT_3RMI() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- return decodeRegisterRange(this, opcodeUnit, in);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- encodeRegisterRange(insn, out);
- }
- },
-
- FORMAT_51L() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int opcode = byte0(opcodeUnit);
- int a = byte1(opcodeUnit);
- long literal = in.readLong();
- return new OneRegisterDecodedInstruction(
- this, opcode, 0, null,
- 0, literal,
- a);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- long literal = insn.getLiteral();
- out.write(
- codeUnit(insn.getOpcode(), insn.getA()),
- unit0(literal),
- unit1(literal),
- unit2(literal),
- unit3(literal));
- }
- },
-
- FORMAT_PACKED_SWITCH_PAYLOAD() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int size = in.read();
- int firstKey = in.readInt();
- int[] targets = new int[size];
-
- for (int i = 0; i < size; i++) {
- targets[i] = in.readInt();
- }
-
- return new PackedSwitchPayloadDecodedInstruction(
- this, opcodeUnit, firstKey, targets);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- PackedSwitchPayloadDecodedInstruction payload =
- (PackedSwitchPayloadDecodedInstruction) insn;
- int[] targets = payload.getTargets();
-
- out.write(payload.getOpcodeUnit());
- out.write(asUnsignedUnit(targets.length));
- out.writeInt(payload.getFirstKey());
-
- for (int target : targets) {
- out.writeInt(target);
- }
- }
- },
-
- FORMAT_SPARSE_SWITCH_PAYLOAD() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int size = in.read();
- int[] keys = new int[size];
- int[] targets = new int[size];
-
- for (int i = 0; i < size; i++) {
- keys[i] = in.readInt();
- }
-
- for (int i = 0; i < size; i++) {
- targets[i] = in.readInt();
- }
-
- return new SparseSwitchPayloadDecodedInstruction(
- this, opcodeUnit, keys, targets);
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- SparseSwitchPayloadDecodedInstruction payload =
- (SparseSwitchPayloadDecodedInstruction) insn;
- int[] keys = payload.getKeys();
- int[] targets = payload.getTargets();
-
- out.write(payload.getOpcodeUnit());
- out.write(asUnsignedUnit(targets.length));
-
- for (int key : keys) {
- out.writeInt(key);
- }
-
- for (int target : targets) {
- out.writeInt(target);
- }
- }
- },
-
- FORMAT_FILL_ARRAY_DATA_PAYLOAD() {
- @Override public DecodedInstruction decode(int opcodeUnit,
- CodeInput in) throws EOFException {
- int elementWidth = in.read();
- int size = in.readInt();
-
- switch (elementWidth) {
- case 1: {
- byte[] array = new byte[size];
- boolean even = true;
- for (int i = 0, value = 0; i < size; i++, even = !even) {
- if (even) {
- value = in.read();
- }
- array[i] = (byte) (value & 0xff);
- value >>= 8;
- }
- return new FillArrayDataPayloadDecodedInstruction(
- this, opcodeUnit, array);
- }
- case 2: {
- short[] array = new short[size];
- for (int i = 0; i < size; i++) {
- array[i] = (short) in.read();
- }
- return new FillArrayDataPayloadDecodedInstruction(
- this, opcodeUnit, array);
- }
- case 4: {
- int[] array = new int[size];
- for (int i = 0; i < size; i++) {
- array[i] = in.readInt();
- }
- return new FillArrayDataPayloadDecodedInstruction(
- this, opcodeUnit, array);
- }
- case 8: {
- long[] array = new long[size];
- for (int i = 0; i < size; i++) {
- array[i] = in.readLong();
- }
- return new FillArrayDataPayloadDecodedInstruction(
- this, opcodeUnit, array);
- }
- }
-
- throw new DexException("bogus element_width: "
- + Hex.u2(elementWidth));
- }
-
- @Override public void encode(DecodedInstruction insn, CodeOutput out) {
- FillArrayDataPayloadDecodedInstruction payload =
- (FillArrayDataPayloadDecodedInstruction) insn;
- short elementWidth = payload.getElementWidthUnit();
- Object data = payload.getData();
-
- out.write(payload.getOpcodeUnit());
- out.write(elementWidth);
- out.writeInt(payload.getSize());
-
- switch (elementWidth) {
- case 1: out.write((byte[]) data); break;
- case 2: out.write((short[]) data); break;
- case 4: out.write((int[]) data); break;
- case 8: out.write((long[]) data); break;
- default: {
- throw new DexException("bogus element_width: "
- + Hex.u2(elementWidth));
- }
- }
- }
- };
-
- /**
- * Decodes an instruction specified by the given opcode unit, reading
- * any required additional code units from the given input source.
+ /*
+ * Format 21h decodes differently depending on the opcode,
+ * because the "signed hat" might represent either a 32-
+ * or 64- bit value.
*/
- public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in)
- throws EOFException;
+ literal <<= (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
- /**
- * Encodes the given instruction.
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ // See above.
+ int opcode = insn.getOpcode();
+ int shift = (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
+ short literal = (short) (insn.getLiteral() >> shift);
+
+ out.write(codeUnit(opcode, insn.getA()), literal);
+ }
+},
+
+ FORMAT_21C() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int index = in.read();
+ IndexType indexType = OpcodeInfo.getIndexType(opcode);
+ return new OneRegisterDecodedInstruction(this, opcode, index, indexType, 0, 0L, a);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), insn.getIndexUnit());
+ }
+},
+
+ FORMAT_23X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int bc = in.read();
+ int b = byte0(bc);
+ int c = byte1(bc);
+ return new ThreeRegisterDecodedInstruction(this, opcode, 0, null, 0, 0L, a, b, c);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), codeUnit(insn.getB(), insn.getC()));
+ }
+},
+
+ FORMAT_22B() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int bc = in.read();
+ int b = byte0(bc);
+ int literal = (byte) byte1(bc); // sign-extend
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a, b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getA()),
+ codeUnit(insn.getB(), insn.getLiteralByte()));
+ }
+},
+
+ FORMAT_22T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int b = nibble3(opcodeUnit);
+ int target = (short) in.read(); // sign-extend
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, baseAddress + target, 0L, a, b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ short relativeTarget = insn.getTargetUnit(out.cursor());
+ out.write(codeUnit(insn.getOpcode(), makeByte(insn.getA(), insn.getB())), relativeTarget);
+ }
+},
+
+ FORMAT_22S() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int b = nibble3(opcodeUnit);
+ int literal = (short) in.read(); // sign-extend
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a, b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), makeByte(insn.getA(), insn.getB())),
+ insn.getLiteralUnit());
+ }
+},
+
+ FORMAT_22C() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int b = nibble3(opcodeUnit);
+ int index = in.read();
+ IndexType indexType = OpcodeInfo.getIndexType(opcode);
+ return new TwoRegisterDecodedInstruction(this, opcode, index, indexType, 0, 0L, a, b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), makeByte(insn.getA(), insn.getB())), insn.getIndexUnit());
+ }
+},
+
+ FORMAT_22CS() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = nibble2(opcodeUnit);
+ int b = nibble3(opcodeUnit);
+ int index = in.read();
+ return new TwoRegisterDecodedInstruction(this,
+ opcode,
+ index,
+ IndexType.FIELD_OFFSET,
+ 0,
+ 0L,
+ a,
+ b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), makeByte(insn.getA(), insn.getB())), insn.getIndexUnit());
+ }
+},
+
+ FORMAT_30T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int literal = byte1(opcodeUnit); // should be zero
+ int target = in.readInt();
+ return new ZeroRegisterDecodedInstruction(this, opcode, 0, null, baseAddress + target, literal);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ int relativeTarget = insn.getTarget(out.cursor());
+ out.write(insn.getOpcodeUnit(), unit0(relativeTarget), unit1(relativeTarget));
+ }
+},
+
+ FORMAT_32X() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int literal = byte1(opcodeUnit); // should be zero
+ int a = in.read();
+ int b = in.read();
+ return new TwoRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a, b);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ out.write(insn.getOpcodeUnit(), insn.getAUnit(), insn.getBUnit());
+ }
+},
+
+ FORMAT_31I() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int literal = in.readInt();
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ int literal = insn.getLiteralInt();
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), unit0(literal), unit1(literal));
+ }
+},
+
+ FORMAT_31T() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int baseAddress = in.cursor() - 1;
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int target = baseAddress + in.readInt();
+
+ /*
+ * Switch instructions need to "forward" their addresses to their
+ * payload target instructions.
*/
- public abstract void encode(DecodedInstruction insn, CodeOutput out);
+ switch (opcode) {
+ case Opcodes.PACKED_SWITCH:
+ case Opcodes.SPARSE_SWITCH: {
+ in.setBaseAddress(target, baseAddress);
+ break;
+ }
+ }
- /**
- * Helper method that decodes any of the register-list formats.
- */
- private static DecodedInstruction decodeRegisterList(
- InstructionCodec format, int opcodeUnit, CodeInput in)
- throws EOFException {
- int opcode = byte0(opcodeUnit);
- int e = nibble2(opcodeUnit);
- int registerCount = nibble3(opcodeUnit);
- int index = in.read();
- int abcd = in.read();
- int a = nibble0(abcd);
- int b = nibble1(abcd);
- int c = nibble2(abcd);
- int d = nibble3(abcd);
- IndexType indexType = OpcodeInfo.getIndexType(opcode);
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, target, 0L, a);
+ }
- // TODO: Having to switch like this is less than ideal.
- switch (registerCount) {
- case 0:
- return new ZeroRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L);
- case 1:
- return new OneRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a);
- case 2:
- return new TwoRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a, b);
- case 3:
- return new ThreeRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a, b, c);
- case 4:
- return new FourRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a, b, c, d);
- case 5:
- return new FiveRegisterDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a, b, c, d, e);
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ int relativeTarget = insn.getTarget(out.cursor());
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), unit0(relativeTarget),
+ unit1(relativeTarget));
+ }
+},
+
+ FORMAT_31C() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ int index = in.readInt();
+ IndexType indexType = OpcodeInfo.getIndexType(opcode);
+ return new OneRegisterDecodedInstruction(this, opcode, index, indexType, 0, 0L, a);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ int index = insn.getIndex();
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), unit0(index), unit1(index));
+ }
+},
+
+ FORMAT_35C() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterList(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterList(insn, out);
+ }
+},
+
+ FORMAT_35MS() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterList(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterList(insn, out);
+ }
+},
+
+ FORMAT_35MI() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterList(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterList(insn, out);
+ }
+},
+
+ FORMAT_3RC() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterRange(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterRange(insn, out);
+ }
+},
+
+ FORMAT_3RMS() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterRange(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterRange(insn, out);
+ }
+},
+
+ FORMAT_3RMI() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ return decodeRegisterRange(this, opcodeUnit, in);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ encodeRegisterRange(insn, out);
+ }
+},
+
+ FORMAT_51L() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int a = byte1(opcodeUnit);
+ long literal = in.readLong();
+ return new OneRegisterDecodedInstruction(this, opcode, 0, null, 0, literal, a);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ long literal = insn.getLiteral();
+ out.write(codeUnit(insn.getOpcode(), insn.getA()), unit0(literal), unit1(literal),
+ unit2(literal), unit3(literal));
+ }
+},
+
+ FORMAT_PACKED_SWITCH_PAYLOAD() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int size = in.read();
+ int firstKey = in.readInt();
+ int[] targets = new int[size];
+
+ for (int i = 0; i < size; i++) {
+ targets[i] = in.readInt();
+ }
+
+ return new PackedSwitchPayloadDecodedInstruction(this, opcodeUnit, firstKey, targets);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ PackedSwitchPayloadDecodedInstruction payload = (PackedSwitchPayloadDecodedInstruction) insn;
+ int[] targets = payload.getTargets();
+
+ out.write(payload.getOpcodeUnit());
+ out.write(asUnsignedUnit(targets.length));
+ out.writeInt(payload.getFirstKey());
+
+ for (int target : targets) {
+ out.writeInt(target);
+ }
+ }
+},
+
+ FORMAT_SPARSE_SWITCH_PAYLOAD() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int size = in.read();
+ int[] keys = new int[size];
+ int[] targets = new int[size];
+
+ for (int i = 0; i < size; i++) {
+ keys[i] = in.readInt();
+ }
+
+ for (int i = 0; i < size; i++) {
+ targets[i] = in.readInt();
+ }
+
+ return new SparseSwitchPayloadDecodedInstruction(this, opcodeUnit, keys, targets);
+ }
+
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ SparseSwitchPayloadDecodedInstruction payload = (SparseSwitchPayloadDecodedInstruction) insn;
+ int[] keys = payload.getKeys();
+ int[] targets = payload.getTargets();
+
+ out.write(payload.getOpcodeUnit());
+ out.write(asUnsignedUnit(targets.length));
+
+ for (int key : keys) {
+ out.writeInt(key);
+ }
+
+ for (int target : targets) {
+ out.writeInt(target);
+ }
+ }
+},
+
+ FORMAT_FILL_ARRAY_DATA_PAYLOAD() {
+ @Override
+ public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException {
+ int elementWidth = in.read();
+ int size = in.readInt();
+
+ switch (elementWidth) {
+ case 1: {
+ byte[] array = new byte[size];
+ boolean even = true;
+ for (int i = 0, value = 0; i < size; i++, even = !even) {
+ if (even) {
+ value = in.read();
+ }
+ array[i] = (byte) (value & 0xff);
+ value >>= 8;
}
-
- throw new DexException("bogus registerCount: "
- + Hex.uNibble(registerCount));
- }
-
- /**
- * Helper method that encodes any of the register-list formats.
- */
- private static void encodeRegisterList(DecodedInstruction insn,
- CodeOutput out) {
- out.write(codeUnit(insn.getOpcode(),
- makeByte(insn.getE(), insn.getRegisterCount())),
- insn.getIndexUnit(),
- codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD()));
- }
-
- /**
- * Helper method that decodes any of the three-unit register-range formats.
- */
- private static DecodedInstruction decodeRegisterRange(
- InstructionCodec format, int opcodeUnit, CodeInput in)
- throws EOFException {
- int opcode = byte0(opcodeUnit);
- int registerCount = byte1(opcodeUnit);
- int index = in.read();
- int a = in.read();
- IndexType indexType = OpcodeInfo.getIndexType(opcode);
- return new RegisterRangeDecodedInstruction(
- format, opcode, index, indexType,
- 0, 0L,
- a, registerCount);
- }
-
- /**
- * Helper method that encodes any of the three-unit register-range formats.
- */
- private static void encodeRegisterRange(DecodedInstruction insn,
- CodeOutput out) {
- out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()),
- insn.getIndexUnit(),
- insn.getAUnit());
- }
-
- private static short codeUnit(int lowByte, int highByte) {
- if ((lowByte & ~0xff) != 0) {
- throw new IllegalArgumentException("bogus lowByte");
+ return new FillArrayDataPayloadDecodedInstruction(this, opcodeUnit, array);
+ }
+ case 2: {
+ short[] array = new short[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = (short) in.read();
}
-
- if ((highByte & ~0xff) != 0) {
- throw new IllegalArgumentException("bogus highByte");
+ return new FillArrayDataPayloadDecodedInstruction(this, opcodeUnit, array);
+ }
+ case 4: {
+ int[] array = new int[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = in.readInt();
}
-
- return (short) (lowByte | (highByte << 8));
- }
-
- private static short codeUnit(int nibble0, int nibble1, int nibble2,
- int nibble3) {
- if ((nibble0 & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus nibble0");
+ return new FillArrayDataPayloadDecodedInstruction(this, opcodeUnit, array);
+ }
+ case 8: {
+ long[] array = new long[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = in.readLong();
}
-
- if ((nibble1 & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus nibble1");
- }
-
- if ((nibble2 & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus nibble2");
- }
-
- if ((nibble3 & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus nibble3");
- }
-
- return (short) (nibble0 | (nibble1 << 4)
- | (nibble2 << 8) | (nibble3 << 12));
+ return new FillArrayDataPayloadDecodedInstruction(this, opcodeUnit, array);
+ }
}
- private static int makeByte(int lowNibble, int highNibble) {
- if ((lowNibble & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus lowNibble");
- }
+ throw new DexException("bogus element_width: " + Hex.u2(elementWidth));
+ }
- if ((highNibble & ~0xf) != 0) {
- throw new IllegalArgumentException("bogus highNibble");
- }
+ @Override
+ public void encode(DecodedInstruction insn, CodeOutput out) {
+ FillArrayDataPayloadDecodedInstruction payload = (FillArrayDataPayloadDecodedInstruction) insn;
+ short elementWidth = payload.getElementWidthUnit();
+ Object data = payload.getData();
- return lowNibble | (highNibble << 4);
+ out.write(payload.getOpcodeUnit());
+ out.write(elementWidth);
+ out.writeInt(payload.getSize());
+
+ switch (elementWidth) {
+ case 1:
+ out.write((byte[]) data);
+ break;
+ case 2:
+ out.write((short[]) data);
+ break;
+ case 4:
+ out.write((int[]) data);
+ break;
+ case 8:
+ out.write((long[]) data);
+ break;
+ default: {
+ throw new DexException("bogus element_width: " + Hex.u2(elementWidth));
+ }
+ }
+ }
+};
+
+ /**
+ * Decodes an instruction specified by the given opcode unit, reading
+ * any required additional code units from the given input source.
+ */
+ public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException;
+
+ /**
+ * Encodes the given instruction.
+ */
+ public abstract void encode(DecodedInstruction insn, CodeOutput out);
+
+ /**
+ * Helper method that decodes any of the register-list formats.
+ */
+ private static DecodedInstruction decodeRegisterList(InstructionCodec format, int opcodeUnit,
+ CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int e = nibble2(opcodeUnit);
+ int registerCount = nibble3(opcodeUnit);
+ int index = in.read();
+ int abcd = in.read();
+ int a = nibble0(abcd);
+ int b = nibble1(abcd);
+ int c = nibble2(abcd);
+ int d = nibble3(abcd);
+ IndexType indexType = OpcodeInfo.getIndexType(opcode);
+
+ // TODO(dx team): Having to switch like this is less than ideal.
+ switch (registerCount) {
+ case 0:
+ return new ZeroRegisterDecodedInstruction(format, opcode, index, indexType, 0, 0L);
+ case 1:
+ return new OneRegisterDecodedInstruction(format, opcode, index, indexType, 0, 0L, a);
+ case 2:
+ return new TwoRegisterDecodedInstruction(format, opcode, index, indexType, 0, 0L, a, b);
+ case 3:
+ return new ThreeRegisterDecodedInstruction(format,
+ opcode,
+ index,
+ indexType,
+ 0,
+ 0L,
+ a,
+ b,
+ c);
+ case 4:
+ return new FourRegisterDecodedInstruction(format,
+ opcode,
+ index,
+ indexType,
+ 0,
+ 0L,
+ a,
+ b,
+ c,
+ d);
+ case 5:
+ return new FiveRegisterDecodedInstruction(format,
+ opcode,
+ index,
+ indexType,
+ 0,
+ 0L,
+ a,
+ b,
+ c,
+ d,
+ e);
}
- private static short asUnsignedUnit(int value) {
- if ((value & ~0xffff) != 0) {
- throw new IllegalArgumentException("bogus unsigned code unit");
- }
+ throw new DexException("bogus registerCount: " + Hex.uNibble(registerCount));
+ }
- return (short) value;
+ /**
+ * Helper method that encodes any of the register-list formats.
+ */
+ private static void encodeRegisterList(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), makeByte(insn.getE(), insn.getRegisterCount())),
+ insn.getIndexUnit(), codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD()));
+ }
+
+ /**
+ * Helper method that decodes any of the three-unit register-range formats.
+ */
+ private static DecodedInstruction decodeRegisterRange(InstructionCodec format, int opcodeUnit,
+ CodeInput in) throws EOFException {
+ int opcode = byte0(opcodeUnit);
+ int registerCount = byte1(opcodeUnit);
+ int index = in.read();
+ int a = in.read();
+ IndexType indexType = OpcodeInfo.getIndexType(opcode);
+ return new RegisterRangeDecodedInstruction(format,
+ opcode,
+ index,
+ indexType,
+ 0,
+ 0L,
+ a,
+ registerCount);
+ }
+
+ /**
+ * Helper method that encodes any of the three-unit register-range formats.
+ */
+ private static void encodeRegisterRange(DecodedInstruction insn, CodeOutput out) {
+ out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()), insn.getIndexUnit(),
+ insn.getAUnit());
+ }
+
+ private static short codeUnit(int lowByte, int highByte) {
+ if ((lowByte & ~0xff) != 0) {
+ throw new IllegalArgumentException("bogus lowByte");
}
- private static short unit0(int value) {
- return (short) value;
+ if ((highByte & ~0xff) != 0) {
+ throw new IllegalArgumentException("bogus highByte");
}
- private static short unit1(int value) {
- return (short) (value >> 16);
+ return (short) (lowByte | (highByte << 8));
+ }
+
+ private static short codeUnit(int nibble0, int nibble1, int nibble2, int nibble3) {
+ if ((nibble0 & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus nibble0");
}
- private static short unit0(long value) {
- return (short) value;
+ if ((nibble1 & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus nibble1");
}
- private static short unit1(long value) {
- return (short) (value >> 16);
+ if ((nibble2 & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus nibble2");
}
- private static short unit2(long value) {
- return (short) (value >> 32);
+ if ((nibble3 & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus nibble3");
}
- private static short unit3(long value) {
- return (short) (value >> 48);
+ return (short) (nibble0 | (nibble1 << 4) | (nibble2 << 8) | (nibble3 << 12));
+ }
+
+ private static int makeByte(int lowNibble, int highNibble) {
+ if ((lowNibble & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus lowNibble");
}
- private static int byte0(int value) {
- return value & 0xff;
+ if ((highNibble & ~0xf) != 0) {
+ throw new IllegalArgumentException("bogus highNibble");
}
- private static int byte1(int value) {
- return (value >> 8) & 0xff;
+ return lowNibble | (highNibble << 4);
+ }
+
+ private static short asUnsignedUnit(int value) {
+ if ((value & ~0xffff) != 0) {
+ throw new IllegalArgumentException("bogus unsigned code unit");
}
- private static int byte2(int value) {
- return (value >> 16) & 0xff;
- }
+ return (short) value;
+ }
- private static int byte3(int value) {
- return value >>> 24;
- }
+ private static short unit0(int value) {
+ return (short) value;
+ }
- private static int nibble0(int value) {
- return value & 0xf;
- }
+ private static short unit1(int value) {
+ return (short) (value >> 16);
+ }
- private static int nibble1(int value) {
- return (value >> 4) & 0xf;
- }
+ private static short unit0(long value) {
+ return (short) value;
+ }
- private static int nibble2(int value) {
- return (value >> 8) & 0xf;
- }
+ private static short unit1(long value) {
+ return (short) (value >> 16);
+ }
- private static int nibble3(int value) {
- return (value >> 12) & 0xf;
- }
+ private static short unit2(long value) {
+ return (short) (value >> 32);
+ }
+
+ private static short unit3(long value) {
+ return (short) (value >> 48);
+ }
+
+ private static int byte0(int value) {
+ return value & 0xff;
+ }
+
+ private static int byte1(int value) {
+ return (value >> 8) & 0xff;
+ }
+
+ private static int nibble0(int value) {
+ return value & 0xf;
+ }
+
+ private static int nibble1(int value) {
+ return (value >> 4) & 0xf;
+ }
+
+ private static int nibble2(int value) {
+ return (value >> 8) & 0xf;
+ }
+
+ private static int nibble3(int value) {
+ return (value >> 12) & 0xf;
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/OneRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/OneRegisterDecodedInstruction.java
index acde53a..cac4d96 100644
--- a/dx/src/com/android/jack/dx/io/instructions/OneRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/OneRegisterDecodedInstruction.java
@@ -22,34 +22,45 @@
* A decoded Dalvik instruction which has one register argument.
*/
public final class OneRegisterDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /**
- * Constructs an instance.
- */
- public OneRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public OneRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- }
+ this.a = a;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 1;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 1;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new OneRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new OneRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java
index f2b5049..0b2ee32 100644
--- a/dx/src/com/android/jack/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java
@@ -20,43 +20,44 @@
* A decoded Dalvik instruction which contains the payload for
* a {@code packed-switch} instruction.
*/
-public final class PackedSwitchPayloadDecodedInstruction
- extends DecodedInstruction {
- /** first key value */
- private final int firstKey;
+public final class PackedSwitchPayloadDecodedInstruction extends DecodedInstruction {
+ /** first key value */
+ private final int firstKey;
- /**
- * array of target addresses. These are absolute, not relative,
- * addresses.
- */
- private final int[] targets;
+ /**
+ * array of target addresses. These are absolute, not relative,
+ * addresses.
+ */
+ private final int[] targets;
- /**
- * Constructs an instance.
- */
- public PackedSwitchPayloadDecodedInstruction(InstructionCodec format,
- int opcode, int firstKey, int[] targets) {
- super(format, opcode, 0, null, 0, 0L);
+ /**
+ * Constructs an instance.
+ */
+ public PackedSwitchPayloadDecodedInstruction(InstructionCodec format, int opcode, int firstKey,
+ int[] targets) {
+ super(format, opcode, 0, null, 0, 0L);
- this.firstKey = firstKey;
- this.targets = targets;
- }
+ this.firstKey = firstKey;
+ this.targets = targets;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 0;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 0;
+ }
- public int getFirstKey() {
- return firstKey;
- }
+ public int getFirstKey() {
+ return firstKey;
+ }
- public int[] getTargets() {
- return targets;
- }
+ public int[] getTargets() {
+ return targets;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- throw new UnsupportedOperationException("no index in instruction");
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ throw new UnsupportedOperationException("no index in instruction");
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/RegisterRangeDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/RegisterRangeDecodedInstruction.java
index 30f1242..eb73d9b 100644
--- a/dx/src/com/android/jack/dx/io/instructions/RegisterRangeDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/RegisterRangeDecodedInstruction.java
@@ -23,38 +23,51 @@
* "A" start register and a register count).
*/
public final class RegisterRangeDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /** register count */
- private final int registerCount;
+ /** register count */
+ private final int registerCount;
- /**
- * Constructs an instance.
- */
- public RegisterRangeDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a, int registerCount) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public RegisterRangeDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a,
+ int registerCount) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- this.registerCount = registerCount;
- }
+ this.a = a;
+ this.registerCount = registerCount;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return registerCount;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return registerCount;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new RegisterRangeDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a, registerCount);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new RegisterRangeDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a,
+ registerCount);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeInput.java b/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeInput.java
index c225f83..29e73ce 100644
--- a/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeInput.java
+++ b/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeInput.java
@@ -21,53 +21,56 @@
/**
* Implementation of {@code CodeInput} that reads from a {@code short[]}.
*/
-public final class ShortArrayCodeInput extends BaseCodeCursor
- implements CodeInput {
- /** source array to read from */
- private final short[] array;
+public final class ShortArrayCodeInput extends BaseCodeCursor implements CodeInput {
+ /** source array to read from */
+ private final short[] array;
- /**
- * Constructs an instance.
- */
- public ShortArrayCodeInput(short[] array) {
- if (array == null) {
- throw new NullPointerException("array == null");
- }
-
- this.array = array;
+ /**
+ * Constructs an instance.
+ */
+ public ShortArrayCodeInput(short[] array) {
+ if (array == null) {
+ throw new NullPointerException("array == null");
}
- /** @inheritDoc */
- public boolean hasMore() {
- return cursor() < array.length;
+ this.array = array;
+ }
+
+ /** @inheritDoc */
+ @Override
+ public boolean hasMore() {
+ return cursor() < array.length;
+ }
+
+ /** @inheritDoc */
+ @Override
+ public int read() throws EOFException {
+ try {
+ int value = array[cursor()];
+ advance(1);
+ return value & 0xffff;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new EOFException();
}
+ }
- /** @inheritDoc */
- public int read() throws EOFException {
- try {
- int value = array[cursor()];
- advance(1);
- return value & 0xffff;
- } catch (ArrayIndexOutOfBoundsException ex) {
- throw new EOFException();
- }
- }
+ /** @inheritDoc */
+ @Override
+ public int readInt() throws EOFException {
+ int short0 = read();
+ int short1 = read();
- /** @inheritDoc */
- public int readInt() throws EOFException {
- int short0 = read();
- int short1 = read();
+ return short0 | (short1 << 16);
+ }
- return short0 | (short1 << 16);
- }
+ /** @inheritDoc */
+ @Override
+ public long readLong() throws EOFException {
+ long short0 = read();
+ long short1 = read();
+ long short2 = read();
+ long short3 = read();
- /** @inheritDoc */
- public long readLong() throws EOFException {
- long short0 = read();
- long short1 = read();
- long short2 = read();
- long short3 = read();
-
- return short0 | (short1 << 16) | (short2 << 32) | (short3 << 48);
- }
+ return short0 | (short1 << 16) | (short2 << 32) | (short3 << 48);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeOutput.java b/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeOutput.java
index 4de2e71..a1a0cd9 100644
--- a/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeOutput.java
+++ b/dx/src/com/android/jack/dx/io/instructions/ShortArrayCodeOutput.java
@@ -19,128 +19,138 @@
/**
* Implementation of {@code CodeOutput} that writes to a {@code short[]}.
*/
-public final class ShortArrayCodeOutput extends BaseCodeCursor
- implements CodeOutput {
- /** array to write to */
- private final short[] array;
+public final class ShortArrayCodeOutput extends BaseCodeCursor implements CodeOutput {
+ /** array to write to */
+ private final short[] array;
- /**
- * Constructs an instance.
- *
- * @param maxSize the maximum number of code units that will be written
- */
- public ShortArrayCodeOutput(int maxSize) {
- if (maxSize < 0) {
- throw new IllegalArgumentException("maxSize < 0");
- }
-
- this.array = new short[maxSize];
+ /**
+ * Constructs an instance.
+ *
+ * @param maxSize the maximum number of code units that will be written
+ */
+ public ShortArrayCodeOutput(int maxSize) {
+ if (maxSize < 0) {
+ throw new IllegalArgumentException("maxSize < 0");
}
- /**
- * Gets the array. The returned array contains exactly the data
- * written (e.g. no leftover space at the end).
- */
- public short[] getArray() {
- int cursor = cursor();
+ this.array = new short[maxSize];
+ }
- if (cursor == array.length) {
- return array;
- }
+ /**
+ * Gets the array. The returned array contains exactly the data
+ * written (e.g. no leftover space at the end).
+ */
+ public short[] getArray() {
+ int cursor = cursor();
- short[] result = new short[cursor];
- System.arraycopy(array, 0, result, 0, cursor);
- return result;
+ if (cursor == array.length) {
+ return array;
}
- /** @inheritDoc */
- public void write(short codeUnit) {
- array[cursor()] = codeUnit;
- advance(1);
- }
+ short[] result = new short[cursor];
+ System.arraycopy(array, 0, result, 0, cursor);
+ return result;
+ }
- /** @inheritDoc */
- public void write(short u0, short u1) {
- write(u0);
- write(u1);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(short codeUnit) {
+ array[cursor()] = codeUnit;
+ advance(1);
+ }
- /** @inheritDoc */
- public void write(short u0, short u1, short u2) {
- write(u0);
- write(u1);
- write(u2);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(short u0, short u1) {
+ write(u0);
+ write(u1);
+ }
- /** @inheritDoc */
- public void write(short u0, short u1, short u2, short u3) {
- write(u0);
- write(u1);
- write(u2);
- write(u3);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(short u0, short u1, short u2) {
+ write(u0);
+ write(u1);
+ write(u2);
+ }
- /** @inheritDoc */
- public void write(short u0, short u1, short u2, short u3, short u4) {
- write(u0);
- write(u1);
- write(u2);
- write(u3);
- write(u4);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(short u0, short u1, short u2, short u3) {
+ write(u0);
+ write(u1);
+ write(u2);
+ write(u3);
+ }
- /** @inheritDoc */
- public void writeInt(int value) {
+ /** @inheritDoc */
+ @Override
+ public void write(short u0, short u1, short u2, short u3, short u4) {
+ write(u0);
+ write(u1);
+ write(u2);
+ write(u3);
+ write(u4);
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void writeInt(int value) {
+ write((short) value);
+ write((short) (value >> 16));
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void writeLong(long value) {
+ write((short) value);
+ write((short) (value >> 16));
+ write((short) (value >> 32));
+ write((short) (value >> 48));
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void write(byte[] data) {
+ int value = 0;
+ boolean even = true;
+ for (byte b : data) {
+ if (even) {
+ value = b & 0xff;
+ even = false;
+ } else {
+ value |= b << 8;
write((short) value);
- write((short) (value >> 16));
+ even = true;
+ }
}
- /** @inheritDoc */
- public void writeLong(long value) {
- write((short) value);
- write((short) (value >> 16));
- write((short) (value >> 32));
- write((short) (value >> 48));
+ if (!even) {
+ write((short) value);
}
+ }
- /** @inheritDoc */
- public void write(byte[] data) {
- int value = 0;
- boolean even = true;
- for (byte b : data) {
- if (even) {
- value = b & 0xff;
- even = false;
- } else {
- value |= b << 8;
- write((short) value);
- even = true;
- }
- }
-
- if (!even) {
- write((short) value);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(short[] data) {
+ for (short unit : data) {
+ write(unit);
}
+ }
- /** @inheritDoc */
- public void write(short[] data) {
- for (short unit : data) {
- write(unit);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(int[] data) {
+ for (int i : data) {
+ writeInt(i);
}
+ }
- /** @inheritDoc */
- public void write(int[] data) {
- for (int i : data) {
- writeInt(i);
- }
+ /** @inheritDoc */
+ @Override
+ public void write(long[] data) {
+ for (long l : data) {
+ writeLong(l);
}
-
- /** @inheritDoc */
- public void write(long[] data) {
- for (long l : data) {
- writeLong(l);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java
index 5155976..781c12c 100644
--- a/dx/src/com/android/jack/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java
@@ -20,47 +20,48 @@
* A decoded Dalvik instruction which contains the payload for
* a {@code packed-switch} instruction.
*/
-public final class SparseSwitchPayloadDecodedInstruction
- extends DecodedInstruction {
- /** array of key values */
- private final int[] keys;
+public final class SparseSwitchPayloadDecodedInstruction extends DecodedInstruction {
+ /** array of key values */
+ private final int[] keys;
- /**
- * array of target addresses. These are absolute, not relative,
- * addresses.
- */
- private final int[] targets;
+ /**
+ * array of target addresses. These are absolute, not relative,
+ * addresses.
+ */
+ private final int[] targets;
- /**
- * Constructs an instance.
- */
- public SparseSwitchPayloadDecodedInstruction(InstructionCodec format,
- int opcode, int[] keys, int[] targets) {
- super(format, opcode, 0, null, 0, 0L);
+ /**
+ * Constructs an instance.
+ */
+ public SparseSwitchPayloadDecodedInstruction(InstructionCodec format, int opcode, int[] keys,
+ int[] targets) {
+ super(format, opcode, 0, null, 0, 0L);
- if (keys.length != targets.length) {
- throw new IllegalArgumentException("keys/targets length mismatch");
- }
-
- this.keys = keys;
- this.targets = targets;
+ if (keys.length != targets.length) {
+ throw new IllegalArgumentException("keys/targets length mismatch");
}
- /** @inheritDoc */
- public int getRegisterCount() {
- return 0;
- }
+ this.keys = keys;
+ this.targets = targets;
+ }
- public int[] getKeys() {
- return keys;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 0;
+ }
- public int[] getTargets() {
- return targets;
- }
+ public int[] getKeys() {
+ return keys;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- throw new UnsupportedOperationException("no index in instruction");
- }
+ public int[] getTargets() {
+ return targets;
+ }
+
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ throw new UnsupportedOperationException("no index in instruction");
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/ThreeRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/ThreeRegisterDecodedInstruction.java
index 3fe93ac..c80d827 100644
--- a/dx/src/com/android/jack/dx/io/instructions/ThreeRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/ThreeRegisterDecodedInstruction.java
@@ -22,52 +22,69 @@
* A decoded Dalvik instruction which has three register arguments.
*/
public final class ThreeRegisterDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /** register argument "B" */
- private final int b;
+ /** register argument "B" */
+ private final int b;
- /** register argument "C" */
- private final int c;
+ /** register argument "C" */
+ private final int c;
- /**
- * Constructs an instance.
- */
- public ThreeRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a, int b, int c) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public ThreeRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a,
+ int b,
+ int c) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- this.b = b;
- this.c = c;
- }
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 3;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 3;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public int getB() {
- return b;
- }
+ /** @inheritDoc */
+ @Override
+ public int getB() {
+ return b;
+ }
- /** @inheritDoc */
- public int getC() {
- return c;
- }
+ /** @inheritDoc */
+ @Override
+ public int getC() {
+ return c;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new ThreeRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a, b, c);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new ThreeRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a,
+ b,
+ c);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/TwoRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/TwoRegisterDecodedInstruction.java
index 6ff4e17..2be0f98 100644
--- a/dx/src/com/android/jack/dx/io/instructions/TwoRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/TwoRegisterDecodedInstruction.java
@@ -22,43 +22,57 @@
* A decoded Dalvik instruction which has two register arguments.
*/
public final class TwoRegisterDecodedInstruction extends DecodedInstruction {
- /** register argument "A" */
- private final int a;
+ /** register argument "A" */
+ private final int a;
- /** register argument "B" */
- private final int b;
+ /** register argument "B" */
+ private final int b;
- /**
- * Constructs an instance.
- */
- public TwoRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal,
- int a, int b) {
- super(format, opcode, index, indexType, target, literal);
+ /**
+ * Constructs an instance.
+ */
+ public TwoRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal,
+ int a,
+ int b) {
+ super(format, opcode, index, indexType, target, literal);
- this.a = a;
- this.b = b;
- }
+ this.a = a;
+ this.b = b;
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 2;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 2;
+ }
- /** @inheritDoc */
- public int getA() {
- return a;
- }
+ /** @inheritDoc */
+ @Override
+ public int getA() {
+ return a;
+ }
- /** @inheritDoc */
- public int getB() {
- return b;
- }
+ /** @inheritDoc */
+ @Override
+ public int getB() {
+ return b;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new TwoRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral(), a, b);
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new TwoRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral(),
+ a,
+ b);
+ }
}
diff --git a/dx/src/com/android/jack/dx/io/instructions/ZeroRegisterDecodedInstruction.java b/dx/src/com/android/jack/dx/io/instructions/ZeroRegisterDecodedInstruction.java
index 0e69a5e..443b854 100644
--- a/dx/src/com/android/jack/dx/io/instructions/ZeroRegisterDecodedInstruction.java
+++ b/dx/src/com/android/jack/dx/io/instructions/ZeroRegisterDecodedInstruction.java
@@ -22,23 +22,32 @@
* A decoded Dalvik instruction which has no register arguments.
*/
public final class ZeroRegisterDecodedInstruction extends DecodedInstruction {
- /**
- * Constructs an instance.
- */
- public ZeroRegisterDecodedInstruction(InstructionCodec format, int opcode,
- int index, IndexType indexType, int target, long literal) {
- super(format, opcode, index, indexType, target, literal);
- }
+ /**
+ * Constructs an instance.
+ */
+ public ZeroRegisterDecodedInstruction(InstructionCodec format,
+ int opcode,
+ int index,
+ IndexType indexType,
+ int target,
+ long literal) {
+ super(format, opcode, index, indexType, target, literal);
+ }
- /** @inheritDoc */
- public int getRegisterCount() {
- return 0;
- }
+ /** @inheritDoc */
+ @Override
+ public int getRegisterCount() {
+ return 0;
+ }
- /** @inheritDoc */
- public DecodedInstruction withIndex(int newIndex) {
- return new ZeroRegisterDecodedInstruction(
- getFormat(), getOpcode(), newIndex, getIndexType(),
- getTarget(), getLiteral());
- }
+ /** @inheritDoc */
+ @Override
+ public DecodedInstruction withIndex(int newIndex) {
+ return new ZeroRegisterDecodedInstruction(getFormat(),
+ getOpcode(),
+ newIndex,
+ getIndexType(),
+ getTarget(),
+ getLiteral());
+ }
}
diff --git a/dx/src/com/android/jack/dx/merge/CollisionPolicy.java b/dx/src/com/android/jack/dx/merge/CollisionPolicy.java
index f30bf0a..1a883ab 100644
--- a/dx/src/com/android/jack/dx/merge/CollisionPolicy.java
+++ b/dx/src/com/android/jack/dx/merge/CollisionPolicy.java
@@ -21,14 +21,14 @@
*/
public enum CollisionPolicy {
- /**
- * Keep the class def from the first dex file and discard the def from the
- * second dex file. This policy is appropriate for incremental builds.
- */
- KEEP_FIRST,
+ /**
+ * Keep the class def from the first dex file and discard the def from the
+ * second dex file. This policy is appropriate for incremental builds.
+ */
+ KEEP_FIRST,
- /**
- * Forbid collisions. This policy is appropriate for merging libraries.
- */
- FAIL
+ /**
+ * Forbid collisions. This policy is appropriate for merging libraries.
+ */
+ FAIL
}
diff --git a/dx/src/com/android/jack/dx/merge/DexMerger.java b/dx/src/com/android/jack/dx/merge/DexMerger.java
index dad2524..b473a5e 100644
--- a/dx/src/com/android/jack/dx/merge/DexMerger.java
+++ b/dx/src/com/android/jack/dx/merge/DexMerger.java
@@ -40,1047 +40,1070 @@
* Combine two dex files into one.
*/
public final class DexMerger {
- private final DexBuffer dexA;
- private final DexBuffer dexB;
- private final CollisionPolicy collisionPolicy;
- private final WriterSizes writerSizes;
+ private final DexBuffer dexA;
+ private final DexBuffer dexB;
+ private final CollisionPolicy collisionPolicy;
+ private final WriterSizes writerSizes;
- private final DexBuffer dexOut = new DexBuffer();
+ private final DexBuffer dexOut = new DexBuffer();
- private final DexBuffer.Section headerOut;
+ private final DexBuffer.Section headerOut;
- /** All IDs and definitions sections */
- private final DexBuffer.Section idsDefsOut;
+ /** All IDs and definitions sections */
+ private final DexBuffer.Section idsDefsOut;
- private final DexBuffer.Section mapListOut;
+ private final DexBuffer.Section mapListOut;
- private final DexBuffer.Section typeListOut;
+ private final DexBuffer.Section typeListOut;
- private final DexBuffer.Section classDataOut;
+ private final DexBuffer.Section classDataOut;
- private final DexBuffer.Section codeOut;
+ private final DexBuffer.Section codeOut;
- private final DexBuffer.Section stringDataOut;
+ private final DexBuffer.Section stringDataOut;
- private final DexBuffer.Section debugInfoOut;
+ private final DexBuffer.Section debugInfoOut;
- private final DexBuffer.Section encodedArrayOut;
+ private final DexBuffer.Section encodedArrayOut;
- /** annotations directory on a type */
- private final DexBuffer.Section annotationsDirectoryOut;
+ /** annotations directory on a type */
+ private final DexBuffer.Section annotationsDirectoryOut;
- /** sets of annotations on a member, parameter or type */
- private final DexBuffer.Section annotationSetOut;
+ /** sets of annotations on a member, parameter or type */
+ private final DexBuffer.Section annotationSetOut;
- /** parameter lists */
- private final DexBuffer.Section annotationSetRefListOut;
+ /** parameter lists */
+ private final DexBuffer.Section annotationSetRefListOut;
- /** individual annotations, each containing zero or more fields */
- private final DexBuffer.Section annotationOut;
+ /** individual annotations, each containing zero or more fields */
+ private final DexBuffer.Section annotationOut;
- private final TableOfContents contentsOut;
+ private final TableOfContents contentsOut;
- private final IndexMap aIndexMap;
- private final IndexMap bIndexMap;
- private final InstructionTransformer aInstructionTransformer;
- private final InstructionTransformer bInstructionTransformer;
+ private final IndexMap aIndexMap;
+ private final IndexMap bIndexMap;
+ private final InstructionTransformer aInstructionTransformer;
+ private final InstructionTransformer bInstructionTransformer;
- /** minimum number of wasted bytes before it's worthwhile to compact the result */
- private int compactWasteThreshold = 1024 * 1024; // 1MiB
+ /** minimum number of wasted bytes before it's worthwhile to compact the result */
+ private int compactWasteThreshold = 1024 * 1024; // 1MiB
- public DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy)
- throws IOException {
- this(dexA, dexB, collisionPolicy, new WriterSizes(dexA, dexB));
+ public DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy)
+ throws IOException {
+ this(dexA, dexB, collisionPolicy, new WriterSizes(dexA, dexB));
+ }
+
+ private DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy,
+ WriterSizes writerSizes) throws IOException {
+ this.dexA = dexA;
+ this.dexB = dexB;
+ this.collisionPolicy = collisionPolicy;
+ this.writerSizes = writerSizes;
+
+ TableOfContents aContents = dexA.getTableOfContents();
+ TableOfContents bContents = dexB.getTableOfContents();
+ aIndexMap = new IndexMap(dexOut, aContents);
+ bIndexMap = new IndexMap(dexOut, bContents);
+ aInstructionTransformer = new InstructionTransformer(aIndexMap);
+ bInstructionTransformer = new InstructionTransformer(bIndexMap);
+
+ headerOut = dexOut.appendSection(writerSizes.header, "header");
+ idsDefsOut = dexOut.appendSection(writerSizes.idsDefs, "ids defs");
+
+ contentsOut = dexOut.getTableOfContents();
+ contentsOut.dataOff = dexOut.getLength();
+
+ contentsOut.mapList.off = dexOut.getLength();
+ contentsOut.mapList.size = 1;
+ mapListOut = dexOut.appendSection(writerSizes.mapList, "map list");
+
+ contentsOut.typeLists.off = dexOut.getLength();
+ typeListOut = dexOut.appendSection(writerSizes.typeList, "type list");
+
+ contentsOut.annotationSetRefLists.off = dexOut.getLength();
+ annotationSetRefListOut =
+ dexOut.appendSection(writerSizes.annotationsSetRefList, "annotation set ref list");
+
+ contentsOut.annotationSets.off = dexOut.getLength();
+ annotationSetOut = dexOut.appendSection(writerSizes.annotationsSet, "annotation sets");
+
+ contentsOut.classDatas.off = dexOut.getLength();
+ classDataOut = dexOut.appendSection(writerSizes.classData, "class data");
+
+ contentsOut.codes.off = dexOut.getLength();
+ codeOut = dexOut.appendSection(writerSizes.code, "code");
+
+ contentsOut.stringDatas.off = dexOut.getLength();
+ stringDataOut = dexOut.appendSection(writerSizes.stringData, "string data");
+
+ contentsOut.debugInfos.off = dexOut.getLength();
+ debugInfoOut = dexOut.appendSection(writerSizes.debugInfo, "debug info");
+
+ contentsOut.annotations.off = dexOut.getLength();
+ annotationOut = dexOut.appendSection(writerSizes.annotation, "annotation");
+
+ contentsOut.encodedArrays.off = dexOut.getLength();
+ encodedArrayOut = dexOut.appendSection(writerSizes.encodedArray, "encoded array");
+
+ contentsOut.annotationsDirectories.off = dexOut.getLength();
+ annotationsDirectoryOut =
+ dexOut.appendSection(writerSizes.annotationsDirectory, "annotations directory");
+
+ dexOut.noMoreSections();
+ contentsOut.dataSize = dexOut.getLength() - contentsOut.dataOff;
+ }
+
+ public void setCompactWasteThreshold(int compactWasteThreshold) {
+ this.compactWasteThreshold = compactWasteThreshold;
+ }
+
+ private DexBuffer mergeDexBuffers() throws IOException {
+ mergeStringIds();
+ mergeTypeIds();
+ mergeTypeLists();
+ mergeProtoIds();
+ mergeFieldIds();
+ mergeMethodIds();
+ mergeAnnotations();
+ unionAnnotationSetsAndDirectories();
+ mergeClassDefs();
+
+ // write the header
+ contentsOut.header.off = 0;
+ contentsOut.header.size = 1;
+ contentsOut.fileSize = dexOut.getLength();
+ contentsOut.computeSizesFromOffsets();
+ contentsOut.writeHeader(headerOut);
+ contentsOut.writeMap(mapListOut);
+
+ // generate and write the hashes
+ new DexHasher().writeHashes(dexOut);
+
+ return dexOut;
+ }
+
+ public DexBuffer merge() throws IOException {
+ long start = System.nanoTime();
+ DexBuffer result = mergeDexBuffers();
+
+ /*
+ * We use pessimistic sizes when merging dex files. If those sizes
+ * result in too many bytes wasted, compact the result. To compact,
+ * simply merge the result with itself.
+ */
+ WriterSizes compactedSizes = new WriterSizes(this);
+ int wastedByteCount = writerSizes.size() - compactedSizes.size();
+ if (wastedByteCount > +compactWasteThreshold) {
+ DexMerger compacter =
+ new DexMerger(dexOut, new DexBuffer(), CollisionPolicy.FAIL, compactedSizes);
+ result = compacter.mergeDexBuffers();
+ System.out.printf("Result compacted from %.1fKiB to %.1fKiB to save %.1fKiB%n",
+ dexOut.getLength() / 1024f, result.getLength() / 1024f, wastedByteCount / 1024f);
}
- private DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy,
- WriterSizes writerSizes) throws IOException {
- this.dexA = dexA;
- this.dexB = dexB;
- this.collisionPolicy = collisionPolicy;
- this.writerSizes = writerSizes;
+ long elapsed = System.nanoTime() - start;
+ System.out.printf("Merged dex A (%d defs/%.1fKiB) with dex B "
+ + "(%d defs/%.1fKiB). Result is %d defs/%.1fKiB. Took %.1fs%n",
+ dexA.getTableOfContents().classDefs.size,
+ dexA.getLength() / 1024f,
+ dexB.getTableOfContents().classDefs.size,
+ dexB.getLength() / 1024f,
+ result.getTableOfContents().classDefs.size,
+ result.getLength() / 1024f,
+ elapsed / 1000000000f);
- TableOfContents aContents = dexA.getTableOfContents();
- TableOfContents bContents = dexB.getTableOfContents();
- aIndexMap = new IndexMap(dexOut, aContents);
- bIndexMap = new IndexMap(dexOut, bContents);
- aInstructionTransformer = new InstructionTransformer(aIndexMap);
- bInstructionTransformer = new InstructionTransformer(bIndexMap);
+ return result;
+ }
- headerOut = dexOut.appendSection(writerSizes.header, "header");
- idsDefsOut = dexOut.appendSection(writerSizes.idsDefs, "ids defs");
+ /**
+ * Reads an IDs section of two dex files and writes an IDs section of a
+ * merged dex file. Populates maps from old to new indices in the process.
+ */
+ abstract class IdMerger<T extends Comparable<T>> {
+ private final DexBuffer.Section out;
- contentsOut = dexOut.getTableOfContents();
- contentsOut.dataOff = dexOut.getLength();
-
- contentsOut.mapList.off = dexOut.getLength();
- contentsOut.mapList.size = 1;
- mapListOut = dexOut.appendSection(writerSizes.mapList, "map list");
-
- contentsOut.typeLists.off = dexOut.getLength();
- typeListOut = dexOut.appendSection(writerSizes.typeList, "type list");
-
- contentsOut.annotationSetRefLists.off = dexOut.getLength();
- annotationSetRefListOut = dexOut.appendSection(
- writerSizes.annotationsSetRefList, "annotation set ref list");
-
- contentsOut.annotationSets.off = dexOut.getLength();
- annotationSetOut = dexOut.appendSection(writerSizes.annotationsSet, "annotation sets");
-
- contentsOut.classDatas.off = dexOut.getLength();
- classDataOut = dexOut.appendSection(writerSizes.classData, "class data");
-
- contentsOut.codes.off = dexOut.getLength();
- codeOut = dexOut.appendSection(writerSizes.code, "code");
-
- contentsOut.stringDatas.off = dexOut.getLength();
- stringDataOut = dexOut.appendSection(writerSizes.stringData, "string data");
-
- contentsOut.debugInfos.off = dexOut.getLength();
- debugInfoOut = dexOut.appendSection(writerSizes.debugInfo, "debug info");
-
- contentsOut.annotations.off = dexOut.getLength();
- annotationOut = dexOut.appendSection(writerSizes.annotation, "annotation");
-
- contentsOut.encodedArrays.off = dexOut.getLength();
- encodedArrayOut = dexOut.appendSection(writerSizes.encodedArray, "encoded array");
-
- contentsOut.annotationsDirectories.off = dexOut.getLength();
- annotationsDirectoryOut = dexOut.appendSection(
- writerSizes.annotationsDirectory, "annotations directory");
-
- dexOut.noMoreSections();
- contentsOut.dataSize = dexOut.getLength() - contentsOut.dataOff;
- }
-
- public void setCompactWasteThreshold(int compactWasteThreshold) {
- this.compactWasteThreshold = compactWasteThreshold;
- }
-
- private DexBuffer mergeDexBuffers() throws IOException {
- mergeStringIds();
- mergeTypeIds();
- mergeTypeLists();
- mergeProtoIds();
- mergeFieldIds();
- mergeMethodIds();
- mergeAnnotations();
- unionAnnotationSetsAndDirectories();
- mergeClassDefs();
-
- // write the header
- contentsOut.header.off = 0;
- contentsOut.header.size = 1;
- contentsOut.fileSize = dexOut.getLength();
- contentsOut.computeSizesFromOffsets();
- contentsOut.writeHeader(headerOut);
- contentsOut.writeMap(mapListOut);
-
- // generate and write the hashes
- new DexHasher().writeHashes(dexOut);
-
- return dexOut;
- }
-
- public DexBuffer merge() throws IOException {
- long start = System.nanoTime();
- DexBuffer result = mergeDexBuffers();
-
- /*
- * We use pessimistic sizes when merging dex files. If those sizes
- * result in too many bytes wasted, compact the result. To compact,
- * simply merge the result with itself.
- */
- WriterSizes compactedSizes = new WriterSizes(this);
- int wastedByteCount = writerSizes.size() - compactedSizes.size();
- if (wastedByteCount > + compactWasteThreshold) {
- DexMerger compacter = new DexMerger(
- dexOut, new DexBuffer(), CollisionPolicy.FAIL, compactedSizes);
- result = compacter.mergeDexBuffers();
- System.out.printf("Result compacted from %.1fKiB to %.1fKiB to save %.1fKiB%n",
- dexOut.getLength() / 1024f,
- result.getLength() / 1024f,
- wastedByteCount / 1024f);
- }
-
- long elapsed = System.nanoTime() - start;
- System.out.printf("Merged dex A (%d defs/%.1fKiB) with dex B "
- + "(%d defs/%.1fKiB). Result is %d defs/%.1fKiB. Took %.1fs%n",
- dexA.getTableOfContents().classDefs.size,
- dexA.getLength() / 1024f,
- dexB.getTableOfContents().classDefs.size,
- dexB.getLength() / 1024f,
- result.getTableOfContents().classDefs.size,
- result.getLength() / 1024f,
- elapsed / 1000000000f);
-
- return result;
+ protected IdMerger(DexBuffer.Section out) {
+ this.out = out;
}
/**
- * Reads an IDs section of two dex files and writes an IDs section of a
- * merged dex file. Populates maps from old to new indices in the process.
+ * Merges already-sorted sections, reading only two values into memory
+ * at a time.
*/
- abstract class IdMerger<T extends Comparable<T>> {
- private final DexBuffer.Section out;
+ public final void mergeSorted() {
+ TableOfContents.Section aSection = getSection(dexA.getTableOfContents());
+ TableOfContents.Section bSection = getSection(dexB.getTableOfContents());
+ getSection(contentsOut).off = out.getPosition();
- protected IdMerger(DexBuffer.Section out) {
- this.out = out;
+ DexBuffer.Section inA = aSection.exists() ? dexA.open(aSection.off) : null;
+ DexBuffer.Section inB = bSection.exists() ? dexB.open(bSection.off) : null;
+ int aOffset = -1;
+ int bOffset = -1;
+ int aIndex = 0;
+ int bIndex = 0;
+ int outCount = 0;
+ T a = null;
+ T b = null;
+
+ while (true) {
+ if (a == null && aIndex < aSection.size) {
+ aOffset = inA.getPosition();
+ a = read(inA, aIndexMap, aIndex);
+ }
+ if (b == null && bIndex < bSection.size) {
+ bOffset = inB.getPosition();
+ b = read(inB, bIndexMap, bIndex);
}
- /**
- * Merges already-sorted sections, reading only two values into memory
- * at a time.
- */
- public final void mergeSorted() {
- TableOfContents.Section aSection = getSection(dexA.getTableOfContents());
- TableOfContents.Section bSection = getSection(dexB.getTableOfContents());
- getSection(contentsOut).off = out.getPosition();
-
- DexBuffer.Section inA = aSection.exists() ? dexA.open(aSection.off) : null;
- DexBuffer.Section inB = bSection.exists() ? dexB.open(bSection.off) : null;
- int aOffset = -1;
- int bOffset = -1;
- int aIndex = 0;
- int bIndex = 0;
- int outCount = 0;
- T a = null;
- T b = null;
-
- while (true) {
- if (a == null && aIndex < aSection.size) {
- aOffset = inA.getPosition();
- a = read(inA, aIndexMap, aIndex);
- }
- if (b == null && bIndex < bSection.size) {
- bOffset = inB.getPosition();
- b = read(inB, bIndexMap, bIndex);
- }
-
- // Write the smaller of a and b. If they're equal, write only once
- boolean advanceA;
- boolean advanceB;
- if (a != null && b != null) {
- int compare = a.compareTo(b);
- advanceA = compare <= 0;
- advanceB = compare >= 0;
- } else {
- advanceA = (a != null);
- advanceB = (b != null);
- }
-
- T toWrite = null;
- if (advanceA) {
- toWrite = a;
- updateIndex(aOffset, aIndexMap, aIndex++, outCount);
- a = null;
- aOffset = -1;
- }
- if (advanceB) {
- toWrite = b;
- updateIndex(bOffset, bIndexMap, bIndex++, outCount);
- b = null;
- bOffset = -1;
- }
- if (toWrite == null) {
- break; // advanceA == false && advanceB == false
- }
- write(toWrite);
- outCount++;
- }
-
- getSection(contentsOut).size = outCount;
- }
-
- /**
- * Merges unsorted sections by reading them completely into memory and
- * sorting in memory.
- */
- public final void mergeUnsorted() {
- getSection(contentsOut).off = out.getPosition();
-
- List<UnsortedValue> all = new ArrayList<UnsortedValue>();
- all.addAll(readUnsortedValues(dexA, aIndexMap));
- all.addAll(readUnsortedValues(dexB, bIndexMap));
- Collections.sort(all);
-
- int outCount = 0;
- for (int i = 0; i < all.size(); ) {
- UnsortedValue e1 = all.get(i++);
- updateIndex(e1.offset, getIndexMap(e1.source), e1.index, outCount - 1);
-
- while (i < all.size() && e1.compareTo(all.get(i)) == 0) {
- UnsortedValue e2 = all.get(i++);
- updateIndex(e2.offset, getIndexMap(e2.source), e2.index, outCount - 1);
- }
-
- write(e1.value);
- outCount++;
- }
-
- getSection(contentsOut).size = outCount;
- }
-
- private List<UnsortedValue> readUnsortedValues(DexBuffer source, IndexMap indexMap) {
- TableOfContents.Section section = getSection(source.getTableOfContents());
- if (!section.exists()) {
- return Collections.emptyList();
- }
-
- List<UnsortedValue> result = new ArrayList<UnsortedValue>();
- DexBuffer.Section in = source.open(section.off);
- for (int i = 0; i < section.size; i++) {
- int offset = in.getPosition();
- T value = read(in, indexMap, 0);
- result.add(new UnsortedValue(source, indexMap, value, i, offset));
- }
- return result;
- }
-
- abstract TableOfContents.Section getSection(TableOfContents tableOfContents);
- abstract T read(DexBuffer.Section in, IndexMap indexMap, int index);
- abstract void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex);
- abstract void write(T value);
-
- class UnsortedValue implements Comparable<UnsortedValue> {
- final DexBuffer source;
- final IndexMap indexMap;
- final T value;
- final int index;
- final int offset;
-
- UnsortedValue(DexBuffer source, IndexMap indexMap, T value, int index, int offset) {
- this.source = source;
- this.indexMap = indexMap;
- this.value = value;
- this.index = index;
- this.offset = offset;
- }
-
- public int compareTo(UnsortedValue unsortedValue) {
- return value.compareTo(unsortedValue.value);
- }
- }
- }
-
- private IndexMap getIndexMap(DexBuffer dexBuffer) {
- if (dexBuffer == dexA) {
- return aIndexMap;
- } else if (dexBuffer == dexB) {
- return bIndexMap;
+ // Write the smaller of a and b. If they're equal, write only once
+ boolean advanceA;
+ boolean advanceB;
+ if (a != null && b != null) {
+ int compare = a.compareTo(b);
+ advanceA = compare <= 0;
+ advanceB = compare >= 0;
} else {
- throw new IllegalArgumentException();
+ advanceA = (a != null);
+ advanceB = (b != null);
}
- }
- private void mergeStringIds() {
- new IdMerger<String>(idsDefsOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.stringIds;
- }
-
- @Override String read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return in.readString();
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.stringIds[oldIndex] = newIndex;
- }
-
- @Override void write(String value) {
- contentsOut.stringDatas.size++;
- idsDefsOut.writeInt(stringDataOut.getPosition());
- stringDataOut.writeStringData(value);
- }
- }.mergeSorted();
- }
-
- private void mergeTypeIds() {
- new IdMerger<Integer>(idsDefsOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.typeIds;
- }
-
- @Override Integer read(DexBuffer.Section in, IndexMap indexMap, int index) {
- int stringIndex = in.readInt();
- return indexMap.adjustString(stringIndex);
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- checkIndex16(newIndex);
- indexMap.typeIds[oldIndex] = (short) newIndex;
- }
-
- @Override void write(Integer value) {
- idsDefsOut.writeInt(value);
- }
- }.mergeSorted();
- }
-
- private void mergeTypeLists() {
- new IdMerger<TypeList>(typeListOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.typeLists;
- }
-
- @Override TypeList read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return indexMap.adjustTypeList(in.readTypeList());
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.putTypeListOffset(offset, typeListOut.getPosition());
- }
-
- @Override void write(TypeList value) {
- typeListOut.writeTypeList(value);
- }
- }.mergeUnsorted();
- }
-
- private void mergeProtoIds() {
- new IdMerger<ProtoId>(idsDefsOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.protoIds;
- }
-
- @Override ProtoId read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return indexMap.adjust(in.readProtoId());
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- checkIndex16(newIndex);
- indexMap.protoIds[oldIndex] = (short) newIndex;
- }
-
- @Override void write(ProtoId value) {
- value.writeTo(idsDefsOut);
- }
- }.mergeSorted();
- }
-
- private void mergeFieldIds() {
- new IdMerger<FieldId>(idsDefsOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.fieldIds;
- }
-
- @Override FieldId read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return indexMap.adjust(in.readFieldId());
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- checkIndex16(newIndex);
- indexMap.fieldIds[oldIndex] = (short) newIndex;
- }
-
- @Override void write(FieldId value) {
- value.writeTo(idsDefsOut);
- }
- }.mergeSorted();
- }
-
- private void mergeMethodIds() {
- new IdMerger<MethodId>(idsDefsOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.methodIds;
- }
-
- @Override MethodId read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return indexMap.adjust(in.readMethodId());
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- checkIndex16(newIndex);
- indexMap.methodIds[oldIndex] = (short) newIndex;
- }
-
- @Override void write(MethodId methodId) {
- methodId.writeTo(idsDefsOut);
- }
- }.mergeSorted();
- }
-
- private void mergeAnnotations() {
- new IdMerger<Annotation>(annotationOut) {
- @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
- return tableOfContents.annotations;
- }
-
- @Override Annotation read(DexBuffer.Section in, IndexMap indexMap, int index) {
- return indexMap.adjust(in.readAnnotation());
- }
-
- @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.putAnnotationOffset(offset, annotationOut.getPosition());
- }
-
- @Override void write(Annotation value) {
- value.writeTo(annotationOut);
- }
- }.mergeUnsorted();
- }
-
- private void mergeClassDefs() {
- SortableType[] types = getSortedTypes();
- contentsOut.classDefs.off = idsDefsOut.getPosition();
- contentsOut.classDefs.size = types.length;
-
- for (SortableType type : types) {
- DexBuffer in = type.getBuffer();
- IndexMap indexMap = (in == dexA) ? aIndexMap : bIndexMap;
- transformClassDef(in, type.getClassDef(), indexMap);
+ T toWrite = null;
+ if (advanceA) {
+ toWrite = a;
+ updateIndex(aOffset, aIndexMap, aIndex++, outCount);
+ a = null;
+ aOffset = -1;
}
+ if (advanceB) {
+ toWrite = b;
+ updateIndex(bOffset, bIndexMap, bIndex++, outCount);
+ b = null;
+ bOffset = -1;
+ }
+ if (toWrite == null) {
+ break; // advanceA == false && advanceB == false
+ }
+ write(toWrite);
+ outCount++;
+ }
+
+ getSection(contentsOut).size = outCount;
}
/**
- * Returns the union of classes from both files, sorted in order such that
- * a class is always preceded by its supertype and implemented interfaces.
+ * Merges unsorted sections by reading them completely into memory and
+ * sorting in memory.
*/
- private SortableType[] getSortedTypes() {
- // size is pessimistic; doesn't include arrays
- SortableType[] sortableTypes = new SortableType[contentsOut.typeIds.size];
- readSortableTypes(sortableTypes, dexA, aIndexMap);
- readSortableTypes(sortableTypes, dexB, bIndexMap);
+ public final void mergeUnsorted() {
+ getSection(contentsOut).off = out.getPosition();
- /*
- * Populate the depths of each sortable type. This makes D iterations
- * through all N types, where 'D' is the depth of the deepest type. For
- * example, the deepest class in libcore is Xalan's KeyIterator, which
- * is 11 types deep.
- */
- while (true) {
- boolean allDone = true;
- for (SortableType sortableType : sortableTypes) {
- if (sortableType != null && !sortableType.isDepthAssigned()) {
- allDone &= sortableType.tryAssignDepth(sortableTypes);
- }
- }
- if (allDone) {
- break;
- }
+ List<UnsortedValue> all = new ArrayList<UnsortedValue>();
+ all.addAll(readUnsortedValues(dexA, aIndexMap));
+ all.addAll(readUnsortedValues(dexB, bIndexMap));
+ Collections.sort(all);
+
+ int outCount = 0;
+ for (int i = 0; i < all.size();) {
+ UnsortedValue e1 = all.get(i++);
+ updateIndex(e1.offset, getIndexMap(e1.source), e1.index, outCount - 1);
+
+ while (i < all.size() && e1.compareTo(all.get(i)) == 0) {
+ UnsortedValue e2 = all.get(i++);
+ updateIndex(e2.offset, getIndexMap(e2.source), e2.index, outCount - 1);
}
- // Now that all types have depth information, the result can be sorted
- Arrays.sort(sortableTypes, SortableType.NULLS_LAST_ORDER);
+ write(e1.value);
+ outCount++;
+ }
- // Strip nulls from the end
- int firstNull = Arrays.asList(sortableTypes).indexOf(null);
- return firstNull != -1
- ? Arrays.copyOfRange(sortableTypes, 0, firstNull)
- : sortableTypes;
+ getSection(contentsOut).size = outCount;
}
+ private List<UnsortedValue> readUnsortedValues(DexBuffer source, IndexMap indexMap) {
+ TableOfContents.Section section = getSection(source.getTableOfContents());
+ if (!section.exists()) {
+ return Collections.emptyList();
+ }
+
+ List<UnsortedValue> result = new ArrayList<UnsortedValue>();
+ DexBuffer.Section in = source.open(section.off);
+ for (int i = 0; i < section.size; i++) {
+ int offset = in.getPosition();
+ T value = read(in, indexMap, 0);
+ result.add(new UnsortedValue(source, indexMap, value, i, offset));
+ }
+ return result;
+ }
+
+ abstract TableOfContents.Section getSection(TableOfContents tableOfContents);
+
+ abstract T read(DexBuffer.Section in, IndexMap indexMap, int index);
+
+ abstract void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex);
+
+ abstract void write(T value);
+
+ class UnsortedValue implements Comparable<UnsortedValue> {
+ final DexBuffer source;
+ final IndexMap indexMap;
+ final T value;
+ final int index;
+ final int offset;
+
+ UnsortedValue(DexBuffer source, IndexMap indexMap, T value, int index, int offset) {
+ this.source = source;
+ this.indexMap = indexMap;
+ this.value = value;
+ this.index = index;
+ this.offset = offset;
+ }
+
+ @Override
+ public int compareTo(UnsortedValue unsortedValue) {
+ return value.compareTo(unsortedValue.value);
+ }
+ }
+ }
+
+ private IndexMap getIndexMap(DexBuffer dexBuffer) {
+ if (dexBuffer == dexA) {
+ return aIndexMap;
+ } else if (dexBuffer == dexB) {
+ return bIndexMap;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private void mergeStringIds() {
+ new IdMerger<String>(idsDefsOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.stringIds;
+ }
+
+ @Override
+ String read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return in.readString();
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ indexMap.stringIds[oldIndex] = newIndex;
+ }
+
+ @Override
+ void write(String value) {
+ contentsOut.stringDatas.size++;
+ idsDefsOut.writeInt(stringDataOut.getPosition());
+ stringDataOut.writeStringData(value);
+ }
+ }.mergeSorted();
+ }
+
+ private void mergeTypeIds() {
+ new IdMerger<Integer>(idsDefsOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.typeIds;
+ }
+
+ @Override
+ Integer read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ int stringIndex = in.readInt();
+ return indexMap.adjustString(stringIndex);
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ checkIndex16(newIndex);
+ indexMap.typeIds[oldIndex] = (short) newIndex;
+ }
+
+ @Override
+ void write(Integer value) {
+ idsDefsOut.writeInt(value);
+ }
+ }.mergeSorted();
+ }
+
+ private void mergeTypeLists() {
+ new IdMerger<TypeList>(typeListOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.typeLists;
+ }
+
+ @Override
+ TypeList read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return indexMap.adjustTypeList(in.readTypeList());
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ indexMap.putTypeListOffset(offset, typeListOut.getPosition());
+ }
+
+ @Override
+ void write(TypeList value) {
+ typeListOut.writeTypeList(value);
+ }
+ }.mergeUnsorted();
+ }
+
+ private void mergeProtoIds() {
+ new IdMerger<ProtoId>(idsDefsOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.protoIds;
+ }
+
+ @Override
+ ProtoId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return indexMap.adjust(in.readProtoId());
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ checkIndex16(newIndex);
+ indexMap.protoIds[oldIndex] = (short) newIndex;
+ }
+
+ @Override
+ void write(ProtoId value) {
+ value.writeTo(idsDefsOut);
+ }
+ }.mergeSorted();
+ }
+
+ private void mergeFieldIds() {
+ new IdMerger<FieldId>(idsDefsOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.fieldIds;
+ }
+
+ @Override
+ FieldId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return indexMap.adjust(in.readFieldId());
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ checkIndex16(newIndex);
+ indexMap.fieldIds[oldIndex] = (short) newIndex;
+ }
+
+ @Override
+ void write(FieldId value) {
+ value.writeTo(idsDefsOut);
+ }
+ }.mergeSorted();
+ }
+
+ private void mergeMethodIds() {
+ new IdMerger<MethodId>(idsDefsOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.methodIds;
+ }
+
+ @Override
+ MethodId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return indexMap.adjust(in.readMethodId());
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ checkIndex16(newIndex);
+ indexMap.methodIds[oldIndex] = (short) newIndex;
+ }
+
+ @Override
+ void write(MethodId methodId) {
+ methodId.writeTo(idsDefsOut);
+ }
+ }.mergeSorted();
+ }
+
+ private void mergeAnnotations() {
+ new IdMerger<Annotation>(annotationOut) {
+ @Override
+ TableOfContents.Section getSection(TableOfContents tableOfContents) {
+ return tableOfContents.annotations;
+ }
+
+ @Override
+ Annotation read(DexBuffer.Section in, IndexMap indexMap, int index) {
+ return indexMap.adjust(in.readAnnotation());
+ }
+
+ @Override
+ void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+ indexMap.putAnnotationOffset(offset, annotationOut.getPosition());
+ }
+
+ @Override
+ void write(Annotation value) {
+ value.writeTo(annotationOut);
+ }
+ }.mergeUnsorted();
+ }
+
+ private void mergeClassDefs() {
+ SortableType[] types = getSortedTypes();
+ contentsOut.classDefs.off = idsDefsOut.getPosition();
+ contentsOut.classDefs.size = types.length;
+
+ for (SortableType type : types) {
+ DexBuffer in = type.getBuffer();
+ IndexMap indexMap = (in == dexA) ? aIndexMap : bIndexMap;
+ transformClassDef(in, type.getClassDef(), indexMap);
+ }
+ }
+
+ /**
+ * Returns the union of classes from both files, sorted in order such that
+ * a class is always preceded by its supertype and implemented interfaces.
+ */
+ private SortableType[] getSortedTypes() {
+ // size is pessimistic; doesn't include arrays
+ SortableType[] sortableTypes = new SortableType[contentsOut.typeIds.size];
+ readSortableTypes(sortableTypes, dexA, aIndexMap);
+ readSortableTypes(sortableTypes, dexB, bIndexMap);
+
+ /*
+ * Populate the depths of each sortable type. This makes D iterations
+ * through all N types, where 'D' is the depth of the deepest type. For
+ * example, the deepest class in libcore is Xalan's KeyIterator, which
+ * is 11 types deep.
+ */
+ while (true) {
+ boolean allDone = true;
+ for (SortableType sortableType : sortableTypes) {
+ if (sortableType != null && !sortableType.isDepthAssigned()) {
+ allDone &= sortableType.tryAssignDepth(sortableTypes);
+ }
+ }
+ if (allDone) {
+ break;
+ }
+ }
+
+ // Now that all types have depth information, the result can be sorted
+ Arrays.sort(sortableTypes, SortableType.NULLS_LAST_ORDER);
+
+ // Strip nulls from the end
+ int firstNull = Arrays.asList(sortableTypes).indexOf(null);
+ return firstNull != -1 ? Arrays.copyOfRange(sortableTypes, 0, firstNull) : sortableTypes;
+ }
+
+ /**
+ * Reads just enough data on each class so that we can sort it and then find
+ * it later.
+ */
+ private void readSortableTypes(SortableType[] sortableTypes, DexBuffer buffer,
+ IndexMap indexMap) {
+ for (ClassDef classDef : buffer.classDefs()) {
+ SortableType sortableType = indexMap.adjust(new SortableType(buffer, classDef));
+ int t = sortableType.getTypeIndex();
+ if (sortableTypes[t] == null) {
+ sortableTypes[t] = sortableType;
+ } else if (collisionPolicy != CollisionPolicy.KEEP_FIRST) {
+ throw new DexException(
+ "Multiple dex files define " + buffer.typeNames().get(classDef.getTypeIndex()));
+ }
+ }
+ }
+
+ /**
+ * Copy annotation sets from each input to the output.
+ *
+ * TODO(dx team): this may write multiple copies of the same annotation set.
+ * We should shrink the output by merging rather than unioning
+ */
+ private void unionAnnotationSetsAndDirectories() {
+ transformAnnotationSets(dexA, aIndexMap);
+ transformAnnotationSets(dexB, bIndexMap);
+ transformAnnotationDirectories(dexA, aIndexMap);
+ transformAnnotationDirectories(dexB, bIndexMap);
+ transformStaticValues(dexA, aIndexMap);
+ transformStaticValues(dexB, bIndexMap);
+ }
+
+ private void transformAnnotationSets(DexBuffer in, IndexMap indexMap) {
+ TableOfContents.Section section = in.getTableOfContents().annotationSets;
+ if (section.exists()) {
+ DexBuffer.Section setIn = in.open(section.off);
+ for (int i = 0; i < section.size; i++) {
+ transformAnnotationSet(indexMap, setIn);
+ }
+ }
+ }
+
+ private void checkIndex16(int index) {
+ if (index > Character.MAX_VALUE || index < 0) {
+ throw new DexException("Too many IDs in dex");
+ }
+ }
+
+ private void transformAnnotationDirectories(DexBuffer in, IndexMap indexMap) {
+ TableOfContents.Section section = in.getTableOfContents().annotationsDirectories;
+ if (section.exists()) {
+ DexBuffer.Section directoryIn = in.open(section.off);
+ for (int i = 0; i < section.size; i++) {
+ transformAnnotationDirectory(in, directoryIn, indexMap);
+ }
+ }
+ }
+
+ private void transformStaticValues(DexBuffer in, IndexMap indexMap) {
+ TableOfContents.Section section = in.getTableOfContents().encodedArrays;
+ if (section.exists()) {
+ DexBuffer.Section staticValuesIn = in.open(section.off);
+ for (int i = 0; i < section.size; i++) {
+ transformStaticValues(staticValuesIn, indexMap);
+ }
+ }
+ }
+
+ /**
+ * Reads a class_def_item beginning at {@code in} and writes the index and
+ * data.
+ */
+ private void transformClassDef(DexBuffer in, ClassDef classDef, IndexMap indexMap) {
+ idsDefsOut.assertFourByteAligned();
+ idsDefsOut.writeInt(classDef.getTypeIndex());
+ idsDefsOut.writeInt(classDef.getAccessFlags());
+ idsDefsOut.writeInt(classDef.getSupertypeIndex());
+ idsDefsOut.writeInt(classDef.getInterfacesOffset());
+
+ int sourceFileIndex = indexMap.adjustString(classDef.getSourceFileIndex());
+ idsDefsOut.writeInt(sourceFileIndex);
+
+ int annotationsOff = classDef.getAnnotationsOffset();
+ idsDefsOut.writeInt(indexMap.adjustAnnotationDirectory(annotationsOff));
+
+ int classDataOff = classDef.getClassDataOffset();
+ if (classDataOff == 0) {
+ idsDefsOut.writeInt(0);
+ } else {
+ idsDefsOut.writeInt(classDataOut.getPosition());
+ ClassData classData = in.readClassData(classDef);
+ transformClassData(in, classData, indexMap);
+ }
+
+ int staticValuesOff = classDef.getStaticValuesOffset();
+ idsDefsOut.writeInt(indexMap.adjustStaticValues(staticValuesOff));
+ }
+
+ /**
+ * Transform all annotations on a class.
+ */
+ private void transformAnnotationDirectory(DexBuffer in, DexBuffer.Section directoryIn,
+ IndexMap indexMap) {
+ contentsOut.annotationsDirectories.size++;
+ annotationsDirectoryOut.assertFourByteAligned();
+ indexMap.putAnnotationDirectoryOffset(directoryIn.getPosition(),
+ annotationsDirectoryOut.getPosition());
+
+ int classAnnotationsOffset = indexMap.adjustAnnotationSet(directoryIn.readInt());
+ annotationsDirectoryOut.writeInt(classAnnotationsOffset);
+
+ int fieldsSize = directoryIn.readInt();
+ annotationsDirectoryOut.writeInt(fieldsSize);
+
+ int methodsSize = directoryIn.readInt();
+ annotationsDirectoryOut.writeInt(methodsSize);
+
+ int parameterListSize = directoryIn.readInt();
+ annotationsDirectoryOut.writeInt(parameterListSize);
+
+ for (int i = 0; i < fieldsSize; i++) {
+ // field index
+ annotationsDirectoryOut.writeInt(indexMap.adjustField(directoryIn.readInt()));
+
+ // annotations offset
+ annotationsDirectoryOut.writeInt(indexMap.adjustAnnotationSet(directoryIn.readInt()));
+ }
+
+ for (int i = 0; i < methodsSize; i++) {
+ // method index
+ annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
+
+ // annotation set offset
+ annotationsDirectoryOut.writeInt(indexMap.adjustAnnotationSet(directoryIn.readInt()));
+ }
+
+ for (int i = 0; i < parameterListSize; i++) {
+ contentsOut.annotationSetRefLists.size++;
+ annotationSetRefListOut.assertFourByteAligned();
+
+ // method index
+ annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
+
+ // annotations offset
+ annotationsDirectoryOut.writeInt(annotationSetRefListOut.getPosition());
+ DexBuffer.Section refListIn = in.open(directoryIn.readInt());
+
+ // parameters
+ int parameterCount = refListIn.readInt();
+ annotationSetRefListOut.writeInt(parameterCount);
+ for (int p = 0; p < parameterCount; p++) {
+ annotationSetRefListOut.writeInt(indexMap.adjustAnnotationSet(refListIn.readInt()));
+ }
+ }
+ }
+
+ /**
+ * Transform all annotations on a single type, member or parameter.
+ */
+ private void transformAnnotationSet(IndexMap indexMap, DexBuffer.Section setIn) {
+ contentsOut.annotationSets.size++;
+ annotationSetOut.assertFourByteAligned();
+ indexMap.putAnnotationSetOffset(setIn.getPosition(), annotationSetOut.getPosition());
+
+ int size = setIn.readInt();
+ annotationSetOut.writeInt(size);
+
+ for (int j = 0; j < size; j++) {
+ annotationSetOut.writeInt(indexMap.adjustAnnotation(setIn.readInt()));
+ }
+ }
+
+ private void transformClassData(DexBuffer in, ClassData classData, IndexMap indexMap) {
+ contentsOut.classDatas.size++;
+
+ ClassData.Field[] staticFields = classData.getStaticFields();
+ ClassData.Field[] instanceFields = classData.getInstanceFields();
+ ClassData.Method[] directMethods = classData.getDirectMethods();
+ ClassData.Method[] virtualMethods = classData.getVirtualMethods();
+
+ classDataOut.writeUleb128(staticFields.length);
+ classDataOut.writeUleb128(instanceFields.length);
+ classDataOut.writeUleb128(directMethods.length);
+ classDataOut.writeUleb128(virtualMethods.length);
+
+ transformFields(indexMap, staticFields);
+ transformFields(indexMap, instanceFields);
+ transformMethods(in, indexMap, directMethods);
+ transformMethods(in, indexMap, virtualMethods);
+ }
+
+ private void transformFields(IndexMap indexMap, ClassData.Field[] fields) {
+ int lastOutFieldIndex = 0;
+ for (ClassData.Field field : fields) {
+ int outFieldIndex = indexMap.adjustField(field.getFieldIndex());
+ classDataOut.writeUleb128(outFieldIndex - lastOutFieldIndex);
+ lastOutFieldIndex = outFieldIndex;
+ classDataOut.writeUleb128(field.getAccessFlags());
+ }
+ }
+
+ private void transformMethods(DexBuffer in, IndexMap indexMap, ClassData.Method[] methods) {
+ int lastOutMethodIndex = 0;
+ for (ClassData.Method method : methods) {
+ int outMethodIndex = indexMap.adjustMethod(method.getMethodIndex());
+ classDataOut.writeUleb128(outMethodIndex - lastOutMethodIndex);
+ lastOutMethodIndex = outMethodIndex;
+
+ classDataOut.writeUleb128(method.getAccessFlags());
+
+ if (method.getCodeOffset() == 0) {
+ classDataOut.writeUleb128(0);
+ } else {
+ codeOut.alignToFourBytes();
+ classDataOut.writeUleb128(codeOut.getPosition());
+ transformCode(in, in.readCode(method), indexMap);
+ }
+ }
+ }
+
+ private void transformCode(DexBuffer in, Code code, IndexMap indexMap) {
+ contentsOut.codes.size++;
+ codeOut.assertFourByteAligned();
+
+ codeOut.writeUnsignedShort(code.getRegistersSize());
+ codeOut.writeUnsignedShort(code.getInsSize());
+ codeOut.writeUnsignedShort(code.getOutsSize());
+
+ Code.Try[] tries = code.getTries();
+ Code.CatchHandler[] catchHandlers = code.getCatchHandlers();
+ codeOut.writeUnsignedShort(tries.length);
+
+ int debugInfoOffset = code.getDebugInfoOffset();
+ if (debugInfoOffset != 0) {
+ codeOut.writeInt(debugInfoOut.getPosition());
+ transformDebugInfoItem(in.open(debugInfoOffset), indexMap);
+ } else {
+ codeOut.writeInt(0);
+ }
+
+ short[] instructions = code.getInstructions();
+ InstructionTransformer transformer =
+ (in == dexA) ? aInstructionTransformer : bInstructionTransformer;
+ short[] newInstructions = transformer.transform(instructions);
+ codeOut.writeInt(newInstructions.length);
+ codeOut.write(newInstructions);
+
+ if (tries.length > 0) {
+ if (newInstructions.length % 2 == 1) {
+ codeOut.writeShort((short) 0); // padding
+ }
+
+ /*
+ * We can't write the tries until we've written the catch handlers.
+ * Unfortunately they're in the opposite order in the dex file so we
+ * need to transform them out-of-order.
+ */
+ DexBuffer.Section triesSection = dexOut.open(codeOut.getPosition());
+ codeOut.skip(tries.length * SizeOf.TRY_ITEM);
+ int[] offsets = transformCatchHandlers(indexMap, catchHandlers);
+ transformTries(triesSection, tries, offsets);
+ }
+ }
+
+ /**
+ * Writes the catch handlers to {@code codeOut} and returns their indices.
+ */
+ private int[] transformCatchHandlers(IndexMap indexMap, Code.CatchHandler[] catchHandlers) {
+ int baseOffset = codeOut.getPosition();
+ codeOut.writeUleb128(catchHandlers.length);
+ int[] offsets = new int[catchHandlers.length];
+ for (int i = 0; i < catchHandlers.length; i++) {
+ offsets[i] = codeOut.getPosition() - baseOffset;
+ transformEncodedCatchHandler(catchHandlers[i], indexMap);
+ }
+ return offsets;
+ }
+
+ private void transformTries(DexBuffer.Section out, Code.Try[] tries, int[] catchHandlerOffsets) {
+ for (Code.Try tryItem : tries) {
+ out.writeInt(tryItem.getStartAddress());
+ out.writeUnsignedShort(tryItem.getInstructionCount());
+ out.writeUnsignedShort(catchHandlerOffsets[tryItem.getCatchHandlerIndex()]);
+ }
+ }
+
+ private static final byte DBG_END_SEQUENCE = 0x00;
+ private static final byte DBG_ADVANCE_PC = 0x01;
+ private static final byte DBG_ADVANCE_LINE = 0x02;
+ private static final byte DBG_START_LOCAL = 0x03;
+ private static final byte DBG_START_LOCAL_EXTENDED = 0x04;
+ private static final byte DBG_END_LOCAL = 0x05;
+ private static final byte DBG_RESTART_LOCAL = 0x06;
+ private static final byte DBG_SET_PROLOGUE_END = 0x07;
+ private static final byte DBG_SET_EPILOGUE_BEGIN = 0x08;
+ private static final byte DBG_SET_FILE = 0x09;
+
+ private void transformDebugInfoItem(DexBuffer.Section in, IndexMap indexMap) {
+ contentsOut.debugInfos.size++;
+ int lineStart = in.readUleb128();
+ debugInfoOut.writeUleb128(lineStart);
+
+ int parametersSize = in.readUleb128();
+ debugInfoOut.writeUleb128(parametersSize);
+
+ for (int p = 0; p < parametersSize; p++) {
+ int parameterName = in.readUleb128p1();
+ debugInfoOut.writeUleb128p1(indexMap.adjustString(parameterName));
+ }
+
+ int addrDiff; // uleb128 address delta.
+ int lineDiff; // sleb128 line delta.
+ int registerNum; // uleb128 register number.
+ int nameIndex; // uleb128p1 string index. Needs indexMap adjustment.
+ int typeIndex; // uleb128p1 type index. Needs indexMap adjustment.
+ int sigIndex; // uleb128p1 string index. Needs indexMap adjustment.
+
+ while (true) {
+ int opcode = in.readByte();
+ debugInfoOut.writeByte(opcode);
+
+ switch (opcode) {
+ case DBG_END_SEQUENCE:
+ return;
+
+ case DBG_ADVANCE_PC:
+ addrDiff = in.readUleb128();
+ debugInfoOut.writeUleb128(addrDiff);
+ break;
+
+ case DBG_ADVANCE_LINE:
+ lineDiff = in.readSleb128();
+ debugInfoOut.writeSleb128(lineDiff);
+ break;
+
+ case DBG_START_LOCAL:
+ case DBG_START_LOCAL_EXTENDED:
+ registerNum = in.readUleb128();
+ debugInfoOut.writeUleb128(registerNum);
+ nameIndex = in.readUleb128p1();
+ debugInfoOut.writeUleb128p1(indexMap.adjustString(nameIndex));
+ typeIndex = in.readUleb128p1();
+ debugInfoOut.writeUleb128p1(indexMap.adjustType(typeIndex));
+ if (opcode == DBG_START_LOCAL_EXTENDED) {
+ sigIndex = in.readUleb128p1();
+ debugInfoOut.writeUleb128p1(indexMap.adjustString(sigIndex));
+ }
+ break;
+
+ case DBG_END_LOCAL:
+ case DBG_RESTART_LOCAL:
+ registerNum = in.readUleb128();
+ debugInfoOut.writeUleb128(registerNum);
+ break;
+
+ case DBG_SET_FILE:
+ nameIndex = in.readUleb128p1();
+ debugInfoOut.writeUleb128p1(indexMap.adjustString(nameIndex));
+ break;
+
+ case DBG_SET_PROLOGUE_END:
+ case DBG_SET_EPILOGUE_BEGIN:
+ default:
+ break;
+ }
+ }
+ }
+
+ private void transformEncodedCatchHandler(Code.CatchHandler catchHandler, IndexMap indexMap) {
+ int catchAllAddress = catchHandler.getCatchAllAddress();
+ int[] typeIndexes = catchHandler.getTypeIndexes();
+ int[] addresses = catchHandler.getAddresses();
+
+ if (catchAllAddress != -1) {
+ codeOut.writeSleb128(-typeIndexes.length);
+ } else {
+ codeOut.writeSleb128(typeIndexes.length);
+ }
+
+ for (int i = 0; i < typeIndexes.length; i++) {
+ codeOut.writeUleb128(indexMap.adjustType(typeIndexes[i]));
+ codeOut.writeUleb128(addresses[i]);
+ }
+
+ if (catchAllAddress != -1) {
+ codeOut.writeUleb128(catchAllAddress);
+ }
+ }
+
+ private void transformStaticValues(DexBuffer.Section in, IndexMap indexMap) {
+ contentsOut.encodedArrays.size++;
+ indexMap.putStaticValuesOffset(in.getPosition(), encodedArrayOut.getPosition());
+ indexMap.adjustEncodedArray(in.readEncodedArray()).writeTo(encodedArrayOut);
+ }
+
+ /**
+ * Byte counts for the sections written when creating a dex. Target sizes
+ * are defined in one of two ways:
+ * <ul>
+ * <li>By pessimistically guessing how large the union of dex files will be.
+ * We're pessimistic because we can't predict the amount of duplication
+ * between dex files, nor can we predict the length of ULEB-encoded
+ * offsets or indices.
+ * <li>By exactly measuring an existing dex.
+ * </ul>
+ */
+ private static class WriterSizes {
+ private int header = SizeOf.HEADER_ITEM;
+ private int idsDefs;
+ private int mapList;
+ private int typeList;
+ private int classData;
+ private int code;
+ private int stringData;
+ private int debugInfo;
+ private int encodedArray;
+ private int annotationsDirectory;
+ private int annotationsSet;
+ private int annotationsSetRefList;
+ private int annotation;
+
/**
- * Reads just enough data on each class so that we can sort it and then find
- * it later.
+ * Compute sizes for merging a and b.
*/
- private void readSortableTypes(SortableType[] sortableTypes, DexBuffer buffer,
- IndexMap indexMap) {
- for (ClassDef classDef : buffer.classDefs()) {
- SortableType sortableType = indexMap.adjust(new SortableType(buffer, classDef));
- int t = sortableType.getTypeIndex();
- if (sortableTypes[t] == null) {
- sortableTypes[t] = sortableType;
- } else if (collisionPolicy != CollisionPolicy.KEEP_FIRST) {
- throw new DexException("Multiple dex files define "
- + buffer.typeNames().get(classDef.getTypeIndex()));
- }
- }
+ public WriterSizes(DexBuffer a, DexBuffer b) {
+ plus(a.getTableOfContents(), false);
+ plus(b.getTableOfContents(), false);
}
- /**
- * Copy annotation sets from each input to the output.
- *
- * TODO: this may write multiple copies of the same annotation set.
- * We should shrink the output by merging rather than unioning
- */
- private void unionAnnotationSetsAndDirectories() {
- transformAnnotationSets(dexA, aIndexMap);
- transformAnnotationSets(dexB, bIndexMap);
- transformAnnotationDirectories(dexA, aIndexMap);
- transformAnnotationDirectories(dexB, bIndexMap);
- transformStaticValues(dexA, aIndexMap);
- transformStaticValues(dexB, bIndexMap);
+ public WriterSizes(DexMerger dexMerger) {
+ header = dexMerger.headerOut.used();
+ idsDefs = dexMerger.idsDefsOut.used();
+ mapList = dexMerger.mapListOut.used();
+ typeList = dexMerger.typeListOut.used();
+ classData = dexMerger.classDataOut.used();
+ code = dexMerger.codeOut.used();
+ stringData = dexMerger.stringDataOut.used();
+ debugInfo = dexMerger.debugInfoOut.used();
+ encodedArray = dexMerger.encodedArrayOut.used();
+ annotationsDirectory = dexMerger.annotationsDirectoryOut.used();
+ annotationsSet = dexMerger.annotationSetOut.used();
+ annotationsSetRefList = dexMerger.annotationSetRefListOut.used();
+ annotation = dexMerger.annotationOut.used();
}
- private void transformAnnotationSets(DexBuffer in, IndexMap indexMap) {
- TableOfContents.Section section = in.getTableOfContents().annotationSets;
- if (section.exists()) {
- DexBuffer.Section setIn = in.open(section.off);
- for (int i = 0; i < section.size; i++) {
- transformAnnotationSet(indexMap, setIn);
- }
- }
+ public void plus(TableOfContents contents, boolean exact) {
+ idsDefs += contents.stringIds.size * SizeOf.STRING_ID_ITEM + contents.typeIds.size
+ * SizeOf.TYPE_ID_ITEM + contents.protoIds.size * SizeOf.PROTO_ID_ITEM
+ + contents.fieldIds.size * SizeOf.MEMBER_ID_ITEM + contents.methodIds.size
+ * SizeOf.MEMBER_ID_ITEM + contents.classDefs.size * SizeOf.CLASS_DEF_ITEM;
+ mapList = SizeOf.UINT + (contents.sections.length * SizeOf.MAP_ITEM);
+ typeList += contents.typeLists.byteCount;
+ stringData += contents.stringDatas.byteCount;
+ annotationsDirectory += contents.annotationsDirectories.byteCount;
+ annotationsSet += contents.annotationSets.byteCount;
+ annotationsSetRefList += contents.annotationSetRefLists.byteCount;
+
+ if (exact) {
+ code += contents.codes.byteCount;
+ classData += contents.classDatas.byteCount;
+ encodedArray += contents.encodedArrays.byteCount;
+ annotation += contents.annotations.byteCount;
+ debugInfo += contents.debugInfos.byteCount;
+ } else {
+ // at most 1/4 of the bytes in a code section are uleb/sleb
+ code += (int) Math.ceil(contents.codes.byteCount * 1.25);
+ // at most 1/3 of the bytes in a class data section are uleb/sleb
+ classData += (int) Math.ceil(contents.classDatas.byteCount * 1.34);
+ // all of the bytes in an encoding arrays section may be uleb/sleb
+ encodedArray += contents.encodedArrays.byteCount * 2;
+ // all of the bytes in an annotations section may be uleb/sleb
+ annotation += (int) Math.ceil(contents.annotations.byteCount * 2);
+ // all of the bytes in a debug info section may be uleb/sleb
+ debugInfo += contents.debugInfos.byteCount * 2;
+ }
+
+ typeList = DexBuffer.fourByteAlign(typeList);
+ code = DexBuffer.fourByteAlign(code);
}
- private void checkIndex16(int index) {
- if (index > Character.MAX_VALUE || index < 0) {
- throw new DexException("Too many IDs in dex");
- }
+ public int size() {
+ return header + idsDefs + mapList + typeList + classData + code + stringData + debugInfo
+ + encodedArray + annotationsDirectory + annotationsSet + annotationsSetRefList
+ + annotation;
+ }
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (args.length < 2) {
+ printUsage();
+ return;
}
- private void transformAnnotationDirectories(DexBuffer in, IndexMap indexMap) {
- TableOfContents.Section section = in.getTableOfContents().annotationsDirectories;
- if (section.exists()) {
- DexBuffer.Section directoryIn = in.open(section.off);
- for (int i = 0; i < section.size; i++) {
- transformAnnotationDirectory(in, directoryIn, indexMap);
- }
- }
+ DexBuffer merged = new DexBuffer(new File(args[1]));
+ for (int i = 2; i < args.length; i++) {
+ DexBuffer toMerge = new DexBuffer(new File(args[i]));
+ merged = new DexMerger(merged, toMerge, CollisionPolicy.KEEP_FIRST).merge();
}
+ merged.writeTo(new File(args[0]));
+ }
- private void transformStaticValues(DexBuffer in, IndexMap indexMap) {
- TableOfContents.Section section = in.getTableOfContents().encodedArrays;
- if (section.exists()) {
- DexBuffer.Section staticValuesIn = in.open(section.off);
- for (int i = 0; i < section.size; i++) {
- transformStaticValues(staticValuesIn, indexMap);
- }
- }
- }
-
- /**
- * Reads a class_def_item beginning at {@code in} and writes the index and
- * data.
- */
- private void transformClassDef(DexBuffer in, ClassDef classDef, IndexMap indexMap) {
- idsDefsOut.assertFourByteAligned();
- idsDefsOut.writeInt(classDef.getTypeIndex());
- idsDefsOut.writeInt(classDef.getAccessFlags());
- idsDefsOut.writeInt(classDef.getSupertypeIndex());
- idsDefsOut.writeInt(classDef.getInterfacesOffset());
-
- int sourceFileIndex = indexMap.adjustString(classDef.getSourceFileIndex());
- idsDefsOut.writeInt(sourceFileIndex);
-
- int annotationsOff = classDef.getAnnotationsOffset();
- idsDefsOut.writeInt(indexMap.adjustAnnotationDirectory(annotationsOff));
-
- int classDataOff = classDef.getClassDataOffset();
- if (classDataOff == 0) {
- idsDefsOut.writeInt(0);
- } else {
- idsDefsOut.writeInt(classDataOut.getPosition());
- ClassData classData = in.readClassData(classDef);
- transformClassData(in, classData, indexMap);
- }
-
- int staticValuesOff = classDef.getStaticValuesOffset();
- idsDefsOut.writeInt(indexMap.adjustStaticValues(staticValuesOff));
- }
-
- /**
- * Transform all annotations on a class.
- */
- private void transformAnnotationDirectory(
- DexBuffer in, DexBuffer.Section directoryIn, IndexMap indexMap) {
- contentsOut.annotationsDirectories.size++;
- annotationsDirectoryOut.assertFourByteAligned();
- indexMap.putAnnotationDirectoryOffset(
- directoryIn.getPosition(), annotationsDirectoryOut.getPosition());
-
- int classAnnotationsOffset = indexMap.adjustAnnotationSet(directoryIn.readInt());
- annotationsDirectoryOut.writeInt(classAnnotationsOffset);
-
- int fieldsSize = directoryIn.readInt();
- annotationsDirectoryOut.writeInt(fieldsSize);
-
- int methodsSize = directoryIn.readInt();
- annotationsDirectoryOut.writeInt(methodsSize);
-
- int parameterListSize = directoryIn.readInt();
- annotationsDirectoryOut.writeInt(parameterListSize);
-
- for (int i = 0; i < fieldsSize; i++) {
- // field index
- annotationsDirectoryOut.writeInt(indexMap.adjustField(directoryIn.readInt()));
-
- // annotations offset
- annotationsDirectoryOut.writeInt(indexMap.adjustAnnotationSet(directoryIn.readInt()));
- }
-
- for (int i = 0; i < methodsSize; i++) {
- // method index
- annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
-
- // annotation set offset
- annotationsDirectoryOut.writeInt(
- indexMap.adjustAnnotationSet(directoryIn.readInt()));
- }
-
- for (int i = 0; i < parameterListSize; i++) {
- contentsOut.annotationSetRefLists.size++;
- annotationSetRefListOut.assertFourByteAligned();
-
- // method index
- annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
-
- // annotations offset
- annotationsDirectoryOut.writeInt(annotationSetRefListOut.getPosition());
- DexBuffer.Section refListIn = in.open(directoryIn.readInt());
-
- // parameters
- int parameterCount = refListIn.readInt();
- annotationSetRefListOut.writeInt(parameterCount);
- for (int p = 0; p < parameterCount; p++) {
- annotationSetRefListOut.writeInt(indexMap.adjustAnnotationSet(refListIn.readInt()));
- }
- }
- }
-
- /**
- * Transform all annotations on a single type, member or parameter.
- */
- private void transformAnnotationSet(IndexMap indexMap, DexBuffer.Section setIn) {
- contentsOut.annotationSets.size++;
- annotationSetOut.assertFourByteAligned();
- indexMap.putAnnotationSetOffset(setIn.getPosition(), annotationSetOut.getPosition());
-
- int size = setIn.readInt();
- annotationSetOut.writeInt(size);
-
- for (int j = 0; j < size; j++) {
- annotationSetOut.writeInt(indexMap.adjustAnnotation(setIn.readInt()));
- }
- }
-
- private void transformClassData(DexBuffer in, ClassData classData, IndexMap indexMap) {
- contentsOut.classDatas.size++;
-
- ClassData.Field[] staticFields = classData.getStaticFields();
- ClassData.Field[] instanceFields = classData.getInstanceFields();
- ClassData.Method[] directMethods = classData.getDirectMethods();
- ClassData.Method[] virtualMethods = classData.getVirtualMethods();
-
- classDataOut.writeUleb128(staticFields.length);
- classDataOut.writeUleb128(instanceFields.length);
- classDataOut.writeUleb128(directMethods.length);
- classDataOut.writeUleb128(virtualMethods.length);
-
- transformFields(indexMap, staticFields);
- transformFields(indexMap, instanceFields);
- transformMethods(in, indexMap, directMethods);
- transformMethods(in, indexMap, virtualMethods);
- }
-
- private void transformFields(IndexMap indexMap, ClassData.Field[] fields) {
- int lastOutFieldIndex = 0;
- for (ClassData.Field field : fields) {
- int outFieldIndex = indexMap.adjustField(field.getFieldIndex());
- classDataOut.writeUleb128(outFieldIndex - lastOutFieldIndex);
- lastOutFieldIndex = outFieldIndex;
- classDataOut.writeUleb128(field.getAccessFlags());
- }
- }
-
- private void transformMethods(DexBuffer in, IndexMap indexMap, ClassData.Method[] methods) {
- int lastOutMethodIndex = 0;
- for (ClassData.Method method : methods) {
- int outMethodIndex = indexMap.adjustMethod(method.getMethodIndex());
- classDataOut.writeUleb128(outMethodIndex - lastOutMethodIndex);
- lastOutMethodIndex = outMethodIndex;
-
- classDataOut.writeUleb128(method.getAccessFlags());
-
- if (method.getCodeOffset() == 0) {
- classDataOut.writeUleb128(0);
- } else {
- codeOut.alignToFourBytes();
- classDataOut.writeUleb128(codeOut.getPosition());
- transformCode(in, in.readCode(method), indexMap);
- }
- }
- }
-
- private void transformCode(DexBuffer in, Code code, IndexMap indexMap) {
- contentsOut.codes.size++;
- codeOut.assertFourByteAligned();
-
- codeOut.writeUnsignedShort(code.getRegistersSize());
- codeOut.writeUnsignedShort(code.getInsSize());
- codeOut.writeUnsignedShort(code.getOutsSize());
-
- Code.Try[] tries = code.getTries();
- Code.CatchHandler[] catchHandlers = code.getCatchHandlers();
- codeOut.writeUnsignedShort(tries.length);
-
- int debugInfoOffset = code.getDebugInfoOffset();
- if (debugInfoOffset != 0) {
- codeOut.writeInt(debugInfoOut.getPosition());
- transformDebugInfoItem(in.open(debugInfoOffset), indexMap);
- } else {
- codeOut.writeInt(0);
- }
-
- short[] instructions = code.getInstructions();
- InstructionTransformer transformer = (in == dexA)
- ? aInstructionTransformer
- : bInstructionTransformer;
- short[] newInstructions = transformer.transform(instructions);
- codeOut.writeInt(newInstructions.length);
- codeOut.write(newInstructions);
-
- if (tries.length > 0) {
- if (newInstructions.length % 2 == 1) {
- codeOut.writeShort((short) 0); // padding
- }
-
- /*
- * We can't write the tries until we've written the catch handlers.
- * Unfortunately they're in the opposite order in the dex file so we
- * need to transform them out-of-order.
- */
- DexBuffer.Section triesSection = dexOut.open(codeOut.getPosition());
- codeOut.skip(tries.length * SizeOf.TRY_ITEM);
- int[] offsets = transformCatchHandlers(indexMap, catchHandlers);
- transformTries(triesSection, tries, offsets);
- }
- }
-
- /**
- * Writes the catch handlers to {@code codeOut} and returns their indices.
- */
- private int[] transformCatchHandlers(IndexMap indexMap, Code.CatchHandler[] catchHandlers) {
- int baseOffset = codeOut.getPosition();
- codeOut.writeUleb128(catchHandlers.length);
- int[] offsets = new int[catchHandlers.length];
- for (int i = 0; i < catchHandlers.length; i++) {
- offsets[i] = codeOut.getPosition() - baseOffset;
- transformEncodedCatchHandler(catchHandlers[i], indexMap);
- }
- return offsets;
- }
-
- private void transformTries(DexBuffer.Section out, Code.Try[] tries,
- int[] catchHandlerOffsets) {
- for (Code.Try tryItem : tries) {
- out.writeInt(tryItem.getStartAddress());
- out.writeUnsignedShort(tryItem.getInstructionCount());
- out.writeUnsignedShort(catchHandlerOffsets[tryItem.getCatchHandlerIndex()]);
- }
- }
-
- private static final byte DBG_END_SEQUENCE = 0x00;
- private static final byte DBG_ADVANCE_PC = 0x01;
- private static final byte DBG_ADVANCE_LINE = 0x02;
- private static final byte DBG_START_LOCAL = 0x03;
- private static final byte DBG_START_LOCAL_EXTENDED = 0x04;
- private static final byte DBG_END_LOCAL = 0x05;
- private static final byte DBG_RESTART_LOCAL = 0x06;
- private static final byte DBG_SET_PROLOGUE_END = 0x07;
- private static final byte DBG_SET_EPILOGUE_BEGIN = 0x08;
- private static final byte DBG_SET_FILE = 0x09;
-
- private void transformDebugInfoItem(DexBuffer.Section in, IndexMap indexMap) {
- contentsOut.debugInfos.size++;
- int lineStart = in.readUleb128();
- debugInfoOut.writeUleb128(lineStart);
-
- int parametersSize = in.readUleb128();
- debugInfoOut.writeUleb128(parametersSize);
-
- for (int p = 0; p < parametersSize; p++) {
- int parameterName = in.readUleb128p1();
- debugInfoOut.writeUleb128p1(indexMap.adjustString(parameterName));
- }
-
- int addrDiff; // uleb128 address delta.
- int lineDiff; // sleb128 line delta.
- int registerNum; // uleb128 register number.
- int nameIndex; // uleb128p1 string index. Needs indexMap adjustment.
- int typeIndex; // uleb128p1 type index. Needs indexMap adjustment.
- int sigIndex; // uleb128p1 string index. Needs indexMap adjustment.
-
- while (true) {
- int opcode = in.readByte();
- debugInfoOut.writeByte(opcode);
-
- switch (opcode) {
- case DBG_END_SEQUENCE:
- return;
-
- case DBG_ADVANCE_PC:
- addrDiff = in.readUleb128();
- debugInfoOut.writeUleb128(addrDiff);
- break;
-
- case DBG_ADVANCE_LINE:
- lineDiff = in.readSleb128();
- debugInfoOut.writeSleb128(lineDiff);
- break;
-
- case DBG_START_LOCAL:
- case DBG_START_LOCAL_EXTENDED:
- registerNum = in.readUleb128();
- debugInfoOut.writeUleb128(registerNum);
- nameIndex = in.readUleb128p1();
- debugInfoOut.writeUleb128p1(indexMap.adjustString(nameIndex));
- typeIndex = in.readUleb128p1();
- debugInfoOut.writeUleb128p1(indexMap.adjustType(typeIndex));
- if (opcode == DBG_START_LOCAL_EXTENDED) {
- sigIndex = in.readUleb128p1();
- debugInfoOut.writeUleb128p1(indexMap.adjustString(sigIndex));
- }
- break;
-
- case DBG_END_LOCAL:
- case DBG_RESTART_LOCAL:
- registerNum = in.readUleb128();
- debugInfoOut.writeUleb128(registerNum);
- break;
-
- case DBG_SET_FILE:
- nameIndex = in.readUleb128p1();
- debugInfoOut.writeUleb128p1(indexMap.adjustString(nameIndex));
- break;
-
- case DBG_SET_PROLOGUE_END:
- case DBG_SET_EPILOGUE_BEGIN:
- default:
- break;
- }
- }
- }
-
- private void transformEncodedCatchHandler(Code.CatchHandler catchHandler, IndexMap indexMap) {
- int catchAllAddress = catchHandler.getCatchAllAddress();
- int[] typeIndexes = catchHandler.getTypeIndexes();
- int[] addresses = catchHandler.getAddresses();
-
- if (catchAllAddress != -1) {
- codeOut.writeSleb128(-typeIndexes.length);
- } else {
- codeOut.writeSleb128(typeIndexes.length);
- }
-
- for (int i = 0; i < typeIndexes.length; i++) {
- codeOut.writeUleb128(indexMap.adjustType(typeIndexes[i]));
- codeOut.writeUleb128(addresses[i]);
- }
-
- if (catchAllAddress != -1) {
- codeOut.writeUleb128(catchAllAddress);
- }
- }
-
- private void transformStaticValues(DexBuffer.Section in, IndexMap indexMap) {
- contentsOut.encodedArrays.size++;
- indexMap.putStaticValuesOffset(in.getPosition(), encodedArrayOut.getPosition());
- indexMap.adjustEncodedArray(in.readEncodedArray()).writeTo(encodedArrayOut);
- }
-
- /**
- * Byte counts for the sections written when creating a dex. Target sizes
- * are defined in one of two ways:
- * <ul>
- * <li>By pessimistically guessing how large the union of dex files will be.
- * We're pessimistic because we can't predict the amount of duplication
- * between dex files, nor can we predict the length of ULEB-encoded
- * offsets or indices.
- * <li>By exactly measuring an existing dex.
- * </ul>
- */
- private static class WriterSizes {
- private int header = SizeOf.HEADER_ITEM;
- private int idsDefs;
- private int mapList;
- private int typeList;
- private int classData;
- private int code;
- private int stringData;
- private int debugInfo;
- private int encodedArray;
- private int annotationsDirectory;
- private int annotationsSet;
- private int annotationsSetRefList;
- private int annotation;
-
- /**
- * Compute sizes for merging a and b.
- */
- public WriterSizes(DexBuffer a, DexBuffer b) {
- plus(a.getTableOfContents(), false);
- plus(b.getTableOfContents(), false);
- }
-
- public WriterSizes(DexMerger dexMerger) {
- header = dexMerger.headerOut.used();
- idsDefs = dexMerger.idsDefsOut.used();
- mapList = dexMerger.mapListOut.used();
- typeList = dexMerger.typeListOut.used();
- classData = dexMerger.classDataOut.used();
- code = dexMerger.codeOut.used();
- stringData = dexMerger.stringDataOut.used();
- debugInfo = dexMerger.debugInfoOut.used();
- encodedArray = dexMerger.encodedArrayOut.used();
- annotationsDirectory = dexMerger.annotationsDirectoryOut.used();
- annotationsSet = dexMerger.annotationSetOut.used();
- annotationsSetRefList = dexMerger.annotationSetRefListOut.used();
- annotation = dexMerger.annotationOut.used();
- }
-
- public void plus(TableOfContents contents, boolean exact) {
- idsDefs += contents.stringIds.size * SizeOf.STRING_ID_ITEM
- + contents.typeIds.size * SizeOf.TYPE_ID_ITEM
- + contents.protoIds.size * SizeOf.PROTO_ID_ITEM
- + contents.fieldIds.size * SizeOf.MEMBER_ID_ITEM
- + contents.methodIds.size * SizeOf.MEMBER_ID_ITEM
- + contents.classDefs.size * SizeOf.CLASS_DEF_ITEM;
- mapList = SizeOf.UINT + (contents.sections.length * SizeOf.MAP_ITEM);
- typeList += contents.typeLists.byteCount;
- stringData += contents.stringDatas.byteCount;
- annotationsDirectory += contents.annotationsDirectories.byteCount;
- annotationsSet += contents.annotationSets.byteCount;
- annotationsSetRefList += contents.annotationSetRefLists.byteCount;
-
- if (exact) {
- code += contents.codes.byteCount;
- classData += contents.classDatas.byteCount;
- encodedArray += contents.encodedArrays.byteCount;
- annotation += contents.annotations.byteCount;
- debugInfo += contents.debugInfos.byteCount;
- } else {
- // at most 1/4 of the bytes in a code section are uleb/sleb
- code += (int) Math.ceil(contents.codes.byteCount * 1.25);
- // at most 1/3 of the bytes in a class data section are uleb/sleb
- classData += (int) Math.ceil(contents.classDatas.byteCount * 1.34);
- // all of the bytes in an encoding arrays section may be uleb/sleb
- encodedArray += contents.encodedArrays.byteCount * 2;
- // all of the bytes in an annotations section may be uleb/sleb
- annotation += (int) Math.ceil(contents.annotations.byteCount * 2);
- // all of the bytes in a debug info section may be uleb/sleb
- debugInfo += contents.debugInfos.byteCount * 2;
- }
-
- typeList = DexBuffer.fourByteAlign(typeList);
- code = DexBuffer.fourByteAlign(code);
- }
-
- public int size() {
- return header + idsDefs + mapList + typeList + classData + code + stringData + debugInfo
- + encodedArray + annotationsDirectory + annotationsSet + annotationsSetRefList
- + annotation;
- }
- }
-
- public static void main(String[] args) throws IOException {
- if (args.length < 2) {
- printUsage();
- return;
- }
-
- DexBuffer merged = new DexBuffer(new File(args[1]));
- for (int i = 2; i < args.length; i++) {
- DexBuffer toMerge = new DexBuffer(new File(args[i]));
- merged = new DexMerger(merged, toMerge, CollisionPolicy.KEEP_FIRST).merge();
- }
- merged.writeTo(new File(args[0]));
- }
-
- private static void printUsage() {
- System.out.println("Usage: DexMerger <out.dex> <a.dex> <b.dex> ...");
- System.out.println();
- System.out.println(
- "If a class is defined in several dex, the class found in the first dex will be used.");
- }
+ private static void printUsage() {
+ System.out.println("Usage: DexMerger <out.dex> <a.dex> <b.dex> ...");
+ System.out.println();
+ System.out.println(
+ "If a class is defined in several dex, the class found in the first dex will be used.");
+ }
}
diff --git a/dx/src/com/android/jack/dx/merge/IndexMap.java b/dx/src/com/android/jack/dx/merge/IndexMap.java
index 37cd30e..59904f3 100644
--- a/dx/src/com/android/jack/dx/merge/IndexMap.java
+++ b/dx/src/com/android/jack/dx/merge/IndexMap.java
@@ -39,269 +39,281 @@
* {@code strings[5]}.
*/
public final class IndexMap {
- private final DexBuffer target;
- public final int[] stringIds;
- public final short[] typeIds;
- public final short[] protoIds;
- public final short[] fieldIds;
- public final short[] methodIds;
- private final HashMap<Integer, Integer> typeListOffsets;
- private final HashMap<Integer, Integer> annotationOffsets;
- private final HashMap<Integer, Integer> annotationSetOffsets;
- private final HashMap<Integer, Integer> annotationDirectoryOffsets;
- private final HashMap<Integer, Integer> staticValuesOffsets;
+ private final DexBuffer target;
+ public final int[] stringIds;
+ public final short[] typeIds;
+ public final short[] protoIds;
+ public final short[] fieldIds;
+ public final short[] methodIds;
+ private final HashMap<Integer, Integer> typeListOffsets;
+ private final HashMap<Integer, Integer> annotationOffsets;
+ private final HashMap<Integer, Integer> annotationSetOffsets;
+ private final HashMap<Integer, Integer> annotationDirectoryOffsets;
+ private final HashMap<Integer, Integer> staticValuesOffsets;
- public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
- this.target = target;
- this.stringIds = new int[tableOfContents.stringIds.size];
- this.typeIds = new short[tableOfContents.typeIds.size];
- this.protoIds = new short[tableOfContents.protoIds.size];
- this.fieldIds = new short[tableOfContents.fieldIds.size];
- this.methodIds = new short[tableOfContents.methodIds.size];
- this.typeListOffsets = new HashMap<Integer, Integer>();
- this.annotationOffsets = new HashMap<Integer, Integer>();
- this.annotationSetOffsets = new HashMap<Integer, Integer>();
- this.annotationDirectoryOffsets = new HashMap<Integer, Integer>();
- this.staticValuesOffsets = new HashMap<Integer, Integer>();
+ public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
+ this.target = target;
+ this.stringIds = new int[tableOfContents.stringIds.size];
+ this.typeIds = new short[tableOfContents.typeIds.size];
+ this.protoIds = new short[tableOfContents.protoIds.size];
+ this.fieldIds = new short[tableOfContents.fieldIds.size];
+ this.methodIds = new short[tableOfContents.methodIds.size];
+ this.typeListOffsets = new HashMap<Integer, Integer>();
+ this.annotationOffsets = new HashMap<Integer, Integer>();
+ this.annotationSetOffsets = new HashMap<Integer, Integer>();
+ this.annotationDirectoryOffsets = new HashMap<Integer, Integer>();
+ this.staticValuesOffsets = new HashMap<Integer, Integer>();
- /*
- * A type list, annotation set, annotation directory, or static value at
- * offset 0 is always empty. Always map offset 0 to 0.
- */
- this.typeListOffsets.put(0, 0);
- this.annotationSetOffsets.put(0, 0);
- this.annotationDirectoryOffsets.put(0, 0);
- this.staticValuesOffsets.put(0, 0);
- }
-
- public void putTypeListOffset(int oldOffset, int newOffset) {
- if (oldOffset <= 0 || newOffset <= 0) {
- throw new IllegalArgumentException();
- }
- typeListOffsets.put(oldOffset, newOffset);
- }
-
- public void putAnnotationOffset(int oldOffset, int newOffset) {
- if (oldOffset <= 0 || newOffset <= 0) {
- throw new IllegalArgumentException();
- }
- annotationOffsets.put(oldOffset, newOffset);
- }
-
- public void putAnnotationSetOffset(int oldOffset, int newOffset) {
- if (oldOffset <= 0 || newOffset <= 0) {
- throw new IllegalArgumentException();
- }
- annotationSetOffsets.put(oldOffset, newOffset);
- }
-
- public void putAnnotationDirectoryOffset(int oldOffset, int newOffset) {
- if (oldOffset <= 0 || newOffset <= 0) {
- throw new IllegalArgumentException();
- }
- annotationDirectoryOffsets.put(oldOffset, newOffset);
- }
-
- public void putStaticValuesOffset(int oldOffset, int newOffset) {
- if (oldOffset <= 0 || newOffset <= 0) {
- throw new IllegalArgumentException();
- }
- staticValuesOffsets.put(oldOffset, newOffset);
- }
-
- public int adjustString(int stringIndex) {
- return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
- }
-
- public int adjustType(int typeIndex) {
- return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : (typeIds[typeIndex] & 0xffff);
- }
-
- public TypeList adjustTypeList(TypeList typeList) {
- if (typeList == TypeList.EMPTY) {
- return typeList;
- }
- short[] types = typeList.getTypes().clone();
- for (int i = 0; i < types.length; i++) {
- types[i] = (short) adjustType(types[i]);
- }
- return new TypeList(target, types);
- }
-
- public int adjustProto(int protoIndex) {
- return protoIds[protoIndex] & 0xffff;
- }
-
- public int adjustField(int fieldIndex) {
- return fieldIds[fieldIndex] & 0xffff;
- }
-
- public int adjustMethod(int methodIndex) {
- return methodIds[methodIndex] & 0xffff;
- }
-
- public int adjustTypeListOffset(int typeListOffset) {
- return typeListOffsets.get(typeListOffset);
- }
-
- public int adjustAnnotation(int annotationOffset) {
- return annotationOffsets.get(annotationOffset);
- }
-
- public int adjustAnnotationSet(int annotationSetOffset) {
- return annotationSetOffsets.get(annotationSetOffset);
- }
-
- public int adjustAnnotationDirectory(int annotationDirectoryOffset) {
- return annotationDirectoryOffsets.get(annotationDirectoryOffset);
- }
-
- public int adjustStaticValues(int staticValuesOffset) {
- return staticValuesOffsets.get(staticValuesOffset);
- }
-
- public MethodId adjust(MethodId methodId) {
- return new MethodId(target,
- adjustType(methodId.getDeclaringClassIndex()),
- adjustProto(methodId.getProtoIndex()),
- adjustString(methodId.getNameIndex()));
- }
-
- public FieldId adjust(FieldId fieldId) {
- return new FieldId(target,
- adjustType(fieldId.getDeclaringClassIndex()),
- adjustType(fieldId.getTypeIndex()),
- adjustString(fieldId.getNameIndex()));
-
- }
-
- public ProtoId adjust(ProtoId protoId) {
- return new ProtoId(target,
- adjustString(protoId.getShortyIndex()),
- adjustType(protoId.getReturnTypeIndex()),
- adjustTypeListOffset(protoId.getParametersOffset()));
- }
-
- public ClassDef adjust(ClassDef classDef) {
- return new ClassDef(target, classDef.getOffset(), adjustType(classDef.getTypeIndex()),
- classDef.getAccessFlags(), adjustType(classDef.getSupertypeIndex()),
- adjustTypeListOffset(classDef.getInterfacesOffset()), classDef.getSourceFileIndex(),
- classDef.getAnnotationsOffset(), classDef.getClassDataOffset(),
- classDef.getStaticValuesOffset());
- }
-
- public SortableType adjust(SortableType sortableType) {
- return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
- }
-
- public EncodedValue adjustEncodedValue(EncodedValue encodedValue) {
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
- new EncodedValueTransformer(encodedValue, out).readValue();
- return new EncodedValue(out.toByteArray());
- }
-
- public EncodedValue adjustEncodedArray(EncodedValue encodedArray) {
- ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
- new EncodedValueTransformer(encodedArray, out).readArray();
- return new EncodedValue(out.toByteArray());
- }
-
- public Annotation adjust(Annotation annotation) {
- int[] names = annotation.getNames().clone();
- EncodedValue[] values = annotation.getValues().clone();
- for (int i = 0; i < names.length; i++) {
- names[i] = adjustString(names[i]);
- values[i] = adjustEncodedValue(values[i]);
- }
- return new Annotation(target, annotation.getVisibility(),
- adjustType(annotation.getTypeIndex()), names, values);
- }
-
- /**
- * Adjust an encoded value or array.
+ /*
+ * A type list, annotation set, annotation directory, or static value at
+ * offset 0 is always empty. Always map offset 0 to 0.
*/
- private final class EncodedValueTransformer extends EncodedValueReader {
- private final ByteOutput out;
+ this.typeListOffsets.put(0, 0);
+ this.annotationSetOffsets.put(0, 0);
+ this.annotationDirectoryOffsets.put(0, 0);
+ this.staticValuesOffsets.put(0, 0);
+ }
- public EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out) {
- super(encodedValue);
- this.out = out;
- }
-
- protected void visitArray(int size) {
- Leb128Utils.writeUnsignedLeb128(out, size);
- }
-
- protected void visitAnnotation(int typeIndex, int size) {
- Leb128Utils.writeUnsignedLeb128(out, adjustType(typeIndex));
- Leb128Utils.writeUnsignedLeb128(out, size);
- }
-
- protected void visitAnnotationName(int index) {
- Leb128Utils.writeUnsignedLeb128(out, adjustString(index));
- }
-
- protected void visitPrimitive(int argAndType, int type, int arg, int size) {
- out.writeByte(argAndType);
- copyBytes(in, out, size);
- }
-
- protected void visitString(int type, int index) {
- writeTypeAndSizeAndIndex(type, adjustString(index));
- }
-
- protected void visitType(int type, int index) {
- writeTypeAndSizeAndIndex(type, adjustType(index));
- }
-
- protected void visitField(int type, int index) {
- writeTypeAndSizeAndIndex(type, adjustField(index));
- }
-
- protected void visitMethod(int type, int index) {
- writeTypeAndSizeAndIndex(type, adjustMethod(index));
- }
-
- protected void visitArrayValue(int argAndType) {
- out.writeByte(argAndType);
- }
-
- protected void visitAnnotationValue(int argAndType) {
- out.writeByte(argAndType);
- }
-
- protected void visitEncodedBoolean(int argAndType) {
- out.writeByte(argAndType);
- }
-
- protected void visitEncodedNull(int argAndType) {
- out.writeByte(argAndType);
- }
-
- private void writeTypeAndSizeAndIndex(int type, int index) {
- int byteCount;
- if (Unsigned.compare(index, 0xff) <= 0) {
- byteCount = 1;
- } else if (Unsigned.compare(index, 0xffff) <= 0) {
- byteCount = 2;
- } else if (Unsigned.compare(index, 0xffffff) <= 0) {
- byteCount = 3;
- } else {
- byteCount = 4;
- }
- int argAndType = ((byteCount - 1) << 5) | type;
- out.writeByte(argAndType);
-
- for (int i = 0; i < byteCount; i++) {
- out.writeByte(index & 0xff);
- index >>>= 8;
- }
- }
-
- private void copyBytes(ByteInput in, ByteOutput out, int size) {
- for (int i = 0; i < size; i++) {
- out.writeByte(in.readByte());
- }
- }
+ public void putTypeListOffset(int oldOffset, int newOffset) {
+ if (oldOffset <= 0 || newOffset <= 0) {
+ throw new IllegalArgumentException();
}
+ typeListOffsets.put(oldOffset, newOffset);
+ }
+
+ public void putAnnotationOffset(int oldOffset, int newOffset) {
+ if (oldOffset <= 0 || newOffset <= 0) {
+ throw new IllegalArgumentException();
+ }
+ annotationOffsets.put(oldOffset, newOffset);
+ }
+
+ public void putAnnotationSetOffset(int oldOffset, int newOffset) {
+ if (oldOffset <= 0 || newOffset <= 0) {
+ throw new IllegalArgumentException();
+ }
+ annotationSetOffsets.put(oldOffset, newOffset);
+ }
+
+ public void putAnnotationDirectoryOffset(int oldOffset, int newOffset) {
+ if (oldOffset <= 0 || newOffset <= 0) {
+ throw new IllegalArgumentException();
+ }
+ annotationDirectoryOffsets.put(oldOffset, newOffset);
+ }
+
+ public void putStaticValuesOffset(int oldOffset, int newOffset) {
+ if (oldOffset <= 0 || newOffset <= 0) {
+ throw new IllegalArgumentException();
+ }
+ staticValuesOffsets.put(oldOffset, newOffset);
+ }
+
+ public int adjustString(int stringIndex) {
+ return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
+ }
+
+ public int adjustType(int typeIndex) {
+ return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : (typeIds[typeIndex] & 0xffff);
+ }
+
+ public TypeList adjustTypeList(TypeList typeList) {
+ if (typeList == TypeList.EMPTY) {
+ return typeList;
+ }
+ short[] types = typeList.getTypes().clone();
+ for (int i = 0; i < types.length; i++) {
+ types[i] = (short) adjustType(types[i]);
+ }
+ return new TypeList(target, types);
+ }
+
+ public int adjustProto(int protoIndex) {
+ return protoIds[protoIndex] & 0xffff;
+ }
+
+ public int adjustField(int fieldIndex) {
+ return fieldIds[fieldIndex] & 0xffff;
+ }
+
+ public int adjustMethod(int methodIndex) {
+ return methodIds[methodIndex] & 0xffff;
+ }
+
+ public int adjustTypeListOffset(int typeListOffset) {
+ return typeListOffsets.get(typeListOffset);
+ }
+
+ public int adjustAnnotation(int annotationOffset) {
+ return annotationOffsets.get(annotationOffset);
+ }
+
+ public int adjustAnnotationSet(int annotationSetOffset) {
+ return annotationSetOffsets.get(annotationSetOffset);
+ }
+
+ public int adjustAnnotationDirectory(int annotationDirectoryOffset) {
+ return annotationDirectoryOffsets.get(annotationDirectoryOffset);
+ }
+
+ public int adjustStaticValues(int staticValuesOffset) {
+ return staticValuesOffsets.get(staticValuesOffset);
+ }
+
+ public MethodId adjust(MethodId methodId) {
+ return new MethodId(target, adjustType(methodId.getDeclaringClassIndex()),
+ adjustProto(methodId.getProtoIndex()), adjustString(methodId.getNameIndex()));
+ }
+
+ public FieldId adjust(FieldId fieldId) {
+ return new FieldId(target, adjustType(fieldId.getDeclaringClassIndex()),
+ adjustType(fieldId.getTypeIndex()), adjustString(fieldId.getNameIndex()));
+
+ }
+
+ public ProtoId adjust(ProtoId protoId) {
+ return new ProtoId(target, adjustString(protoId.getShortyIndex()),
+ adjustType(protoId.getReturnTypeIndex()),
+ adjustTypeListOffset(protoId.getParametersOffset()));
+ }
+
+ public ClassDef adjust(ClassDef classDef) {
+ return new ClassDef(target,
+ classDef.getOffset(),
+ adjustType(classDef.getTypeIndex()),
+ classDef.getAccessFlags(),
+ adjustType(classDef.getSupertypeIndex()),
+ adjustTypeListOffset(classDef.getInterfacesOffset()),
+ classDef.getSourceFileIndex(),
+ classDef.getAnnotationsOffset(),
+ classDef.getClassDataOffset(),
+ classDef.getStaticValuesOffset());
+ }
+
+ public SortableType adjust(SortableType sortableType) {
+ return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
+ }
+
+ public EncodedValue adjustEncodedValue(EncodedValue encodedValue) {
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
+ new EncodedValueTransformer(encodedValue, out).readValue();
+ return new EncodedValue(out.toByteArray());
+ }
+
+ public EncodedValue adjustEncodedArray(EncodedValue encodedArray) {
+ ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
+ new EncodedValueTransformer(encodedArray, out).readArray();
+ return new EncodedValue(out.toByteArray());
+ }
+
+ public Annotation adjust(Annotation annotation) {
+ int[] names = annotation.getNames().clone();
+ EncodedValue[] values = annotation.getValues().clone();
+ for (int i = 0; i < names.length; i++) {
+ names[i] = adjustString(names[i]);
+ values[i] = adjustEncodedValue(values[i]);
+ }
+ return new Annotation(target, annotation.getVisibility(), adjustType(annotation.getTypeIndex()),
+ names, values);
+ }
+
+ /**
+ * Adjust an encoded value or array.
+ */
+ private final class EncodedValueTransformer extends EncodedValueReader {
+ private final ByteOutput out;
+
+ public EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out) {
+ super(encodedValue);
+ this.out = out;
+ }
+
+ @Override
+ protected void visitArray(int size) {
+ Leb128Utils.writeUnsignedLeb128(out, size);
+ }
+
+ @Override
+ protected void visitAnnotation(int typeIndex, int size) {
+ Leb128Utils.writeUnsignedLeb128(out, adjustType(typeIndex));
+ Leb128Utils.writeUnsignedLeb128(out, size);
+ }
+
+ @Override
+ protected void visitAnnotationName(int index) {
+ Leb128Utils.writeUnsignedLeb128(out, adjustString(index));
+ }
+
+ @Override
+ protected void visitPrimitive(int argAndType, int type, int arg, int size) {
+ out.writeByte(argAndType);
+ copyBytes(in, out, size);
+ }
+
+ @Override
+ protected void visitString(int type, int index) {
+ writeTypeAndSizeAndIndex(type, adjustString(index));
+ }
+
+ @Override
+ protected void visitType(int type, int index) {
+ writeTypeAndSizeAndIndex(type, adjustType(index));
+ }
+
+ @Override
+ protected void visitField(int type, int index) {
+ writeTypeAndSizeAndIndex(type, adjustField(index));
+ }
+
+ @Override
+ protected void visitMethod(int type, int index) {
+ writeTypeAndSizeAndIndex(type, adjustMethod(index));
+ }
+
+ @Override
+ protected void visitArrayValue(int argAndType) {
+ out.writeByte(argAndType);
+ }
+
+ @Override
+ protected void visitAnnotationValue(int argAndType) {
+ out.writeByte(argAndType);
+ }
+
+ @Override
+ protected void visitEncodedBoolean(int argAndType) {
+ out.writeByte(argAndType);
+ }
+
+ @Override
+ protected void visitEncodedNull(int argAndType) {
+ out.writeByte(argAndType);
+ }
+
+ private void writeTypeAndSizeAndIndex(int type, int index) {
+ int byteCount;
+ if (Unsigned.compare(index, 0xff) <= 0) {
+ byteCount = 1;
+ } else if (Unsigned.compare(index, 0xffff) <= 0) {
+ byteCount = 2;
+ } else if (Unsigned.compare(index, 0xffffff) <= 0) {
+ byteCount = 3;
+ } else {
+ byteCount = 4;
+ }
+ int argAndType = ((byteCount - 1) << 5) | type;
+ out.writeByte(argAndType);
+
+ for (int i = 0; i < byteCount; i++) {
+ out.writeByte(index & 0xff);
+ index >>>= 8;
+ }
+ }
+
+ private void copyBytes(ByteInput in, ByteOutput out, int size) {
+ for (int i = 0; i < size; i++) {
+ out.writeByte(in.readByte());
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/merge/InstructionTransformer.java b/dx/src/com/android/jack/dx/merge/InstructionTransformer.java
index 0aa5364..65d3a3b 100644
--- a/dx/src/com/android/jack/dx/merge/InstructionTransformer.java
+++ b/dx/src/com/android/jack/dx/merge/InstructionTransformer.java
@@ -23,90 +23,94 @@
import com.android.jack.dx.util.DexException;
final class InstructionTransformer {
- private final IndexMap indexMap;
- private final CodeReader reader;
- private DecodedInstruction[] mappedInstructions;
- private int mappedAt;
+ private final IndexMap indexMap;
+ private final CodeReader reader;
+ private DecodedInstruction[] mappedInstructions;
+ private int mappedAt;
- public InstructionTransformer(IndexMap indexMap) {
- this.indexMap = indexMap;
- this.reader = new CodeReader();
- this.reader.setAllVisitors(new GenericVisitor());
- this.reader.setStringVisitor(new StringVisitor());
- this.reader.setTypeVisitor(new TypeVisitor());
- this.reader.setFieldVisitor(new FieldVisitor());
- this.reader.setMethodVisitor(new MethodVisitor());
+ public InstructionTransformer(IndexMap indexMap) {
+ this.indexMap = indexMap;
+ this.reader = new CodeReader();
+ this.reader.setAllVisitors(new GenericVisitor());
+ this.reader.setStringVisitor(new StringVisitor());
+ this.reader.setTypeVisitor(new TypeVisitor());
+ this.reader.setFieldVisitor(new FieldVisitor());
+ this.reader.setMethodVisitor(new MethodVisitor());
+ }
+
+ public short[] transform(short[] encodedInstructions) throws DexException {
+ DecodedInstruction[] decodedInstructions = DecodedInstruction.decodeAll(encodedInstructions);
+ int size = decodedInstructions.length;
+
+ mappedInstructions = new DecodedInstruction[size];
+ mappedAt = 0;
+ reader.visitAll(decodedInstructions);
+
+ ShortArrayCodeOutput out = new ShortArrayCodeOutput(size);
+ for (DecodedInstruction instruction : mappedInstructions) {
+ if (instruction != null) {
+ instruction.encode(out);
+ }
}
- public short[] transform(short[] encodedInstructions) throws DexException {
- DecodedInstruction[] decodedInstructions =
- DecodedInstruction.decodeAll(encodedInstructions);
- int size = decodedInstructions.length;
+ return out.getArray();
+ }
- mappedInstructions = new DecodedInstruction[size];
- mappedAt = 0;
- reader.visitAll(decodedInstructions);
-
- ShortArrayCodeOutput out = new ShortArrayCodeOutput(size);
- for (DecodedInstruction instruction : mappedInstructions) {
- if (instruction != null) {
- instruction.encode(out);
- }
- }
-
- return out.getArray();
+ private class GenericVisitor implements CodeReader.Visitor {
+ @Override
+ public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+ mappedInstructions[mappedAt++] = one;
}
+ }
- private class GenericVisitor implements CodeReader.Visitor {
- public void visit(DecodedInstruction[] all, DecodedInstruction one) {
- mappedInstructions[mappedAt++] = one;
- }
+ private class StringVisitor implements CodeReader.Visitor {
+ @Override
+ public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+ int stringId = one.getIndex();
+ int mappedId = indexMap.adjustString(stringId);
+ boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
+ jumboCheck(isJumbo, mappedId);
+ mappedInstructions[mappedAt++] = one.withIndex(mappedId);
}
+ }
- private class StringVisitor implements CodeReader.Visitor {
- public void visit(DecodedInstruction[] all, DecodedInstruction one) {
- int stringId = one.getIndex();
- int mappedId = indexMap.adjustString(stringId);
- boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
- jumboCheck(isJumbo, mappedId);
- mappedInstructions[mappedAt++] = one.withIndex(mappedId);
- }
+ private class FieldVisitor implements CodeReader.Visitor {
+ @Override
+ public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+ int fieldId = one.getIndex();
+ int mappedId = indexMap.adjustField(fieldId);
+ boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
+ jumboCheck(isJumbo, mappedId);
+ mappedInstructions[mappedAt++] = one.withIndex(mappedId);
}
+ }
- private class FieldVisitor implements CodeReader.Visitor {
- public void visit(DecodedInstruction[] all, DecodedInstruction one) {
- int fieldId = one.getIndex();
- int mappedId = indexMap.adjustField(fieldId);
- boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
- jumboCheck(isJumbo, mappedId);
- mappedInstructions[mappedAt++] = one.withIndex(mappedId);
- }
+ private class TypeVisitor implements CodeReader.Visitor {
+ @Override
+ public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+ int typeId = one.getIndex();
+ int mappedId = indexMap.adjustType(typeId);
+ boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
+ jumboCheck(isJumbo, mappedId);
+ mappedInstructions[mappedAt++] = one.withIndex(mappedId);
}
+ }
- private class TypeVisitor implements CodeReader.Visitor {
- public void visit(DecodedInstruction[] all, DecodedInstruction one) {
- int typeId = one.getIndex();
- int mappedId = indexMap.adjustType(typeId);
- boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
- jumboCheck(isJumbo, mappedId);
- mappedInstructions[mappedAt++] = one.withIndex(mappedId);
- }
+ private class MethodVisitor implements CodeReader.Visitor {
+ @Override
+ public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+ int methodId = one.getIndex();
+ int mappedId = indexMap.adjustMethod(methodId);
+ boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
+ jumboCheck(isJumbo, mappedId);
+ mappedInstructions[mappedAt++] = one.withIndex(mappedId);
}
+ }
- private class MethodVisitor implements CodeReader.Visitor {
- public void visit(DecodedInstruction[] all, DecodedInstruction one) {
- int methodId = one.getIndex();
- int mappedId = indexMap.adjustMethod(methodId);
- boolean isJumbo = (one.getOpcode() == Opcodes.CONST_STRING_JUMBO);
- jumboCheck(isJumbo, mappedId);
- mappedInstructions[mappedAt++] = one.withIndex(mappedId);
- }
+ private static void jumboCheck(boolean isJumbo, int newIndex) {
+ if (!isJumbo && (newIndex > 0xffff)) {
+ throw new DexException(
+ "Cannot merge new index " + newIndex + " into a non-jumbo instruction!");
}
-
- private static void jumboCheck(boolean isJumbo, int newIndex) {
- if (!isJumbo && (newIndex > 0xffff)) {
- throw new DexException("Cannot merge new index " + newIndex +
- " into a non-jumbo instruction!");
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/merge/SortableType.java b/dx/src/com/android/jack/dx/merge/SortableType.java
index 9435619..a479a89 100644
--- a/dx/src/com/android/jack/dx/merge/SortableType.java
+++ b/dx/src/com/android/jack/dx/merge/SortableType.java
@@ -26,81 +26,82 @@
* preceded by its supertype and implemented interfaces.
*/
final class SortableType {
- public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() {
- public int compare(SortableType a, SortableType b) {
- if (a == b) {
- return 0;
- }
- if (b == null) {
- return -1;
- }
- if (a == null) {
- return 1;
- }
- if (a.depth != b.depth) {
- return a.depth - b.depth;
- }
- return a.getTypeIndex() - b.getTypeIndex();
- }
- };
+ public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() {
+ @Override
+ public int compare(SortableType a, SortableType b) {
+ if (a == b) {
+ return 0;
+ }
+ if (b == null) {
+ return -1;
+ }
+ if (a == null) {
+ return 1;
+ }
+ if (a.depth != b.depth) {
+ return a.depth - b.depth;
+ }
+ return a.getTypeIndex() - b.getTypeIndex();
+ }
+ };
- private final DexBuffer buffer;
- private ClassDef classDef;
- private int depth = -1;
+ private final DexBuffer buffer;
+ private ClassDef classDef;
+ private int depth = -1;
- public SortableType(DexBuffer buffer, ClassDef classDef) {
- this.buffer = buffer;
- this.classDef = classDef;
+ public SortableType(DexBuffer buffer, ClassDef classDef) {
+ this.buffer = buffer;
+ this.classDef = classDef;
+ }
+
+ public DexBuffer getBuffer() {
+ return buffer;
+ }
+
+ public ClassDef getClassDef() {
+ return classDef;
+ }
+
+ public int getTypeIndex() {
+ return classDef.getTypeIndex();
+ }
+
+ /**
+ * Assigns this type's depth if the depths of its supertype and implemented
+ * interfaces are known. Returns false if the depth couldn't be computed
+ * yet.
+ */
+ public boolean tryAssignDepth(SortableType[] types) {
+ int max;
+ if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) {
+ max = 0; // this is Object.class or an interface
+ } else {
+ SortableType sortableSupertype = types[classDef.getSupertypeIndex()];
+ if (sortableSupertype == null) {
+ max = 1; // unknown, so assume it's a root.
+ } else if (sortableSupertype.depth == -1) {
+ return false;
+ } else {
+ max = sortableSupertype.depth;
+ }
}
- public DexBuffer getBuffer() {
- return buffer;
+ for (short interfaceIndex : classDef.getInterfaces()) {
+ SortableType implemented = types[interfaceIndex];
+ if (implemented == null) {
+ max = Math.max(max, 1); // unknown, so assume it's a root.
+ } else if (implemented.depth == -1) {
+ return false;
+ } else {
+ max = Math.max(max, implemented.depth);
+ }
}
- public ClassDef getClassDef() {
- return classDef;
- }
+ depth = max + 1;
+ return true;
+ }
- public int getTypeIndex() {
- return classDef.getTypeIndex();
- }
-
- /**
- * Assigns this type's depth if the depths of its supertype and implemented
- * interfaces are known. Returns false if the depth couldn't be computed
- * yet.
- */
- public boolean tryAssignDepth(SortableType[] types) {
- int max;
- if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) {
- max = 0; // this is Object.class or an interface
- } else {
- SortableType sortableSupertype = types[classDef.getSupertypeIndex()];
- if (sortableSupertype == null) {
- max = 1; // unknown, so assume it's a root.
- } else if (sortableSupertype.depth == -1) {
- return false;
- } else {
- max = sortableSupertype.depth;
- }
- }
-
- for (short interfaceIndex : classDef.getInterfaces()) {
- SortableType implemented = types[interfaceIndex];
- if (implemented == null) {
- max = Math.max(max, 1); // unknown, so assume it's a root.
- } else if (implemented.depth == -1) {
- return false;
- } else {
- max = Math.max(max, implemented.depth);
- }
- }
-
- depth = max + 1;
- return true;
- }
-
- public boolean isDepthAssigned() {
- return depth != -1;
- }
+ public boolean isDepthAssigned() {
+ return depth != -1;
+ }
}
diff --git a/dx/src/com/android/jack/dx/merge/TypeList.java b/dx/src/com/android/jack/dx/merge/TypeList.java
index a34d000..0c5b4f9 100644
--- a/dx/src/com/android/jack/dx/merge/TypeList.java
+++ b/dx/src/com/android/jack/dx/merge/TypeList.java
@@ -19,40 +19,43 @@
import com.android.jack.dx.io.DexBuffer;
import com.android.jack.dx.util.Unsigned;
-import java.util.Arrays;
-
+/**
+ * TODO(jack team)
+ */
public final class TypeList implements Comparable<TypeList> {
- public static final TypeList EMPTY = new TypeList(null, new short[0]);
+ public static final TypeList EMPTY = new TypeList(null, new short[0]);
- private final DexBuffer buffer;
- private final short[] types;
+ private final DexBuffer buffer;
+ private final short[] types;
- public TypeList(DexBuffer buffer, short[] types) {
- this.buffer = buffer;
- this.types = types;
+ public TypeList(DexBuffer buffer, short[] types) {
+ this.buffer = buffer;
+ this.types = types;
+ }
+
+ public short[] getTypes() {
+ return types;
+ }
+
+ @Override
+ public int compareTo(TypeList other) {
+ for (int i = 0; i < types.length && i < other.types.length; i++) {
+ if (types[i] != other.types[i]) {
+ return Unsigned.compare(types[i], other.types[i]);
+ }
}
+ return Unsigned.compare(types.length, other.types.length);
+ }
- public short[] getTypes() {
- return types;
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("(");
+ for (int i = 0, typesLength = types.length; i < typesLength; i++) {
+ result.append(buffer != null ? buffer.typeNames().get(types[i]) : types[i]);
}
-
- public int compareTo(TypeList other) {
- for (int i = 0; i < types.length && i < other.types.length; i++) {
- if (types[i] != other.types[i]) {
- return Unsigned.compare(types[i], other.types[i]);
- }
- }
- return Unsigned.compare(types.length, other.types.length);
- }
-
- @Override public String toString() {
- StringBuilder result = new StringBuilder();
- result.append("(");
- for (int i = 0, typesLength = types.length; i < typesLength; i++) {
- result.append(buffer != null ? buffer.typeNames().get(types[i]) : types[i]);
- }
- result.append(")");
- return result.toString();
- }
+ result.append(")");
+ return result.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/annotation/Annotation.java b/dx/src/com/android/jack/dx/rop/annotation/Annotation.java
index ccf331e..a0453e8 100644
--- a/dx/src/com/android/jack/dx/rop/annotation/Annotation.java
+++ b/dx/src/com/android/jack/dx/rop/annotation/Annotation.java
@@ -31,194 +31,195 @@
* associated type and additionally consist of a set of (name, value)
* pairs, where the names are unique.
*/
-public final class Annotation extends MutabilityControl
- implements Comparable<Annotation>, ToHuman {
- /** {@code non-null;} type of the annotation */
- private final CstType type;
+public final class Annotation extends MutabilityControl implements Comparable<Annotation>, ToHuman {
+ /** {@code non-null;} type of the annotation */
+ private final CstType type;
- /** {@code non-null;} the visibility of the annotation */
- private final AnnotationVisibility visibility;
+ /** {@code non-null;} the visibility of the annotation */
+ private final AnnotationVisibility visibility;
- /** {@code non-null;} map from names to {@link NameValuePair} instances */
- private final TreeMap<CstString, NameValuePair> elements;
+ /** {@code non-null;} map from names to {@link NameValuePair} instances */
+ private final TreeMap<CstString, NameValuePair> elements;
- /**
- * Construct an instance. It initially contains no elements.
- *
- * @param type {@code non-null;} type of the annotation
- * @param visibility {@code non-null;} the visibility of the annotation
- */
- public Annotation(CstType type, AnnotationVisibility visibility) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
-
- if (visibility == null) {
- throw new NullPointerException("visibility == null");
- }
-
- this.type = type;
- this.visibility = visibility;
- this.elements = new TreeMap<CstString, NameValuePair>();
+ /**
+ * Construct an instance. It initially contains no elements.
+ *
+ * @param type {@code non-null;} type of the annotation
+ * @param visibility {@code non-null;} the visibility of the annotation
+ */
+ public Annotation(CstType type, AnnotationVisibility visibility) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (! (other instanceof Annotation)) {
- return false;
- }
-
- Annotation otherAnnotation = (Annotation) other;
-
- if (! (type.equals(otherAnnotation.type)
- && (visibility == otherAnnotation.visibility))) {
- return false;
- }
-
- return elements.equals(otherAnnotation.elements);
+ if (visibility == null) {
+ throw new NullPointerException("visibility == null");
}
- /** {@inheritDoc} */
- public int hashCode() {
- int hash = type.hashCode();
- hash = (hash * 31) + elements.hashCode();
- hash = (hash * 31) + visibility.hashCode();
- return hash;
+ this.type = type;
+ this.visibility = visibility;
+ this.elements = new TreeMap<CstString, NameValuePair>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Annotation)) {
+ return false;
}
- /** {@inheritDoc} */
- public int compareTo(Annotation other) {
- int result = type.compareTo(other.type);
+ Annotation otherAnnotation = (Annotation) other;
- if (result != 0) {
- return result;
- }
-
- result = visibility.compareTo(other.visibility);
-
- if (result != 0) {
- return result;
- }
-
- Iterator<NameValuePair> thisIter = elements.values().iterator();
- Iterator<NameValuePair> otherIter = other.elements.values().iterator();
-
- while (thisIter.hasNext() && otherIter.hasNext()) {
- NameValuePair thisOne = thisIter.next();
- NameValuePair otherOne = otherIter.next();
-
- result = thisOne.compareTo(otherOne);
- if (result != 0) {
- return result;
- }
- }
-
- if (thisIter.hasNext()) {
- return 1;
- } else if (otherIter.hasNext()) {
- return -1;
- }
-
- return 0;
+ if (!(type.equals(otherAnnotation.type) && (visibility == otherAnnotation.visibility))) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return toHuman();
+ return elements.equals(otherAnnotation.elements);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ int hash = type.hashCode();
+ hash = (hash * 31) + elements.hashCode();
+ hash = (hash * 31) + visibility.hashCode();
+ return hash;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Annotation other) {
+ int result = type.compareTo(other.type);
+
+ if (result != 0) {
+ return result;
}
- /** {@inheritDoc} */
- public String toHuman() {
- StringBuilder sb = new StringBuilder();
+ result = visibility.compareTo(other.visibility);
- sb.append(visibility.toHuman());
- sb.append("-annotation ");
- sb.append(type.toHuman());
- sb.append(" {");
-
- boolean first = true;
- for (NameValuePair pair : elements.values()) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(pair.getName().toHuman());
- sb.append(": ");
- sb.append(pair.getValue().toHuman());
- }
-
- sb.append("}");
- return sb.toString();
+ if (result != 0) {
+ return result;
}
- /**
- * Gets the type of this instance.
- *
- * @return {@code non-null;} the type
- */
- public CstType getType() {
- return type;
+ Iterator<NameValuePair> thisIter = elements.values().iterator();
+ Iterator<NameValuePair> otherIter = other.elements.values().iterator();
+
+ while (thisIter.hasNext() && otherIter.hasNext()) {
+ NameValuePair thisOne = thisIter.next();
+ NameValuePair otherOne = otherIter.next();
+
+ result = thisOne.compareTo(otherOne);
+ if (result != 0) {
+ return result;
+ }
}
- /**
- * Gets the visibility of this instance.
- *
- * @return {@code non-null;} the visibility
- */
- public AnnotationVisibility getVisibility() {
- return visibility;
+ if (thisIter.hasNext()) {
+ return 1;
+ } else if (otherIter.hasNext()) {
+ return -1;
}
- /**
- * Put an element into the set of (name, value) pairs for this instance.
- * If there is a preexisting element with the same name, it will be
- * replaced by this method.
- *
- * @param pair {@code non-null;} the (name, value) pair to place into this instance
- */
- public void put(NameValuePair pair) {
- throwIfImmutable();
+ return 0;
+ }
- if (pair == null) {
- throw new NullPointerException("pair == null");
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return toHuman();
+ }
- elements.put(pair.getName(), pair);
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(visibility.toHuman());
+ sb.append("-annotation ");
+ sb.append(type.toHuman());
+ sb.append(" {");
+
+ boolean first = true;
+ for (NameValuePair pair : elements.values()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(pair.getName().toHuman());
+ sb.append(": ");
+ sb.append(pair.getValue().toHuman());
}
- /**
- * Add an element to the set of (name, value) pairs for this instance.
- * It is an error to call this method if there is a preexisting element
- * with the same name.
- *
- * @param pair {@code non-null;} the (name, value) pair to add to this instance
- */
- public void add(NameValuePair pair) {
- throwIfImmutable();
+ sb.append("}");
+ return sb.toString();
+ }
- if (pair == null) {
- throw new NullPointerException("pair == null");
- }
+ /**
+ * Gets the type of this instance.
+ *
+ * @return {@code non-null;} the type
+ */
+ public CstType getType() {
+ return type;
+ }
- CstString name = pair.getName();
+ /**
+ * Gets the visibility of this instance.
+ *
+ * @return {@code non-null;} the visibility
+ */
+ public AnnotationVisibility getVisibility() {
+ return visibility;
+ }
- if (elements.get(name) != null) {
- throw new IllegalArgumentException("name already added: " + name);
- }
+ /**
+ * Put an element into the set of (name, value) pairs for this instance.
+ * If there is a preexisting element with the same name, it will be
+ * replaced by this method.
+ *
+ * @param pair {@code non-null;} the (name, value) pair to place into this instance
+ */
+ public void put(NameValuePair pair) {
+ throwIfImmutable();
- elements.put(name, pair);
+ if (pair == null) {
+ throw new NullPointerException("pair == null");
}
- /**
- * Gets the set of name-value pairs contained in this instance. The
- * result is always unmodifiable.
- *
- * @return {@code non-null;} the set of name-value pairs
- */
- public Collection<NameValuePair> getNameValuePairs() {
- return Collections.unmodifiableCollection(elements.values());
+ elements.put(pair.getName(), pair);
+ }
+
+ /**
+ * Add an element to the set of (name, value) pairs for this instance.
+ * It is an error to call this method if there is a preexisting element
+ * with the same name.
+ *
+ * @param pair {@code non-null;} the (name, value) pair to add to this instance
+ */
+ public void add(NameValuePair pair) {
+ throwIfImmutable();
+
+ if (pair == null) {
+ throw new NullPointerException("pair == null");
}
+
+ CstString name = pair.getName();
+
+ if (elements.get(name) != null) {
+ throw new IllegalArgumentException("name already added: " + name);
+ }
+
+ elements.put(name, pair);
+ }
+
+ /**
+ * Gets the set of name-value pairs contained in this instance. The
+ * result is always unmodifiable.
+ *
+ * @return {@code non-null;} the set of name-value pairs
+ */
+ public Collection<NameValuePair> getNameValuePairs() {
+ return Collections.unmodifiableCollection(elements.values());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/annotation/AnnotationVisibility.java b/dx/src/com/android/jack/dx/rop/annotation/AnnotationVisibility.java
index e8ca504..874de4e 100644
--- a/dx/src/com/android/jack/dx/rop/annotation/AnnotationVisibility.java
+++ b/dx/src/com/android/jack/dx/rop/annotation/AnnotationVisibility.java
@@ -22,25 +22,23 @@
* Visibility scope of an annotation.
*/
public enum AnnotationVisibility implements ToHuman {
- RUNTIME("runtime"),
- BUILD("build"),
- SYSTEM("system"),
- EMBEDDED("embedded");
+ RUNTIME("runtime"), BUILD("build"), SYSTEM("system"), EMBEDDED("embedded");
- /** {@code non-null;} the human-oriented string representation */
- private final String human;
+ /** {@code non-null;} the human-oriented string representation */
+ private final String human;
- /**
- * Constructs an instance.
- *
- * @param human {@code non-null;} the human-oriented string representation
- */
- private AnnotationVisibility(String human) {
- this.human = human;
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param human {@code non-null;} the human-oriented string representation
+ */
+ private AnnotationVisibility(String human) {
+ this.human = human;
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return human;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return human;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/annotation/Annotations.java b/dx/src/com/android/jack/dx/rop/annotation/Annotations.java
index 9f9f92b..626f963 100644
--- a/dx/src/com/android/jack/dx/rop/annotation/Annotations.java
+++ b/dx/src/com/android/jack/dx/rop/annotation/Annotations.java
@@ -27,187 +27,186 @@
/**
* List of {@link Annotation} instances.
*/
-public final class Annotations extends MutabilityControl
- implements Comparable<Annotations> {
- /** {@code non-null;} immutable empty instance */
- public static final Annotations EMPTY = new Annotations();
+public final class Annotations extends MutabilityControl implements Comparable<Annotations> {
+ /** {@code non-null;} immutable empty instance */
+ public static final Annotations EMPTY = new Annotations();
- static {
- EMPTY.setImmutable();
+ static {
+ EMPTY.setImmutable();
+ }
+
+ /** {@code non-null;} map from types to annotations */
+ private final TreeMap<CstType, Annotation> annotations;
+
+ /**
+ * Constructs an immutable instance which is the combination of the
+ * two given instances. The two instances must contain disjoint sets
+ * of types.
+ *
+ * @param a1 {@code non-null;} an instance
+ * @param a2 {@code non-null;} the other instance
+ * @return {@code non-null;} the combination
+ * @throws IllegalArgumentException thrown if there is a duplicate type
+ */
+ public static Annotations combine(Annotations a1, Annotations a2) {
+ Annotations result = new Annotations();
+
+ result.addAll(a1);
+ result.addAll(a2);
+ result.setImmutable();
+
+ return result;
+ }
+
+ /**
+ * Constructs an immutable instance which is the combination of the
+ * given instance with the given additional annotation. The latter's
+ * type must not already appear in the former.
+ *
+ * @param annotations {@code non-null;} the instance to augment
+ * @param annotation {@code non-null;} the additional annotation
+ * @return {@code non-null;} the combination
+ * @throws IllegalArgumentException thrown if there is a duplicate type
+ */
+ public static Annotations combine(Annotations annotations, Annotation annotation) {
+ Annotations result = new Annotations();
+
+ result.addAll(annotations);
+ result.add(annotation);
+ result.setImmutable();
+
+ return result;
+ }
+
+ /**
+ * Constructs an empty instance.
+ */
+ public Annotations() {
+ annotations = new TreeMap<CstType, Annotation>();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return annotations.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Annotations)) {
+ return false;
}
- /** {@code non-null;} map from types to annotations */
- private final TreeMap<CstType, Annotation> annotations;
+ Annotations otherAnnotations = (Annotations) other;
- /**
- * Constructs an immutable instance which is the combination of the
- * two given instances. The two instances must contain disjoint sets
- * of types.
- *
- * @param a1 {@code non-null;} an instance
- * @param a2 {@code non-null;} the other instance
- * @return {@code non-null;} the combination
- * @throws IllegalArgumentException thrown if there is a duplicate type
- */
- public static Annotations combine(Annotations a1, Annotations a2) {
- Annotations result = new Annotations();
+ return annotations.equals(otherAnnotations.annotations);
+ }
- result.addAll(a1);
- result.addAll(a2);
- result.setImmutable();
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Annotations other) {
+ Iterator<Annotation> thisIter = annotations.values().iterator();
+ Iterator<Annotation> otherIter = other.annotations.values().iterator();
+ while (thisIter.hasNext() && otherIter.hasNext()) {
+ Annotation thisOne = thisIter.next();
+ Annotation otherOne = otherIter.next();
+
+ int result = thisOne.compareTo(otherOne);
+ if (result != 0) {
return result;
+ }
}
- /**
- * Constructs an immutable instance which is the combination of the
- * given instance with the given additional annotation. The latter's
- * type must not already appear in the former.
- *
- * @param annotations {@code non-null;} the instance to augment
- * @param annotation {@code non-null;} the additional annotation
- * @return {@code non-null;} the combination
- * @throws IllegalArgumentException thrown if there is a duplicate type
- */
- public static Annotations combine(Annotations annotations,
- Annotation annotation) {
- Annotations result = new Annotations();
-
- result.addAll(annotations);
- result.add(annotation);
- result.setImmutable();
-
- return result;
+ if (thisIter.hasNext()) {
+ return 1;
+ } else if (otherIter.hasNext()) {
+ return -1;
}
- /**
- * Constructs an empty instance.
- */
- public Annotations() {
- annotations = new TreeMap<CstType, Annotation>();
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+
+ sb.append("annotations{");
+
+ for (Annotation a : annotations.values()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(a.toHuman());
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return annotations.hashCode();
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Gets the number of elements in this instance.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int size() {
+ return annotations.size();
+ }
+
+ /**
+ * Adds an element to this instance. There must not already be an
+ * element of the same type.
+ *
+ * @param annotation {@code non-null;} the element to add
+ * @throws IllegalArgumentException thrown if there is a duplicate type
+ */
+ public void add(Annotation annotation) {
+ throwIfImmutable();
+
+ if (annotation == null) {
+ throw new NullPointerException("annotation == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (! (other instanceof Annotations)) {
- return false;
- }
+ CstType type = annotation.getType();
- Annotations otherAnnotations = (Annotations) other;
-
- return annotations.equals(otherAnnotations.annotations);
+ if (annotations.containsKey(type)) {
+ throw new IllegalArgumentException("duplicate type: " + type.toHuman());
}
- /** {@inheritDoc} */
- public int compareTo(Annotations other) {
- Iterator<Annotation> thisIter = annotations.values().iterator();
- Iterator<Annotation> otherIter = other.annotations.values().iterator();
+ annotations.put(type, annotation);
+ }
- while (thisIter.hasNext() && otherIter.hasNext()) {
- Annotation thisOne = thisIter.next();
- Annotation otherOne = otherIter.next();
+ /**
+ * Adds all of the elements of the given instance to this one. The
+ * instances must not have any duplicate types.
+ *
+ * @param toAdd {@code non-null;} the annotations to add
+ * @throws IllegalArgumentException thrown if there is a duplicate type
+ */
+ public void addAll(Annotations toAdd) {
+ throwIfImmutable();
- int result = thisOne.compareTo(otherOne);
- if (result != 0) {
- return result;
- }
- }
-
- if (thisIter.hasNext()) {
- return 1;
- } else if (otherIter.hasNext()) {
- return -1;
- }
-
- return 0;
+ if (toAdd == null) {
+ throw new NullPointerException("toAdd == null");
}
- /** {@inheritDoc} */
- public String toString() {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
-
- sb.append("annotations{");
-
- for (Annotation a : annotations.values()) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(a.toHuman());
- }
-
- sb.append("}");
- return sb.toString();
+ for (Annotation a : toAdd.annotations.values()) {
+ add(a);
}
+ }
- /**
- * Gets the number of elements in this instance.
- *
- * @return {@code >= 0;} the size
- */
- public int size() {
- return annotations.size();
- }
-
- /**
- * Adds an element to this instance. There must not already be an
- * element of the same type.
- *
- * @param annotation {@code non-null;} the element to add
- * @throws IllegalArgumentException thrown if there is a duplicate type
- */
- public void add(Annotation annotation) {
- throwIfImmutable();
-
- if (annotation == null) {
- throw new NullPointerException("annotation == null");
- }
-
- CstType type = annotation.getType();
-
- if (annotations.containsKey(type)) {
- throw new IllegalArgumentException("duplicate type: " +
- type.toHuman());
- }
-
- annotations.put(type, annotation);
- }
-
- /**
- * Adds all of the elements of the given instance to this one. The
- * instances must not have any duplicate types.
- *
- * @param toAdd {@code non-null;} the annotations to add
- * @throws IllegalArgumentException thrown if there is a duplicate type
- */
- public void addAll(Annotations toAdd) {
- throwIfImmutable();
-
- if (toAdd == null) {
- throw new NullPointerException("toAdd == null");
- }
-
- for (Annotation a : toAdd.annotations.values()) {
- add(a);
- }
- }
-
- /**
- * Gets the set of annotations contained in this instance. The
- * result is always unmodifiable.
- *
- * @return {@code non-null;} the set of annotations
- */
- public Collection<Annotation> getAnnotations() {
- return Collections.unmodifiableCollection(annotations.values());
- }
+ /**
+ * Gets the set of annotations contained in this instance. The
+ * result is always unmodifiable.
+ *
+ * @return {@code non-null;} the set of annotations
+ */
+ public Collection<Annotation> getAnnotations() {
+ return Collections.unmodifiableCollection(annotations.values());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/annotation/AnnotationsList.java b/dx/src/com/android/jack/dx/rop/annotation/AnnotationsList.java
index a013673..dc0522f 100644
--- a/dx/src/com/android/jack/dx/rop/annotation/AnnotationsList.java
+++ b/dx/src/com/android/jack/dx/rop/annotation/AnnotationsList.java
@@ -21,71 +21,69 @@
/**
* List of {@link Annotations} instances.
*/
-public final class AnnotationsList
- extends FixedSizeList {
- /** {@code non-null;} immutable empty instance */
- public static final AnnotationsList EMPTY = new AnnotationsList(0);
+public final class AnnotationsList extends FixedSizeList {
+ /** {@code non-null;} immutable empty instance */
+ public static final AnnotationsList EMPTY = new AnnotationsList(0);
- /**
- * Constructs an immutable instance which is the combination of
- * the two given instances. The two instances must each have the
- * same number of elements, and each pair of elements must contain
- * disjoint sets of types.
- *
- * @param list1 {@code non-null;} an instance
- * @param list2 {@code non-null;} the other instance
- * @return {@code non-null;} the combination
- */
- public static AnnotationsList combine(AnnotationsList list1,
- AnnotationsList list2) {
- int size = list1.size();
+ /**
+ * Constructs an immutable instance which is the combination of
+ * the two given instances. The two instances must each have the
+ * same number of elements, and each pair of elements must contain
+ * disjoint sets of types.
+ *
+ * @param list1 {@code non-null;} an instance
+ * @param list2 {@code non-null;} the other instance
+ * @return {@code non-null;} the combination
+ */
+ public static AnnotationsList combine(AnnotationsList list1, AnnotationsList list2) {
+ int size = list1.size();
- if (size != list2.size()) {
- throw new IllegalArgumentException("list1.size() != list2.size()");
- }
-
- AnnotationsList result = new AnnotationsList(size);
-
- for (int i = 0; i < size; i++) {
- Annotations a1 = list1.get(i);
- Annotations a2 = list2.get(i);
- result.set(i, Annotations.combine(a1, a2));
- }
-
- result.setImmutable();
- return result;
+ if (size != list2.size()) {
+ throw new IllegalArgumentException("list1.size() != list2.size()");
}
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public AnnotationsList(int size) {
- super(size);
+ AnnotationsList result = new AnnotationsList(size);
+
+ for (int i = 0; i < size; i++) {
+ Annotations a1 = list1.get(i);
+ Annotations a2 = list2.get(i);
+ result.set(i, Annotations.combine(a1, a2));
}
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public Annotations get(int n) {
- return (Annotations) get0(n);
- }
+ result.setImmutable();
+ return result;
+ }
- /**
- * Sets the element at the given index. The given element must be
- * immutable.
- *
- * @param n {@code >= 0, < size();} which index
- * @param a {@code null-ok;} the element to set at {@code n}
- */
- public void set(int n, Annotations a) {
- a.throwIfMutable();
- set0(n, a);
- }
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public AnnotationsList(int size) {
+ super(size);
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Annotations get(int n) {
+ return (Annotations) get0(n);
+ }
+
+ /**
+ * Sets the element at the given index. The given element must be
+ * immutable.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param a {@code null-ok;} the element to set at {@code n}
+ */
+ public void set(int n, Annotations a) {
+ a.throwIfMutable();
+ set0(n, a);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/annotation/NameValuePair.java b/dx/src/com/android/jack/dx/rop/annotation/NameValuePair.java
index 7661fbf..018e299 100644
--- a/dx/src/com/android/jack/dx/rop/annotation/NameValuePair.java
+++ b/dx/src/com/android/jack/dx/rop/annotation/NameValuePair.java
@@ -23,84 +23,87 @@
* A (name, value) pair. These are used as the contents of an annotation.
*/
public final class NameValuePair implements Comparable<NameValuePair> {
- /** {@code non-null;} the name */
- private final CstString name;
+ /** {@code non-null;} the name */
+ private final CstString name;
- /** {@code non-null;} the value */
- private final Constant value;
+ /** {@code non-null;} the value */
+ private final Constant value;
- /**
- * Construct an instance.
- *
- * @param name {@code non-null;} the name
- * @param value {@code non-null;} the value
- */
- public NameValuePair(CstString name, Constant value) {
- if (name == null) {
- throw new NullPointerException("name == null");
- }
-
- if (value == null) {
- throw new NullPointerException("value == null");
- }
-
- this.name = name;
- this.value = value;
+ /**
+ * Construct an instance.
+ *
+ * @param name {@code non-null;} the name
+ * @param value {@code non-null;} the value
+ */
+ public NameValuePair(CstString name, Constant value) {
+ if (name == null) {
+ throw new NullPointerException("name == null");
}
- /** {@inheritDoc} */
- public String toString() {
- return name.toHuman() + ":" + value;
+ if (value == null) {
+ throw new NullPointerException("value == null");
}
- /** {@inheritDoc} */
- public int hashCode() {
- return name.hashCode() * 31 + value.hashCode();
+ this.name = name;
+ this.value = value;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return name.toHuman() + ":" + value;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return name.hashCode() * 31 + value.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof NameValuePair)) {
+ return false;
}
- /** {@inheritDoc} */
- public boolean equals(Object other) {
- if (! (other instanceof NameValuePair)) {
- return false;
- }
+ NameValuePair otherPair = (NameValuePair) other;
- NameValuePair otherPair = (NameValuePair) other;
+ return name.equals(otherPair.name) && value.equals(otherPair.value);
+ }
- return name.equals(otherPair.name)
- && value.equals(otherPair.value);
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Instances of this class compare in name-major and value-minor
+ * order.</p>
+ */
+ @Override
+ public int compareTo(NameValuePair other) {
+ int result = name.compareTo(other.name);
+
+ if (result != 0) {
+ return result;
}
- /**
- * {@inheritDoc}
- *
- * <p>Instances of this class compare in name-major and value-minor
- * order.</p>
- */
- public int compareTo(NameValuePair other) {
- int result = name.compareTo(other.name);
+ return value.compareTo(other.value);
+ }
- if (result != 0) {
- return result;
- }
+ /**
+ * Gets the name.
+ *
+ * @return {@code non-null;} the name
+ */
+ public CstString getName() {
+ return name;
+ }
- return value.compareTo(other.value);
- }
-
- /**
- * Gets the name.
- *
- * @return {@code non-null;} the name
- */
- public CstString getName() {
- return name;
- }
-
- /**
- * Gets the value.
- *
- * @return {@code non-null;} the value
- */
- public Constant getValue() {
- return value;
- }
+ /**
+ * Gets the value.
+ *
+ * @return {@code non-null;} the value
+ */
+ public Constant getValue() {
+ return value;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/AccessFlags.java b/dx/src/com/android/jack/dx/rop/code/AccessFlags.java
index 95385bd..7dc3a80 100644
--- a/dx/src/com/android/jack/dx/rop/code/AccessFlags.java
+++ b/dx/src/com/android/jack/dx/rop/code/AccessFlags.java
@@ -28,379 +28,373 @@
* is only used in a very limited way.
*/
public final class AccessFlags {
- /** public member / class */
- public static final int ACC_PUBLIC = 0x0001;
+ /** public member / class */
+ public static final int ACC_PUBLIC = 0x0001;
- /** private member */
- public static final int ACC_PRIVATE = 0x0002;
+ /** private member */
+ public static final int ACC_PRIVATE = 0x0002;
- /** protected member */
- public static final int ACC_PROTECTED = 0x0004;
+ /** protected member */
+ public static final int ACC_PROTECTED = 0x0004;
- /** static member */
- public static final int ACC_STATIC = 0x0008;
+ /** static member */
+ public static final int ACC_STATIC = 0x0008;
- /** final member / class */
- public static final int ACC_FINAL = 0x0010;
+ /** final member / class */
+ public static final int ACC_FINAL = 0x0010;
- /**
- * synchronized method; only valid in dex files for {@code native}
- * methods
- */
- public static final int ACC_SYNCHRONIZED = 0x0020;
+ /**
+ * synchronized method; only valid in dex files for {@code native}
+ * methods
+ */
+ public static final int ACC_SYNCHRONIZED = 0x0020;
- /**
- * class with new-style {@code invokespecial} for superclass
- * method access
- */
- public static final int ACC_SUPER = 0x0020;
+ /**
+ * class with new-style {@code invokespecial} for superclass
+ * method access
+ */
+ public static final int ACC_SUPER = 0x0020;
- /** volatile field */
- public static final int ACC_VOLATILE = 0x0040;
+ /** volatile field */
+ public static final int ACC_VOLATILE = 0x0040;
- /** bridge method (generated) */
- public static final int ACC_BRIDGE = 0x0040;
+ /** bridge method (generated) */
+ public static final int ACC_BRIDGE = 0x0040;
- /** transient field */
- public static final int ACC_TRANSIENT = 0x0080;
+ /** transient field */
+ public static final int ACC_TRANSIENT = 0x0080;
- /** varargs method */
- public static final int ACC_VARARGS = 0x0080;
+ /** varargs method */
+ public static final int ACC_VARARGS = 0x0080;
- /** native method */
- public static final int ACC_NATIVE = 0x0100;
+ /** native method */
+ public static final int ACC_NATIVE = 0x0100;
- /** "class" is in fact an public static final interface */
- public static final int ACC_INTERFACE = 0x0200;
+ /** "class" is in fact an public static final interface */
+ public static final int ACC_INTERFACE = 0x0200;
- /** abstract method / class */
- public static final int ACC_ABSTRACT = 0x0400;
+ /** abstract method / class */
+ public static final int ACC_ABSTRACT = 0x0400;
- /**
- * method with strict floating point ({@code strictfp})
- * behavior
- */
- public static final int ACC_STRICT = 0x0800;
+ /**
+ * method with strict floating point ({@code strictfp})
+ * behavior
+ */
+ public static final int ACC_STRICT = 0x0800;
- /** synthetic member */
- public static final int ACC_SYNTHETIC = 0x1000;
+ /** synthetic member */
+ public static final int ACC_SYNTHETIC = 0x1000;
- /** class is an annotation type */
- public static final int ACC_ANNOTATION = 0x2000;
+ /** class is an annotation type */
+ public static final int ACC_ANNOTATION = 0x2000;
- /**
- * class is an enumerated type; field is an element of an enumerated
- * type
- */
- public static final int ACC_ENUM = 0x4000;
+ /**
+ * class is an enumerated type; field is an element of an enumerated
+ * type
+ */
+ public static final int ACC_ENUM = 0x4000;
- /** method is a constructor */
- public static final int ACC_CONSTRUCTOR = 0x10000;
+ /** method is a constructor */
+ public static final int ACC_CONSTRUCTOR = 0x10000;
- /**
- * method was declared {@code synchronized}; has no effect on
- * execution (other than inspecting this flag, per se)
- */
- public static final int ACC_DECLARED_SYNCHRONIZED = 0x20000;
+ /**
+ * method was declared {@code synchronized}; has no effect on
+ * execution (other than inspecting this flag, per se)
+ */
+ public static final int ACC_DECLARED_SYNCHRONIZED = 0x20000;
- /** flags defined on classes */
- public static final int CLASS_FLAGS =
- ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT |
- ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
+ /** flags defined on classes */
+ public static final int CLASS_FLAGS = ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE
+ | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
- /** flags defined on inner classes */
- public static final int INNER_CLASS_FLAGS =
- ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
- ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION |
- ACC_ENUM;
+ /** flags defined on inner classes */
+ public static final int INNER_CLASS_FLAGS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC
+ | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
- /** flags defined on fields */
- public static final int FIELD_FLAGS =
- ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
- ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM;
+ /** flags defined on fields */
+ public static final int FIELD_FLAGS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC
+ | ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM;
- /** flags defined on methods */
- public static final int METHOD_FLAGS =
- ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
- ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
- ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR |
- ACC_DECLARED_SYNCHRONIZED;
+ /** flags defined on methods */
+ public static final int METHOD_FLAGS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC
+ | ACC_FINAL | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | ACC_ABSTRACT
+ | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR | ACC_DECLARED_SYNCHRONIZED;
- /** indicates conversion of class flags */
- private static final int CONV_CLASS = 1;
+ /** indicates conversion of class flags */
+ private static final int CONV_CLASS = 1;
- /** indicates conversion of field flags */
- private static final int CONV_FIELD = 2;
+ /** indicates conversion of field flags */
+ private static final int CONV_FIELD = 2;
- /** indicates conversion of method flags */
- private static final int CONV_METHOD = 3;
+ /** indicates conversion of method flags */
+ private static final int CONV_METHOD = 3;
- /**
- * This class is uninstantiable.
- */
- private AccessFlags() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private AccessFlags() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Returns a human-oriented string representing the given access flags,
+ * as defined on classes (not fields or methods).
+ *
+ * @param flags the flags
+ * @return {@code non-null;} human-oriented string
+ */
+ public static String classString(int flags) {
+ return humanHelper(flags, CLASS_FLAGS, CONV_CLASS);
+ }
+
+ /**
+ * Returns a human-oriented string representing the given access flags,
+ * as defined on inner classes.
+ *
+ * @param flags the flags
+ * @return {@code non-null;} human-oriented string
+ */
+ public static String innerClassString(int flags) {
+ return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS);
+ }
+
+ /**
+ * Returns a human-oriented string representing the given access flags,
+ * as defined on fields (not classes or methods).
+ *
+ * @param flags the flags
+ * @return {@code non-null;} human-oriented string
+ */
+ public static String fieldString(int flags) {
+ return humanHelper(flags, FIELD_FLAGS, CONV_FIELD);
+ }
+
+ /**
+ * Returns a human-oriented string representing the given access flags,
+ * as defined on methods (not classes or fields).
+ *
+ * @param flags the flags
+ * @return {@code non-null;} human-oriented string
+ */
+ public static String methodString(int flags) {
+ return humanHelper(flags, METHOD_FLAGS, CONV_METHOD);
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_PUBLIC} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_PUBLIC} flag
+ */
+ public static boolean isPublic(int flags) {
+ return (flags & ACC_PUBLIC) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_PROTECTED} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_PROTECTED} flag
+ */
+ public static boolean isProtected(int flags) {
+ return (flags & ACC_PROTECTED) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_PRIVATE} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_PRIVATE} flag
+ */
+ public static boolean isPrivate(int flags) {
+ return (flags & ACC_PRIVATE) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_STATIC} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_STATIC} flag
+ */
+ public static boolean isStatic(int flags) {
+ return (flags & ACC_STATIC) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_CONSTRUCTOR} is on in
+ * the given flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_CONSTRUCTOR} flag
+ */
+ public static boolean isConstructor(int flags) {
+ return (flags & ACC_CONSTRUCTOR) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_INTERFACE} is on in
+ * the given flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_INTERFACE} flag
+ */
+ public static boolean isInterface(int flags) {
+ return (flags & ACC_INTERFACE) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_SYNCHRONIZED} is on in
+ * the given flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_SYNCHRONIZED} flag
+ */
+ public static boolean isSynchronized(int flags) {
+ return (flags & ACC_SYNCHRONIZED) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_ABSTRACT} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_ABSTRACT} flag
+ */
+ public static boolean isAbstract(int flags) {
+ return (flags & ACC_ABSTRACT) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_NATIVE} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_NATIVE} flag
+ */
+ public static boolean isNative(int flags) {
+ return (flags & ACC_NATIVE) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_ANNOTATION} is on in the given
+ * flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_ANNOTATION} flag
+ */
+ public static boolean isAnnotation(int flags) {
+ return (flags & ACC_ANNOTATION) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_DECLARED_SYNCHRONIZED} is
+ * on in the given flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
+ */
+ public static boolean isDeclaredSynchronized(int flags) {
+ return (flags & ACC_DECLARED_SYNCHRONIZED) != 0;
+ }
+
+ /**
+ * Returns whether the flag {@code ACC_ENUM} is on in the given flags.
+ *
+ * @param flags the flags to check
+ * @return the value of the {@code ACC_ENUM} flag
+ */
+ public static boolean isEnum(int flags) {
+ return (flags & ACC_ENUM) != 0;
+ }
+
+ /**
+ * Helper to return a human-oriented string representing the given
+ * access flags.
+ *
+ * @param flags the defined flags
+ * @param mask mask for the "defined" bits
+ * @param what what the flags represent (one of {@code CONV_*})
+ * @return {@code non-null;} human-oriented string
+ */
+ private static String humanHelper(int flags, int mask, int what) {
+ StringBuffer sb = new StringBuffer(80);
+ int extra = flags & ~mask;
+
+ flags &= mask;
+
+ if ((flags & ACC_PUBLIC) != 0) {
+ sb.append("|public");
+ }
+ if ((flags & ACC_PRIVATE) != 0) {
+ sb.append("|private");
+ }
+ if ((flags & ACC_PROTECTED) != 0) {
+ sb.append("|protected");
+ }
+ if ((flags & ACC_STATIC) != 0) {
+ sb.append("|static");
+ }
+ if ((flags & ACC_FINAL) != 0) {
+ sb.append("|final");
+ }
+ if ((flags & ACC_SYNCHRONIZED) != 0) {
+ if (what == CONV_CLASS) {
+ sb.append("|super");
+ } else {
+ sb.append("|synchronized");
+ }
+ }
+ if ((flags & ACC_VOLATILE) != 0) {
+ if (what == CONV_METHOD) {
+ sb.append("|bridge");
+ } else {
+ sb.append("|volatile");
+ }
+ }
+ if ((flags & ACC_TRANSIENT) != 0) {
+ if (what == CONV_METHOD) {
+ sb.append("|varargs");
+ } else {
+ sb.append("|transient");
+ }
+ }
+ if ((flags & ACC_NATIVE) != 0) {
+ sb.append("|native");
+ }
+ if ((flags & ACC_INTERFACE) != 0) {
+ sb.append("|interface");
+ }
+ if ((flags & ACC_ABSTRACT) != 0) {
+ sb.append("|abstract");
+ }
+ if ((flags & ACC_STRICT) != 0) {
+ sb.append("|strictfp");
+ }
+ if ((flags & ACC_SYNTHETIC) != 0) {
+ sb.append("|synthetic");
+ }
+ if ((flags & ACC_ANNOTATION) != 0) {
+ sb.append("|annotation");
+ }
+ if ((flags & ACC_ENUM) != 0) {
+ sb.append("|enum");
+ }
+ if ((flags & ACC_CONSTRUCTOR) != 0) {
+ sb.append("|constructor");
+ }
+ if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+ sb.append("|declared_synchronized");
}
- /**
- * Returns a human-oriented string representing the given access flags,
- * as defined on classes (not fields or methods).
- *
- * @param flags the flags
- * @return {@code non-null;} human-oriented string
- */
- public static String classString(int flags) {
- return humanHelper(flags, CLASS_FLAGS, CONV_CLASS);
+ if ((extra != 0) || (sb.length() == 0)) {
+ sb.append('|');
+ sb.append(Hex.u2(extra));
}
- /**
- * Returns a human-oriented string representing the given access flags,
- * as defined on inner classes.
- *
- * @param flags the flags
- * @return {@code non-null;} human-oriented string
- */
- public static String innerClassString(int flags) {
- return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS);
- }
-
- /**
- * Returns a human-oriented string representing the given access flags,
- * as defined on fields (not classes or methods).
- *
- * @param flags the flags
- * @return {@code non-null;} human-oriented string
- */
- public static String fieldString(int flags) {
- return humanHelper(flags, FIELD_FLAGS, CONV_FIELD);
- }
-
- /**
- * Returns a human-oriented string representing the given access flags,
- * as defined on methods (not classes or fields).
- *
- * @param flags the flags
- * @return {@code non-null;} human-oriented string
- */
- public static String methodString(int flags) {
- return humanHelper(flags, METHOD_FLAGS, CONV_METHOD);
- }
-
- /**
- * Returns whether the flag {@code ACC_PUBLIC} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_PUBLIC} flag
- */
- public static boolean isPublic(int flags) {
- return (flags & ACC_PUBLIC) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_PROTECTED} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_PROTECTED} flag
- */
- public static boolean isProtected(int flags) {
- return (flags & ACC_PROTECTED) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_PRIVATE} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_PRIVATE} flag
- */
- public static boolean isPrivate(int flags) {
- return (flags & ACC_PRIVATE) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_STATIC} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_STATIC} flag
- */
- public static boolean isStatic(int flags) {
- return (flags & ACC_STATIC) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_CONSTRUCTOR} is on in
- * the given flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_CONSTRUCTOR} flag
- */
- public static boolean isConstructor(int flags) {
- return (flags & ACC_CONSTRUCTOR) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_INTERFACE} is on in
- * the given flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_INTERFACE} flag
- */
- public static boolean isInterface(int flags) {
- return (flags & ACC_INTERFACE) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_SYNCHRONIZED} is on in
- * the given flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_SYNCHRONIZED} flag
- */
- public static boolean isSynchronized(int flags) {
- return (flags & ACC_SYNCHRONIZED) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_ABSTRACT} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_ABSTRACT} flag
- */
- public static boolean isAbstract(int flags) {
- return (flags & ACC_ABSTRACT) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_NATIVE} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_NATIVE} flag
- */
- public static boolean isNative(int flags) {
- return (flags & ACC_NATIVE) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_ANNOTATION} is on in the given
- * flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_ANNOTATION} flag
- */
- public static boolean isAnnotation(int flags) {
- return (flags & ACC_ANNOTATION) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_DECLARED_SYNCHRONIZED} is
- * on in the given flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
- */
- public static boolean isDeclaredSynchronized(int flags) {
- return (flags & ACC_DECLARED_SYNCHRONIZED) != 0;
- }
-
- /**
- * Returns whether the flag {@code ACC_ENUM} is on in the given flags.
- *
- * @param flags the flags to check
- * @return the value of the {@code ACC_ENUM} flag
- */
- public static boolean isEnum(int flags) {
- return (flags & ACC_ENUM) != 0;
- }
-
- /**
- * Helper to return a human-oriented string representing the given
- * access flags.
- *
- * @param flags the defined flags
- * @param mask mask for the "defined" bits
- * @param what what the flags represent (one of {@code CONV_*})
- * @return {@code non-null;} human-oriented string
- */
- private static String humanHelper(int flags, int mask, int what) {
- StringBuffer sb = new StringBuffer(80);
- int extra = flags & ~mask;
-
- flags &= mask;
-
- if ((flags & ACC_PUBLIC) != 0) {
- sb.append("|public");
- }
- if ((flags & ACC_PRIVATE) != 0) {
- sb.append("|private");
- }
- if ((flags & ACC_PROTECTED) != 0) {
- sb.append("|protected");
- }
- if ((flags & ACC_STATIC) != 0) {
- sb.append("|static");
- }
- if ((flags & ACC_FINAL) != 0) {
- sb.append("|final");
- }
- if ((flags & ACC_SYNCHRONIZED) != 0) {
- if (what == CONV_CLASS) {
- sb.append("|super");
- } else {
- sb.append("|synchronized");
- }
- }
- if ((flags & ACC_VOLATILE) != 0) {
- if (what == CONV_METHOD) {
- sb.append("|bridge");
- } else {
- sb.append("|volatile");
- }
- }
- if ((flags & ACC_TRANSIENT) != 0) {
- if (what == CONV_METHOD) {
- sb.append("|varargs");
- } else {
- sb.append("|transient");
- }
- }
- if ((flags & ACC_NATIVE) != 0) {
- sb.append("|native");
- }
- if ((flags & ACC_INTERFACE) != 0) {
- sb.append("|interface");
- }
- if ((flags & ACC_ABSTRACT) != 0) {
- sb.append("|abstract");
- }
- if ((flags & ACC_STRICT) != 0) {
- sb.append("|strictfp");
- }
- if ((flags & ACC_SYNTHETIC) != 0) {
- sb.append("|synthetic");
- }
- if ((flags & ACC_ANNOTATION) != 0) {
- sb.append("|annotation");
- }
- if ((flags & ACC_ENUM) != 0) {
- sb.append("|enum");
- }
- if ((flags & ACC_CONSTRUCTOR) != 0) {
- sb.append("|constructor");
- }
- if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
- sb.append("|declared_synchronized");
- }
-
- if ((extra != 0) || (sb.length() == 0)) {
- sb.append('|');
- sb.append(Hex.u2(extra));
- }
-
- return sb.substring(1);
- }
+ return sb.substring(1);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/BasicBlock.java b/dx/src/com/android/jack/dx/rop/code/BasicBlock.java
index c87fc52..6fa8306 100644
--- a/dx/src/com/android/jack/dx/rop/code/BasicBlock.java
+++ b/dx/src/com/android/jack/dx/rop/code/BasicBlock.java
@@ -25,257 +25,254 @@
* Basic block of register-based instructions.
*/
public final class BasicBlock implements LabeledItem {
- /** {@code >= 0;} target label for this block */
- private final int label;
+ /** {@code >= 0;} target label for this block */
+ private final int label;
- /** {@code non-null;} list of instructions in this block */
- private final InsnList insns;
+ /** {@code non-null;} list of instructions in this block */
+ private final InsnList insns;
- /**
- * {@code non-null;} full list of successors that this block may
- * branch to
- */
- private final IntList successors;
+ /**
+ * {@code non-null;} full list of successors that this block may
+ * branch to
+ */
+ private final IntList successors;
- /**
- * {@code >= -1;} the primary / standard-flow / "default" successor, or
- * {@code -1} if this block has no successors (that is, it
- * exits the function/method)
- */
- private final int primarySuccessor;
+ /**
+ * {@code >= -1;} the primary / standard-flow / "default" successor, or
+ * {@code -1} if this block has no successors (that is, it
+ * exits the function/method)
+ */
+ private final int primarySuccessor;
- /**
- * Constructs an instance. The predecessor set is set to {@code null}.
- *
- * @param label {@code >= 0;} target label for this block
- * @param insns {@code non-null;} list of instructions in this block
- * @param successors {@code non-null;} full list of successors that this
- * block may branch to
- * @param primarySuccessor {@code >= -1;} the primary / standard-flow /
- * "default" successor, or {@code -1} if this block has no
- * successors (that is, it exits the function/method or is an
- * unconditional throw)
- */
- public BasicBlock(int label, InsnList insns, IntList successors,
- int primarySuccessor) {
- if (label < 0) {
- throw new IllegalArgumentException("label < 0");
- }
-
- try {
- insns.throwIfMutable();
- } catch (NullPointerException ex) {
- // Elucidate exception.
- throw new NullPointerException("insns == null");
- }
-
- int sz = insns.size();
-
- if (sz == 0) {
- throw new IllegalArgumentException("insns.size() == 0");
- }
-
- for (int i = sz - 2; i >= 0; i--) {
- Rop one = insns.get(i).getOpcode();
- if (one.getBranchingness() != Rop.BRANCH_NONE) {
- throw new IllegalArgumentException("insns[" + i + "] is a " +
- "branch or can throw");
- }
- }
-
- Insn lastInsn = insns.get(sz - 1);
- if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
- throw new IllegalArgumentException("insns does not end with " +
- "a branch or throwing " +
- "instruction");
- }
-
- try {
- successors.throwIfMutable();
- } catch (NullPointerException ex) {
- // Elucidate exception.
- throw new NullPointerException("successors == null");
- }
-
- if (primarySuccessor < -1) {
- throw new IllegalArgumentException("primarySuccessor < -1");
- }
-
- if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
- throw new IllegalArgumentException(
- "primarySuccessor " + primarySuccessor + " not in successors " + successors);
- }
-
- this.label = label;
- this.insns = insns;
- this.successors = successors;
- this.primarySuccessor = primarySuccessor;
+ /**
+ * Constructs an instance. The predecessor set is set to {@code null}.
+ *
+ * @param label {@code >= 0;} target label for this block
+ * @param insns {@code non-null;} list of instructions in this block
+ * @param successors {@code non-null;} full list of successors that this
+ * block may branch to
+ * @param primarySuccessor {@code >= -1;} the primary / standard-flow /
+ * "default" successor, or {@code -1} if this block has no
+ * successors (that is, it exits the function/method or is an
+ * unconditional throw)
+ */
+ public BasicBlock(int label, InsnList insns, IntList successors, int primarySuccessor) {
+ if (label < 0) {
+ throw new IllegalArgumentException("label < 0");
}
+ try {
+ insns.throwIfMutable();
+ } catch (NullPointerException ex) {
+ // Elucidate exception.
+ throw new NullPointerException("insns == null");
+ }
+
+ int sz = insns.size();
+
+ if (sz == 0) {
+ throw new IllegalArgumentException("insns.size() == 0");
+ }
+
+ for (int i = sz - 2; i >= 0; i--) {
+ Rop one = insns.get(i).getOpcode();
+ if (one.getBranchingness() != Rop.BRANCH_NONE) {
+ throw new IllegalArgumentException("insns[" + i + "] is a " + "branch or can throw");
+ }
+ }
+
+ Insn lastInsn = insns.get(sz - 1);
+ if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
+ throw new IllegalArgumentException(
+ "insns does not end with " + "a branch or throwing " + "instruction");
+ }
+
+ try {
+ successors.throwIfMutable();
+ } catch (NullPointerException ex) {
+ // Elucidate exception.
+ throw new NullPointerException("successors == null");
+ }
+
+ if (primarySuccessor < -1) {
+ throw new IllegalArgumentException("primarySuccessor < -1");
+ }
+
+ if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
+ throw new IllegalArgumentException(
+ "primarySuccessor " + primarySuccessor + " not in successors " + successors);
+ }
+
+ this.label = label;
+ this.insns = insns;
+ this.successors = successors;
+ this.primarySuccessor = primarySuccessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Instances of this class compare by identity. That is,
+ * {@code x.equals(y)} is only true if {@code x == y}.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return (this == other);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Return the identity hashcode of this instance. This is proper,
+ * since instances of this class compare by identity (see {@link #equals}).
+ */
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ /**
+ * Gets the target label of this block.
+ *
+ * @return {@code >= 0;} the label
+ */
+ @Override
+ public int getLabel() {
+ return label;
+ }
+
+ /**
+ * Gets the list of instructions inside this block.
+ *
+ * @return {@code non-null;} the instruction list
+ */
+ public InsnList getInsns() {
+ return insns;
+ }
+
+ /**
+ * Gets the list of successors that this block may branch to.
+ *
+ * @return {@code non-null;} the successors list
+ */
+ public IntList getSuccessors() {
+ return successors;
+ }
+
+ /**
+ * Gets the primary successor of this block.
+ *
+ * @return {@code >= -1;} the primary successor, or {@code -1} if this
+ * block has no successors at all
+ */
+ public int getPrimarySuccessor() {
+ return primarySuccessor;
+ }
+
+ /**
+ * Gets the secondary successor of this block. It is only valid to call
+ * this method on blocks that have exactly two successors.
+ *
+ * @return {@code >= 0;} the secondary successor
+ */
+ public int getSecondarySuccessor() {
+ if (successors.size() != 2) {
+ throw new UnsupportedOperationException("block doesn't have exactly two successors");
+ }
+
+ int succ = successors.get(0);
+ if (succ == primarySuccessor) {
+ succ = successors.get(1);
+ }
+
+ return succ;
+ }
+
+ /**
+ * Gets the first instruction of this block. This is just a
+ * convenient shorthand for {@code getInsns().get(0)}.
+ *
+ * @return {@code non-null;} the first instruction
+ */
+ public Insn getFirstInsn() {
+ return insns.get(0);
+ }
+
+ /**
+ * Gets the last instruction of this block. This is just a
+ * convenient shorthand for {@code getInsns().getLast()}.
+ *
+ * @return {@code non-null;} the last instruction
+ */
+ public Insn getLastInsn() {
+ return insns.getLast();
+ }
+
+ /**
+ * Returns whether this block might throw an exception. This is
+ * just a convenient shorthand for {@code getLastInsn().canThrow()}.
+ *
+ * @return {@code true} iff this block might throw an
+ * exception
+ */
+ public boolean canThrow() {
+ return insns.getLast().canThrow();
+ }
+
+ /**
+ * Returns whether this block has any associated exception handlers.
+ * This is just a shorthand for inspecting the last instruction in
+ * the block to see if it could throw, and if so, whether it in fact
+ * has any associated handlers.
+ *
+ * @return {@code true} iff this block has any associated
+ * exception handlers
+ */
+ public boolean hasExceptionHandlers() {
+ Insn lastInsn = insns.getLast();
+ return lastInsn.getCatches().size() != 0;
+ }
+
+ /**
+ * Returns the exception handler types associated with this block,
+ * if any. This is just a shorthand for inspecting the last
+ * instruction in the block to see if it could throw, and if so,
+ * grabbing the catch list out of it. If not, this returns an
+ * empty list (not {@code null}).
+ *
+ * @return {@code non-null;} the exception handler types associated with
+ * this block
+ */
+ public TypeList getExceptionHandlerTypes() {
+ Insn lastInsn = insns.getLast();
+ return lastInsn.getCatches();
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the registers in each instruction are offset by the given
+ * amount.
+ *
+ * @param delta the amount to offset register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public BasicBlock withRegisterOffset(int delta) {
+ return new BasicBlock(label, insns.withRegisterOffset(delta), successors, primarySuccessor);
+ }
+
+ @Override
+ public String toString() {
+ return '{' + Hex.u2(label) + '}';
+ }
+
+ /**
+ * BasicBlock visitor interface
+ */
+ public interface Visitor {
/**
- * {@inheritDoc}
- *
- * Instances of this class compare by identity. That is,
- * {@code x.equals(y)} is only true if {@code x == y}.
+ * Visits a basic block
+ * @param b block visited
*/
- @Override
- public boolean equals(Object other) {
- return (this == other);
- }
-
- /**
- * {@inheritDoc}
- *
- * Return the identity hashcode of this instance. This is proper,
- * since instances of this class compare by identity (see {@link #equals}).
- */
- @Override
- public int hashCode() {
- return System.identityHashCode(this);
- }
-
- /**
- * Gets the target label of this block.
- *
- * @return {@code >= 0;} the label
- */
- public int getLabel() {
- return label;
- }
-
- /**
- * Gets the list of instructions inside this block.
- *
- * @return {@code non-null;} the instruction list
- */
- public InsnList getInsns() {
- return insns;
- }
-
- /**
- * Gets the list of successors that this block may branch to.
- *
- * @return {@code non-null;} the successors list
- */
- public IntList getSuccessors() {
- return successors;
- }
-
- /**
- * Gets the primary successor of this block.
- *
- * @return {@code >= -1;} the primary successor, or {@code -1} if this
- * block has no successors at all
- */
- public int getPrimarySuccessor() {
- return primarySuccessor;
- }
-
- /**
- * Gets the secondary successor of this block. It is only valid to call
- * this method on blocks that have exactly two successors.
- *
- * @return {@code >= 0;} the secondary successor
- */
- public int getSecondarySuccessor() {
- if (successors.size() != 2) {
- throw new UnsupportedOperationException(
- "block doesn't have exactly two successors");
- }
-
- int succ = successors.get(0);
- if (succ == primarySuccessor) {
- succ = successors.get(1);
- }
-
- return succ;
- }
-
- /**
- * Gets the first instruction of this block. This is just a
- * convenient shorthand for {@code getInsns().get(0)}.
- *
- * @return {@code non-null;} the first instruction
- */
- public Insn getFirstInsn() {
- return insns.get(0);
- }
-
- /**
- * Gets the last instruction of this block. This is just a
- * convenient shorthand for {@code getInsns().getLast()}.
- *
- * @return {@code non-null;} the last instruction
- */
- public Insn getLastInsn() {
- return insns.getLast();
- }
-
- /**
- * Returns whether this block might throw an exception. This is
- * just a convenient shorthand for {@code getLastInsn().canThrow()}.
- *
- * @return {@code true} iff this block might throw an
- * exception
- */
- public boolean canThrow() {
- return insns.getLast().canThrow();
- }
-
- /**
- * Returns whether this block has any associated exception handlers.
- * This is just a shorthand for inspecting the last instruction in
- * the block to see if it could throw, and if so, whether it in fact
- * has any associated handlers.
- *
- * @return {@code true} iff this block has any associated
- * exception handlers
- */
- public boolean hasExceptionHandlers() {
- Insn lastInsn = insns.getLast();
- return lastInsn.getCatches().size() != 0;
- }
-
- /**
- * Returns the exception handler types associated with this block,
- * if any. This is just a shorthand for inspecting the last
- * instruction in the block to see if it could throw, and if so,
- * grabbing the catch list out of it. If not, this returns an
- * empty list (not {@code null}).
- *
- * @return {@code non-null;} the exception handler types associated with
- * this block
- */
- public TypeList getExceptionHandlerTypes() {
- Insn lastInsn = insns.getLast();
- return lastInsn.getCatches();
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * the registers in each instruction are offset by the given
- * amount.
- *
- * @param delta the amount to offset register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public BasicBlock withRegisterOffset(int delta) {
- return new BasicBlock(label, insns.withRegisterOffset(delta),
- successors, primarySuccessor);
- }
-
- public String toString() {
- return '{' + Hex.u2(label) + '}';
- }
-
- /**
- * BasicBlock visitor interface
- */
- public interface Visitor {
- /**
- * Visits a basic block
- * @param b block visited
- */
- public void visitBlock (BasicBlock b);
- }
+ public void visitBlock(BasicBlock b);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/BasicBlockList.java b/dx/src/com/android/jack/dx/rop/code/BasicBlockList.java
index 3d5ddca..150dbe2 100644
--- a/dx/src/com/android/jack/dx/rop/code/BasicBlockList.java
+++ b/dx/src/com/android/jack/dx/rop/code/BasicBlockList.java
@@ -26,371 +26,374 @@
* List of {@link BasicBlock} instances.
*/
public final class BasicBlockList extends LabeledList {
- /**
- * {@code >= -1;} the count of registers required by this method or
- * {@code -1} if not yet calculated
- */
+ /**
+ * {@code >= -1;} the count of registers required by this method or
+ * {@code -1} if not yet calculated
+ */
+ private int regCount;
+
+ /**
+ * Constructs an instance. All indices initially contain {@code null},
+ * and the first-block label is initially {@code -1}.
+ *
+ * @param size the size of the list
+ */
+ public BasicBlockList(int size) {
+ super(size);
+
+ regCount = -1;
+ }
+
+ /**
+ * Constructs a mutable copy for {@code getMutableCopy()}.
+ *
+ * @param old block to copy
+ */
+ private BasicBlockList(BasicBlockList old) {
+ super(old);
+ regCount = old.regCount;
+ }
+
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public BasicBlock get(int n) {
+ return (BasicBlock) get0(n);
+ }
+
+ /**
+ * Sets the basic block at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param bb {@code null-ok;} the element to set at {@code n}
+ */
+ public void set(int n, BasicBlock bb) {
+ super.set(n, bb);
+
+ // Reset regCount, since it will need to be recalculated.
+ regCount = -1;
+ }
+
+ /**
+ * Returns how many registers this method requires. This is simply
+ * the maximum of register-number-plus-category referred to by this
+ * instance's instructions (indirectly through {@link BasicBlock}
+ * instances).
+ *
+ * @return {@code >= 0;} the register count
+ */
+ public int getRegCount() {
+ if (regCount == -1) {
+ RegCountVisitor visitor = new RegCountVisitor();
+ forEachInsn(visitor);
+ regCount = visitor.getRegCount();
+ }
+
+ return regCount;
+ }
+
+ /**
+ * Gets the total instruction count for this instance. This is the
+ * sum of the instruction counts of each block.
+ *
+ * @return {@code >= 0;} the total instruction count
+ */
+ public int getInstructionCount() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = (BasicBlock) getOrNull0(i);
+ if (one != null) {
+ result += one.getInsns().size();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the total instruction count for this instance, ignoring
+ * mark-local instructions which are not actually emitted.
+ *
+ * @return {@code >= 0;} the total instruction count
+ */
+ public int getEffectiveInstructionCount() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = (BasicBlock) getOrNull0(i);
+ if (one != null) {
+ InsnList insns = one.getInsns();
+ int insnsSz = insns.size();
+
+ for (int j = 0; j < insnsSz; j++) {
+ Insn insn = insns.get(j);
+
+ if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) {
+ result++;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the first block in the list with the given label, if any.
+ *
+ * @param label {@code >= 0;} the label to look for
+ * @return {@code non-null;} the so-labelled block
+ * @throws IllegalArgumentException thrown if the label isn't found
+ */
+ public BasicBlock labelToBlock(int label) {
+ int idx = indexOfLabel(label);
+
+ if (idx < 0) {
+ throw new IllegalArgumentException("no such label: " + Hex.u2(label));
+ }
+
+ return get(idx);
+ }
+
+ /**
+ * Visits each instruction of each block in the list, in order.
+ *
+ * @param visitor {@code non-null;} visitor to use
+ */
+ public void forEachInsn(Insn.Visitor visitor) {
+ int sz = size();
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = get(i);
+ InsnList insns = one.getInsns();
+ insns.forEach(visitor);
+ }
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the registers in each instruction are offset by the given
+ * amount. Mutability of the result is inherited from the
+ * original.
+ *
+ * @param delta the amount to offset register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public BasicBlockList withRegisterOffset(int delta) {
+ int sz = size();
+ BasicBlockList result = new BasicBlockList(sz);
+
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = (BasicBlock) get0(i);
+ if (one != null) {
+ result.set(i, one.withRegisterOffset(delta));
+ }
+ }
+
+ if (isImmutable()) {
+ result.setImmutable();
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a mutable copy of this list.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public BasicBlockList getMutableCopy() {
+ return new BasicBlockList(this);
+ }
+
+ /**
+ * Gets the preferred successor for the given block. If the block
+ * only has one successor, then that is the preferred successor.
+ * Otherwise, if the block has a primay successor, then that is
+ * the preferred successor. If the block has no successors, then
+ * this returns {@code null}.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code null-ok;} the preferred successor, if any
+ */
+ public BasicBlock preferredSuccessorOf(BasicBlock block) {
+ int primarySuccessor = block.getPrimarySuccessor();
+ IntList successors = block.getSuccessors();
+ int succSize = successors.size();
+
+ switch (succSize) {
+ case 0: {
+ return null;
+ }
+ case 1: {
+ return labelToBlock(successors.get(0));
+ }
+ }
+
+ if (primarySuccessor != -1) {
+ return labelToBlock(primarySuccessor);
+ } else {
+ return labelToBlock(successors.get(0));
+ }
+ }
+
+ /**
+ * Compares the catches of two blocks for equality. This includes
+ * both the catch types and target labels.
+ *
+ * @param block1 {@code non-null;} one block to compare
+ * @param block2 {@code non-null;} the other block to compare
+ * @return {@code true} if the two blocks' non-primary successors
+ * are identical
+ */
+ public boolean catchesEqual(BasicBlock block1, BasicBlock block2) {
+ TypeList catches1 = block1.getExceptionHandlerTypes();
+ TypeList catches2 = block2.getExceptionHandlerTypes();
+
+ if (!StdTypeList.equalContents(catches1, catches2)) {
+ return false;
+ }
+
+ IntList succ1 = block1.getSuccessors();
+ IntList succ2 = block2.getSuccessors();
+ int size = succ1.size(); // Both are guaranteed to be the same size.
+
+ int primary1 = block1.getPrimarySuccessor();
+ int primary2 = block2.getPrimarySuccessor();
+
+ if (((primary1 == -1) || (primary2 == -1)) && (primary1 != primary2)) {
+ /*
+ * For the current purpose, both blocks in question must
+ * either both have a primary or both not have a primary to
+ * be considered equal, and it turns out here that that's not
+ * the case.
+ */
+ return false;
+ }
+
+ for (int i = 0; i < size; i++) {
+ int label1 = succ1.get(i);
+ int label2 = succ2.get(i);
+
+ if (label1 == primary1) {
+ /*
+ * It should be the case that block2's primary is at the
+ * same index. If not, we consider the blocks unequal for
+ * the current purpose.
+ */
+ if (label2 != primary2) {
+ return false;
+ }
+ continue;
+ }
+
+ if (label1 != label2) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Instruction visitor class for counting registers used.
+ */
+ private static class RegCountVisitor implements Insn.Visitor {
+ /** {@code >= 0;} register count in-progress */
private int regCount;
/**
- * Constructs an instance. All indices initially contain {@code null},
- * and the first-block label is initially {@code -1}.
- *
- * @param size the size of the list
+ * Constructs an instance.
*/
- public BasicBlockList(int size) {
- super(size);
-
- regCount = -1;
+ public RegCountVisitor() {
+ regCount = 0;
}
/**
- * Constructs a mutable copy for {@code getMutableCopy()}.
+ * Gets the register count.
*
- * @param old block to copy
- */
- private BasicBlockList(BasicBlockList old) {
- super(old);
- regCount = old.regCount;
- }
-
-
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public BasicBlock get(int n) {
- return (BasicBlock) get0(n);
- }
-
- /**
- * Sets the basic block at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param bb {@code null-ok;} the element to set at {@code n}
- */
- public void set(int n, BasicBlock bb) {
- super.set(n, bb);
-
- // Reset regCount, since it will need to be recalculated.
- regCount = -1;
- }
-
- /**
- * Returns how many registers this method requires. This is simply
- * the maximum of register-number-plus-category referred to by this
- * instance's instructions (indirectly through {@link BasicBlock}
- * instances).
- *
- * @return {@code >= 0;} the register count
+ * @return {@code >= 0;} the count
*/
public int getRegCount() {
- if (regCount == -1) {
- RegCountVisitor visitor = new RegCountVisitor();
- forEachInsn(visitor);
- regCount = visitor.getRegCount();
- }
+ return regCount;
+ }
- return regCount;
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainInsn(PlainInsn insn) {
+ visit(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPlainCstInsn(PlainCstInsn insn) {
+ visit(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitSwitchInsn(SwitchInsn insn) {
+ visit(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+ visit(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingInsn(ThrowingInsn insn) {
+ visit(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+ visit(insn);
}
/**
- * Gets the total instruction count for this instance. This is the
- * sum of the instruction counts of each block.
+ * Helper for all the {@code visit*} methods.
*
- * @return {@code >= 0;} the total instruction count
+ * @param insn {@code non-null;} instruction being visited
*/
- public int getInstructionCount() {
- int sz = size();
- int result = 0;
+ private void visit(Insn insn) {
+ RegisterSpec result = insn.getResult();
- for (int i = 0; i < sz; i++) {
- BasicBlock one = (BasicBlock) getOrNull0(i);
- if (one != null) {
- result += one.getInsns().size();
- }
- }
+ if (result != null) {
+ processReg(result);
+ }
- return result;
+ RegisterSpecList sources = insn.getSources();
+ int sz = sources.size();
+
+ for (int i = 0; i < sz; i++) {
+ processReg(sources.get(i));
+ }
}
/**
- * Gets the total instruction count for this instance, ignoring
- * mark-local instructions which are not actually emitted.
+ * Processes the given register spec.
*
- * @return {@code >= 0;} the total instruction count
+ * @param spec {@code non-null;} the register spec
*/
- public int getEffectiveInstructionCount() {
- int sz = size();
- int result = 0;
+ private void processReg(RegisterSpec spec) {
+ int reg = spec.getNextReg();
- for (int i = 0; i < sz; i++) {
- BasicBlock one = (BasicBlock) getOrNull0(i);
- if (one != null) {
- InsnList insns = one.getInsns();
- int insnsSz = insns.size();
-
- for (int j = 0; j < insnsSz; j++) {
- Insn insn = insns.get(j);
-
- if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) {
- result++;
- }
- }
- }
- }
-
- return result;
+ if (reg > regCount) {
+ regCount = reg;
+ }
}
-
- /**
- * Gets the first block in the list with the given label, if any.
- *
- * @param label {@code >= 0;} the label to look for
- * @return {@code non-null;} the so-labelled block
- * @throws IllegalArgumentException thrown if the label isn't found
- */
- public BasicBlock labelToBlock(int label) {
- int idx = indexOfLabel(label);
-
- if (idx < 0) {
- throw new IllegalArgumentException("no such label: "
- + Hex.u2(label));
- }
-
- return get(idx);
- }
-
- /**
- * Visits each instruction of each block in the list, in order.
- *
- * @param visitor {@code non-null;} visitor to use
- */
- public void forEachInsn(Insn.Visitor visitor) {
- int sz = size();
-
- for (int i = 0; i < sz; i++) {
- BasicBlock one = get(i);
- InsnList insns = one.getInsns();
- insns.forEach(visitor);
- }
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * the registers in each instruction are offset by the given
- * amount. Mutability of the result is inherited from the
- * original.
- *
- * @param delta the amount to offset register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public BasicBlockList withRegisterOffset(int delta) {
- int sz = size();
- BasicBlockList result = new BasicBlockList(sz);
-
- for (int i = 0; i < sz; i++) {
- BasicBlock one = (BasicBlock) get0(i);
- if (one != null) {
- result.set(i, one.withRegisterOffset(delta));
- }
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
- }
-
- /**
- * Returns a mutable copy of this list.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public BasicBlockList getMutableCopy() {
- return new BasicBlockList(this);
- }
-
- /**
- * Gets the preferred successor for the given block. If the block
- * only has one successor, then that is the preferred successor.
- * Otherwise, if the block has a primay successor, then that is
- * the preferred successor. If the block has no successors, then
- * this returns {@code null}.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code null-ok;} the preferred successor, if any
- */
- public BasicBlock preferredSuccessorOf(BasicBlock block) {
- int primarySuccessor = block.getPrimarySuccessor();
- IntList successors = block.getSuccessors();
- int succSize = successors.size();
-
- switch (succSize) {
- case 0: {
- return null;
- }
- case 1: {
- return labelToBlock(successors.get(0));
- }
- }
-
- if (primarySuccessor != -1) {
- return labelToBlock(primarySuccessor);
- } else {
- return labelToBlock(successors.get(0));
- }
- }
-
- /**
- * Compares the catches of two blocks for equality. This includes
- * both the catch types and target labels.
- *
- * @param block1 {@code non-null;} one block to compare
- * @param block2 {@code non-null;} the other block to compare
- * @return {@code true} if the two blocks' non-primary successors
- * are identical
- */
- public boolean catchesEqual(BasicBlock block1, BasicBlock block2) {
- TypeList catches1 = block1.getExceptionHandlerTypes();
- TypeList catches2 = block2.getExceptionHandlerTypes();
-
- if (!StdTypeList.equalContents(catches1, catches2)) {
- return false;
- }
-
- IntList succ1 = block1.getSuccessors();
- IntList succ2 = block2.getSuccessors();
- int size = succ1.size(); // Both are guaranteed to be the same size.
-
- int primary1 = block1.getPrimarySuccessor();
- int primary2 = block2.getPrimarySuccessor();
-
- if (((primary1 == -1) || (primary2 == -1))
- && (primary1 != primary2)) {
- /*
- * For the current purpose, both blocks in question must
- * either both have a primary or both not have a primary to
- * be considered equal, and it turns out here that that's not
- * the case.
- */
- return false;
- }
-
- for (int i = 0; i < size; i++) {
- int label1 = succ1.get(i);
- int label2 = succ2.get(i);
-
- if (label1 == primary1) {
- /*
- * It should be the case that block2's primary is at the
- * same index. If not, we consider the blocks unequal for
- * the current purpose.
- */
- if (label2 != primary2) {
- return false;
- }
- continue;
- }
-
- if (label1 != label2) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Instruction visitor class for counting registers used.
- */
- private static class RegCountVisitor
- implements Insn.Visitor {
- /** {@code >= 0;} register count in-progress */
- private int regCount;
-
- /**
- * Constructs an instance.
- */
- public RegCountVisitor() {
- regCount = 0;
- }
-
- /**
- * Gets the register count.
- *
- * @return {@code >= 0;} the count
- */
- public int getRegCount() {
- return regCount;
- }
-
- /** {@inheritDoc} */
- public void visitPlainInsn(PlainInsn insn) {
- visit(insn);
- }
-
- /** {@inheritDoc} */
- public void visitPlainCstInsn(PlainCstInsn insn) {
- visit(insn);
- }
-
- /** {@inheritDoc} */
- public void visitSwitchInsn(SwitchInsn insn) {
- visit(insn);
- }
-
- /** {@inheritDoc} */
- public void visitThrowingCstInsn(ThrowingCstInsn insn) {
- visit(insn);
- }
-
- /** {@inheritDoc} */
- public void visitThrowingInsn(ThrowingInsn insn) {
- visit(insn);
- }
-
- /** {@inheritDoc} */
- public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
- visit(insn);
- }
-
- /**
- * Helper for all the {@code visit*} methods.
- *
- * @param insn {@code non-null;} instruction being visited
- */
- private void visit(Insn insn) {
- RegisterSpec result = insn.getResult();
-
- if (result != null) {
- processReg(result);
- }
-
- RegisterSpecList sources = insn.getSources();
- int sz = sources.size();
-
- for (int i = 0; i < sz; i++) {
- processReg(sources.get(i));
- }
- }
-
- /**
- * Processes the given register spec.
- *
- * @param spec {@code non-null;} the register spec
- */
- private void processReg(RegisterSpec spec) {
- int reg = spec.getNextReg();
-
- if (reg > regCount) {
- regCount = reg;
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/ConservativeTranslationAdvice.java b/dx/src/com/android/jack/dx/rop/code/ConservativeTranslationAdvice.java
index 6a4ee22..3077f81 100644
--- a/dx/src/com/android/jack/dx/rop/code/ConservativeTranslationAdvice.java
+++ b/dx/src/com/android/jack/dx/rop/code/ConservativeTranslationAdvice.java
@@ -20,33 +20,32 @@
* Implementation of {@link TranslationAdvice} which conservatively answers
* {@code false} to all methods.
*/
-public final class ConservativeTranslationAdvice
- implements TranslationAdvice {
- /** {@code non-null;} standard instance of this class */
- public static final ConservativeTranslationAdvice THE_ONE =
- new ConservativeTranslationAdvice();
+public final class ConservativeTranslationAdvice implements TranslationAdvice {
+ /** {@code non-null;} standard instance of this class */
+ public static final ConservativeTranslationAdvice THE_ONE = new ConservativeTranslationAdvice();
- /**
- * This class is not publicly instantiable. Use {@link #THE_ONE}.
- */
- private ConservativeTranslationAdvice() {
- // This space intentionally left blank.
- }
+ /**
+ * This class is not publicly instantiable. Use {@link #THE_ONE}.
+ */
+ private ConservativeTranslationAdvice() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- public boolean hasConstantOperation(Rop opcode,
- RegisterSpec sourceA, RegisterSpec sourceB) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasConstantOperation(Rop opcode, RegisterSpec sourceA, RegisterSpec sourceB) {
+ return false;
+ }
- /** {@inheritDoc} */
- public boolean requiresSourcesInOrder(Rop opcode,
- RegisterSpecList sources) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources) {
+ return false;
+ }
- /** {@inheritDoc} */
- public int getMaxOptimalRegisterCount() {
- return Integer.MAX_VALUE;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int getMaxOptimalRegisterCount() {
+ return Integer.MAX_VALUE;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/CstInsn.java b/dx/src/com/android/jack/dx/rop/code/CstInsn.java
index 4e5a7fe..c639863 100644
--- a/dx/src/com/android/jack/dx/rop/code/CstInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/CstInsn.java
@@ -21,54 +21,52 @@
/**
* Instruction which contains an explicit reference to a constant.
*/
-public abstract class CstInsn
- extends Insn {
- /** {@code non-null;} the constant */
- private final Constant cst;
+public abstract class CstInsn extends Insn {
+ /** {@code non-null;} the constant */
+ private final Constant cst;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param sources {@code non-null;} specs for all the sources
- * @param cst {@code non-null;} constant
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cst {@code non-null;} constant
+ */
+ public CstInsn(Rop opcode, SourcePosition position, RegisterSpec result, RegisterSpecList sources,
+ Constant cst) {
+ super(opcode, position, result, sources);
+
+ if (cst == null) {
+ throw new NullPointerException("cst == null");
+ }
+
+ this.cst = cst;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getInlineString() {
+ return cst.toHuman();
+ }
+
+ /**
+ * Gets the constant.
+ *
+ * @return {@code non-null;} the constant
+ */
+ public Constant getConstant() {
+ return cst;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean contentEquals(Insn b) {
+ /*
+ * The cast (CstInsn)b below should always succeed since
+ * Insn.contentEquals compares classes of this and b.
*/
- public CstInsn(Rop opcode, SourcePosition position, RegisterSpec result,
- RegisterSpecList sources, Constant cst) {
- super(opcode, position, result, sources);
-
- if (cst == null) {
- throw new NullPointerException("cst == null");
- }
-
- this.cst = cst;
- }
-
- /** {@inheritDoc} */
- @Override
- public String getInlineString() {
- return cst.toHuman();
- }
-
- /**
- * Gets the constant.
- *
- * @return {@code non-null;} the constant
- */
- public Constant getConstant() {
- return cst;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean contentEquals(Insn b) {
- /*
- * The cast (CstInsn)b below should always succeed since
- * Insn.contentEquals compares classes of this and b.
- */
- return super.contentEquals(b)
- && cst.equals(((CstInsn)b).getConstant());
- }
+ return super.contentEquals(b) && cst.equals(((CstInsn) b).getConstant());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/DexTranslationAdvice.java b/dx/src/com/android/jack/dx/rop/code/DexTranslationAdvice.java
index 4654a39..10d647f 100644
--- a/dx/src/com/android/jack/dx/rop/code/DexTranslationAdvice.java
+++ b/dx/src/com/android/jack/dx/rop/code/DexTranslationAdvice.java
@@ -23,108 +23,105 @@
* Implementation of {@link TranslationAdvice} which represents what
* the dex format will be able to represent.
*/
-public final class DexTranslationAdvice
- implements TranslationAdvice {
- /** {@code non-null;} standard instance of this class */
- public static final DexTranslationAdvice THE_ONE =
- new DexTranslationAdvice();
+public final class DexTranslationAdvice implements TranslationAdvice {
+ /** {@code non-null;} standard instance of this class */
+ public static final DexTranslationAdvice THE_ONE = new DexTranslationAdvice();
- /** debug advice for disabling invoke-range optimization */
- public static final DexTranslationAdvice NO_SOURCES_IN_ORDER =
- new DexTranslationAdvice(true);
+ /** debug advice for disabling invoke-range optimization */
+ public static final DexTranslationAdvice NO_SOURCES_IN_ORDER = new DexTranslationAdvice(true);
- /**
- * The minimum source width, in register units, for an invoke
- * instruction that requires its sources to be in order and contiguous.
- */
- private static final int MIN_INVOKE_IN_ORDER = 6;
+ /**
+ * The minimum source width, in register units, for an invoke
+ * instruction that requires its sources to be in order and contiguous.
+ */
+ private static final int MIN_INVOKE_IN_ORDER = 6;
- /** when true: always returns false for requiresSourcesInOrder */
- private final boolean disableSourcesInOrder;
+ /** when true: always returns false for requiresSourcesInOrder */
+ private final boolean disableSourcesInOrder;
- /**
- * This class is not publicly instantiable. Use {@link #THE_ONE}.
- */
- private DexTranslationAdvice() {
- disableSourcesInOrder = false;
+ /**
+ * This class is not publicly instantiable. Use {@link #THE_ONE}.
+ */
+ private DexTranslationAdvice() {
+ disableSourcesInOrder = false;
+ }
+
+ private DexTranslationAdvice(boolean disableInvokeRange) {
+ this.disableSourcesInOrder = disableInvokeRange;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasConstantOperation(Rop opcode, RegisterSpec sourceA, RegisterSpec sourceB) {
+ if (sourceA.getType() != Type.INT) {
+ return false;
}
- private DexTranslationAdvice(boolean disableInvokeRange) {
- this.disableSourcesInOrder = disableInvokeRange;
+ // Return false if second source isn't a constant
+ if (!(sourceB.getTypeBearer() instanceof CstInteger)) {
+ // Except for rsub-int (reverse sub) where first source is constant
+ if (sourceA.getTypeBearer() instanceof CstInteger && opcode.getOpcode() == RegOps.SUB) {
+ CstInteger cst = (CstInteger) sourceA.getTypeBearer();
+ return cst.fitsIn16Bits();
+ } else {
+ return false;
+ }
}
- /** {@inheritDoc} */
- public boolean hasConstantOperation(Rop opcode,
- RegisterSpec sourceA, RegisterSpec sourceB) {
- if (sourceA.getType() != Type.INT) {
- return false;
- }
+ CstInteger cst = (CstInteger) sourceB.getTypeBearer();
- // Return false if second source isn't a constant
- if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
- // Except for rsub-int (reverse sub) where first source is constant
- if (sourceA.getTypeBearer() instanceof CstInteger &&
- opcode.getOpcode() == RegOps.SUB) {
- CstInteger cst = (CstInteger) sourceA.getTypeBearer();
- return cst.fitsIn16Bits();
- } else {
- return false;
- }
- }
+ switch (opcode.getOpcode()) {
+ // These have 8 and 16 bit cst representations
+ case RegOps.REM:
+ case RegOps.ADD:
+ case RegOps.MUL:
+ case RegOps.DIV:
+ case RegOps.AND:
+ case RegOps.OR:
+ case RegOps.XOR:
+ return cst.fitsIn16Bits();
+ // These only have 8 bit cst reps
+ case RegOps.SHL:
+ case RegOps.SHR:
+ case RegOps.USHR:
+ return cst.fitsIn8Bits();
+ // No sub-const insn, so check if equivalent add-const fits
+ case RegOps.SUB:
+ CstInteger cst2 = CstInteger.make(-cst.getValue());
+ return cst2.fitsIn16Bits();
+ default:
+ return false;
+ }
+ }
- CstInteger cst = (CstInteger) sourceB.getTypeBearer();
+ /** {@inheritDoc} */
+ @Override
+ public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources) {
- switch (opcode.getOpcode()) {
- // These have 8 and 16 bit cst representations
- case RegOps.REM:
- case RegOps.ADD:
- case RegOps.MUL:
- case RegOps.DIV:
- case RegOps.AND:
- case RegOps.OR:
- case RegOps.XOR:
- return cst.fitsIn16Bits();
- // These only have 8 bit cst reps
- case RegOps.SHL:
- case RegOps.SHR:
- case RegOps.USHR:
- return cst.fitsIn8Bits();
- // No sub-const insn, so check if equivalent add-const fits
- case RegOps.SUB:
- CstInteger cst2 = CstInteger.make(-cst.getValue());
- return cst2.fitsIn16Bits();
- default:
- return false;
- }
+ return !disableSourcesInOrder && opcode.isCallLike()
+ && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
+ }
+
+ /**
+ * Calculates the total rop width of the list of SSA registers
+ *
+ * @param sources {@code non-null;} list of SSA registers
+ * @return {@code >= 0;} rop-form width in register units
+ */
+ private int totalRopWidth(RegisterSpecList sources) {
+ int sz = sources.size();
+ int total = 0;
+
+ for (int i = 0; i < sz; i++) {
+ total += sources.get(i).getCategory();
}
- /** {@inheritDoc} */
- public boolean requiresSourcesInOrder(Rop opcode,
- RegisterSpecList sources) {
+ return total;
+ }
- return !disableSourcesInOrder && opcode.isCallLike()
- && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
- }
-
- /**
- * Calculates the total rop width of the list of SSA registers
- *
- * @param sources {@code non-null;} list of SSA registers
- * @return {@code >= 0;} rop-form width in register units
- */
- private int totalRopWidth(RegisterSpecList sources) {
- int sz = sources.size();
- int total = 0;
-
- for (int i = 0; i < sz; i++) {
- total += sources.get(i).getCategory();
- }
-
- return total;
- }
-
- /** {@inheritDoc} */
- public int getMaxOptimalRegisterCount() {
- return 16;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int getMaxOptimalRegisterCount() {
+ return 16;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/Exceptions.java b/dx/src/com/android/jack/dx/rop/code/Exceptions.java
index f91f459..ff2fe73 100644
--- a/dx/src/com/android/jack/dx/rop/code/Exceptions.java
+++ b/dx/src/com/android/jack/dx/rop/code/Exceptions.java
@@ -23,111 +23,103 @@
* Common exception types.
*/
public final class Exceptions {
- /** {@code non-null;} the type {@code java.lang.ArithmeticException} */
- public static final Type TYPE_ArithmeticException =
- Type.intern("Ljava/lang/ArithmeticException;");
+ /** {@code non-null;} the type {@code java.lang.ArithmeticException} */
+ public static final Type TYPE_ArithmeticException =
+ Type.intern("Ljava/lang/ArithmeticException;");
- /**
- * {@code non-null;} the type
- * {@code java.lang.ArrayIndexOutOfBoundsException}
- */
- public static final Type TYPE_ArrayIndexOutOfBoundsException =
- Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
+ /**
+ * {@code non-null;} the type
+ * {@code java.lang.ArrayIndexOutOfBoundsException}
+ */
+ public static final Type TYPE_ArrayIndexOutOfBoundsException =
+ Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
- /** {@code non-null;} the type {@code java.lang.ArrayStoreException} */
- public static final Type TYPE_ArrayStoreException =
- Type.intern("Ljava/lang/ArrayStoreException;");
+ /** {@code non-null;} the type {@code java.lang.ArrayStoreException} */
+ public static final Type TYPE_ArrayStoreException =
+ Type.intern("Ljava/lang/ArrayStoreException;");
- /** {@code non-null;} the type {@code java.lang.ClassCastException} */
- public static final Type TYPE_ClassCastException =
- Type.intern("Ljava/lang/ClassCastException;");
+ /** {@code non-null;} the type {@code java.lang.ClassCastException} */
+ public static final Type TYPE_ClassCastException = Type.intern("Ljava/lang/ClassCastException;");
- /** {@code non-null;} the type {@code java.lang.Error} */
- public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;");
+ /** {@code non-null;} the type {@code java.lang.Error} */
+ public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;");
- /**
- * {@code non-null;} the type
- * {@code java.lang.IllegalMonitorStateException}
- */
- public static final Type TYPE_IllegalMonitorStateException =
- Type.intern("Ljava/lang/IllegalMonitorStateException;");
+ /**
+ * {@code non-null;} the type
+ * {@code java.lang.IllegalMonitorStateException}
+ */
+ public static final Type TYPE_IllegalMonitorStateException =
+ Type.intern("Ljava/lang/IllegalMonitorStateException;");
- /** {@code non-null;} the type {@code java.lang.NegativeArraySizeException} */
- public static final Type TYPE_NegativeArraySizeException =
- Type.intern("Ljava/lang/NegativeArraySizeException;");
+ /** {@code non-null;} the type {@code java.lang.NegativeArraySizeException} */
+ public static final Type TYPE_NegativeArraySizeException =
+ Type.intern("Ljava/lang/NegativeArraySizeException;");
- /** {@code non-null;} the type {@code java.lang.NullPointerException} */
- public static final Type TYPE_NullPointerException =
- Type.intern("Ljava/lang/NullPointerException;");
+ /** {@code non-null;} the type {@code java.lang.NullPointerException} */
+ public static final Type TYPE_NullPointerException =
+ Type.intern("Ljava/lang/NullPointerException;");
- /** {@code non-null;} the list {@code [java.lang.Error]} */
- public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error);
+ /** {@code non-null;} the list {@code [java.lang.Error]} */
+ public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error);
- /**
- * {@code non-null;} the list {@code[java.lang.Error,
- * java.lang.ArithmeticException]}
- */
- public static final StdTypeList LIST_Error_ArithmeticException =
- StdTypeList.make(TYPE_Error, TYPE_ArithmeticException);
+ /**
+ * {@code non-null;} the list {@code[java.lang.Error,
+ * java.lang.ArithmeticException]}
+ */
+ public static final StdTypeList LIST_Error_ArithmeticException =
+ StdTypeList.make(TYPE_Error, TYPE_ArithmeticException);
- /**
- * {@code non-null;} the list {@code[java.lang.Error,
- * java.lang.ClassCastException]}
- */
- public static final StdTypeList LIST_Error_ClassCastException =
- StdTypeList.make(TYPE_Error, TYPE_ClassCastException);
+ /**
+ * {@code non-null;} the list {@code[java.lang.Error,
+ * java.lang.ClassCastException]}
+ */
+ public static final StdTypeList LIST_Error_ClassCastException =
+ StdTypeList.make(TYPE_Error, TYPE_ClassCastException);
- /**
- * {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NegativeArraySizeException]}
- */
- public static final StdTypeList LIST_Error_NegativeArraySizeException =
- StdTypeList.make(TYPE_Error, TYPE_NegativeArraySizeException);
+ /**
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NegativeArraySizeException]}
+ */
+ public static final StdTypeList LIST_Error_NegativeArraySizeException =
+ StdTypeList.make(TYPE_Error, TYPE_NegativeArraySizeException);
- /**
- * {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NullPointerException]}
- */
- public static final StdTypeList LIST_Error_NullPointerException =
- StdTypeList.make(TYPE_Error, TYPE_NullPointerException);
+ /**
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NullPointerException]}
+ */
+ public static final StdTypeList LIST_Error_NullPointerException =
+ StdTypeList.make(TYPE_Error, TYPE_NullPointerException);
- /**
- * {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NullPointerException,
- * java.lang.ArrayIndexOutOfBoundsException]}
- */
- public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds =
- StdTypeList.make(TYPE_Error,
- TYPE_NullPointerException,
- TYPE_ArrayIndexOutOfBoundsException);
+ /**
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NullPointerException,
+ * java.lang.ArrayIndexOutOfBoundsException]}
+ */
+ public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds =
+ StdTypeList.make(TYPE_Error, TYPE_NullPointerException, TYPE_ArrayIndexOutOfBoundsException);
- /**
- * {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NullPointerException,
- * java.lang.ArrayIndexOutOfBoundsException,
- * java.lang.ArrayStoreException]}
- */
- public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore =
- StdTypeList.make(TYPE_Error,
- TYPE_NullPointerException,
- TYPE_ArrayIndexOutOfBoundsException,
- TYPE_ArrayStoreException);
+ /**
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NullPointerException,
+ * java.lang.ArrayIndexOutOfBoundsException,
+ * java.lang.ArrayStoreException]}
+ */
+ public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore = StdTypeList.make(
+ TYPE_Error, TYPE_NullPointerException, TYPE_ArrayIndexOutOfBoundsException,
+ TYPE_ArrayStoreException);
- /**
- * {@code non-null;} the list {@code [java.lang.Error,
- * java.lang.NullPointerException,
- * java.lang.IllegalMonitorStateException]}
- */
- public static final StdTypeList
- LIST_Error_Null_IllegalMonitorStateException =
- StdTypeList.make(TYPE_Error,
- TYPE_NullPointerException,
- TYPE_IllegalMonitorStateException);
+ /**
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NullPointerException,
+ * java.lang.IllegalMonitorStateException]}
+ */
+ public static final StdTypeList LIST_Error_Null_IllegalMonitorStateException =
+ StdTypeList.make(TYPE_Error, TYPE_NullPointerException, TYPE_IllegalMonitorStateException);
- /**
- * This class is uninstantiable.
- */
- private Exceptions() {
- // This space intentionally left blank.
- }
+ /**
+ * This class is uninstantiable.
+ */
+ private Exceptions() {
+ // This space intentionally left blank.
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/FillArrayDataInsn.java b/dx/src/com/android/jack/dx/rop/code/FillArrayDataInsn.java
index f92fd71..fb0ebb3 100644
--- a/dx/src/com/android/jack/dx/rop/code/FillArrayDataInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/FillArrayDataInsn.java
@@ -27,90 +27,84 @@
* Instruction which fills a newly created array with a predefined list of
* constant values.
*/
-public final class FillArrayDataInsn
- extends Insn {
+public final class FillArrayDataInsn extends Insn {
- /** non-null: initial values to fill the newly created array */
- private final ArrayList<Constant> initValues;
+ /** non-null: initial values to fill the newly created array */
+ private final ArrayList<Constant> initValues;
- /**
- * non-null: type of the array. Will be used to determine the width of
- * elements in the array-data table.
- */
- private final Constant arrayType;
+ /**
+ * non-null: type of the array. Will be used to determine the width of
+ * elements in the array-data table.
+ */
+ private final Constant arrayType;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param sources {@code non-null;} specs for all the sources
- * @param initValues {@code non-null;} list of initial values to fill the array
- * @param cst {@code non-null;} type of the new array
- */
- public FillArrayDataInsn(Rop opcode, SourcePosition position,
- RegisterSpecList sources,
- ArrayList<Constant> initValues,
- Constant cst) {
- super(opcode, position, null, sources);
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param initValues {@code non-null;} list of initial values to fill the array
+ * @param cst {@code non-null;} type of the new array
+ */
+ public FillArrayDataInsn(Rop opcode, SourcePosition position, RegisterSpecList sources,
+ ArrayList<Constant> initValues, Constant cst) {
+ super(opcode, position, null, sources);
- if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
- throw new IllegalArgumentException("bogus branchingness");
- }
-
- this.initValues = initValues;
- this.arrayType = cst;
+ if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+ throw new IllegalArgumentException("bogus branchingness");
}
+ this.initValues = initValues;
+ this.arrayType = cst;
+ }
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return StdTypeList.EMPTY;
- }
- /**
- * Return the list of init values
- * @return {@code non-null;} list of init values
- */
- public ArrayList<Constant> getInitValues() {
- return initValues;
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return StdTypeList.EMPTY;
+ }
- /**
- * Return the type of the newly created array
- * @return {@code non-null;} array type
- */
- public Constant getConstant() {
- return arrayType;
- }
+ /**
+ * Return the list of init values
+ * @return {@code non-null;} list of init values
+ */
+ public ArrayList<Constant> getInitValues() {
+ return initValues;
+ }
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitFillArrayDataInsn(this);
- }
+ /**
+ * Return the type of the newly created array
+ * @return {@code non-null;} array type
+ */
+ public Constant getConstant() {
+ return arrayType;
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- throw new UnsupportedOperationException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitFillArrayDataInsn(this);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new FillArrayDataInsn(getOpcode(), getPosition(),
- getSources().withOffset(delta),
- initValues, arrayType);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ throw new UnsupportedOperationException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new FillArrayDataInsn(getOpcode(), getPosition(), getSources().withOffset(delta),
+ initValues, arrayType);
+ }
- return new FillArrayDataInsn(getOpcode(), getPosition(),
- sources, initValues, arrayType);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
+
+ return new FillArrayDataInsn(getOpcode(), getPosition(), sources, initValues, arrayType);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/Insn.java b/dx/src/com/android/jack/dx/rop/code/Insn.java
index 312f051..11475a6 100644
--- a/dx/src/com/android/jack/dx/rop/code/Insn.java
+++ b/dx/src/com/android/jack/dx/rop/code/Insn.java
@@ -28,429 +28,432 @@
* information.
*/
public abstract class Insn implements ToHuman {
- /** {@code non-null;} opcode */
- private final Rop opcode;
+ /** {@code non-null;} opcode */
+ private final Rop opcode;
- /** {@code non-null;} source position */
- private final SourcePosition position;
+ /** {@code non-null;} source position */
+ private final SourcePosition position;
- /** {@code null-ok;} spec for the result of this instruction, if any */
- private final RegisterSpec result;
+ /** {@code null-ok;} spec for the result of this instruction, if any */
+ private final RegisterSpec result;
- /** {@code non-null;} specs for all the sources of this instruction */
- private final RegisterSpecList sources;
+ /** {@code non-null;} specs for all the sources of this instruction */
+ private final RegisterSpecList sources;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param sources {@code non-null;} specs for all the sources
- */
- public Insn(Rop opcode, SourcePosition position, RegisterSpec result,
- RegisterSpecList sources) {
- if (opcode == null) {
- throw new NullPointerException("opcode == null");
- }
-
- if (position == null) {
- throw new NullPointerException("position == null");
- }
-
- if (sources == null) {
- throw new NullPointerException("sources == null");
- }
-
- this.opcode = opcode;
- this.position = position;
- this.result = result;
- this.sources = sources;
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param sources {@code non-null;} specs for all the sources
+ */
+ public Insn(Rop opcode, SourcePosition position, RegisterSpec result, RegisterSpecList sources) {
+ if (opcode == null) {
+ throw new NullPointerException("opcode == null");
}
- /**
- * {@inheritDoc}
- *
- * Instances of this class compare by identity. That is,
- * {@code x.equals(y)} is only true if {@code x == y}.
- */
- @Override
- public final boolean equals(Object other) {
- return (this == other);
+ if (position == null) {
+ throw new NullPointerException("position == null");
}
+ if (sources == null) {
+ throw new NullPointerException("sources == null");
+ }
+
+ this.opcode = opcode;
+ this.position = position;
+ this.result = result;
+ this.sources = sources;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Instances of this class compare by identity. That is,
+ * {@code x.equals(y)} is only true if {@code x == y}.
+ */
+ @Override
+ public final boolean equals(Object other) {
+ return (this == other);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation returns the identity hashcode of this
+ * instance. This is proper, since instances of this class compare
+ * by identity (see {@link #equals}).
+ */
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return toStringWithInline(getInlineString());
+ }
+
+ /**
+ * Gets a human-oriented (and slightly lossy) string for this instance.
+ *
+ * @return {@code non-null;} the human string form
+ */
+ @Override
+ public String toHuman() {
+ return toHumanWithInline(getInlineString());
+ }
+
+ /**
+ * Gets an "inline" string portion for toHuman(), if available. This
+ * is the portion that appears after the Rop opcode
+ *
+ * @return {@code null-ok;} if non-null, the inline text for toHuman()
+ */
+ public String getInlineString() {
+ return null;
+ }
+
+ /**
+ * Gets the opcode.
+ *
+ * @return {@code non-null;} the opcode
+ */
+ public final Rop getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Gets the source position.
+ *
+ * @return {@code non-null;} the source position
+ */
+ public final SourcePosition getPosition() {
+ return position;
+ }
+
+ /**
+ * Gets the result spec, if any. A return value of {@code null}
+ * means this instruction returns nothing.
+ *
+ * @return {@code null-ok;} the result spec, if any
+ */
+ public final RegisterSpec getResult() {
+ return result;
+ }
+
+ /**
+ * Gets the spec of a local variable assignment that occurs at this
+ * instruction, or null if no local variable assignment occurs. This
+ * may be the result register, or for {@code mark-local} insns
+ * it may be the source.
+ *
+ * @return {@code null-ok;} a named register spec or null
+ */
+ public final RegisterSpec getLocalAssignment() {
+ RegisterSpec assignment;
+ if (opcode.getOpcode() == RegOps.MARK_LOCAL) {
+ assignment = sources.get(0);
+ } else {
+ assignment = result;
+ }
+
+ if (assignment == null) {
+ return null;
+ }
+
+ LocalItem localItem = assignment.getLocalItem();
+
+ if (localItem == null) {
+ return null;
+ }
+
+ return assignment;
+ }
+
+ /**
+ * Gets the source specs.
+ *
+ * @return {@code non-null;} the source specs
+ */
+ public final RegisterSpecList getSources() {
+ return sources;
+ }
+
+ /**
+ * Gets whether this instruction can possibly throw an exception. This
+ * is just a convenient wrapper for {@code getOpcode().canThrow()}.
+ *
+ * @return {@code true} iff this instruction can possibly throw
+ */
+ public final boolean canThrow() {
+ return opcode.canThrow();
+ }
+
+ /**
+ * Gets the list of possibly-caught exceptions. This returns {@link
+ * StdTypeList#EMPTY} if this instruction has no handlers,
+ * which can be <i>either</i> if this instruction can't possibly
+ * throw or if it merely doesn't handle any of its possible
+ * exceptions. To determine whether this instruction can throw,
+ * use {@link #canThrow}.
+ *
+ * @return {@code non-null;} the catches list
+ */
+ public abstract TypeList getCatches();
+
+ /**
+ * Calls the appropriate method on the given visitor, depending on the
+ * class of this instance. Subclasses must override this.
+ *
+ * @param visitor {@code non-null;} the visitor to call on
+ */
+ public abstract void accept(Visitor visitor);
+
+ /**
+ * Returns an instance that is just like this one, except that it
+ * has a catch list with the given item appended to the end. This
+ * method throws an exception if this instance can't possibly
+ * throw. To determine whether this instruction can throw, use
+ * {@link #canThrow}.
+ *
+ * @param type {@code non-null;} type to append to the catch list
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract Insn withAddedCatch(Type type);
+
+ /**
+ * Returns an instance that is just like this one, except that all
+ * register references have been offset by the given delta.
+ *
+ * @param delta the amount to offset register references by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract Insn withRegisterOffset(int delta);
+
+ /**
+ * Returns an instance that is just like this one, except that, if
+ * possible, the insn is converted into a version in which a source
+ * (if it is a constant) is represented directly rather than as a
+ * register reference. {@code this} is returned in cases where the
+ * translation is not possible.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public Insn withSourceLiteral() {
+ return this;
+ }
+
+ /**
+ * Returns an exact copy of this Insn
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public Insn copy() {
+ return withRegisterOffset(0);
+ }
+
+
+ /**
+ * Compares, handling nulls safely
+ *
+ * @param a first object
+ * @param b second object
+ * @return true if they're equal or both null.
+ */
+ private static boolean equalsHandleNulls(Object a, Object b) {
+ return (a == b) || ((a != null) && a.equals(b));
+ }
+
+ /**
+ * Compares Insn contents, since {@code Insn.equals()} is defined
+ * to be an identity compare. Insn's are {@code contentEquals()}
+ * if they have the same opcode, registers, source position, and other
+ * metadata.
+ *
+ * @return true in the case described above
+ */
+ public boolean contentEquals(Insn b) {
+ return opcode == b.getOpcode() && position.equals(b.getPosition())
+ && (getClass() == b.getClass()) && equalsHandleNulls(result, b.getResult())
+ && equalsHandleNulls(sources, b.getSources())
+ && StdTypeList.equalContents(getCatches(), b.getCatches());
+ }
+
+ /**
+ * Returns an instance that is just like this one, except
+ * with new result and source registers.
+ *
+ * @param result {@code null-ok;} new result register
+ * @param sources {@code non-null;} new sources registers
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public abstract Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources);
+
+ /**
+ * Returns the string form of this instance, with the given bit added in
+ * the standard location for an inline argument.
+ *
+ * @param extra {@code null-ok;} the inline argument string
+ * @return {@code non-null;} the string form
+ */
+ protected final String toStringWithInline(String extra) {
+ StringBuffer sb = new StringBuffer(80);
+
+ sb.append("Insn{");
+ sb.append(position);
+ sb.append(' ');
+ sb.append(opcode);
+
+ if (extra != null) {
+ sb.append(' ');
+ sb.append(extra);
+ }
+
+ sb.append(" :: ");
+
+ if (result != null) {
+ sb.append(result);
+ sb.append(" <- ");
+ }
+
+ sb.append(sources);
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the human string form of this instance, with the given
+ * bit added in the standard location for an inline argument.
+ *
+ * @param extra {@code null-ok;} the inline argument string
+ * @return {@code non-null;} the human string form
+ */
+ protected final String toHumanWithInline(String extra) {
+ StringBuffer sb = new StringBuffer(80);
+
+ sb.append(position);
+ sb.append(": ");
+ sb.append(opcode.getNickname());
+
+ if (extra != null) {
+ sb.append("(");
+ sb.append(extra);
+ sb.append(")");
+ }
+
+ if (result == null) {
+ sb.append(" .");
+ } else {
+ sb.append(" ");
+ sb.append(result.toHuman());
+ }
+
+ sb.append(" <-");
+
+ int sz = sources.size();
+ if (sz == 0) {
+ sb.append(" .");
+ } else {
+ for (int i = 0; i < sz; i++) {
+ sb.append(" ");
+ sb.append(sources.get(i).toHuman());
+ }
+ }
+
+ return sb.toString();
+ }
+
+
+ /**
+ * Visitor interface for this (outer) class.
+ */
+ public static interface Visitor {
/**
- * {@inheritDoc}
+ * Visits a {@link PlainInsn}.
*
- * This implementation returns the identity hashcode of this
- * instance. This is proper, since instances of this class compare
- * by identity (see {@link #equals}).
+ * @param insn {@code non-null;} the instruction to visit
*/
+ public void visitPlainInsn(PlainInsn insn);
+
+ /**
+ * Visits a {@link PlainCstInsn}.
+ *
+ * @param insn {@code non-null;} the instruction to visit
+ */
+ public void visitPlainCstInsn(PlainCstInsn insn);
+
+ /**
+ * Visits a {@link SwitchInsn}.
+ *
+ * @param insn {@code non-null;} the instruction to visit
+ */
+ public void visitSwitchInsn(SwitchInsn insn);
+
+ /**
+ * Visits a {@link ThrowingCstInsn}.
+ *
+ * @param insn {@code non-null;} the instruction to visit
+ */
+ public void visitThrowingCstInsn(ThrowingCstInsn insn);
+
+ /**
+ * Visits a {@link ThrowingInsn}.
+ *
+ * @param insn {@code non-null;} the instruction to visit
+ */
+ public void visitThrowingInsn(ThrowingInsn insn);
+
+ /**
+ * Visits a {@link FillArrayDataInsn}.
+ *
+ * @param insn {@code non-null;} the instruction to visit
+ */
+ public void visitFillArrayDataInsn(FillArrayDataInsn insn);
+ }
+
+ /**
+ * Base implementation of {@link Visitor}, which has empty method
+ * bodies for all methods.
+ */
+ public static class BaseVisitor implements Visitor {
+ /** {@inheritDoc} */
@Override
- public final int hashCode() {
- return System.identityHashCode(this);
+ public void visitPlainInsn(PlainInsn insn) {
+ // This space intentionally left blank.
}
/** {@inheritDoc} */
@Override
- public String toString() {
- return toStringWithInline(getInlineString());
+ public void visitPlainCstInsn(PlainCstInsn insn) {
+ // This space intentionally left blank.
}
- /**
- * Gets a human-oriented (and slightly lossy) string for this instance.
- *
- * @return {@code non-null;} the human string form
- */
- public String toHuman() {
- return toHumanWithInline(getInlineString());
+ /** {@inheritDoc} */
+ @Override
+ public void visitSwitchInsn(SwitchInsn insn) {
+ // This space intentionally left blank.
}
- /**
- * Gets an "inline" string portion for toHuman(), if available. This
- * is the portion that appears after the Rop opcode
- *
- * @return {@code null-ok;} if non-null, the inline text for toHuman()
- */
- public String getInlineString() {
- return null;
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+ // This space intentionally left blank.
}
- /**
- * Gets the opcode.
- *
- * @return {@code non-null;} the opcode
- */
- public final Rop getOpcode() {
- return opcode;
+ /** {@inheritDoc} */
+ @Override
+ public void visitThrowingInsn(ThrowingInsn insn) {
+ // This space intentionally left blank.
}
- /**
- * Gets the source position.
- *
- * @return {@code non-null;} the source position
- */
- public final SourcePosition getPosition() {
- return position;
+ /** {@inheritDoc} */
+ @Override
+ public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+ // This space intentionally left blank.
}
-
- /**
- * Gets the result spec, if any. A return value of {@code null}
- * means this instruction returns nothing.
- *
- * @return {@code null-ok;} the result spec, if any
- */
- public final RegisterSpec getResult() {
- return result;
- }
-
- /**
- * Gets the spec of a local variable assignment that occurs at this
- * instruction, or null if no local variable assignment occurs. This
- * may be the result register, or for {@code mark-local} insns
- * it may be the source.
- *
- * @return {@code null-ok;} a named register spec or null
- */
- public final RegisterSpec getLocalAssignment() {
- RegisterSpec assignment;
- if (opcode.getOpcode() == RegOps.MARK_LOCAL) {
- assignment = sources.get(0);
- } else {
- assignment = result;
- }
-
- if (assignment == null) {
- return null;
- }
-
- LocalItem localItem = assignment.getLocalItem();
-
- if (localItem == null) {
- return null;
- }
-
- return assignment;
- }
-
- /**
- * Gets the source specs.
- *
- * @return {@code non-null;} the source specs
- */
- public final RegisterSpecList getSources() {
- return sources;
- }
-
- /**
- * Gets whether this instruction can possibly throw an exception. This
- * is just a convenient wrapper for {@code getOpcode().canThrow()}.
- *
- * @return {@code true} iff this instruction can possibly throw
- */
- public final boolean canThrow() {
- return opcode.canThrow();
- }
-
- /**
- * Gets the list of possibly-caught exceptions. This returns {@link
- * StdTypeList#EMPTY} if this instruction has no handlers,
- * which can be <i>either</i> if this instruction can't possibly
- * throw or if it merely doesn't handle any of its possible
- * exceptions. To determine whether this instruction can throw,
- * use {@link #canThrow}.
- *
- * @return {@code non-null;} the catches list
- */
- public abstract TypeList getCatches();
-
- /**
- * Calls the appropriate method on the given visitor, depending on the
- * class of this instance. Subclasses must override this.
- *
- * @param visitor {@code non-null;} the visitor to call on
- */
- public abstract void accept(Visitor visitor);
-
- /**
- * Returns an instance that is just like this one, except that it
- * has a catch list with the given item appended to the end. This
- * method throws an exception if this instance can't possibly
- * throw. To determine whether this instruction can throw, use
- * {@link #canThrow}.
- *
- * @param type {@code non-null;} type to append to the catch list
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract Insn withAddedCatch(Type type);
-
- /**
- * Returns an instance that is just like this one, except that all
- * register references have been offset by the given delta.
- *
- * @param delta the amount to offset register references by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract Insn withRegisterOffset(int delta);
-
- /**
- * Returns an instance that is just like this one, except that, if
- * possible, the insn is converted into a version in which a source
- * (if it is a constant) is represented directly rather than as a
- * register reference. {@code this} is returned in cases where the
- * translation is not possible.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public Insn withSourceLiteral() {
- return this;
- }
-
- /**
- * Returns an exact copy of this Insn
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public Insn copy() {
- return withRegisterOffset(0);
- }
-
-
- /**
- * Compares, handling nulls safely
- *
- * @param a first object
- * @param b second object
- * @return true if they're equal or both null.
- */
- private static boolean equalsHandleNulls (Object a, Object b) {
- return (a == b) || ((a != null) && a.equals(b));
- }
-
- /**
- * Compares Insn contents, since {@code Insn.equals()} is defined
- * to be an identity compare. Insn's are {@code contentEquals()}
- * if they have the same opcode, registers, source position, and other
- * metadata.
- *
- * @return true in the case described above
- */
- public boolean contentEquals(Insn b) {
- return opcode == b.getOpcode()
- && position.equals(b.getPosition())
- && (getClass() == b.getClass())
- && equalsHandleNulls(result, b.getResult())
- && equalsHandleNulls(sources, b.getSources())
- && StdTypeList.equalContents(getCatches(), b.getCatches());
- }
-
- /**
- * Returns an instance that is just like this one, except
- * with new result and source registers.
- *
- * @param result {@code null-ok;} new result register
- * @param sources {@code non-null;} new sources registers
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public abstract Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources);
-
- /**
- * Returns the string form of this instance, with the given bit added in
- * the standard location for an inline argument.
- *
- * @param extra {@code null-ok;} the inline argument string
- * @return {@code non-null;} the string form
- */
- protected final String toStringWithInline(String extra) {
- StringBuffer sb = new StringBuffer(80);
-
- sb.append("Insn{");
- sb.append(position);
- sb.append(' ');
- sb.append(opcode);
-
- if (extra != null) {
- sb.append(' ');
- sb.append(extra);
- }
-
- sb.append(" :: ");
-
- if (result != null) {
- sb.append(result);
- sb.append(" <- ");
- }
-
- sb.append(sources);
- sb.append('}');
-
- return sb.toString();
- }
-
- /**
- * Returns the human string form of this instance, with the given
- * bit added in the standard location for an inline argument.
- *
- * @param extra {@code null-ok;} the inline argument string
- * @return {@code non-null;} the human string form
- */
- protected final String toHumanWithInline(String extra) {
- StringBuffer sb = new StringBuffer(80);
-
- sb.append(position);
- sb.append(": ");
- sb.append(opcode.getNickname());
-
- if (extra != null) {
- sb.append("(");
- sb.append(extra);
- sb.append(")");
- }
-
- if (result == null) {
- sb.append(" .");
- } else {
- sb.append(" ");
- sb.append(result.toHuman());
- }
-
- sb.append(" <-");
-
- int sz = sources.size();
- if (sz == 0) {
- sb.append(" .");
- } else {
- for (int i = 0; i < sz; i++) {
- sb.append(" ");
- sb.append(sources.get(i).toHuman());
- }
- }
-
- return sb.toString();
- }
-
-
- /**
- * Visitor interface for this (outer) class.
- */
- public static interface Visitor {
- /**
- * Visits a {@link PlainInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitPlainInsn(PlainInsn insn);
-
- /**
- * Visits a {@link PlainCstInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitPlainCstInsn(PlainCstInsn insn);
-
- /**
- * Visits a {@link SwitchInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitSwitchInsn(SwitchInsn insn);
-
- /**
- * Visits a {@link ThrowingCstInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitThrowingCstInsn(ThrowingCstInsn insn);
-
- /**
- * Visits a {@link ThrowingInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitThrowingInsn(ThrowingInsn insn);
-
- /**
- * Visits a {@link FillArrayDataInsn}.
- *
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitFillArrayDataInsn(FillArrayDataInsn insn);
- }
-
- /**
- * Base implementation of {@link Visitor}, which has empty method
- * bodies for all methods.
- */
- public static class BaseVisitor implements Visitor {
- /** {@inheritDoc} */
- public void visitPlainInsn(PlainInsn insn) {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- public void visitPlainCstInsn(PlainCstInsn insn) {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- public void visitSwitchInsn(SwitchInsn insn) {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- public void visitThrowingCstInsn(ThrowingCstInsn insn) {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- public void visitThrowingInsn(ThrowingInsn insn) {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
- // This space intentionally left blank.
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/InsnList.java b/dx/src/com/android/jack/dx/rop/code/InsnList.java
index fb78741..0d55c67 100644
--- a/dx/src/com/android/jack/dx/rop/code/InsnList.java
+++ b/dx/src/com/android/jack/dx/rop/code/InsnList.java
@@ -21,110 +21,113 @@
/**
* List of {@link Insn} instances.
*/
-public final class InsnList
- extends FixedSizeList {
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public InsnList(int size) {
- super(size);
+public final class InsnList extends FixedSizeList {
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public InsnList(int size) {
+ super(size);
+ }
+
+ /**
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
+ */
+ public Insn get(int n) {
+ return (Insn) get0(n);
+ }
+
+ /**
+ * Sets the instruction at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param insn {@code non-null;} the instruction to set at {@code n}
+ */
+ public void set(int n, Insn insn) {
+ set0(n, insn);
+ }
+
+ /**
+ * Gets the last instruction. This is just a convenient shorthand for
+ * {@code get(size() - 1)}.
+ *
+ * @return {@code non-null;} the last instruction
+ */
+ public Insn getLast() {
+ return get(size() - 1);
+ }
+
+ /**
+ * Visits each instruction in the list, in order.
+ *
+ * @param visitor {@code non-null;} visitor to use
+ */
+ public void forEach(Insn.Visitor visitor) {
+ int sz = size();
+
+ for (int i = 0; i < sz; i++) {
+ get(i).accept(visitor);
+ }
+ }
+
+ /**
+ * Compares the contents of this {@code InsnList} with another.
+ * The blocks must have the same number of insns, and each Insn must
+ * also return true to {@code Insn.contentEquals()}.
+ *
+ * @param b to compare
+ * @return true in the case described above.
+ */
+ public boolean contentEquals(InsnList b) {
+ if (b == null) {
+ return false;
}
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public Insn get(int n) {
- return (Insn) get0(n);
+ int sz = size();
+
+ if (sz != b.size()) {
+ return false;
}
- /**
- * Sets the instruction at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param insn {@code non-null;} the instruction to set at {@code n}
- */
- public void set(int n, Insn insn) {
- set0(n, insn);
+ for (int i = 0; i < sz; i++) {
+ if (!get(i).contentEquals(b.get(i))) {
+ return false;
+ }
}
- /**
- * Gets the last instruction. This is just a convenient shorthand for
- * {@code get(size() - 1)}.
- *
- * @return {@code non-null;} the last instruction
- */
- public Insn getLast() {
- return get(size() - 1);
+ return true;
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the registers in each instruction are offset by the given
+ * amount. Mutability of the result is inherited from the
+ * original.
+ *
+ * @param delta the amount to offset register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public InsnList withRegisterOffset(int delta) {
+ int sz = size();
+ InsnList result = new InsnList(sz);
+
+ for (int i = 0; i < sz; i++) {
+ Insn one = (Insn) get0(i);
+ if (one != null) {
+ result.set0(i, one.withRegisterOffset(delta));
+ }
}
- /**
- * Visits each instruction in the list, in order.
- *
- * @param visitor {@code non-null;} visitor to use
- */
- public void forEach(Insn.Visitor visitor) {
- int sz = size();
-
- for (int i = 0; i < sz; i++) {
- get(i).accept(visitor);
- }
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Compares the contents of this {@code InsnList} with another.
- * The blocks must have the same number of insns, and each Insn must
- * also return true to {@code Insn.contentEquals()}.
- *
- * @param b to compare
- * @return true in the case described above.
- */
- public boolean contentEquals(InsnList b) {
- if (b == null) return false;
-
- int sz = size();
-
- if (sz != b.size()) return false;
-
- for (int i = 0; i < sz; i++) {
- if (!get(i).contentEquals(b.get(i))) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * the registers in each instruction are offset by the given
- * amount. Mutability of the result is inherited from the
- * original.
- *
- * @param delta the amount to offset register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public InsnList withRegisterOffset(int delta) {
- int sz = size();
- InsnList result = new InsnList(sz);
-
- for (int i = 0; i < sz; i++) {
- Insn one = (Insn) get0(i);
- if (one != null) {
- result.set0(i, one.withRegisterOffset(delta));
- }
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
- }
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/LocalItem.java b/dx/src/com/android/jack/dx/rop/code/LocalItem.java
index fd9c952..9ebf093 100644
--- a/dx/src/com/android/jack/dx/rop/code/LocalItem.java
+++ b/dx/src/com/android/jack/dx/rop/code/LocalItem.java
@@ -23,35 +23,35 @@
* A local variable item: either a name or a signature or both.
*/
public class LocalItem implements Comparable<LocalItem> {
- /** {@code null-ok;} local variable name */
- private final CstString name;
+ /** {@code null-ok;} local variable name */
+ private final CstString name;
- /** {@code null-ok;} local variable type */
- private final CstType type;
+ /** {@code null-ok;} local variable type */
+ private final CstType type;
- /** {@code null-ok;} local variable signature */
- private final CstString signature;
+ /** {@code null-ok;} local variable signature */
+ private final CstString signature;
- /**
- * Make a new item. If both name and type are null, null is returned.
- *
- * TODO: intern these
- *
- * @param name {@code null-ok;} local variable name
- * @param type {@code null-ok;} local variable type
- * @param signature {@code null-ok;} local variable signature which will be referenced as-is by
- * the sig_idx in the debug_info_item (cf. the documentation for debug_info_item and the
- * discussion under {@code dalvik.annotation.Signature} in "dex-format.html")
- * @return {@code null-ok;} appropriate instance.
- */
- public static LocalItem make(CstString name, CstType type, CstString signature) {
- if (name == null && type == null) {
- return null;
- }
-
- return new LocalItem (name, type, signature);
+ /**
+ * Make a new item. If both name and type are null, null is returned.
+ *
+ * TODO(dx team): intern these
+ *
+ * @param name {@code null-ok;} local variable name
+ * @param type {@code null-ok;} local variable type
+ * @param signature {@code null-ok;} local variable signature which will be referenced as-is by
+ * the sig_idx in the debug_info_item (cf. the documentation for debug_info_item and the
+ * discussion under {@code dalvik.annotation.Signature} in "dex-format.html")
+ * @return {@code null-ok;} appropriate instance.
+ */
+ public static LocalItem make(CstString name, CstType type, CstString signature) {
+ if (name == null && type == null) {
+ return null;
}
+ return new LocalItem(name, type, signature);
+ }
+
/**
* Constructs instance.
*
@@ -59,131 +59,131 @@
* @param type {@code null-ok;} local variable type
* @param signature {@code null-ok;} local variable signature
*/
- private LocalItem(CstString name, CstType type, CstString signature) {
- this.name = name;
- this.type = type;
- this.signature = signature;
+ private LocalItem(CstString name, CstType type, CstString signature) {
+ this.name = name;
+ this.type = type;
+ this.signature = signature;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof LocalItem)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof LocalItem)) {
- return false;
- }
+ LocalItem local = (LocalItem) other;
- LocalItem local = (LocalItem) other;
+ return 0 == compareTo(local);
+ }
- return 0 == compareTo(local);
+ /**
+ * Compares two strings like String.compareTo(), excepts treats a null
+ * as the least-possible string value.
+ *
+ * @return negative integer, zero, or positive integer in accordance
+ * with Comparable.compareTo()
+ */
+ private static int compareHandlesNulls(CstString a, CstString b) {
+ if (a == b) {
+ return 0;
+ } else if (a == null) {
+ return -1;
+ } else if (b == null) {
+ return 1;
+ } else {
+ return a.compareTo(b);
+ }
+ }
+
+ /**
+ * Compares two CstType like CstType.compareTo(), excepts treats a null
+ * as the least-possible string value.
+ *
+ * @return negative integer, zero, or positive integer in accordance
+ * with Comparable.compareTo()
+ */
+ private static int compareHandlesNulls(CstType a, CstType b) {
+ if (a == b) {
+ return 0;
+ } else if (a == null) {
+ return -1;
+ } else if (b == null) {
+ return 1;
+ } else {
+ return a.compareTo(b);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(LocalItem local) {
+ int ret;
+
+ ret = compareHandlesNulls(name, local.name);
+
+ if (ret != 0) {
+ return ret;
}
- /**
- * Compares two strings like String.compareTo(), excepts treats a null
- * as the least-possible string value.
- *
- * @return negative integer, zero, or positive integer in accordance
- * with Comparable.compareTo()
- */
- private static int compareHandlesNulls(CstString a, CstString b) {
- if (a == b) {
- return 0;
- } else if (a == null) {
- return -1;
- } else if (b == null) {
- return 1;
- } else {
- return a.compareTo(b);
- }
+ ret = compareHandlesNulls(type, local.type);
+
+ if (ret != 0) {
+ return ret;
}
- /**
- * Compares two CstType like CstType.compareTo(), excepts treats a null
- * as the least-possible string value.
- *
- * @return negative integer, zero, or positive integer in accordance
- * with Comparable.compareTo()
- */
- private static int compareHandlesNulls(CstType a, CstType b) {
- if (a == b) {
- return 0;
- } else if (a == null) {
- return -1;
- } else if (b == null) {
- return 1;
- } else {
- return a.compareTo(b);
- }
+ ret = compareHandlesNulls(signature, local.signature);
+
+ return ret;
+ }
+
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return (name == null ? 0 : name.hashCode()) * 31 + (type == null ? 0 : type.hashCode())
+ + (signature == null ? 0 : signature.hashCode()) * 17;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ if (name != null && type == null && signature == null) {
+ return name.toQuoted();
+ } else if (name == null && type == null && signature == null) {
+ return "";
}
- /** {@inheritDoc} */
- public int compareTo(LocalItem local) {
- int ret;
+ return "[" + (name == null ? "" : name.toQuoted()) + "|"
+ + (type == null ? "" : type.getDescriptor().toQuoted()) + "|"
+ + (signature == null ? "" : signature.toQuoted());
+ }
- ret = compareHandlesNulls(name, local.name);
+ /**
+ * Gets name.
+ *
+ * @return {@code null-ok;} name
+ */
+ public CstString getName() {
+ return name;
+ }
- if (ret != 0) {
- return ret;
- }
+ /**
+ * Gets the signature that must be represented to successfully implement the source language's
+ * semantics (cf. the discussion under {@code dalvik.annotation.Signature} in "dex-format.html")
+ *
+ * @return signature
+ */
+ public CstString getSignature() {
+ return signature;
+ }
- ret = compareHandlesNulls(type, local.type);
-
- if (ret != 0) {
- return ret;
- }
-
- ret = compareHandlesNulls(signature, local.signature);
-
- return ret;
- }
-
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return (name == null ? 0 : name.hashCode()) * 31
- + (type == null ? 0 : type.hashCode())
- + (signature == null ? 0 : signature.hashCode()) * 17;
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- if (name != null && type == null && signature == null) {
- return name.toQuoted();
- } else if (name == null && type == null && signature == null) {
- return "";
- }
-
- return "[" + (name == null ? "" : name.toQuoted())
- + "|" + (type == null ? "" : type.getDescriptor().toQuoted())
- + "|" + (signature == null ? "" : signature.toQuoted());
- }
-
- /**
- * Gets name.
- *
- * @return {@code null-ok;} name
- */
- public CstString getName() {
- return name;
- }
-
- /**
- * Gets the signature that must be represented to successfully implement the source language's
- * semantics (cf. the discussion under {@code dalvik.annotation.Signature} in "dex-format.html")
- *
- * @return signature
- */
- public CstString getSignature() {
- return signature;
- }
-
- /**
- * Gets type.
- *
- * @return {@code null-ok;} type.
- */
- public CstType getType() {
- return type;
- }
+ /**
+ * Gets type.
+ *
+ * @return {@code null-ok;} type.
+ */
+ public CstType getType() {
+ return type;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/LocalVariableExtractor.java b/dx/src/com/android/jack/dx/rop/code/LocalVariableExtractor.java
index 6420d38..739150c 100644
--- a/dx/src/com/android/jack/dx/rop/code/LocalVariableExtractor.java
+++ b/dx/src/com/android/jack/dx/rop/code/LocalVariableExtractor.java
@@ -24,168 +24,162 @@
* a method.
*/
public final class LocalVariableExtractor {
- /** {@code non-null;} method being extracted from */
- private final RopMethod method;
+ /** {@code non-null;} method being extracted from */
+ private final RopMethod method;
- /** {@code non-null;} block list for the method */
- private final BasicBlockList blocks;
+ /** {@code non-null;} block list for the method */
+ private final BasicBlockList blocks;
- /** {@code non-null;} result in-progress */
- private final LocalVariableInfo resultInfo;
+ /** {@code non-null;} result in-progress */
+ private final LocalVariableInfo resultInfo;
- /** {@code non-null;} work set indicating blocks needing to be processed */
- private final int[] workSet;
+ /** {@code non-null;} work set indicating blocks needing to be processed */
+ private final int[] workSet;
- /**
- * Extracts out all the local variable information from the given method.
- *
- * @param method {@code non-null;} the method to extract from
- * @return {@code non-null;} the extracted information
- */
- public static LocalVariableInfo extract(RopMethod method) {
- LocalVariableExtractor lve = new LocalVariableExtractor(method);
- return lve.doit();
+ /**
+ * Extracts out all the local variable information from the given method.
+ *
+ * @param method {@code non-null;} the method to extract from
+ * @return {@code non-null;} the extracted information
+ */
+ public static LocalVariableInfo extract(RopMethod method) {
+ LocalVariableExtractor lve = new LocalVariableExtractor(method);
+ return lve.doit();
+ }
+
+ /**
+ * Constructs an instance. This method is private. Use {@link #extract}.
+ *
+ * @param method {@code non-null;} the method to extract from
+ */
+ private LocalVariableExtractor(RopMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /**
- * Constructs an instance. This method is private. Use {@link #extract}.
- *
- * @param method {@code non-null;} the method to extract from
- */
- private LocalVariableExtractor(RopMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
+ BasicBlockList blocks = method.getBlocks();
+ int maxLabel = blocks.getMaxLabel();
- BasicBlockList blocks = method.getBlocks();
- int maxLabel = blocks.getMaxLabel();
+ this.method = method;
+ this.blocks = blocks;
+ this.resultInfo = new LocalVariableInfo(method);
+ this.workSet = Bits.makeBitSet(maxLabel);
+ }
- this.method = method;
- this.blocks = blocks;
- this.resultInfo = new LocalVariableInfo(method);
- this.workSet = Bits.makeBitSet(maxLabel);
+ /**
+ * Does the extraction.
+ *
+ * @return {@code non-null;} the extracted information
+ */
+ private LocalVariableInfo doit() {
+ for (int label = method.getFirstLabel(); label >= 0; label = Bits.findFirst(workSet, 0)) {
+ Bits.clear(workSet, label);
+ processBlock(label);
}
- /**
- * Does the extraction.
- *
- * @return {@code non-null;} the extracted information
+ resultInfo.setImmutable();
+ return resultInfo;
+ }
+
+ /**
+ * Processes a single block.
+ *
+ * @param label {@code >= 0;} label of the block to process
+ */
+ private void processBlock(int label) {
+ RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
+ BasicBlock block = blocks.labelToBlock(label);
+ InsnList insns = block.getInsns();
+ int insnSz = insns.size();
+
+ /*
+ * We may have to treat the last instruction specially: If it
+ * can (but doesn't always) throw, and the exception can be
+ * caught within the same method, then we need to use the
+ * state *before* executing it to be what is merged into
+ * exception targets.
*/
- private LocalVariableInfo doit() {
- for (int label = method.getFirstLabel();
- label >= 0;
- label = Bits.findFirst(workSet, 0)) {
- Bits.clear(workSet, label);
- processBlock(label);
- }
+ boolean canThrowDuringLastInsn =
+ block.hasExceptionHandlers() && (insns.getLast().getResult() != null);
+ int freezeSecondaryStateAt = insnSz - 1;
+ RegisterSpecSet secondaryState = primaryState;
- resultInfo.setImmutable();
- return resultInfo;
- }
-
- /**
- * Processes a single block.
- *
- * @param label {@code >= 0;} label of the block to process
+ /*
+ * Iterate over the instructions, adding information for each place
+ * that the active variable set changes.
*/
- private void processBlock(int label) {
- RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
- BasicBlock block = blocks.labelToBlock(label);
- InsnList insns = block.getInsns();
- int insnSz = insns.size();
- /*
- * We may have to treat the last instruction specially: If it
- * can (but doesn't always) throw, and the exception can be
- * caught within the same method, then we need to use the
- * state *before* executing it to be what is merged into
- * exception targets.
- */
- boolean canThrowDuringLastInsn = block.hasExceptionHandlers() &&
- (insns.getLast().getResult() != null);
- int freezeSecondaryStateAt = insnSz - 1;
- RegisterSpecSet secondaryState = primaryState;
-
- /*
- * Iterate over the instructions, adding information for each place
- * that the active variable set changes.
- */
-
- for (int i = 0; i < insnSz; i++) {
- if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
- // Until this point, primaryState == secondaryState.
- primaryState.setImmutable();
- primaryState = primaryState.mutableCopy();
- }
-
- Insn insn = insns.get(i);
- RegisterSpec result;
-
- result = insn.getLocalAssignment();
-
- if (result == null) {
- /*
- * If an assignment assigns over an existing local, make
- * sure to mark the local as going out of scope.
- */
-
- result = insn.getResult();
-
- if (result != null
- && primaryState.get(result.getReg()) != null) {
- primaryState.remove(primaryState.get(result.getReg()));
- }
- continue;
- }
-
- result = result.withSimpleType();
-
- RegisterSpec already = primaryState.get(result);
- /*
- * The equals() check ensures we only add new info if
- * the instruction causes a change to the set of
- * active variables.
- */
- if (!result.equals(already)) {
- /*
- * If this insn represents a local moving from one register
- * to another, remove the association between the old register
- * and the local.
- */
- RegisterSpec previous
- = primaryState.localItemToSpec(result.getLocalItem());
-
- if (previous != null
- && (previous.getReg() != result.getReg())) {
-
- primaryState.remove(previous);
- }
-
- resultInfo.addAssignment(insn, result);
- primaryState.put(result);
- }
- }
-
+for (int i = 0; i < insnSz; i++) {
+ if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
+ // Until this point, primaryState == secondaryState.
primaryState.setImmutable();
+ primaryState = primaryState.mutableCopy();
+ }
+ Insn insn = insns.get(i);
+ RegisterSpec result;
+
+ result = insn.getLocalAssignment();
+
+ if (result == null) {
/*
- * Merge this state into the start state for each successor,
- * and update the work set where required (that is, in cases
- * where the start state for a block changes).
+ * If an assignment assigns over an existing local, make
+ * sure to mark the local as going out of scope.
*/
- IntList successors = block.getSuccessors();
- int succSz = successors.size();
- int primarySuccessor = block.getPrimarySuccessor();
+result = insn.getResult();
- for (int i = 0; i < succSz; i++) {
- int succ = successors.get(i);
- RegisterSpecSet state = (succ == primarySuccessor) ?
- primaryState : secondaryState;
-
- if (resultInfo.mergeStarts(succ, state)) {
- Bits.set(workSet, succ);
- }
+ if (result != null && primaryState.get(result.getReg()) != null) {
+ primaryState.remove(primaryState.get(result.getReg()));
}
+ continue;
+ }
+
+ result = result.withSimpleType();
+
+ RegisterSpec already = primaryState.get(result);
+ /*
+ * The equals() check ensures we only add new info if
+ * the instruction causes a change to the set of
+ * active variables.
+ */
+ if (!result.equals(already)) {
+ /*
+ * If this insn represents a local moving from one register
+ * to another, remove the association between the old register
+ * and the local.
+ */
+ RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem());
+
+ if (previous != null && (previous.getReg() != result.getReg())) {
+
+ primaryState.remove(previous);
+ }
+
+ resultInfo.addAssignment(insn, result);
+ primaryState.put(result);
+ }
}
+
+ primaryState.setImmutable();
+
+ /*
+ * Merge this state into the start state for each successor,
+ * and update the work set where required (that is, in cases
+ * where the start state for a block changes).
+ */
+
+IntList successors = block.getSuccessors();
+ int succSz = successors.size();
+ int primarySuccessor = block.getPrimarySuccessor();
+
+ for (int i = 0; i < succSz; i++) {
+ int succ = successors.get(i);
+ RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState;
+
+ if (resultInfo.mergeStarts(succ, state)) {
+ Bits.set(workSet, succ);
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/LocalVariableInfo.java b/dx/src/com/android/jack/dx/rop/code/LocalVariableInfo.java
index a15402f..f476154 100644
--- a/dx/src/com/android/jack/dx/rop/code/LocalVariableInfo.java
+++ b/dx/src/com/android/jack/dx/rop/code/LocalVariableInfo.java
@@ -16,7 +16,6 @@
package com.android.jack.dx.rop.code;
-import com.android.jack.dx.rop.type.TypeBearer;
import com.android.jack.dx.util.MutabilityControl;
import java.util.HashMap;
@@ -25,230 +24,226 @@
* Container for local variable information for a particular {@link
* RopMethod}.
*/
-public final class LocalVariableInfo
- extends MutabilityControl {
- /** {@code >= 0;} the register count for the method */
- private final int regCount;
+public final class LocalVariableInfo extends MutabilityControl {
+ /** {@code >= 0;} the register count for the method */
+ private final int regCount;
- /**
- * {@code non-null;} {@link RegisterSpecSet} to use when indicating a block
- * that has no locals; it is empty and immutable but has an appropriate
- * max size for the method
- */
- private final RegisterSpecSet emptySet;
+ /**
+ * {@code non-null;} {@link RegisterSpecSet} to use when indicating a block
+ * that has no locals; it is empty and immutable but has an appropriate
+ * max size for the method
+ */
+ private final RegisterSpecSet emptySet;
- /**
- * {@code non-null;} array consisting of register sets representing the
- * sets of variables already assigned upon entry to each block,
- * where array indices correspond to block labels
- */
- private final RegisterSpecSet[] blockStarts;
+ /**
+ * {@code non-null;} array consisting of register sets representing the
+ * sets of variables already assigned upon entry to each block,
+ * where array indices correspond to block labels
+ */
+ private final RegisterSpecSet[] blockStarts;
- /** {@code non-null;} map from instructions to the variable each assigns */
- private final HashMap<Insn, RegisterSpec> insnAssignments;
+ /** {@code non-null;} map from instructions to the variable each assigns */
+ private final HashMap<Insn, RegisterSpec> insnAssignments;
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the method being represented by this instance
- */
- public LocalVariableInfo(RopMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- BasicBlockList blocks = method.getBlocks();
- int maxLabel = blocks.getMaxLabel();
-
- this.regCount = blocks.getRegCount();
- this.emptySet = new RegisterSpecSet(regCount);
- this.blockStarts = new RegisterSpecSet[maxLabel];
- this.insnAssignments =
- new HashMap<Insn, RegisterSpec>(blocks.getInstructionCount());
-
- emptySet.setImmutable();
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the method being represented by this instance
+ */
+ public LocalVariableInfo(RopMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /**
- * Sets the register set associated with the start of the block with
- * the given label.
- *
- * @param label {@code >= 0;} the block label
- * @param specs {@code non-null;} the register set to associate with the block
- */
- public void setStarts(int label, RegisterSpecSet specs) {
- throwIfImmutable();
+ BasicBlockList blocks = method.getBlocks();
+ int maxLabel = blocks.getMaxLabel();
- if (specs == null) {
- throw new NullPointerException("specs == null");
- }
+ this.regCount = blocks.getRegCount();
+ this.emptySet = new RegisterSpecSet(regCount);
+ this.blockStarts = new RegisterSpecSet[maxLabel];
+ this.insnAssignments = new HashMap<Insn, RegisterSpec>(blocks.getInstructionCount());
- try {
- blockStarts[label] = specs;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus label");
- }
+ emptySet.setImmutable();
+ }
+
+ /**
+ * Sets the register set associated with the start of the block with
+ * the given label.
+ *
+ * @param label {@code >= 0;} the block label
+ * @param specs {@code non-null;} the register set to associate with the block
+ */
+ public void setStarts(int label, RegisterSpecSet specs) {
+ throwIfImmutable();
+
+ if (specs == null) {
+ throw new NullPointerException("specs == null");
}
- /**
- * Merges the given register set into the set for the block with the
- * given label. If there was not already an associated set, then this
- * is the same as calling {@link #setStarts}. Otherwise, this will
- * merge the two sets and call {@link #setStarts} on the result of the
- * merge.
- *
- * @param label {@code >= 0;} the block label
- * @param specs {@code non-null;} the register set to merge into the start set
- * for the block
- * @return {@code true} if the merge resulted in an actual change
- * to the associated set (including storing one for the first time) or
- * {@code false} if there was no change
- */
- public boolean mergeStarts(int label, RegisterSpecSet specs) {
- RegisterSpecSet start = getStarts0(label);
- boolean changed = false;
+ try {
+ blockStarts[label] = specs;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus label");
+ }
+ }
- if (start == null) {
- setStarts(label, specs);
- return true;
- }
+ /**
+ * Merges the given register set into the set for the block with the
+ * given label. If there was not already an associated set, then this
+ * is the same as calling {@link #setStarts}. Otherwise, this will
+ * merge the two sets and call {@link #setStarts} on the result of the
+ * merge.
+ *
+ * @param label {@code >= 0;} the block label
+ * @param specs {@code non-null;} the register set to merge into the start set
+ * for the block
+ * @return {@code true} if the merge resulted in an actual change
+ * to the associated set (including storing one for the first time) or
+ * {@code false} if there was no change
+ */
+ public boolean mergeStarts(int label, RegisterSpecSet specs) {
+ RegisterSpecSet start = getStarts0(label);
- RegisterSpecSet newStart = start.mutableCopy();
- if (start.size() != 0) {
- newStart.intersect(specs, true);
- } else {
- newStart = specs.mutableCopy();
- }
-
- if (start.equals(newStart)) {
- return false;
- }
-
- newStart.setImmutable();
- setStarts(label, newStart);
-
- return true;
+ if (start == null) {
+ setStarts(label, specs);
+ return true;
}
- /**
- * Gets the register set associated with the start of the block
- * with the given label. This returns an empty set with the appropriate
- * max size if no set was associated with the block in question.
- *
- * @param label {@code >= 0;} the block label
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet getStarts(int label) {
- RegisterSpecSet result = getStarts0(label);
-
- return (result != null) ? result : emptySet;
+ RegisterSpecSet newStart = start.mutableCopy();
+ if (start.size() != 0) {
+ newStart.intersect(specs, true);
+ } else {
+ newStart = specs.mutableCopy();
}
- /**
- * Gets the register set associated with the start of the given
- * block. This is just convenient shorthand for
- * {@code getStarts(block.getLabel())}.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet getStarts(BasicBlock block) {
- return getStarts(block.getLabel());
+ if (start.equals(newStart)) {
+ return false;
}
- /**
- * Gets a mutable copy of the register set associated with the
- * start of the block with the given label. This returns a
- * newly-allocated empty {@link RegisterSpecSet} of appropriate
- * max size if there is not yet any set associated with the block.
- *
- * @param label {@code >= 0;} the block label
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet mutableCopyOfStarts(int label) {
- RegisterSpecSet result = getStarts0(label);
+ newStart.setImmutable();
+ setStarts(label, newStart);
- return (result != null) ?
- result.mutableCopy() : new RegisterSpecSet(regCount);
+ return true;
+ }
+
+ /**
+ * Gets the register set associated with the start of the block
+ * with the given label. This returns an empty set with the appropriate
+ * max size if no set was associated with the block in question.
+ *
+ * @param label {@code >= 0;} the block label
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet getStarts(int label) {
+ RegisterSpecSet result = getStarts0(label);
+
+ return (result != null) ? result : emptySet;
+ }
+
+ /**
+ * Gets the register set associated with the start of the given
+ * block. This is just convenient shorthand for
+ * {@code getStarts(block.getLabel())}.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet getStarts(BasicBlock block) {
+ return getStarts(block.getLabel());
+ }
+
+ /**
+ * Gets a mutable copy of the register set associated with the
+ * start of the block with the given label. This returns a
+ * newly-allocated empty {@link RegisterSpecSet} of appropriate
+ * max size if there is not yet any set associated with the block.
+ *
+ * @param label {@code >= 0;} the block label
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet mutableCopyOfStarts(int label) {
+ RegisterSpecSet result = getStarts0(label);
+
+ return (result != null) ? result.mutableCopy() : new RegisterSpecSet(regCount);
+ }
+
+ /**
+ * Adds an assignment association for the given instruction and
+ * register spec. This throws an exception if the instruction
+ * doesn't actually perform a named variable assignment.
+ *
+ * <b>Note:</b> Although the instruction contains its own spec for
+ * the result, it still needs to be passed in explicitly to this
+ * method, since the spec that is stored here should always have a
+ * simple type and the one in the instruction can be an arbitrary
+ * {@link TypeBearer} (such as a constant value).
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @param spec {@code non-null;} the associated register spec
+ */
+ public void addAssignment(Insn insn, RegisterSpec spec) {
+ throwIfImmutable();
+
+ if (insn == null) {
+ throw new NullPointerException("insn == null");
}
- /**
- * Adds an assignment association for the given instruction and
- * register spec. This throws an exception if the instruction
- * doesn't actually perform a named variable assignment.
- *
- * <b>Note:</b> Although the instruction contains its own spec for
- * the result, it still needs to be passed in explicitly to this
- * method, since the spec that is stored here should always have a
- * simple type and the one in the instruction can be an arbitrary
- * {@link TypeBearer} (such as a constant value).
- *
- * @param insn {@code non-null;} the instruction in question
- * @param spec {@code non-null;} the associated register spec
- */
- public void addAssignment(Insn insn, RegisterSpec spec) {
- throwIfImmutable();
-
- if (insn == null) {
- throw new NullPointerException("insn == null");
- }
-
- if (spec == null) {
- throw new NullPointerException("spec == null");
- }
-
- insnAssignments.put(insn, spec);
+ if (spec == null) {
+ throw new NullPointerException("spec == null");
}
- /**
- * Gets the named register being assigned by the given instruction, if
- * previously stored in this instance.
- *
- * @param insn {@code non-null;} instruction in question
- * @return {@code null-ok;} the named register being assigned, if any
- */
- public RegisterSpec getAssignment(Insn insn) {
- return insnAssignments.get(insn);
- }
+ insnAssignments.put(insn, spec);
+ }
- /**
- * Gets the number of assignments recorded by this instance.
- *
- * @return {@code >= 0;} the number of assignments
- */
- public int getAssignmentCount() {
- return insnAssignments.size();
- }
+ /**
+ * Gets the named register being assigned by the given instruction, if
+ * previously stored in this instance.
+ *
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code null-ok;} the named register being assigned, if any
+ */
+ public RegisterSpec getAssignment(Insn insn) {
+ return insnAssignments.get(insn);
+ }
- public void debugDump() {
- for (int label = 0 ; label < blockStarts.length; label++) {
- if (blockStarts[label] == null) {
- continue;
- }
+ /**
+ * Gets the number of assignments recorded by this instance.
+ *
+ * @return {@code >= 0;} the number of assignments
+ */
+ public int getAssignmentCount() {
+ return insnAssignments.size();
+ }
- if (blockStarts[label] == emptySet) {
- System.out.printf("%04x: empty set\n", label);
- } else {
- System.out.printf("%04x: %s\n", label, blockStarts[label]);
- }
- }
- }
+ public void debugDump() {
+ for (int label = 0; label < blockStarts.length; label++) {
+ if (blockStarts[label] == null) {
+ continue;
+ }
- /**
- * Helper method, to get the starts for a label, throwing the
- * right exception for range problems.
- *
- * @param label {@code >= 0;} the block label
- * @return {@code null-ok;} associated register set or {@code null} if there
- * is none
- */
- private RegisterSpecSet getStarts0(int label) {
- try {
- return blockStarts[label];
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus label");
- }
+ if (blockStarts[label] == emptySet) {
+ System.out.printf("%04x: empty set\n", label);
+ } else {
+ System.out.printf("%04x: %s\n", label, blockStarts[label]);
+ }
}
+ }
+
+ /**
+ * Helper method, to get the starts for a label, throwing the
+ * right exception for range problems.
+ *
+ * @param label {@code >= 0;} the block label
+ * @return {@code null-ok;} associated register set or {@code null} if there
+ * is none
+ */
+ private RegisterSpecSet getStarts0(int label) {
+ try {
+ return blockStarts[label];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus label");
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/PlainCstInsn.java b/dx/src/com/android/jack/dx/rop/code/PlainCstInsn.java
index 597b92d..2220d4a 100644
--- a/dx/src/com/android/jack/dx/rop/code/PlainCstInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/PlainCstInsn.java
@@ -25,63 +25,55 @@
* Instruction which contains an explicit reference to a constant
* but which cannot throw an exception.
*/
-public final class PlainCstInsn
- extends CstInsn {
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param sources {@code non-null;} specs for all the sources
- * @param cst {@code non-null;} the constant
- */
- public PlainCstInsn(Rop opcode, SourcePosition position,
- RegisterSpec result, RegisterSpecList sources,
- Constant cst) {
- super(opcode, position, result, sources, cst);
+public final class PlainCstInsn extends CstInsn {
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cst {@code non-null;} the constant
+ */
+ public PlainCstInsn(Rop opcode, SourcePosition position, RegisterSpec result,
+ RegisterSpecList sources, Constant cst) {
+ super(opcode, position, result, sources, cst);
- if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
- throw new IllegalArgumentException("bogus branchingness");
- }
+ if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+ throw new IllegalArgumentException("bogus branchingness");
}
+ }
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return StdTypeList.EMPTY;
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return StdTypeList.EMPTY;
+ }
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitPlainCstInsn(this);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitPlainCstInsn(this);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- throw new UnsupportedOperationException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ throw new UnsupportedOperationException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new PlainCstInsn(getOpcode(), getPosition(),
- getResult().withOffset(delta),
- getSources().withOffset(delta),
- getConstant());
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new PlainCstInsn(getOpcode(), getPosition(), getResult().withOffset(delta),
+ getSources().withOffset(delta), getConstant());
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
- return new PlainCstInsn(getOpcode(), getPosition(),
- result,
- sources,
- getConstant());
+ return new PlainCstInsn(getOpcode(), getPosition(), result, sources, getConstant());
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/PlainInsn.java b/dx/src/com/android/jack/dx/rop/code/PlainInsn.java
index a674537..3a31840 100644
--- a/dx/src/com/android/jack/dx/rop/code/PlainInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/PlainInsn.java
@@ -27,131 +27,121 @@
* Plain instruction, which has no embedded data and which cannot possibly
* throw an exception.
*/
-public final class PlainInsn
- extends Insn {
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param sources {@code non-null;} specs for all the sources
- */
- public PlainInsn(Rop opcode, SourcePosition position,
- RegisterSpec result, RegisterSpecList sources) {
- super(opcode, position, result, sources);
+public final class PlainInsn extends Insn {
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param sources {@code non-null;} specs for all the sources
+ */
+ public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
+ RegisterSpecList sources) {
+ super(opcode, position, result, sources);
- switch (opcode.getBranchingness()) {
- case Rop.BRANCH_SWITCH:
- case Rop.BRANCH_THROW: {
- throw new IllegalArgumentException("bogus branchingness");
- }
+ switch (opcode.getBranchingness()) {
+ case Rop.BRANCH_SWITCH:
+ case Rop.BRANCH_THROW: {
+ throw new IllegalArgumentException("bogus branchingness");
+ }
+ }
+
+ if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
+ // move-result-pseudo is required here
+ throw new IllegalArgumentException("can't mix branchingness with result");
+ }
+ }
+
+ /**
+ * Constructs a single-source instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param source {@code non-null;} spec for the source
+ */
+ public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result, RegisterSpec source) {
+ this(opcode, position, result, RegisterSpecList.make(source));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return StdTypeList.EMPTY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitPlainInsn(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ throw new UnsupportedOperationException("unsupported");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new PlainInsn(getOpcode(), getPosition(), getResult().withOffset(delta),
+ getSources().withOffset(delta));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn withSourceLiteral() {
+ RegisterSpecList sources = getSources();
+ int szSources = sources.size();
+
+ if (szSources == 0) {
+ return this;
+ }
+
+ TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
+
+ if (!lastType.isConstant()) {
+ // Check for reverse subtraction, where first source is constant
+ TypeBearer firstType = sources.get(0).getTypeBearer();
+ if (szSources == 2 && firstType.isConstant()) {
+ Constant cst = (Constant) firstType;
+ RegisterSpecList newSources = sources.withoutFirst();
+ Rop newRop = Rops.ropFor(getOpcode().getOpcode(), getResult(), newSources, cst);
+ return new PlainCstInsn(newRop, getPosition(), getResult(), newSources, cst);
+ }
+ return this;
+ } else {
+
+ Constant cst = (Constant) lastType;
+
+ RegisterSpecList newSources = sources.withoutLast();
+
+ Rop newRop;
+ try {
+ // Check for constant subtraction and flip it to be addition
+ int opcode = getOpcode().getOpcode();
+ if (opcode == RegOps.SUB && cst instanceof CstInteger) {
+ opcode = RegOps.ADD;
+ cst = CstInteger.make(-((CstInteger) cst).getValue());
}
+ newRop = Rops.ropFor(opcode, getResult(), newSources, cst);
+ } catch (IllegalArgumentException ex) {
+ // There's no rop for this case
+ return this;
+ }
- if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
- // move-result-pseudo is required here
- throw new IllegalArgumentException
- ("can't mix branchingness with result");
- }
+ return new PlainCstInsn(newRop, getPosition(), getResult(), newSources, cst);
}
-
- /**
- * Constructs a single-source instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param source {@code non-null;} spec for the source
- */
- public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
- RegisterSpec source) {
- this(opcode, position, result, RegisterSpecList.make(source));
- }
-
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return StdTypeList.EMPTY;
- }
-
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitPlainInsn(this);
- }
-
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- throw new UnsupportedOperationException("unsupported");
- }
-
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new PlainInsn(getOpcode(), getPosition(),
- getResult().withOffset(delta),
- getSources().withOffset(delta));
- }
-
- /** {@inheritDoc} */
- @Override
- public Insn withSourceLiteral() {
- RegisterSpecList sources = getSources();
- int szSources = sources.size();
-
- if (szSources == 0) {
- return this;
- }
-
- TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
-
- if (!lastType.isConstant()) {
- // Check for reverse subtraction, where first source is constant
- TypeBearer firstType = sources.get(0).getTypeBearer();
- if (szSources == 2 && firstType.isConstant()) {
- Constant cst = (Constant) firstType;
- RegisterSpecList newSources = sources.withoutFirst();
- Rop newRop = Rops.ropFor(getOpcode().getOpcode(), getResult(),
- newSources, cst);
- return new PlainCstInsn(newRop, getPosition(), getResult(),
- newSources, cst);
- }
- return this;
- } else {
-
- Constant cst = (Constant) lastType;
-
- RegisterSpecList newSources = sources.withoutLast();
-
- Rop newRop;
- try {
- // Check for constant subtraction and flip it to be addition
- int opcode = getOpcode().getOpcode();
- if (opcode == RegOps.SUB && cst instanceof CstInteger) {
- opcode = RegOps.ADD;
- cst = CstInteger.make(-((CstInteger)cst).getValue());
- }
- newRop = Rops.ropFor(opcode, getResult(), newSources, cst);
- } catch (IllegalArgumentException ex) {
- // There's no rop for this case
- return this;
- }
-
- return new PlainCstInsn(newRop, getPosition(),
- getResult(), newSources, cst);
- }
- }
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
- return new PlainInsn(getOpcode(), getPosition(),
- result,
- sources);
+ return new PlainInsn(getOpcode(), getPosition(), result, sources);
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/RegOps.java b/dx/src/com/android/jack/dx/rop/code/RegOps.java
index a863a89..4587a04 100644
--- a/dx/src/com/android/jack/dx/rop/code/RegOps.java
+++ b/dx/src/com/android/jack/dx/rop/code/RegOps.java
@@ -29,371 +29,427 @@
* each of the values.
*/
public final class RegOps {
- /** {@code nop()} */
- public static final int NOP = 1;
+ /** {@code nop()} */
+ public static final int NOP = 1;
- /** {@code T: any type; r,x: T :: r = x;} */
- public static final int MOVE = 2;
+ /** {@code T: any type; r,x: T :: r = x;} */
+ public static final int MOVE = 2;
- /** {@code T: any type; r,param(x): T :: r = param(x)} */
- public static final int MOVE_PARAM = 3;
+ /** {@code T: any type; r,param(x): T :: r = param(x)} */
+ public static final int MOVE_PARAM = 3;
- /**
- * {@code T: Throwable; r: T :: r = caught_exception}.
- * <b>Note:</b> This opcode should only ever be used in the
- * first instruction of a block, and such blocks must be
- * the start of an exception handler.
- */
- public static final int MOVE_EXCEPTION = 4;
+ /**
+ * {@code T: Throwable; r: T :: r = caught_exception}.
+ * <b>Note:</b> This opcode should only ever be used in the
+ * first instruction of a block, and such blocks must be
+ * the start of an exception handler.
+ */
+ public static final int MOVE_EXCEPTION = 4;
- /** {@code T: any type; r, literal: T :: r = literal;} */
- public static final int CONST = 5;
+ /** {@code T: any type; r, literal: T :: r = literal;} */
+ public static final int CONST = 5;
- /** {@code goto label} */
- public static final int GOTO = 6;
+ /** {@code goto label} */
+ public static final int GOTO = 6;
- /**
- * {@code T: int or Object; x,y: T :: if (x == y) goto
- * label}
- */
- public static final int IF_EQ = 7;
+ /**
+ * {@code T: int or Object; x,y: T :: if (x == y) goto
+ * label}
+ */
+ public static final int IF_EQ = 7;
- /**
- * {@code T: int or Object; x,y: T :: if (x != y) goto
- * label}
- */
- public static final int IF_NE = 8;
+ /**
+ * {@code T: int or Object; x,y: T :: if (x != y) goto
+ * label}
+ */
+ public static final int IF_NE = 8;
- /** {@code x,y: int :: if (x < y) goto label} */
- public static final int IF_LT = 9;
+ /** {@code x,y: int :: if (x < y) goto label} */
+ public static final int IF_LT = 9;
- /** {@code x,y: int :: if (x >= y) goto label} */
- public static final int IF_GE = 10;
+ /** {@code x,y: int :: if (x >= y) goto label} */
+ public static final int IF_GE = 10;
- /** {@code x,y: int :: if (x <= y) goto label} */
- public static final int IF_LE = 11;
+ /** {@code x,y: int :: if (x <= y) goto label} */
+ public static final int IF_LE = 11;
- /** {@code x,y: int :: if (x > y) goto label} */
- public static final int IF_GT = 12;
+ /** {@code x,y: int :: if (x > y) goto label} */
+ public static final int IF_GT = 12;
- /** {@code x: int :: goto table[x]} */
- public static final int SWITCH = 13;
+ /** {@code x: int :: goto table[x]} */
+ public static final int SWITCH = 13;
- /** {@code T: any numeric type; r,x,y: T :: r = x + y} */
- public static final int ADD = 14;
+ /** {@code T: any numeric type; r,x,y: T :: r = x + y} */
+ public static final int ADD = 14;
- /** {@code T: any numeric type; r,x,y: T :: r = x - y} */
- public static final int SUB = 15;
+ /** {@code T: any numeric type; r,x,y: T :: r = x - y} */
+ public static final int SUB = 15;
- /** {@code T: any numeric type; r,x,y: T :: r = x * y} */
- public static final int MUL = 16;
+ /** {@code T: any numeric type; r,x,y: T :: r = x * y} */
+ public static final int MUL = 16;
- /** {@code T: any numeric type; r,x,y: T :: r = x / y} */
- public static final int DIV = 17;
+ /** {@code T: any numeric type; r,x,y: T :: r = x / y} */
+ public static final int DIV = 17;
- /**
- * {@code T: any numeric type; r,x,y: T :: r = x % y}
- * (Java-style remainder)
- */
- public static final int REM = 18;
+ /**
+ * {@code T: any numeric type; r,x,y: T :: r = x % y}
+ * (Java-style remainder)
+ */
+ public static final int REM = 18;
- /** {@code T: any numeric type; r,x: T :: r = -x} */
- public static final int NEG = 19;
+ /** {@code T: any numeric type; r,x: T :: r = -x} */
+ public static final int NEG = 19;
- /** {@code T: any integral type; r,x,y: T :: r = x & y} */
- public static final int AND = 20;
+ /** {@code T: any integral type; r,x,y: T :: r = x & y} */
+ public static final int AND = 20;
- /** {@code T: any integral type; r,x,y: T :: r = x | y} */
- public static final int OR = 21;
+ /** {@code T: any integral type; r,x,y: T :: r = x | y} */
+ public static final int OR = 21;
- /** {@code T: any integral type; r,x,y: T :: r = x ^ y} */
- public static final int XOR = 22;
+ /** {@code T: any integral type; r,x,y: T :: r = x ^ y} */
+ public static final int XOR = 22;
- /**
- * {@code T: any integral type; r,x: T; y: int :: r = x << y}
- */
- public static final int SHL = 23;
+ /**
+ * {@code T: any integral type; r,x: T; y: int :: r = x << y}
+ */
+ public static final int SHL = 23;
- /**
- * {@code T: any integral type; r,x: T; y: int :: r = x >> y}
- * (signed right-shift)
- */
- public static final int SHR = 24;
+ /**
+ * {@code T: any integral type; r,x: T; y: int :: r = x >> y}
+ * (signed right-shift)
+ */
+ public static final int SHR = 24;
- /**
- * {@code T: any integral type; r,x: T; y: int :: r = x >>> y}
- * (unsigned right-shift)
- */
- public static final int USHR = 25;
+ /**
+ * {@code T: any integral type; r,x: T; y: int :: r = x >>> y}
+ * (unsigned right-shift)
+ */
+ public static final int USHR = 25;
- /** {@code T: any integral type; r,x: T :: r = ~x} */
- public static final int NOT = 26;
+ /** {@code T: any integral type; r,x: T :: r = ~x} */
+ public static final int NOT = 26;
- /**
- * {@code T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0
- * : (x > y) ? 1 : -1} (Java-style "cmpl" where a NaN is
- * considered "less than" all other values; also used for integral
- * comparisons)
- */
- public static final int CMPL = 27;
+ /**
+ * {@code T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0
+ * : (x > y) ? 1 : -1} (Java-style "cmpl" where a NaN is
+ * considered "less than" all other values; also used for integral
+ * comparisons)
+ */
+ public static final int CMPL = 27;
- /**
- * {@code T: any floating point type; r: int; x,y: T :: r = (x == y) ? 0
- * : (x < y) ? -1 : 1} (Java-style "cmpg" where a NaN is
- * considered "greater than" all other values)
- */
- public static final int CMPG = 28;
+ /**
+ * {@code T: any floating point type; r: int; x,y: T :: r = (x == y) ? 0
+ * : (x < y) ? -1 : 1} (Java-style "cmpg" where a NaN is
+ * considered "greater than" all other values)
+ */
+ public static final int CMPG = 28;
- /**
- * {@code T: any numeric type; U: any numeric type; r: T; x: U ::
- * r = (T) x} (numeric type conversion between the four
- * "real" numeric types)
- */
- public static final int CONV = 29;
+ /**
+ * {@code T: any numeric type; U: any numeric type; r: T; x: U ::
+ * r = (T) x} (numeric type conversion between the four
+ * "real" numeric types)
+ */
+ public static final int CONV = 29;
- /**
- * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
- * convert int to byte)
- */
- public static final int TO_BYTE = 30;
+ /**
+ * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
+ * convert int to byte)
+ */
+ public static final int TO_BYTE = 30;
- /**
- * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
- */
- public static final int TO_CHAR = 31;
+ /**
+ * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
+ */
+ public static final int TO_CHAR = 31;
- /**
- * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
- * convert int to short)
- */
- public static final int TO_SHORT = 32;
+ /**
+ * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
+ * convert int to short)
+ */
+ public static final int TO_SHORT = 32;
- /** {@code T: return type for the method; x: T; return x} */
- public static final int RETURN = 33;
+ /** {@code T: return type for the method; x: T; return x} */
+ public static final int RETURN = 33;
- /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
- public static final int ARRAY_LENGTH = 34;
+ /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
+ public static final int ARRAY_LENGTH = 34;
- /** {@code x: Throwable :: throw(x)} */
- public static final int THROW = 35;
+ /** {@code x: Throwable :: throw(x)} */
+ public static final int THROW = 35;
- /** {@code x: Object :: monitorenter(x)} */
- public static final int MONITOR_ENTER = 36;
+ /** {@code x: Object :: monitorenter(x)} */
+ public static final int MONITOR_ENTER = 36;
- /** {@code x: Object :: monitorexit(x)} */
- public static final int MONITOR_EXIT = 37;
+ /** {@code x: Object :: monitorexit(x)} */
+ public static final int MONITOR_EXIT = 37;
- /** {@code T: any type; r: T; x: T[]; y: int :: r = x[y]} */
- public static final int AGET = 38;
+ /** {@code T: any type; r: T; x: T[]; y: int :: r = x[y]} */
+ public static final int AGET = 38;
- /** {@code T: any type; x: T; y: T[]; z: int :: x[y] = z} */
- public static final int APUT = 39;
+ /** {@code T: any type; x: T; y: T[]; z: int :: x[y] = z} */
+ public static final int APUT = 39;
- /**
- * {@code T: any non-array object type :: r =
- * alloc(T)} (allocate heap space for an object)
- */
- public static final int NEW_INSTANCE = 40;
+ /**
+ * {@code T: any non-array object type :: r =
+ * alloc(T)} (allocate heap space for an object)
+ */
+ public static final int NEW_INSTANCE = 40;
- /** {@code T: any array type; r: T; x: int :: r = new T[x]} */
- public static final int NEW_ARRAY = 41;
+ /** {@code T: any array type; r: T; x: int :: r = new T[x]} */
+ public static final int NEW_ARRAY = 41;
- /**
- * {@code T: any array type; r: T; x: int; v0..vx: T :: r = new T[x]
- * {v0, ..., vx}}
- */
- public static final int FILLED_NEW_ARRAY = 42;
+ /**
+ * {@code T: any array type; r: T; x: int; v0..vx: T :: r = new T[x]
+ * {v0, ..., vx}}
+ */
+ public static final int FILLED_NEW_ARRAY = 42;
- /**
- * {@code T: any object type; x: Object :: (T) x} (can
- * throw {@code ClassCastException})
- */
- public static final int CHECK_CAST = 43;
+ /**
+ * {@code T: any object type; x: Object :: (T) x} (can
+ * throw {@code ClassCastException})
+ */
+ public static final int CHECK_CAST = 43;
- /**
- * {@code T: any object type; x: Object :: x instanceof T}
- */
- public static final int INSTANCE_OF = 44;
+ /**
+ * {@code T: any object type; x: Object :: x instanceof T}
+ */
+ public static final int INSTANCE_OF = 44;
- /**
- * {@code T: any type; r: T; x: Object; f: instance field spec of
- * type T :: r = x.f}
- */
- public static final int GET_FIELD = 45;
+ /**
+ * {@code T: any type; r: T; x: Object; f: instance field spec of
+ * type T :: r = x.f}
+ */
+ public static final int GET_FIELD = 45;
- /**
- * {@code T: any type; r: T; f: static field spec of type T :: r =
- * f}
- */
- public static final int GET_STATIC = 46;
+ /**
+ * {@code T: any type; r: T; f: static field spec of type T :: r =
+ * f}
+ */
+ public static final int GET_STATIC = 46;
- /**
- * {@code T: any type; x: T; y: Object; f: instance field spec of type
- * T :: y.f = x}
- */
- public static final int PUT_FIELD = 47;
+ /**
+ * {@code T: any type; x: T; y: Object; f: instance field spec of type
+ * T :: y.f = x}
+ */
+ public static final int PUT_FIELD = 47;
- /**
- * {@code T: any type; f: static field spec of type T; x: T :: f = x}
- */
- public static final int PUT_STATIC = 48;
+ /**
+ * {@code T: any type; f: static field spec of type T; x: T :: f = x}
+ */
+ public static final int PUT_STATIC = 48;
- /**
- * {@code Tr, T0, T1...: any types; r: Tr; m: static method spec;
- * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)} (call static
- * method)
- */
- public static final int INVOKE_STATIC = 49;
+ /**
+ * {@code Tr, T0, T1...: any types; r: Tr; m: static method spec;
+ * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)} (call static
+ * method)
+ */
+ public static final int INVOKE_STATIC = 49;
- /**
- * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
- * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call normal
- * virtual method)
- */
- public static final int INVOKE_VIRTUAL = 50;
+ /**
+ * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
+ * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call normal
+ * virtual method)
+ */
+ public static final int INVOKE_VIRTUAL = 50;
- /**
- * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
- * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
- * superclass virtual method)
- */
- public static final int INVOKE_SUPER = 51;
+ /**
+ * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
+ * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
+ * superclass virtual method)
+ */
+ public static final int INVOKE_SUPER = 51;
- /**
- * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
- * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
- * direct/special method)
- */
- public static final int INVOKE_DIRECT = 52;
+ /**
+ * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
+ * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
+ * direct/special method)
+ */
+ public static final int INVOKE_DIRECT = 52;
- /**
- * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
- * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
- * ...)} (call interface method)
- */
- public static final int INVOKE_INTERFACE = 53;
+ /**
+ * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
+ * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
+ * ...)} (call interface method)
+ */
+ public static final int INVOKE_INTERFACE = 53;
- /**
- * {@code T0: any type; name: local variable name :: mark(name,T0)}
- * (mark beginning or end of local variable name)
- */
- public static final int MARK_LOCAL = 54;
+ /**
+ * {@code T0: any type; name: local variable name :: mark(name,T0)}
+ * (mark beginning or end of local variable name)
+ */
+ public static final int MARK_LOCAL = 54;
- /**
- * {@code T: Any type; r: T :: r = return_type}.
- * <b>Note:</b> This opcode should only ever be used in the
- * first instruction of a block following an invoke-*.
- */
- public static final int MOVE_RESULT = 55;
+ /**
+ * {@code T: Any type; r: T :: r = return_type}.
+ * <b>Note:</b> This opcode should only ever be used in the
+ * first instruction of a block following an invoke-*.
+ */
+ public static final int MOVE_RESULT = 55;
- /**
- * {@code T: Any type; r: T :: r = return_type}.
- * <b>Note:</b> This opcode should only ever be used in the
- * first instruction of a block following a non-invoke throwing insn
- */
- public static final int MOVE_RESULT_PSEUDO = 56;
+ /**
+ * {@code T: Any type; r: T :: r = return_type}.
+ * <b>Note:</b> This opcode should only ever be used in the
+ * first instruction of a block following a non-invoke throwing insn
+ */
+ public static final int MOVE_RESULT_PSEUDO = 56;
- /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
- public static final int FILL_ARRAY_DATA = 57;
+ /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
+ public static final int FILL_ARRAY_DATA = 57;
- /**
- * This class is uninstantiable.
- */
- private RegOps() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private RegOps() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Gets the name of the given opcode.
+ *
+ * @param opcode the opcode
+ * @return {@code non-null;} its name
+ */
+ public static String opName(int opcode) {
+ switch (opcode) {
+ case NOP:
+ return "nop";
+ case MOVE:
+ return "move";
+ case MOVE_PARAM:
+ return "move-param";
+ case MOVE_EXCEPTION:
+ return "move-exception";
+ case CONST:
+ return "const";
+ case GOTO:
+ return "goto";
+ case IF_EQ:
+ return "if-eq";
+ case IF_NE:
+ return "if-ne";
+ case IF_LT:
+ return "if-lt";
+ case IF_GE:
+ return "if-ge";
+ case IF_LE:
+ return "if-le";
+ case IF_GT:
+ return "if-gt";
+ case SWITCH:
+ return "switch";
+ case ADD:
+ return "add";
+ case SUB:
+ return "sub";
+ case MUL:
+ return "mul";
+ case DIV:
+ return "div";
+ case REM:
+ return "rem";
+ case NEG:
+ return "neg";
+ case AND:
+ return "and";
+ case OR:
+ return "or";
+ case XOR:
+ return "xor";
+ case SHL:
+ return "shl";
+ case SHR:
+ return "shr";
+ case USHR:
+ return "ushr";
+ case NOT:
+ return "not";
+ case CMPL:
+ return "cmpl";
+ case CMPG:
+ return "cmpg";
+ case CONV:
+ return "conv";
+ case TO_BYTE:
+ return "to-byte";
+ case TO_CHAR:
+ return "to-char";
+ case TO_SHORT:
+ return "to-short";
+ case RETURN:
+ return "return";
+ case ARRAY_LENGTH:
+ return "array-length";
+ case THROW:
+ return "throw";
+ case MONITOR_ENTER:
+ return "monitor-enter";
+ case MONITOR_EXIT:
+ return "monitor-exit";
+ case AGET:
+ return "aget";
+ case APUT:
+ return "aput";
+ case NEW_INSTANCE:
+ return "new-instance";
+ case NEW_ARRAY:
+ return "new-array";
+ case FILLED_NEW_ARRAY:
+ return "filled-new-array";
+ case CHECK_CAST:
+ return "check-cast";
+ case INSTANCE_OF:
+ return "instance-of";
+ case GET_FIELD:
+ return "get-field";
+ case GET_STATIC:
+ return "get-static";
+ case PUT_FIELD:
+ return "put-field";
+ case PUT_STATIC:
+ return "put-static";
+ case INVOKE_STATIC:
+ return "invoke-static";
+ case INVOKE_VIRTUAL:
+ return "invoke-virtual";
+ case INVOKE_SUPER:
+ return "invoke-super";
+ case INVOKE_DIRECT:
+ return "invoke-direct";
+ case INVOKE_INTERFACE:
+ return "invoke-interface";
+ case MOVE_RESULT:
+ return "move-result";
+ case MOVE_RESULT_PSEUDO:
+ return "move-result-pseudo";
+ case FILL_ARRAY_DATA:
+ return "fill-array-data";
}
- /**
- * Gets the name of the given opcode.
- *
- * @param opcode the opcode
- * @return {@code non-null;} its name
- */
- public static String opName(int opcode) {
- switch (opcode) {
- case NOP: return "nop";
- case MOVE: return "move";
- case MOVE_PARAM: return "move-param";
- case MOVE_EXCEPTION: return "move-exception";
- case CONST: return "const";
- case GOTO: return "goto";
- case IF_EQ: return "if-eq";
- case IF_NE: return "if-ne";
- case IF_LT: return "if-lt";
- case IF_GE: return "if-ge";
- case IF_LE: return "if-le";
- case IF_GT: return "if-gt";
- case SWITCH: return "switch";
- case ADD: return "add";
- case SUB: return "sub";
- case MUL: return "mul";
- case DIV: return "div";
- case REM: return "rem";
- case NEG: return "neg";
- case AND: return "and";
- case OR: return "or";
- case XOR: return "xor";
- case SHL: return "shl";
- case SHR: return "shr";
- case USHR: return "ushr";
- case NOT: return "not";
- case CMPL: return "cmpl";
- case CMPG: return "cmpg";
- case CONV: return "conv";
- case TO_BYTE: return "to-byte";
- case TO_CHAR: return "to-char";
- case TO_SHORT: return "to-short";
- case RETURN: return "return";
- case ARRAY_LENGTH: return "array-length";
- case THROW: return "throw";
- case MONITOR_ENTER: return "monitor-enter";
- case MONITOR_EXIT: return "monitor-exit";
- case AGET: return "aget";
- case APUT: return "aput";
- case NEW_INSTANCE: return "new-instance";
- case NEW_ARRAY: return "new-array";
- case FILLED_NEW_ARRAY: return "filled-new-array";
- case CHECK_CAST: return "check-cast";
- case INSTANCE_OF: return "instance-of";
- case GET_FIELD: return "get-field";
- case GET_STATIC: return "get-static";
- case PUT_FIELD: return "put-field";
- case PUT_STATIC: return "put-static";
- case INVOKE_STATIC: return "invoke-static";
- case INVOKE_VIRTUAL: return "invoke-virtual";
- case INVOKE_SUPER: return "invoke-super";
- case INVOKE_DIRECT: return "invoke-direct";
- case INVOKE_INTERFACE: return "invoke-interface";
- case MOVE_RESULT: return "move-result";
- case MOVE_RESULT_PSEUDO: return "move-result-pseudo";
- case FILL_ARRAY_DATA: return "fill-array-data";
- }
+ return "unknown-" + Hex.u1(opcode);
+ }
- return "unknown-" + Hex.u1(opcode);
+ /**
+ * Given an IF_* RegOp, returns the right-to-left flipped version. For
+ * example, IF_GT becomes IF_LT.
+ *
+ * @param opcode An IF_* RegOp
+ * @return flipped IF Regop
+ */
+ public static int flippedIfOpcode(final int opcode) {
+ switch (opcode) {
+ case RegOps.IF_EQ:
+ case RegOps.IF_NE:
+ return opcode;
+ case RegOps.IF_LT:
+ return RegOps.IF_GT;
+ case RegOps.IF_GE:
+ return RegOps.IF_LE;
+ case RegOps.IF_LE:
+ return RegOps.IF_GE;
+ case RegOps.IF_GT:
+ return RegOps.IF_LT;
+ default:
+ throw new RuntimeException("Unrecognized IF regop: " + opcode);
}
-
- /**
- * Given an IF_* RegOp, returns the right-to-left flipped version. For
- * example, IF_GT becomes IF_LT.
- *
- * @param opcode An IF_* RegOp
- * @return flipped IF Regop
- */
- public static int flippedIfOpcode(final int opcode) {
- switch (opcode) {
- case RegOps.IF_EQ:
- case RegOps.IF_NE:
- return opcode;
- case RegOps.IF_LT:
- return RegOps.IF_GT;
- case RegOps.IF_GE:
- return RegOps.IF_LE;
- case RegOps.IF_LE:
- return RegOps.IF_GE;
- case RegOps.IF_GT:
- return RegOps.IF_LT;
- default:
- throw new RuntimeException("Unrecognized IF regop: " + opcode);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/RegisterSpec.java b/dx/src/com/android/jack/dx/rop/code/RegisterSpec.java
index 2460041..e9f1474 100644
--- a/dx/src/com/android/jack/dx/rop/code/RegisterSpec.java
+++ b/dx/src/com/android/jack/dx/rop/code/RegisterSpec.java
@@ -28,630 +28,626 @@
* Combination of a register number and a type, used as the sources and
* destinations of register-based operations.
*/
-public final class RegisterSpec
- implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
- /** {@code non-null;} string to prefix register numbers with */
- public static final String PREFIX = "v";
+public final class RegisterSpec implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
+ /** {@code non-null;} string to prefix register numbers with */
+ public static final String PREFIX = "v";
- /** {@code non-null;} intern table for instances */
- private static final HashMap<Object, RegisterSpec> theInterns =
- new HashMap<Object, RegisterSpec>(1000);
+ /** {@code non-null;} intern table for instances */
+ private static final HashMap<Object, RegisterSpec> theInterns =
+ new HashMap<Object, RegisterSpec>(1000);
- /** {@code non-null;} common comparison instance used while interning */
- private static final ForComparison theInterningItem = new ForComparison();
+ /** {@code non-null;} common comparison instance used while interning */
+ private static final ForComparison theInterningItem = new ForComparison();
+ /** {@code >= 0;} register number */
+ private final int reg;
+
+ /** {@code non-null;} type loaded or stored */
+ private final TypeBearer type;
+
+ /**
+ * {@code null-ok;} local variable info associated with this register,
+ * if any
+ */
+ private final LocalItem local;
+
+ /**
+ * Intern the given triple as an instance of this class.
+ *
+ * @param reg {@code >= 0;} the register number
+ * @param type {@code non-null;} the type (or possibly actual value) which
+ * is loaded from or stored to the indicated register
+ * @param local {@code null-ok;} the associated local variable, if any
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ private static RegisterSpec intern(int reg, TypeBearer type, LocalItem local) {
+ synchronized (theInterns) {
+ theInterningItem.set(reg, type, local);
+ RegisterSpec found = theInterns.get(theInterningItem);
+
+ if (found != null) {
+ return found;
+ }
+
+ found = theInterningItem.toRegisterSpec();
+ theInterns.put(found, found);
+ return found;
+ }
+ }
+
+ /**
+ * Returns an instance for the given register number and type, with
+ * no variable info. This method is allowed to return shared
+ * instances (but doesn't necessarily do so).
+ *
+ * @param reg {@code >= 0;} the register number
+ * @param type {@code non-null;} the type (or possibly actual value) which
+ * is loaded from or stored to the indicated register
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpec make(int reg, TypeBearer type) {
+ return intern(reg, type, null);
+ }
+
+ /**
+ * Returns an instance for the given register number, type, and
+ * variable info. This method is allowed to return shared
+ * instances (but doesn't necessarily do so).
+ *
+ * @param reg {@code >= 0;} the register number
+ * @param type {@code non-null;} the type (or possibly actual value) which
+ * is loaded from or stored to the indicated register
+ * @param local {@code non-null;} the associated local variable
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpec make(int reg, TypeBearer type, LocalItem local) {
+ if (local == null) {
+ throw new NullPointerException("local == null");
+ }
+
+ return intern(reg, type, local);
+ }
+
+ /**
+ * Returns an instance for the given register number, type, and
+ * variable info. This method is allowed to return shared
+ * instances (but doesn't necessarily do so).
+ *
+ * @param reg {@code >= 0;} the register number
+ * @param type {@code non-null;} the type (or possibly actual value) which
+ * is loaded from or stored to the indicated register
+ * @param local {@code null-ok;} the associated variable info or null for
+ * none
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpec makeLocalOptional(int reg, TypeBearer type, LocalItem local) {
+
+ return intern(reg, type, local);
+ }
+
+ /**
+ * Gets the string form for the given register number.
+ *
+ * @param reg {@code >= 0;} the register number
+ * @return {@code non-null;} the string form
+ */
+ public static String regString(int reg) {
+ return PREFIX + reg;
+ }
+
+ /**
+ * Constructs an instance. This constructor is private. Use
+ * {@link #make}.
+ *
+ * @param reg {@code >= 0;} the register number
+ * @param type {@code non-null;} the type (or possibly actual value) which
+ * is loaded from or stored to the indicated register
+ * @param local {@code null-ok;} the associated local variable, if any
+ */
+ private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
+ if (reg < 0) {
+ throw new IllegalArgumentException("reg < 0");
+ }
+
+ if (type == null) {
+ throw new NullPointerException("type == null");
+ }
+
+ this.reg = reg;
+ this.type = type;
+ this.local = local;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RegisterSpec)) {
+ if (other instanceof ForComparison) {
+ ForComparison fc = (ForComparison) other;
+ return equals(fc.reg, fc.type, fc.local);
+ }
+ return false;
+ }
+
+ RegisterSpec spec = (RegisterSpec) other;
+ return equals(spec.reg, spec.type, spec.local);
+ }
+
+ /**
+ * Like {@code equals}, but only consider the simple types of the
+ * registers. That is, this compares {@code getType()} on the types
+ * to ignore whatever arbitrary extra stuff might be carried around
+ * by an outer {@link TypeBearer}.
+ *
+ * @param other {@code null-ok;} spec to compare to
+ * @return {@code true} iff {@code this} and {@code other} are equal
+ * in the stated way
+ */
+ public boolean equalsUsingSimpleType(RegisterSpec other) {
+ if (!matchesVariable(other)) {
+ return false;
+ }
+
+ return (reg == other.reg);
+ }
+
+ /**
+ * Like {@link #equalsUsingSimpleType} but ignoring the register number.
+ * This is useful to determine if two instances refer to the "same"
+ * local variable.
+ *
+ * @param other {@code null-ok;} spec to compare to
+ * @return {@code true} iff {@code this} and {@code other} are equal
+ * in the stated way
+ */
+ public boolean matchesVariable(RegisterSpec other) {
+ if (other == null) {
+ return false;
+ }
+
+ return type.getType().equals(other.type.getType())
+ && ((local == other.local) || ((local != null) && local.equals(other.local)));
+ }
+
+ /**
+ * Helper for {@link #equals} and {@link #ForComparison.equals},
+ * which actually does the test.
+ *
+ * @param reg value of the instance variable, for another instance
+ * @param type value of the instance variable, for another instance
+ * @param local value of the instance variable, for another instance
+ * @return whether this instance is equal to one with the given
+ * values
+ */
+ private boolean equals(int reg, TypeBearer type, LocalItem local) {
+ return (this.reg == reg) && this.type.equals(type)
+ && ((this.local == local) || ((this.local != null) && this.local.equals(local)));
+ }
+
+ /**
+ * Compares by (in priority order) register number, unwrapped type
+ * (that is types not {@link TypeBearer}s, and local info.
+ *
+ * @param other {@code non-null;} spec to compare to
+ * @return {@code -1..1;} standard result of comparison
+ */
+ @Override
+ public int compareTo(RegisterSpec other) {
+ if (this.reg < other.reg) {
+ return -1;
+ } else if (this.reg > other.reg) {
+ return 1;
+ }
+
+ int compare = type.getType().compareTo(other.type.getType());
+
+ if (compare != 0) {
+ return compare;
+ }
+
+ if (this.local == null) {
+ return (other.local == null) ? 0 : -1;
+ } else if (other.local == null) {
+ return 1;
+ }
+
+ return this.local.compareTo(other.local);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return hashCodeOf(reg, type, local);
+ }
+
+ /**
+ * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
+ * which actually does the calculation.
+ *
+ * @param reg value of the instance variable
+ * @param type value of the instance variable
+ * @param local value of the instance variable
+ * @return the hash code
+ */
+ private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
+ int hash = (local != null) ? local.hashCode() : 0;
+
+ hash = (hash * 31 + type.hashCode()) * 31 + reg;
+ return hash;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return toString0(false);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return toString0(true);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return type.getType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public TypeBearer getFrameType() {
+ return type.getFrameType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int getBasicType() {
+ return type.getBasicType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int getBasicFrameType() {
+ return type.getBasicFrameType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isConstant() {
+ return false;
+ }
+
+ /**
+ * Gets the register number.
+ *
+ * @return {@code >= 0;} the register number
+ */
+ public int getReg() {
+ return reg;
+ }
+
+ /**
+ * Gets the type (or actual value) which is loaded from or stored
+ * to the register associated with this instance.
+ *
+ * @return {@code non-null;} the type
+ */
+ public TypeBearer getTypeBearer() {
+ return type;
+ }
+
+ /**
+ * Gets the variable info associated with this instance, if any.
+ *
+ * @return {@code null-ok;} the variable info, or {@code null} if this
+ * instance has none
+ */
+ public LocalItem getLocalItem() {
+ return local;
+ }
+
+ /**
+ * Gets the next available register number after the one in this
+ * instance. This is equal to the register number plus the width
+ * (category) of the type used. Among other things, this may also
+ * be used to determine the minimum required register count
+ * implied by this instance.
+ *
+ * @return {@code >= 0;} the required registers size
+ */
+ public int getNextReg() {
+ return reg + getCategory();
+ }
+
+ /**
+ * Gets the category of this instance's type. This is just a convenient
+ * shorthand for {@code getType().getCategory()}.
+ *
+ * @see #isCategory1
+ * @see #isCategory2
+ * @return {@code 1..2;} the category of this instance's type
+ */
+ public int getCategory() {
+ return type.getType().getCategory();
+ }
+
+ /**
+ * Gets whether this instance's type is category 1. This is just a
+ * convenient shorthand for {@code getType().isCategory1()}.
+ *
+ * @see #getCategory
+ * @see #isCategory2
+ * @return whether or not this instance's type is of category 1
+ */
+ public boolean isCategory1() {
+ return type.getType().isCategory1();
+ }
+
+ /**
+ * Gets whether this instance's type is category 2. This is just a
+ * convenient shorthand for {@code getType().isCategory2()}.
+ *
+ * @see #getCategory
+ * @see #isCategory1
+ * @return whether or not this instance's type is of category 2
+ */
+ public boolean isCategory2() {
+ return type.getType().isCategory2();
+ }
+
+ /**
+ * Gets the string form for just the register number of this instance.
+ *
+ * @return {@code non-null;} the register string form
+ */
+ public String regString() {
+ return regString(reg);
+ }
+
+ /**
+ * Returns an instance that is the intersection between this instance
+ * and the given one, if any. The intersection is defined as follows:
+ *
+ * <ul>
+ * <li>If {@code other} is {@code null}, then the result
+ * is {@code null}.
+ * <li>If the register numbers don't match, then the intersection
+ * is {@code null}. Otherwise, the register number of the
+ * intersection is the same as the one in the two instances.</li>
+ * <li>If the types returned by {@code getType()} are not
+ * {@code equals()}, then the intersection is null.</li>
+ * <li>If the type bearers returned by {@code getTypeBearer()}
+ * are {@code equals()}, then the intersection's type bearer
+ * is the one from this instance. Otherwise, the intersection's
+ * type bearer is the {@code getType()} of this instance.</li>
+ * <li>If the locals are {@code equals()}, then the local info
+ * of the intersection is the local info of this instance. Otherwise,
+ * the local info of the intersection is {@code null}.</li>
+ * </ul>
+ *
+ * @param other {@code null-ok;} instance to intersect with (or {@code null})
+ * @param localPrimary whether local variables are primary to the
+ * intersection; if {@code true}, then the only non-null
+ * results occur when registers being intersected have equal local
+ * infos (or both have {@code null} local infos)
+ * @return {@code null-ok;} the intersection
+ */
+ public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
+ if (this == other) {
+ // Easy out.
+ return this;
+ }
+
+ if ((other == null) || (reg != other.getReg())) {
+ return null;
+ }
+
+ LocalItem resultLocal = ((local == null) || !local.equals(other.getLocalItem())) ? null : local;
+ boolean sameName = (resultLocal == local);
+
+ if (localPrimary && !sameName) {
+ return null;
+ }
+
+ Type thisType = getType();
+ Type otherType = other.getType();
+
+ // Note: Types are always interned.
+ if (thisType != otherType) {
+ return null;
+ }
+
+ TypeBearer resultTypeBearer = type.equals(other.getTypeBearer()) ? type : thisType;
+
+ if ((resultTypeBearer == type) && sameName) {
+ // It turns out that the intersection is "this" after all.
+ return this;
+ }
+
+ return (resultLocal == null) ? make(reg, resultTypeBearer)
+ : make(reg, resultTypeBearer, resultLocal);
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that the
+ * register number is replaced by the given one.
+ *
+ * @param newReg {@code >= 0;} the new register number
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpec withReg(int newReg) {
+ if (reg == newReg) {
+ return this;
+ }
+
+ return makeLocalOptional(newReg, type, local);
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the type is replaced by the given one.
+ *
+ * @param newType {@code non-null;} the new type
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpec withType(TypeBearer newType) {
+ return makeLocalOptional(reg, newType, local);
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that the
+ * register number is offset by the given amount.
+ *
+ * @param delta the amount to offset the register number by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpec withOffset(int delta) {
+ if (delta == 0) {
+ return this;
+ }
+
+ return withReg(reg + delta);
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the type bearer is replaced by the actual underlying type
+ * (thereby stripping off non-type information) with any
+ * initialization information stripped away as well.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpec withSimpleType() {
+ TypeBearer orig = type;
+ Type newType;
+
+ if (orig instanceof Type) {
+ newType = (Type) orig;
+ } else {
+ newType = orig.getType();
+ }
+
+ if (newType.isUninitialized()) {
+ newType = newType.getInitializedType();
+ }
+
+ if (newType == orig) {
+ return this;
+ }
+
+ return makeLocalOptional(reg, newType, local);
+ }
+
+ /**
+ * Returns an instance that is identical to this one except that the
+ * local variable is as specified in the parameter.
+ *
+ * @param local {@code null-ok;} the local item or null for none
+ * @return an appropriate instance
+ */
+ public RegisterSpec withLocalItem(LocalItem local) {
+ if ((this.local == local) || ((this.local != null) && this.local.equals(local))) {
+
+ return this;
+ }
+
+ return makeLocalOptional(reg, type, local);
+ }
+
+
+ /**
+ * Helper for {@link #toString} and {@link #toHuman}.
+ *
+ * @param human whether to be human-oriented
+ * @return {@code non-null;} the string form
+ */
+ private String toString0(boolean human) {
+ StringBuffer sb = new StringBuffer(40);
+
+ sb.append(regString());
+ sb.append(":");
+
+ if (local != null) {
+ sb.append(local.toString());
+ }
+
+ Type justType = type.getType();
+ sb.append(justType);
+
+ if (justType != type) {
+ sb.append("=");
+ if (human && (type instanceof CstString)) {
+ sb.append(((CstString) type).toQuoted());
+ } else if (human && (type instanceof Constant)) {
+ sb.append(type.toHuman());
+ } else {
+ sb.append(type);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Holder of register spec data for the purposes of comparison (so that
+ * {@code RegisterSpec} itself can still keep {@code final}
+ * instance variables.
+ */
+ private static class ForComparison {
/** {@code >= 0;} register number */
- private final int reg;
+ private int reg;
/** {@code non-null;} type loaded or stored */
- private final TypeBearer type;
+ private TypeBearer type;
/**
- * {@code null-ok;} local variable info associated with this register,
- * if any
+ * {@code null-ok;} local variable associated with this
+ * register, if any
*/
- private final LocalItem local;
+ private LocalItem local;
/**
- * Intern the given triple as an instance of this class.
+ * Set all the instance variables.
*
* @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
+ * @param type {@code non-null;} the type (or possibly actual
+ * value) which is loaded from or stored to the indicated
+ * register
* @param local {@code null-ok;} the associated local variable, if any
* @return {@code non-null;} an appropriately-constructed instance
*/
- private static RegisterSpec intern(int reg, TypeBearer type,
- LocalItem local) {
- synchronized (theInterns) {
- theInterningItem.set(reg, type, local);
- RegisterSpec found = theInterns.get(theInterningItem);
-
- if (found != null) {
- return found;
- }
-
- found = theInterningItem.toRegisterSpec();
- theInterns.put(found, found);
- return found;
- }
+ public void set(int reg, TypeBearer type, LocalItem local) {
+ this.reg = reg;
+ this.type = type;
+ this.local = local;
}
/**
- * Returns an instance for the given register number and type, with
- * no variable info. This method is allowed to return shared
- * instances (but doesn't necessarily do so).
+ * Construct a {@code RegisterSpec} of this instance's
+ * contents.
*
- * @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
* @return {@code non-null;} an appropriately-constructed instance
*/
- public static RegisterSpec make(int reg, TypeBearer type) {
- return intern(reg, type, null);
- }
-
- /**
- * Returns an instance for the given register number, type, and
- * variable info. This method is allowed to return shared
- * instances (but doesn't necessarily do so).
- *
- * @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
- * @param local {@code non-null;} the associated local variable
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpec make(int reg, TypeBearer type,
- LocalItem local) {
- if (local == null) {
- throw new NullPointerException("local == null");
- }
-
- return intern(reg, type, local);
- }
-
- /**
- * Returns an instance for the given register number, type, and
- * variable info. This method is allowed to return shared
- * instances (but doesn't necessarily do so).
- *
- * @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
- * @param local {@code null-ok;} the associated variable info or null for
- * none
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpec makeLocalOptional(
- int reg, TypeBearer type, LocalItem local) {
-
- return intern(reg, type, local);
- }
-
- /**
- * Gets the string form for the given register number.
- *
- * @param reg {@code >= 0;} the register number
- * @return {@code non-null;} the string form
- */
- public static String regString(int reg) {
- return PREFIX + reg;
- }
-
- /**
- * Constructs an instance. This constructor is private. Use
- * {@link #make}.
- *
- * @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
- * @param local {@code null-ok;} the associated local variable, if any
- */
- private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
- if (reg < 0) {
- throw new IllegalArgumentException("reg < 0");
- }
-
- if (type == null) {
- throw new NullPointerException("type == null");
- }
-
- this.reg = reg;
- this.type = type;
- this.local = local;
+ public RegisterSpec toRegisterSpec() {
+ return new RegisterSpec(reg, type, local);
}
/** {@inheritDoc} */
@Override
public boolean equals(Object other) {
- if (!(other instanceof RegisterSpec)) {
- if (other instanceof ForComparison) {
- ForComparison fc = (ForComparison) other;
- return equals(fc.reg, fc.type, fc.local);
- }
- return false;
- }
+ if (!(other instanceof RegisterSpec)) {
+ return false;
+ }
- RegisterSpec spec = (RegisterSpec) other;
- return equals(spec.reg, spec.type, spec.local);
- }
-
- /**
- * Like {@code equals}, but only consider the simple types of the
- * registers. That is, this compares {@code getType()} on the types
- * to ignore whatever arbitrary extra stuff might be carried around
- * by an outer {@link TypeBearer}.
- *
- * @param other {@code null-ok;} spec to compare to
- * @return {@code true} iff {@code this} and {@code other} are equal
- * in the stated way
- */
- public boolean equalsUsingSimpleType(RegisterSpec other) {
- if (!matchesVariable(other)) {
- return false;
- }
-
- return (reg == other.reg);
- }
-
- /**
- * Like {@link #equalsUsingSimpleType} but ignoring the register number.
- * This is useful to determine if two instances refer to the "same"
- * local variable.
- *
- * @param other {@code null-ok;} spec to compare to
- * @return {@code true} iff {@code this} and {@code other} are equal
- * in the stated way
- */
- public boolean matchesVariable(RegisterSpec other) {
- if (other == null) {
- return false;
- }
-
- return type.getType().equals(other.type.getType())
- && ((local == other.local)
- || ((local != null) && local.equals(other.local)));
- }
-
- /**
- * Helper for {@link #equals} and {@link #ForComparison.equals},
- * which actually does the test.
- *
- * @param reg value of the instance variable, for another instance
- * @param type value of the instance variable, for another instance
- * @param local value of the instance variable, for another instance
- * @return whether this instance is equal to one with the given
- * values
- */
- private boolean equals(int reg, TypeBearer type, LocalItem local) {
- return (this.reg == reg)
- && this.type.equals(type)
- && ((this.local == local)
- || ((this.local != null) && this.local.equals(local)));
- }
-
- /**
- * Compares by (in priority order) register number, unwrapped type
- * (that is types not {@link TypeBearer}s, and local info.
- *
- * @param other {@code non-null;} spec to compare to
- * @return {@code -1..1;} standard result of comparison
- */
- public int compareTo(RegisterSpec other) {
- if (this.reg < other.reg) {
- return -1;
- } else if (this.reg > other.reg) {
- return 1;
- }
-
- int compare = type.getType().compareTo(other.type.getType());
-
- if (compare != 0) {
- return compare;
- }
-
- if (this.local == null) {
- return (other.local == null) ? 0 : -1;
- } else if (other.local == null) {
- return 1;
- }
-
- return this.local.compareTo(other.local);
+ RegisterSpec spec = (RegisterSpec) other;
+ return spec.equals(reg, type, local);
}
/** {@inheritDoc} */
@Override
public int hashCode() {
- return hashCodeOf(reg, type, local);
+ return hashCodeOf(reg, type, local);
}
-
- /**
- * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
- * which actually does the calculation.
- *
- * @param reg value of the instance variable
- * @param type value of the instance variable
- * @param local value of the instance variable
- * @return the hash code
- */
- private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
- int hash = (local != null) ? local.hashCode() : 0;
-
- hash = (hash * 31 + type.hashCode()) * 31 + reg;
- return hash;
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return toString0(false);
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return toString0(true);
- }
-
- /** {@inheritDoc} */
- public Type getType() {
- return type.getType();
- }
-
- /** {@inheritDoc} */
- public TypeBearer getFrameType() {
- return type.getFrameType();
- }
-
- /** {@inheritDoc} */
- public final int getBasicType() {
- return type.getBasicType();
- }
-
- /** {@inheritDoc} */
- public final int getBasicFrameType() {
- return type.getBasicFrameType();
- }
-
- /** {@inheritDoc} */
- public final boolean isConstant() {
- return false;
- }
-
- /**
- * Gets the register number.
- *
- * @return {@code >= 0;} the register number
- */
- public int getReg() {
- return reg;
- }
-
- /**
- * Gets the type (or actual value) which is loaded from or stored
- * to the register associated with this instance.
- *
- * @return {@code non-null;} the type
- */
- public TypeBearer getTypeBearer() {
- return type;
- }
-
- /**
- * Gets the variable info associated with this instance, if any.
- *
- * @return {@code null-ok;} the variable info, or {@code null} if this
- * instance has none
- */
- public LocalItem getLocalItem() {
- return local;
- }
-
- /**
- * Gets the next available register number after the one in this
- * instance. This is equal to the register number plus the width
- * (category) of the type used. Among other things, this may also
- * be used to determine the minimum required register count
- * implied by this instance.
- *
- * @return {@code >= 0;} the required registers size
- */
- public int getNextReg() {
- return reg + getCategory();
- }
-
- /**
- * Gets the category of this instance's type. This is just a convenient
- * shorthand for {@code getType().getCategory()}.
- *
- * @see #isCategory1
- * @see #isCategory2
- * @return {@code 1..2;} the category of this instance's type
- */
- public int getCategory() {
- return type.getType().getCategory();
- }
-
- /**
- * Gets whether this instance's type is category 1. This is just a
- * convenient shorthand for {@code getType().isCategory1()}.
- *
- * @see #getCategory
- * @see #isCategory2
- * @return whether or not this instance's type is of category 1
- */
- public boolean isCategory1() {
- return type.getType().isCategory1();
- }
-
- /**
- * Gets whether this instance's type is category 2. This is just a
- * convenient shorthand for {@code getType().isCategory2()}.
- *
- * @see #getCategory
- * @see #isCategory1
- * @return whether or not this instance's type is of category 2
- */
- public boolean isCategory2() {
- return type.getType().isCategory2();
- }
-
- /**
- * Gets the string form for just the register number of this instance.
- *
- * @return {@code non-null;} the register string form
- */
- public String regString() {
- return regString(reg);
- }
-
- /**
- * Returns an instance that is the intersection between this instance
- * and the given one, if any. The intersection is defined as follows:
- *
- * <ul>
- * <li>If {@code other} is {@code null}, then the result
- * is {@code null}.
- * <li>If the register numbers don't match, then the intersection
- * is {@code null}. Otherwise, the register number of the
- * intersection is the same as the one in the two instances.</li>
- * <li>If the types returned by {@code getType()} are not
- * {@code equals()}, then the intersection is null.</li>
- * <li>If the type bearers returned by {@code getTypeBearer()}
- * are {@code equals()}, then the intersection's type bearer
- * is the one from this instance. Otherwise, the intersection's
- * type bearer is the {@code getType()} of this instance.</li>
- * <li>If the locals are {@code equals()}, then the local info
- * of the intersection is the local info of this instance. Otherwise,
- * the local info of the intersection is {@code null}.</li>
- * </ul>
- *
- * @param other {@code null-ok;} instance to intersect with (or {@code null})
- * @param localPrimary whether local variables are primary to the
- * intersection; if {@code true}, then the only non-null
- * results occur when registers being intersected have equal local
- * infos (or both have {@code null} local infos)
- * @return {@code null-ok;} the intersection
- */
- public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
- if (this == other) {
- // Easy out.
- return this;
- }
-
- if ((other == null) || (reg != other.getReg())) {
- return null;
- }
-
- LocalItem resultLocal =
- ((local == null) || !local.equals(other.getLocalItem()))
- ? null : local;
- boolean sameName = (resultLocal == local);
-
- if (localPrimary && !sameName) {
- return null;
- }
-
- Type thisType = getType();
- Type otherType = other.getType();
-
- // Note: Types are always interned.
- if (thisType != otherType) {
- return null;
- }
-
- TypeBearer resultTypeBearer =
- type.equals(other.getTypeBearer()) ? type : thisType;
-
- if ((resultTypeBearer == type) && sameName) {
- // It turns out that the intersection is "this" after all.
- return this;
- }
-
- return (resultLocal == null) ? make(reg, resultTypeBearer) :
- make(reg, resultTypeBearer, resultLocal);
- }
-
- /**
- * Returns an instance that is identical to this one, except that the
- * register number is replaced by the given one.
- *
- * @param newReg {@code >= 0;} the new register number
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpec withReg(int newReg) {
- if (reg == newReg) {
- return this;
- }
-
- return makeLocalOptional(newReg, type, local);
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * the type is replaced by the given one.
- *
- * @param newType {@code non-null;} the new type
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpec withType(TypeBearer newType) {
- return makeLocalOptional(reg, newType, local);
- }
-
- /**
- * Returns an instance that is identical to this one, except that the
- * register number is offset by the given amount.
- *
- * @param delta the amount to offset the register number by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpec withOffset(int delta) {
- if (delta == 0) {
- return this;
- }
-
- return withReg(reg + delta);
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * the type bearer is replaced by the actual underlying type
- * (thereby stripping off non-type information) with any
- * initialization information stripped away as well.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpec withSimpleType() {
- TypeBearer orig = type;
- Type newType;
-
- if (orig instanceof Type) {
- newType = (Type) orig;
- } else {
- newType = orig.getType();
- }
-
- if (newType.isUninitialized()) {
- newType = newType.getInitializedType();
- }
-
- if (newType == orig) {
- return this;
- }
-
- return makeLocalOptional(reg, newType, local);
- }
-
- /**
- * Returns an instance that is identical to this one except that the
- * local variable is as specified in the parameter.
- *
- * @param local {@code null-ok;} the local item or null for none
- * @return an appropriate instance
- */
- public RegisterSpec withLocalItem(LocalItem local) {
- if ((this.local== local)
- || ((this.local != null) && this.local.equals(local))) {
-
- return this;
- }
-
- return makeLocalOptional(reg, type, local);
- }
-
-
- /**
- * Helper for {@link #toString} and {@link #toHuman}.
- *
- * @param human whether to be human-oriented
- * @return {@code non-null;} the string form
- */
- private String toString0(boolean human) {
- StringBuffer sb = new StringBuffer(40);
-
- sb.append(regString());
- sb.append(":");
-
- if (local != null) {
- sb.append(local.toString());
- }
-
- Type justType = type.getType();
- sb.append(justType);
-
- if (justType != type) {
- sb.append("=");
- if (human && (type instanceof CstString)) {
- sb.append(((CstString) type).toQuoted());
- } else if (human && (type instanceof Constant)) {
- sb.append(type.toHuman());
- } else {
- sb.append(type);
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Holder of register spec data for the purposes of comparison (so that
- * {@code RegisterSpec} itself can still keep {@code final}
- * instance variables.
- */
- private static class ForComparison {
- /** {@code >= 0;} register number */
- private int reg;
-
- /** {@code non-null;} type loaded or stored */
- private TypeBearer type;
-
- /**
- * {@code null-ok;} local variable associated with this
- * register, if any
- */
- private LocalItem local;
-
- /**
- * Set all the instance variables.
- *
- * @param reg {@code >= 0;} the register number
- * @param type {@code non-null;} the type (or possibly actual
- * value) which is loaded from or stored to the indicated
- * register
- * @param local {@code null-ok;} the associated local variable, if any
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public void set(int reg, TypeBearer type, LocalItem local) {
- this.reg = reg;
- this.type = type;
- this.local = local;
- }
-
- /**
- * Construct a {@code RegisterSpec} of this instance's
- * contents.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpec toRegisterSpec() {
- return new RegisterSpec(reg, type, local);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof RegisterSpec)) {
- return false;
- }
-
- RegisterSpec spec = (RegisterSpec) other;
- return spec.equals(reg, type, local);
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return hashCodeOf(reg, type, local);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/RegisterSpecList.java b/dx/src/com/android/jack/dx/rop/code/RegisterSpecList.java
index 50649fe..9f270ba 100644
--- a/dx/src/com/android/jack/dx/rop/code/RegisterSpecList.java
+++ b/dx/src/com/android/jack/dx/rop/code/RegisterSpecList.java
@@ -25,385 +25,383 @@
/**
* List of {@link RegisterSpec} instances.
*/
-public final class RegisterSpecList
- extends FixedSizeList implements TypeList {
- /** {@code non-null;} no-element instance */
- public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
+public final class RegisterSpecList extends FixedSizeList implements TypeList {
+ /** {@code non-null;} no-element instance */
+ public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
- /**
- * Makes a single-element instance.
- *
- * @param spec {@code non-null;} the element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpecList make(RegisterSpec spec) {
- RegisterSpecList result = new RegisterSpecList(1);
- result.set(0, spec);
- return result;
+ /**
+ * Makes a single-element instance.
+ *
+ * @param spec {@code non-null;} the element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpecList make(RegisterSpec spec) {
+ RegisterSpecList result = new RegisterSpecList(1);
+ result.set(0, spec);
+ return result;
+ }
+
+ /**
+ * Makes a two-element instance.
+ *
+ * @param spec0 {@code non-null;} the first element
+ * @param spec1 {@code non-null;} the second element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1) {
+ RegisterSpecList result = new RegisterSpecList(2);
+ result.set(0, spec0);
+ result.set(1, spec1);
+ return result;
+ }
+
+ /**
+ * Makes a three-element instance.
+ *
+ * @param spec0 {@code non-null;} the first element
+ * @param spec1 {@code non-null;} the second element
+ * @param spec2 {@code non-null;} the third element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1, RegisterSpec spec2) {
+ RegisterSpecList result = new RegisterSpecList(3);
+ result.set(0, spec0);
+ result.set(1, spec1);
+ result.set(2, spec2);
+ return result;
+ }
+
+ /**
+ * Makes a four-element instance.
+ *
+ * @param spec0 {@code non-null;} the first element
+ * @param spec1 {@code non-null;} the second element
+ * @param spec2 {@code non-null;} the third element
+ * @param spec3 {@code non-null;} the fourth element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1, RegisterSpec spec2,
+ RegisterSpec spec3) {
+ RegisterSpecList result = new RegisterSpecList(4);
+ result.set(0, spec0);
+ result.set(1, spec1);
+ result.set(2, spec2);
+ result.set(3, spec3);
+ return result;
+ }
+
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public RegisterSpecList(int size) {
+ super(size);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Type getType(int n) {
+ return get(n).getType().getType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getWordCount() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ result += getType(i).getCategory();
}
- /**
- * Makes a two-element instance.
- *
- * @param spec0 {@code non-null;} the first element
- * @param spec1 {@code non-null;} the second element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpecList make(RegisterSpec spec0,
- RegisterSpec spec1) {
- RegisterSpecList result = new RegisterSpecList(2);
- result.set(0, spec0);
- result.set(1, spec1);
- return result;
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public TypeList withAddedType(Type type) {
+ throw new UnsupportedOperationException("unsupported");
+ }
+
+ /**
+ * Gets the indicated element. It is an error to call this with the
+ * index for an element which was never set; if you do that, this
+ * will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
+ */
+ public RegisterSpec get(int n) {
+ return (RegisterSpec) get0(n);
+ }
+
+ /**
+ * Returns a RegisterSpec in this list that uses the specified register,
+ * or null if there is none in this list.
+ * @param reg Register to find
+ * @return RegisterSpec that uses argument or null.
+ */
+ public RegisterSpec specForRegister(int reg) {
+ int sz = size();
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec rs;
+
+ rs = get(i);
+
+ if (rs.getReg() == reg) {
+ return rs;
+ }
}
- /**
- * Makes a three-element instance.
- *
- * @param spec0 {@code non-null;} the first element
- * @param spec1 {@code non-null;} the second element
- * @param spec2 {@code non-null;} the third element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
- RegisterSpec spec2) {
- RegisterSpecList result = new RegisterSpecList(3);
- result.set(0, spec0);
- result.set(1, spec1);
- result.set(2, spec2);
- return result;
+ return null;
+ }
+
+ /**
+ * Returns the index of a RegisterSpec in this list that uses the specified
+ * register, or -1 if none in this list uses the register.
+ * @param reg Register to find
+ * @return index of RegisterSpec or -1
+ */
+ public int indexOfRegister(int reg) {
+ int sz = size();
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec rs;
+
+ rs = get(i);
+
+ if (rs.getReg() == reg) {
+ return i;
+ }
}
- /**
- * Makes a four-element instance.
- *
- * @param spec0 {@code non-null;} the first element
- * @param spec1 {@code non-null;} the second element
- * @param spec2 {@code non-null;} the third element
- * @param spec3 {@code non-null;} the fourth element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
- RegisterSpec spec2,
- RegisterSpec spec3) {
- RegisterSpecList result = new RegisterSpecList(4);
- result.set(0, spec0);
- result.set(1, spec1);
- result.set(2, spec2);
- result.set(3, spec3);
- return result;
+ return -1;
+ }
+
+ /**
+ * Sets the element at the given index.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @param spec {@code non-null;} the value to store
+ */
+ public void set(int n, RegisterSpec spec) {
+ set0(n, spec);
+ }
+
+ /**
+ * Gets the minimum required register count implied by this
+ * instance. This is equal to the highest register number referred
+ * to plus the widest width (largest category) of the type used in
+ * that register.
+ *
+ * @return {@code >= 0;} the required registers size
+ */
+ public int getRegistersSize() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec spec = (RegisterSpec) get0(i);
+ if (spec != null) {
+ int min = spec.getNextReg();
+ if (min > result) {
+ result = min;
+ }
+ }
}
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public RegisterSpecList(int size) {
- super(size);
+ return result;
+ }
+
+ /**
+ * Returns a new instance, which is the same as this instance,
+ * except that it has an additional element prepended to the original.
+ * Mutability of the result is inherited from the original.
+ *
+ * @param spec {@code non-null;} the new first spec (to prepend)
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList withFirst(RegisterSpec spec) {
+ int sz = size();
+ RegisterSpecList result = new RegisterSpecList(sz + 1);
+
+ for (int i = 0; i < sz; i++) {
+ result.set0(i + 1, get0(i));
}
- /** {@inheritDoc} */
- public Type getType(int n) {
- return get(n).getType().getType();
+ result.set0(0, spec);
+ if (isImmutable()) {
+ result.setImmutable();
}
- /** {@inheritDoc} */
- public int getWordCount() {
- int sz = size();
- int result = 0;
+ return result;
+ }
- for (int i = 0; i < sz; i++) {
- result += getType(i).getCategory();
- }
+ /**
+ * Returns a new instance, which is the same as this instance,
+ * except that its first element is removed. Mutability of the
+ * result is inherited from the original.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList withoutFirst() {
+ int newSize = size() - 1;
- return result;
+ if (newSize == 0) {
+ return EMPTY;
}
- /** {@inheritDoc} */
- public TypeList withAddedType(Type type) {
- throw new UnsupportedOperationException("unsupported");
+ RegisterSpecList result = new RegisterSpecList(newSize);
+
+ for (int i = 0; i < newSize; i++) {
+ result.set0(i, get0(i + 1));
}
- /**
- * Gets the indicated element. It is an error to call this with the
- * index for an element which was never set; if you do that, this
- * will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which element
- * @return {@code non-null;} the indicated element
- */
- public RegisterSpec get(int n) {
- return (RegisterSpec) get0(n);
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Returns a RegisterSpec in this list that uses the specified register,
- * or null if there is none in this list.
- * @param reg Register to find
- * @return RegisterSpec that uses argument or null.
- */
- public RegisterSpec specForRegister(int reg) {
- int sz = size();
- for (int i = 0; i < sz; i++) {
- RegisterSpec rs;
+ return result;
+ }
- rs = get(i);
+ /**
+ * Returns a new instance, which is the same as this instance,
+ * except that its last element is removed. Mutability of the
+ * result is inherited from the original.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList withoutLast() {
+ int newSize = size() - 1;
- if (rs.getReg() == reg) {
- return rs;
- }
- }
-
- return null;
+ if (newSize == 0) {
+ return EMPTY;
}
- /**
- * Returns the index of a RegisterSpec in this list that uses the specified
- * register, or -1 if none in this list uses the register.
- * @param reg Register to find
- * @return index of RegisterSpec or -1
- */
- public int indexOfRegister(int reg) {
- int sz = size();
- for (int i = 0; i < sz; i++) {
- RegisterSpec rs;
+ RegisterSpecList result = new RegisterSpecList(newSize);
- rs = get(i);
-
- if (rs.getReg() == reg) {
- return i;
- }
- }
-
- return -1;
+ for (int i = 0; i < newSize; i++) {
+ result.set0(i, get0(i));
}
- /**
- * Sets the element at the given index.
- *
- * @param n {@code >= 0, < size();} which element
- * @param spec {@code non-null;} the value to store
- */
- public void set(int n, RegisterSpec spec) {
- set0(n, spec);
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Gets the minimum required register count implied by this
- * instance. This is equal to the highest register number referred
- * to plus the widest width (largest category) of the type used in
- * that register.
- *
- * @return {@code >= 0;} the required registers size
- */
- public int getRegistersSize() {
- int sz = size();
- int result = 0;
+ return result;
+ }
- for (int i = 0; i < sz; i++) {
- RegisterSpec spec = (RegisterSpec) get0(i);
- if (spec != null) {
- int min = spec.getNextReg();
- if (min > result) {
- result = min;
- }
- }
- }
+ /**
+ * Returns a new instance, which contains a subset of the elements
+ * specified by the given BitSet. Indexes in the BitSet with a zero
+ * are included, while indexes with a one are excluded. Mutability
+ * of the result is inherited from the original.
+ *
+ * @param exclusionSet {@code non-null;} set of registers to exclude
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList subset(BitSet exclusionSet) {
+ int newSize = size() - exclusionSet.cardinality();
- return result;
+ if (newSize == 0) {
+ return EMPTY;
}
- /**
- * Returns a new instance, which is the same as this instance,
- * except that it has an additional element prepended to the original.
- * Mutability of the result is inherited from the original.
- *
- * @param spec {@code non-null;} the new first spec (to prepend)
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList withFirst(RegisterSpec spec) {
- int sz = size();
- RegisterSpecList result = new RegisterSpecList(sz + 1);
+ RegisterSpecList result = new RegisterSpecList(newSize);
- for (int i = 0; i < sz; i++) {
- result.set0(i + 1, get0(i));
- }
-
- result.set0(0, spec);
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ int newIndex = 0;
+ for (int oldIndex = 0; oldIndex < size(); oldIndex++) {
+ if (!exclusionSet.get(oldIndex)) {
+ result.set0(newIndex, get0(oldIndex));
+ newIndex++;
+ }
}
- /**
- * Returns a new instance, which is the same as this instance,
- * except that its first element is removed. Mutability of the
- * result is inherited from the original.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList withoutFirst() {
- int newSize = size() - 1;
-
- if (newSize == 0) {
- return EMPTY;
- }
-
- RegisterSpecList result = new RegisterSpecList(newSize);
-
- for (int i = 0; i < newSize; i++) {
- result.set0(i, get0(i + 1));
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Returns a new instance, which is the same as this instance,
- * except that its last element is removed. Mutability of the
- * result is inherited from the original.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList withoutLast() {
- int newSize = size() - 1;
+ return result;
+ }
- if (newSize == 0) {
- return EMPTY;
- }
+ /**
+ * Returns an instance that is identical to this one, except that
+ * all register numbers are offset by the given amount. Mutability
+ * of the result is inherited from the original.
+ *
+ * @param delta the amount to offset the register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList withOffset(int delta) {
+ int sz = size();
- RegisterSpecList result = new RegisterSpecList(newSize);
-
- for (int i = 0; i < newSize; i++) {
- result.set0(i, get0(i));
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ if (sz == 0) {
+ // Don't bother making a new zero-element instance.
+ return this;
}
- /**
- * Returns a new instance, which contains a subset of the elements
- * specified by the given BitSet. Indexes in the BitSet with a zero
- * are included, while indexes with a one are excluded. Mutability
- * of the result is inherited from the original.
- *
- * @param exclusionSet {@code non-null;} set of registers to exclude
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList subset(BitSet exclusionSet) {
- int newSize = size() - exclusionSet.cardinality();
+ RegisterSpecList result = new RegisterSpecList(sz);
- if (newSize == 0) {
- return EMPTY;
- }
-
- RegisterSpecList result = new RegisterSpecList(newSize);
-
- int newIndex = 0;
- for (int oldIndex = 0; oldIndex < size(); oldIndex++) {
- if (!exclusionSet.get(oldIndex)) {
- result.set0(newIndex, get0(oldIndex));
- newIndex++;
- }
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec one = (RegisterSpec) get0(i);
+ if (one != null) {
+ result.set0(i, one.withOffset(delta));
+ }
}
- /**
- * Returns an instance that is identical to this one, except that
- * all register numbers are offset by the given amount. Mutability
- * of the result is inherited from the original.
- *
- * @param delta the amount to offset the register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList withOffset(int delta) {
- int sz = size();
-
- if (sz == 0) {
- // Don't bother making a new zero-element instance.
- return this;
- }
-
- RegisterSpecList result = new RegisterSpecList(sz);
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec one = (RegisterSpec) get0(i);
- if (one != null) {
- result.set0(i, one.withOffset(delta));
- }
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Returns an instance that is identical to this one, except that
- * all incompatible register numbers are renumbered sequentially from
- * the given base, with the first number duplicated if indicated. If
- * a null BitSet is given, it indicates all registers are compatible.
- *
- * @param base the base register number
- * @param duplicateFirst whether to duplicate the first number
- * @param compatRegs {@code null-ok;} either a {@code non-null} set of
- * compatible registers, or {@code null} to indicate all registers are
- * compatible
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecList withExpandedRegisters(int base,
- boolean duplicateFirst,
- BitSet compatRegs) {
- int sz = size();
+ return result;
+ }
- if (sz == 0) {
- // Don't bother making a new zero-element instance.
- return this;
- }
+ /**
+ * Returns an instance that is identical to this one, except that
+ * all incompatible register numbers are renumbered sequentially from
+ * the given base, with the first number duplicated if indicated. If
+ * a null BitSet is given, it indicates all registers are compatible.
+ *
+ * @param base the base register number
+ * @param duplicateFirst whether to duplicate the first number
+ * @param compatRegs {@code null-ok;} either a {@code non-null} set of
+ * compatible registers, or {@code null} to indicate all registers are
+ * compatible
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecList withExpandedRegisters(int base, boolean duplicateFirst,
+ BitSet compatRegs) {
+ int sz = size();
- RegisterSpecList result = new RegisterSpecList(sz);
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec one = (RegisterSpec) get0(i);
- boolean replace = (compatRegs == null) ? true : !compatRegs.get(i);
-
- if (replace) {
- result.set0(i, one.withReg(base));
- if (!duplicateFirst) {
- base += one.getCategory();
- }
- } else {
- result.set0(i, one);
- }
-
- if (duplicateFirst) {
- duplicateFirst = false;
- }
- }
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
+ if (sz == 0) {
+ // Don't bother making a new zero-element instance.
+ return this;
}
+
+ RegisterSpecList result = new RegisterSpecList(sz);
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec one = (RegisterSpec) get0(i);
+ boolean replace = (compatRegs == null) ? true : !compatRegs.get(i);
+
+ if (replace) {
+ result.set0(i, one.withReg(base));
+ if (!duplicateFirst) {
+ base += one.getCategory();
+ }
+ } else {
+ result.set0(i, one);
+ }
+
+ if (duplicateFirst) {
+ duplicateFirst = false;
+ }
+ }
+
+ if (isImmutable()) {
+ result.setImmutable();
+ }
+
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/RegisterSpecSet.java b/dx/src/com/android/jack/dx/rop/code/RegisterSpecSet.java
index 4116155..7538027 100644
--- a/dx/src/com/android/jack/dx/rop/code/RegisterSpecSet.java
+++ b/dx/src/com/android/jack/dx/rop/code/RegisterSpecSet.java
@@ -22,375 +22,373 @@
* Set of {@link RegisterSpec} instances, where a given register number
* may appear only once in the set.
*/
-public final class RegisterSpecSet
- extends MutabilityControl {
- /** {@code non-null;} no-element instance */
- public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0);
+public final class RegisterSpecSet extends MutabilityControl {
+ /** {@code non-null;} no-element instance */
+ public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0);
- /**
- * {@code non-null;} array of register specs, where each element is
- * {@code null} or is an instance whose {@code reg}
- * matches the array index
- */
- private final RegisterSpec[] specs;
+ /**
+ * {@code non-null;} array of register specs, where each element is
+ * {@code null} or is an instance whose {@code reg}
+ * matches the array index
+ */
+ private final RegisterSpec[] specs;
- /** {@code >= -1;} size of the set or {@code -1} if not yet calculated */
- private int size;
+ /** {@code >= -1;} size of the set or {@code -1} if not yet calculated */
+ private int size;
- /**
- * Constructs an instance. The instance is initially empty.
- *
- * @param maxSize {@code >= 0;} the maximum register number (exclusive) that
- * may be represented in this instance
- */
- public RegisterSpecSet(int maxSize) {
- super(maxSize != 0);
+ /**
+ * Constructs an instance. The instance is initially empty.
+ *
+ * @param maxSize {@code >= 0;} the maximum register number (exclusive) that
+ * may be represented in this instance
+ */
+ public RegisterSpecSet(int maxSize) {
+ super(maxSize != 0);
- this.specs = new RegisterSpec[maxSize];
- this.size = 0;
+ this.specs = new RegisterSpec[maxSize];
+ this.size = 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RegisterSpecSet)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof RegisterSpecSet)) {
- return false;
- }
+ RegisterSpecSet otherSet = (RegisterSpecSet) other;
+ RegisterSpec[] otherSpecs = otherSet.specs;
+ int len = specs.length;
- RegisterSpecSet otherSet = (RegisterSpecSet) other;
- RegisterSpec[] otherSpecs = otherSet.specs;
- int len = specs.length;
-
- if ((len != otherSpecs.length) || (size() != otherSet.size())) {
- return false;
- }
-
- for (int i = 0; i < len; i++) {
- RegisterSpec s1 = specs[i];
- RegisterSpec s2 = otherSpecs[i];
-
- if (s1 == s2) {
- continue;
- }
-
- if ((s1 == null) || !s1.equals(s2)) {
- return false;
- }
- }
-
- return true;
+ if ((len != otherSpecs.length) || (size() != otherSet.size())) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- int len = specs.length;
- int hash = 0;
+ for (int i = 0; i < len; i++) {
+ RegisterSpec s1 = specs[i];
+ RegisterSpec s2 = otherSpecs[i];
- for (int i = 0; i < len; i++) {
- RegisterSpec spec = specs[i];
- int oneHash = (spec == null) ? 0 : spec.hashCode();
- hash = (hash * 31) + oneHash;
- }
+ if (s1 == s2) {
+ continue;
+ }
- return hash;
+ if ((s1 == null) || !s1.equals(s2)) {
+ return false;
+ }
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int len = specs.length;
- StringBuffer sb = new StringBuffer(len * 25);
+ return true;
+ }
- sb.append('{');
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ int len = specs.length;
+ int hash = 0;
- boolean any = false;
- for (int i = 0; i < len; i++) {
- RegisterSpec spec = specs[i];
- if (spec != null) {
- if (any) {
- sb.append(", ");
- } else {
- any = true;
- }
- sb.append(spec);
- }
- }
-
- sb.append('}');
- return sb.toString();
+ for (int i = 0; i < len; i++) {
+ RegisterSpec spec = specs[i];
+ int oneHash = (spec == null) ? 0 : spec.hashCode();
+ hash = (hash * 31) + oneHash;
}
- /**
- * Gets the maximum number of registers that may be in this instance, which
- * is also the maximum-plus-one of register numbers that may be
- * represented.
- *
- * @return {@code >= 0;} the maximum size
- */
- public int getMaxSize() {
- return specs.length;
+ return hash;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int len = specs.length;
+ StringBuffer sb = new StringBuffer(len * 25);
+
+ sb.append('{');
+
+ boolean any = false;
+ for (int i = 0; i < len; i++) {
+ RegisterSpec spec = specs[i];
+ if (spec != null) {
+ if (any) {
+ sb.append(", ");
+ } else {
+ any = true;
+ }
+ sb.append(spec);
+ }
}
- /**
- * Gets the current size of this instance.
- *
- * @return {@code >= 0;} the size
- */
- public int size() {
- int result = size;
+ sb.append('}');
+ return sb.toString();
+ }
- if (result < 0) {
- int len = specs.length;
+ /**
+ * Gets the maximum number of registers that may be in this instance, which
+ * is also the maximum-plus-one of register numbers that may be
+ * represented.
+ *
+ * @return {@code >= 0;} the maximum size
+ */
+ public int getMaxSize() {
+ return specs.length;
+ }
- result = 0;
- for (int i = 0; i < len; i++) {
- if (specs[i] != null) {
- result++;
- }
- }
+ /**
+ * Gets the current size of this instance.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int size() {
+ int result = size;
- size = result;
+ if (result < 0) {
+ int len = specs.length;
+
+ result = 0;
+ for (int i = 0; i < len; i++) {
+ if (specs[i] != null) {
+ result++;
}
+ }
- return result;
+ size = result;
}
- /**
- * Gets the element with the given register number, if any.
- *
- * @param reg {@code >= 0;} the desired register number
- * @return {@code null-ok;} the element with the given register number or
- * {@code null} if there is none
- */
- public RegisterSpec get(int reg) {
- try {
- return specs[reg];
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus reg");
- }
+ return result;
+ }
+
+ /**
+ * Gets the element with the given register number, if any.
+ *
+ * @param reg {@code >= 0;} the desired register number
+ * @return {@code null-ok;} the element with the given register number or
+ * {@code null} if there is none
+ */
+ public RegisterSpec get(int reg) {
+ try {
+ return specs[reg];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus reg");
+ }
+ }
+
+ /**
+ * Gets the element with the same register number as the given
+ * spec, if any. This is just a convenient shorthand for
+ * {@code get(spec.getReg())}.
+ *
+ * @param spec {@code non-null;} spec with the desired register number
+ * @return {@code null-ok;} the element with the matching register number or
+ * {@code null} if there is none
+ */
+ public RegisterSpec get(RegisterSpec spec) {
+ return get(spec.getReg());
+ }
+
+ /**
+ * Returns the spec in this set that's currently associated with a
+ * given local (type, name, and signature), or {@code null} if there is
+ * none. This ignores the register number of the given spec but
+ * matches on everything else.
+ *
+ * @param spec {@code non-null;} local to look for
+ * @return {@code null-ok;} first register found that matches, if any
+ */
+ public RegisterSpec findMatchingLocal(RegisterSpec spec) {
+ int length = specs.length;
+
+ for (int reg = 0; reg < length; reg++) {
+ RegisterSpec s = specs[reg];
+
+ if (s == null) {
+ continue;
+ }
+
+ if (spec.matchesVariable(s)) {
+ return s;
+ }
}
- /**
- * Gets the element with the same register number as the given
- * spec, if any. This is just a convenient shorthand for
- * {@code get(spec.getReg())}.
- *
- * @param spec {@code non-null;} spec with the desired register number
- * @return {@code null-ok;} the element with the matching register number or
- * {@code null} if there is none
- */
- public RegisterSpec get(RegisterSpec spec) {
- return get(spec.getReg());
+ return null;
+ }
+
+ /**
+ * Returns the spec in this set that's currently associated with a given
+ * local (name and signature), or {@code null} if there is none.
+ *
+ * @param local {@code non-null;} local item to search for
+ * @return {@code null-ok;} first register found with matching name and signature
+ */
+ public RegisterSpec localItemToSpec(LocalItem local) {
+ int length = specs.length;
+
+ for (int reg = 0; reg < length; reg++) {
+ RegisterSpec spec = specs[reg];
+
+ if ((spec != null) && local.equals(spec.getLocalItem())) {
+ return spec;
+ }
}
- /**
- * Returns the spec in this set that's currently associated with a
- * given local (type, name, and signature), or {@code null} if there is
- * none. This ignores the register number of the given spec but
- * matches on everything else.
- *
- * @param spec {@code non-null;} local to look for
- * @return {@code null-ok;} first register found that matches, if any
- */
- public RegisterSpec findMatchingLocal(RegisterSpec spec) {
- int length = specs.length;
+ return null;
+ }
- for (int reg = 0; reg < length; reg++) {
- RegisterSpec s = specs[reg];
+ /**
+ * Removes a spec from the set. Only the register number
+ * of the parameter is significant.
+ *
+ * @param toRemove {@code non-null;} register to remove.
+ */
+ public void remove(RegisterSpec toRemove) {
+ try {
+ specs[toRemove.getReg()] = null;
+ size = -1;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus reg");
+ }
+ }
- if (s == null) {
- continue;
- }
+ /**
+ * Puts the given spec into the set. If there is already an element in
+ * the set with the same register number, it is replaced. Additionally,
+ * if the previous element is for a category-2 register, then that
+ * previous element is nullified. Finally, if the given spec is for
+ * a category-2 register, then the immediately subsequent element
+ * is nullified.
+ *
+ * @param spec {@code non-null;} the register spec to put in the instance
+ */
+ public void put(RegisterSpec spec) {
+ throwIfImmutable();
- if (spec.matchesVariable(s)) {
- return s;
- }
- }
-
- return null;
+ if (spec == null) {
+ throw new NullPointerException("spec == null");
}
- /**
- * Returns the spec in this set that's currently associated with a given
- * local (name and signature), or {@code null} if there is none.
- *
- * @param local {@code non-null;} local item to search for
- * @return {@code null-ok;} first register found with matching name and signature
- */
- public RegisterSpec localItemToSpec(LocalItem local) {
- int length = specs.length;
+ size = -1;
- for (int reg = 0; reg < length; reg++) {
- RegisterSpec spec = specs[reg];
+ try {
+ int reg = spec.getReg();
+ specs[reg] = spec;
- if ((spec != null) && local.equals(spec.getLocalItem())) {
- return spec;
- }
+ if (reg > 0) {
+ int prevReg = reg - 1;
+ RegisterSpec prevSpec = specs[prevReg];
+ if ((prevSpec != null) && (prevSpec.getCategory() == 2)) {
+ specs[prevReg] = null;
}
+ }
- return null;
+ if (spec.getCategory() == 2) {
+ specs[reg + 1] = null;
+ }
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("spec.getReg() out of range");
+ }
+ }
+
+ /**
+ * Put the entire contents of the given set into this one.
+ *
+ * @param set {@code non-null;} the set to put into this instance
+ */
+ public void putAll(RegisterSpecSet set) {
+ int max = set.getMaxSize();
+
+ for (int i = 0; i < max; i++) {
+ RegisterSpec spec = set.get(i);
+ if (spec != null) {
+ put(spec);
+ }
+ }
+ }
+
+ /**
+ * Intersects this instance with the given one, modifying this
+ * instance. The intersection consists of the pairwise
+ * {@link RegisterSpec#intersect} of corresponding elements from
+ * this instance and the given one where both are non-null.
+ *
+ * @param other {@code non-null;} set to intersect with
+ * @param localPrimary whether local variables are primary to
+ * the intersection; if {@code true}, then the only non-null
+ * result elements occur when registers being intersected have
+ * equal names (or both have {@code null} names)
+ */
+ public void intersect(RegisterSpecSet other, boolean localPrimary) {
+ throwIfImmutable();
+
+ RegisterSpec[] otherSpecs = other.specs;
+ int thisLen = specs.length;
+ int len = Math.min(thisLen, otherSpecs.length);
+
+ size = -1;
+
+ for (int i = 0; i < len; i++) {
+ RegisterSpec spec = specs[i];
+
+ if (spec == null) {
+ continue;
+ }
+
+ RegisterSpec intersection = spec.intersect(otherSpecs[i], localPrimary);
+ if (intersection != spec) {
+ specs[i] = intersection;
+ }
}
- /**
- * Removes a spec from the set. Only the register number
- * of the parameter is significant.
- *
- * @param toRemove {@code non-null;} register to remove.
- */
- public void remove(RegisterSpec toRemove) {
- try {
- specs[toRemove.getReg()] = null;
- size = -1;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus reg");
- }
+ for (int i = len; i < thisLen; i++) {
+ specs[i] = null;
+ }
+ }
+
+ /**
+ * Returns an instance that is identical to this one, except that
+ * all register numbers are offset by the given amount. Mutability
+ * of the result is inherited from the original.
+ *
+ * @param delta the amount to offset the register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RegisterSpecSet withOffset(int delta) {
+ int len = specs.length;
+ RegisterSpecSet result = new RegisterSpecSet(len + delta);
+
+ for (int i = 0; i < len; i++) {
+ RegisterSpec spec = specs[i];
+ if (spec != null) {
+ result.put(spec.withOffset(delta));
+ }
}
- /**
- * Puts the given spec into the set. If there is already an element in
- * the set with the same register number, it is replaced. Additionally,
- * if the previous element is for a category-2 register, then that
- * previous element is nullified. Finally, if the given spec is for
- * a category-2 register, then the immediately subsequent element
- * is nullified.
- *
- * @param spec {@code non-null;} the register spec to put in the instance
- */
- public void put(RegisterSpec spec) {
- throwIfImmutable();
+ result.size = size;
- if (spec == null) {
- throw new NullPointerException("spec == null");
- }
-
- size = -1;
-
- try {
- int reg = spec.getReg();
- specs[reg] = spec;
-
- if (reg > 0) {
- int prevReg = reg - 1;
- RegisterSpec prevSpec = specs[prevReg];
- if ((prevSpec != null) && (prevSpec.getCategory() == 2)) {
- specs[prevReg] = null;
- }
- }
-
- if (spec.getCategory() == 2) {
- specs[reg + 1] = null;
- }
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("spec.getReg() out of range");
- }
+ if (isImmutable()) {
+ result.setImmutable();
}
- /**
- * Put the entire contents of the given set into this one.
- *
- * @param set {@code non-null;} the set to put into this instance
- */
- public void putAll(RegisterSpecSet set) {
- int max = set.getMaxSize();
+ return result;
+ }
- for (int i = 0; i < max; i++) {
- RegisterSpec spec = set.get(i);
- if (spec != null) {
- put(spec);
- }
- }
+ /**
+ * Makes and return a mutable copy of this instance.
+ *
+ * @return {@code non-null;} the mutable copy
+ */
+ public RegisterSpecSet mutableCopy() {
+ int len = specs.length;
+ RegisterSpecSet copy = new RegisterSpecSet(len);
+
+ for (int i = 0; i < len; i++) {
+ RegisterSpec spec = specs[i];
+ if (spec != null) {
+ copy.put(spec);
+ }
}
- /**
- * Intersects this instance with the given one, modifying this
- * instance. The intersection consists of the pairwise
- * {@link RegisterSpec#intersect} of corresponding elements from
- * this instance and the given one where both are non-null.
- *
- * @param other {@code non-null;} set to intersect with
- * @param localPrimary whether local variables are primary to
- * the intersection; if {@code true}, then the only non-null
- * result elements occur when registers being intersected have
- * equal names (or both have {@code null} names)
- */
- public void intersect(RegisterSpecSet other, boolean localPrimary) {
- throwIfImmutable();
+ copy.size = size;
- RegisterSpec[] otherSpecs = other.specs;
- int thisLen = specs.length;
- int len = Math.min(thisLen, otherSpecs.length);
-
- size = -1;
-
- for (int i = 0; i < len; i++) {
- RegisterSpec spec = specs[i];
-
- if (spec == null) {
- continue;
- }
-
- RegisterSpec intersection =
- spec.intersect(otherSpecs[i], localPrimary);
- if (intersection != spec) {
- specs[i] = intersection;
- }
- }
-
- for (int i = len; i < thisLen; i++) {
- specs[i] = null;
- }
- }
-
- /**
- * Returns an instance that is identical to this one, except that
- * all register numbers are offset by the given amount. Mutability
- * of the result is inherited from the original.
- *
- * @param delta the amount to offset the register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RegisterSpecSet withOffset(int delta) {
- int len = specs.length;
- RegisterSpecSet result = new RegisterSpecSet(len + delta);
-
- for (int i = 0; i < len; i++) {
- RegisterSpec spec = specs[i];
- if (spec != null) {
- result.put(spec.withOffset(delta));
- }
- }
-
- result.size = size;
-
- if (isImmutable()) {
- result.setImmutable();
- }
-
- return result;
- }
-
- /**
- * Makes and return a mutable copy of this instance.
- *
- * @return {@code non-null;} the mutable copy
- */
- public RegisterSpecSet mutableCopy() {
- int len = specs.length;
- RegisterSpecSet copy = new RegisterSpecSet(len);
-
- for (int i = 0; i < len; i++) {
- RegisterSpec spec = specs[i];
- if (spec != null) {
- copy.put(spec);
- }
- }
-
- copy.size = size;
-
- return copy;
- }
+ return copy;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/Rop.java b/dx/src/com/android/jack/dx/rop/code/Rop.java
index 161a0ee..3ae002b 100644
--- a/dx/src/com/android/jack/dx/rop/code/Rop.java
+++ b/dx/src/com/android/jack/dx/rop/code/Rop.java
@@ -25,383 +25,392 @@
* Class that describes all the immutable parts of register-based operations.
*/
public final class Rop {
- /** minimum {@code BRANCH_*} value */
- public static final int BRANCH_MIN = 1;
+ /** minimum {@code BRANCH_*} value */
+ public static final int BRANCH_MIN = 1;
- /** indicates a non-branching op */
- public static final int BRANCH_NONE = 1;
+ /** indicates a non-branching op */
+ public static final int BRANCH_NONE = 1;
- /** indicates a function/method return */
- public static final int BRANCH_RETURN = 2;
+ /** indicates a function/method return */
+ public static final int BRANCH_RETURN = 2;
- /** indicates an unconditional goto */
- public static final int BRANCH_GOTO = 3;
+ /** indicates an unconditional goto */
+ public static final int BRANCH_GOTO = 3;
- /** indicates a two-way branch */
- public static final int BRANCH_IF = 4;
+ /** indicates a two-way branch */
+ public static final int BRANCH_IF = 4;
- /** indicates a switch-style branch */
- public static final int BRANCH_SWITCH = 5;
+ /** indicates a switch-style branch */
+ public static final int BRANCH_SWITCH = 5;
- /** indicates a throw-style branch (both always-throws and may-throw) */
- public static final int BRANCH_THROW = 6;
+ /** indicates a throw-style branch (both always-throws and may-throw) */
+ public static final int BRANCH_THROW = 6;
- /** maximum {@code BRANCH_*} value */
- public static final int BRANCH_MAX = 6;
+ /** maximum {@code BRANCH_*} value */
+ public static final int BRANCH_MAX = 6;
- /** the opcode; one of the constants in {@link RegOps} */
- private final int opcode;
+ /** the opcode; one of the constants in {@link RegOps} */
+ private final int opcode;
- /**
- * {@code non-null;} result type of this operation; {@link Type#VOID} for
- * no-result operations
- */
- private final Type result;
+ /**
+ * {@code non-null;} result type of this operation; {@link Type#VOID} for
+ * no-result operations
+ */
+ private final Type result;
- /** {@code non-null;} types of all the sources of this operation */
- private final TypeList sources;
+ /** {@code non-null;} types of all the sources of this operation */
+ private final TypeList sources;
- /** {@code non-null;} list of possible types thrown by this operation */
- private final TypeList exceptions;
+ /** {@code non-null;} list of possible types thrown by this operation */
+ private final TypeList exceptions;
- /**
- * the branchingness of this op; one of the {@code BRANCH_*}
- * constants in this class
- */
- private final int branchingness;
+ /**
+ * the branchingness of this op; one of the {@code BRANCH_*}
+ * constants in this class
+ */
+ private final int branchingness;
- /** whether this is a function/method call op or similar */
- private final boolean isCallLike;
+ /** whether this is a function/method call op or similar */
+ private final boolean isCallLike;
- /** {@code null-ok;} nickname, if specified (used for debugging) */
- private final String nickname;
+ /** {@code null-ok;} nickname, if specified (used for debugging) */
+ private final String nickname;
- /**
- * Constructs an instance. This method is private. Use one of the
- * public constructors.
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result {@code non-null;} result type of this operation; {@link
- * Type#VOID} for no-result operations
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param exceptions {@code non-null;} list of possible types thrown by this
- * operation
- * @param branchingness the branchingness of this op; one of the
- * {@code BRANCH_*} constants
- * @param isCallLike whether the op is a function/method call or similar
- * @param nickname {@code null-ok;} optional nickname (used for debugging)
- */
- public Rop(int opcode, Type result, TypeList sources,
- TypeList exceptions, int branchingness, boolean isCallLike,
- String nickname) {
- if (result == null) {
- throw new NullPointerException("result == null");
- }
-
- if (sources == null) {
- throw new NullPointerException("sources == null");
- }
-
- if (exceptions == null) {
- throw new NullPointerException("exceptions == null");
- }
-
- if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) {
- throw new IllegalArgumentException("bogus branchingness");
- }
-
- if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) {
- throw new IllegalArgumentException("exceptions / branchingness " +
- "mismatch");
- }
-
- this.opcode = opcode;
- this.result = result;
- this.sources = sources;
- this.exceptions = exceptions;
- this.branchingness = branchingness;
- this.isCallLike = isCallLike;
- this.nickname = nickname;
+ /**
+ * Constructs an instance. This method is private. Use one of the
+ * public constructors.
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param result {@code non-null;} result type of this operation; {@link
+ * Type#VOID} for no-result operations
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param exceptions {@code non-null;} list of possible types thrown by this
+ * operation
+ * @param branchingness the branchingness of this op; one of the
+ * {@code BRANCH_*} constants
+ * @param isCallLike whether the op is a function/method call or similar
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
+ */
+ public Rop(int opcode,
+ Type result,
+ TypeList sources,
+ TypeList exceptions,
+ int branchingness,
+ boolean isCallLike,
+ String nickname) {
+ if (result == null) {
+ throw new NullPointerException("result == null");
}
- /**
- * Constructs an instance. The constructed instance is never a
- * call-like op (see {@link #isCallLike}).
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result {@code non-null;} result type of this operation; {@link
- * Type#VOID} for no-result operations
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param exceptions {@code non-null;} list of possible types thrown by this
- * operation
- * @param branchingness the branchingness of this op; one of the
- * {@code BRANCH_*} constants
- * @param nickname {@code null-ok;} optional nickname (used for debugging)
- */
- public Rop(int opcode, Type result, TypeList sources,
- TypeList exceptions, int branchingness, String nickname) {
- this(opcode, result, sources, exceptions, branchingness, false,
- nickname);
+ if (sources == null) {
+ throw new NullPointerException("sources == null");
}
- /**
- * Constructs a no-exception instance. The constructed instance is never a
- * call-like op (see {@link #isCallLike}).
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result {@code non-null;} result type of this operation; {@link
- * Type#VOID} for no-result operations
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param branchingness the branchingness of this op; one of the
- * {@code BRANCH_*} constants
- * @param nickname {@code null-ok;} optional nickname (used for debugging)
- */
- public Rop(int opcode, Type result, TypeList sources, int branchingness,
- String nickname) {
- this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false,
- nickname);
+ if (exceptions == null) {
+ throw new NullPointerException("exceptions == null");
}
- /**
- * Constructs a non-branching no-exception instance. The
- * {@code branchingness} is always {@code BRANCH_NONE},
- * and it is never a call-like op (see {@link #isCallLike}).
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result {@code non-null;} result type of this operation; {@link
- * Type#VOID} for no-result operations
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param nickname {@code null-ok;} optional nickname (used for debugging)
- */
- public Rop(int opcode, Type result, TypeList sources, String nickname) {
- this(opcode, result, sources, StdTypeList.EMPTY, Rop.BRANCH_NONE,
- false, nickname);
+ if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) {
+ throw new IllegalArgumentException("bogus branchingness");
}
- /**
- * Constructs a non-empty exceptions instance. Its
- * {@code branchingness} is always {@code BRANCH_THROW},
- * but it is never a call-like op (see {@link #isCallLike}).
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result {@code non-null;} result type of this operation; {@link
- * Type#VOID} for no-result operations
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param exceptions {@code non-null;} list of possible types thrown by this
- * operation
- * @param nickname {@code null-ok;} optional nickname (used for debugging)
- */
- public Rop(int opcode, Type result, TypeList sources, TypeList exceptions,
- String nickname) {
- this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false,
- nickname);
+ if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) {
+ throw new IllegalArgumentException("exceptions / branchingness " + "mismatch");
}
- /**
- * Constructs a non-nicknamed instance with non-empty exceptions, which
- * is always a call-like op (see {@link #isCallLike}). Its
- * {@code branchingness} is always {@code BRANCH_THROW}.
- *
- * @param opcode the opcode; one of the constants in {@link RegOps}
- * @param sources {@code non-null;} types of all the sources of this operation
- * @param exceptions {@code non-null;} list of possible types thrown by this
- * operation
- */
- public Rop(int opcode, TypeList sources, TypeList exceptions) {
- this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true,
- null);
+ this.opcode = opcode;
+ this.result = result;
+ this.sources = sources;
+ this.exceptions = exceptions;
+ this.branchingness = branchingness;
+ this.isCallLike = isCallLike;
+ this.nickname = nickname;
+ }
+
+ /**
+ * Constructs an instance. The constructed instance is never a
+ * call-like op (see {@link #isCallLike}).
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param result {@code non-null;} result type of this operation; {@link
+ * Type#VOID} for no-result operations
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param exceptions {@code non-null;} list of possible types thrown by this
+ * operation
+ * @param branchingness the branchingness of this op; one of the
+ * {@code BRANCH_*} constants
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
+ */
+ public Rop(int opcode,
+ Type result,
+ TypeList sources,
+ TypeList exceptions,
+ int branchingness,
+ String nickname) {
+ this(opcode, result, sources, exceptions, branchingness, false, nickname);
+ }
+
+ /**
+ * Constructs a no-exception instance. The constructed instance is never a
+ * call-like op (see {@link #isCallLike}).
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param result {@code non-null;} result type of this operation; {@link
+ * Type#VOID} for no-result operations
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param branchingness the branchingness of this op; one of the
+ * {@code BRANCH_*} constants
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
+ */
+ public Rop(int opcode, Type result, TypeList sources, int branchingness, String nickname) {
+ this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false, nickname);
+ }
+
+ /**
+ * Constructs a non-branching no-exception instance. The
+ * {@code branchingness} is always {@code BRANCH_NONE},
+ * and it is never a call-like op (see {@link #isCallLike}).
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param result {@code non-null;} result type of this operation; {@link
+ * Type#VOID} for no-result operations
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
+ */
+ public Rop(int opcode, Type result, TypeList sources, String nickname) {
+ this(opcode, result, sources, StdTypeList.EMPTY, Rop.BRANCH_NONE, false, nickname);
+ }
+
+ /**
+ * Constructs a non-empty exceptions instance. Its
+ * {@code branchingness} is always {@code BRANCH_THROW},
+ * but it is never a call-like op (see {@link #isCallLike}).
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param result {@code non-null;} result type of this operation; {@link
+ * Type#VOID} for no-result operations
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param exceptions {@code non-null;} list of possible types thrown by this
+ * operation
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
+ */
+ public Rop(int opcode, Type result, TypeList sources, TypeList exceptions, String nickname) {
+ this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false, nickname);
+ }
+
+ /**
+ * Constructs a non-nicknamed instance with non-empty exceptions, which
+ * is always a call-like op (see {@link #isCallLike}). Its
+ * {@code branchingness} is always {@code BRANCH_THROW}.
+ *
+ * @param opcode the opcode; one of the constants in {@link RegOps}
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param exceptions {@code non-null;} list of possible types thrown by this
+ * operation
+ */
+ public Rop(int opcode, TypeList sources, TypeList exceptions) {
+ this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true, null);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ // Easy out.
+ return true;
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- // Easy out.
- return true;
- }
-
- if (!(other instanceof Rop)) {
- return false;
- }
-
- Rop rop = (Rop) other;
-
- return (opcode == rop.opcode) &&
- (branchingness == rop.branchingness) &&
- (result == rop.result) &&
- sources.equals(rop.sources) &&
- exceptions.equals(rop.exceptions);
+ if (!(other instanceof Rop)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- int h = (opcode * 31) + branchingness;
- h = (h * 31) + result.hashCode();
- h = (h * 31) + sources.hashCode();
- h = (h * 31) + exceptions.hashCode();
+ Rop rop = (Rop) other;
- return h;
+ return (opcode == rop.opcode) && (branchingness == rop.branchingness) && (result == rop.result)
+ && sources.equals(rop.sources) && exceptions.equals(rop.exceptions);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ int h = (opcode * 31) + branchingness;
+ h = (h * 31) + result.hashCode();
+ h = (h * 31) + sources.hashCode();
+ h = (h * 31) + exceptions.hashCode();
+
+ return h;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(40);
+
+ sb.append("Rop{");
+
+ sb.append(RegOps.opName(opcode));
+
+ if (result != Type.VOID) {
+ sb.append(" ");
+ sb.append(result);
+ } else {
+ sb.append(" .");
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(40);
+ sb.append(" <-");
- sb.append("Rop{");
+ int sz = sources.size();
+ if (sz == 0) {
+ sb.append(" .");
+ } else {
+ for (int i = 0; i < sz; i++) {
+ sb.append(' ');
+ sb.append(sources.getType(i));
+ }
+ }
- sb.append(RegOps.opName(opcode));
+ if (isCallLike) {
+ sb.append(" call");
+ }
- if (result != Type.VOID) {
- sb.append(" ");
- sb.append(result);
+ sz = exceptions.size();
+ if (sz != 0) {
+ sb.append(" throws");
+ for (int i = 0; i < sz; i++) {
+ sb.append(' ');
+ Type one = exceptions.getType(i);
+ if (one == Type.THROWABLE) {
+ sb.append("<any>");
} else {
- sb.append(" .");
+ sb.append(exceptions.getType(i));
}
-
- sb.append(" <-");
-
- int sz = sources.size();
- if (sz == 0) {
- sb.append(" .");
- } else {
- for (int i = 0; i < sz; i++) {
- sb.append(' ');
- sb.append(sources.getType(i));
- }
- }
-
- if (isCallLike) {
- sb.append(" call");
- }
-
- sz = exceptions.size();
- if (sz != 0) {
- sb.append(" throws");
- for (int i = 0; i < sz; i++) {
- sb.append(' ');
- Type one = exceptions.getType(i);
- if (one == Type.THROWABLE) {
- sb.append("<any>");
- } else {
- sb.append(exceptions.getType(i));
- }
- }
- } else {
- switch (branchingness) {
- case BRANCH_NONE: sb.append(" flows"); break;
- case BRANCH_RETURN: sb.append(" returns"); break;
- case BRANCH_GOTO: sb.append(" gotos"); break;
- case BRANCH_IF: sb.append(" ifs"); break;
- case BRANCH_SWITCH: sb.append(" switches"); break;
- default: sb.append(" " + Hex.u1(branchingness)); break;
- }
- }
-
- sb.append('}');
-
- return sb.toString();
+ }
+ } else {
+ switch (branchingness) {
+ case BRANCH_NONE:
+ sb.append(" flows");
+ break;
+ case BRANCH_RETURN:
+ sb.append(" returns");
+ break;
+ case BRANCH_GOTO:
+ sb.append(" gotos");
+ break;
+ case BRANCH_IF:
+ sb.append(" ifs");
+ break;
+ case BRANCH_SWITCH:
+ sb.append(" switches");
+ break;
+ default:
+ sb.append(" " + Hex.u1(branchingness));
+ break;
+ }
}
- /**
- * Gets the opcode.
- *
- * @return the opcode
- */
- public int getOpcode() {
- return opcode;
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /**
+ * Gets the opcode.
+ *
+ * @return the opcode
+ */
+ public int getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Gets the result type. A return value of {@link Type#VOID}
+ * means this operation returns nothing.
+ *
+ * @return {@code null-ok;} the result spec
+ */
+ public Type getResult() {
+ return result;
+ }
+
+ /**
+ * Gets the source types.
+ *
+ * @return {@code non-null;} the source types
+ */
+ public TypeList getSources() {
+ return sources;
+ }
+
+ /**
+ * Gets the list of exception types that might be thrown.
+ *
+ * @return {@code non-null;} the list of exception types
+ */
+ public TypeList getExceptions() {
+ return exceptions;
+ }
+
+ /**
+ * Gets the branchingness of this instance.
+ *
+ * @return the branchingness
+ */
+ public int getBranchingness() {
+ return branchingness;
+ }
+
+ /**
+ * Gets whether this opcode is a function/method call or similar.
+ *
+ * @return {@code true} iff this opcode is call-like
+ */
+ public boolean isCallLike() {
+ return isCallLike;
+ }
+
+
+ /**
+ * Gets whether this opcode is commutative (the order of its sources are
+ * unimportant) or not. All commutative Rops have exactly two sources and
+ * have no branchiness.
+ *
+ * @return true if rop is commutative
+ */
+ public boolean isCommutative() {
+ switch (opcode) {
+ case RegOps.AND:
+ case RegOps.OR:
+ case RegOps.XOR:
+ case RegOps.ADD:
+ case RegOps.MUL:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Gets the nickname. If this instance has no nickname, this returns
+ * the result of calling {@link #toString}.
+ *
+ * @return {@code non-null;} the nickname
+ */
+ public String getNickname() {
+ if (nickname != null) {
+ return nickname;
}
- /**
- * Gets the result type. A return value of {@link Type#VOID}
- * means this operation returns nothing.
- *
- * @return {@code null-ok;} the result spec
- */
- public Type getResult() {
- return result;
- }
+ return toString();
+ }
- /**
- * Gets the source types.
- *
- * @return {@code non-null;} the source types
- */
- public TypeList getSources() {
- return sources;
- }
-
- /**
- * Gets the list of exception types that might be thrown.
- *
- * @return {@code non-null;} the list of exception types
- */
- public TypeList getExceptions() {
- return exceptions;
- }
-
- /**
- * Gets the branchingness of this instance.
- *
- * @return the branchingness
- */
- public int getBranchingness() {
- return branchingness;
- }
-
- /**
- * Gets whether this opcode is a function/method call or similar.
- *
- * @return {@code true} iff this opcode is call-like
- */
- public boolean isCallLike() {
- return isCallLike;
- }
-
-
- /**
- * Gets whether this opcode is commutative (the order of its sources are
- * unimportant) or not. All commutative Rops have exactly two sources and
- * have no branchiness.
- *
- * @return true if rop is commutative
- */
- public boolean isCommutative() {
- switch (opcode) {
- case RegOps.AND:
- case RegOps.OR:
- case RegOps.XOR:
- case RegOps.ADD:
- case RegOps.MUL:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Gets the nickname. If this instance has no nickname, this returns
- * the result of calling {@link #toString}.
- *
- * @return {@code non-null;} the nickname
- */
- public String getNickname() {
- if (nickname != null) {
- return nickname;
- }
-
- return toString();
- }
-
- /**
- * Gets whether this operation can possibly throw an exception. This
- * is just a convenient wrapper for
- * {@code getExceptions().size() != 0}.
- *
- * @return {@code true} iff this operation can possibly throw
- */
- public final boolean canThrow() {
- return (exceptions.size() != 0);
- }
+ /**
+ * Gets whether this operation can possibly throw an exception. This
+ * is just a convenient wrapper for
+ * {@code getExceptions().size() != 0}.
+ *
+ * @return {@code true} iff this operation can possibly throw
+ */
+ public final boolean canThrow() {
+ return (exceptions.size() != 0);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/RopMethod.java b/dx/src/com/android/jack/dx/rop/code/RopMethod.java
index 412dc0d..3133652 100644
--- a/dx/src/com/android/jack/dx/rop/code/RopMethod.java
+++ b/dx/src/com/android/jack/dx/rop/code/RopMethod.java
@@ -16,7 +16,6 @@
package com.android.jack.dx.rop.code;
-import com.android.jack.dx.util.Bits;
import com.android.jack.dx.util.Hex;
import com.android.jack.dx.util.IntList;
@@ -24,184 +23,183 @@
* All of the parts that make up a method at the rop layer.
*/
public final class RopMethod {
- /** {@code non-null;} basic block list of the method */
- private final BasicBlockList blocks;
+ /** {@code non-null;} basic block list of the method */
+ private final BasicBlockList blocks;
- /** {@code >= 0;} label for the block which starts the method */
- private final int firstLabel;
+ /** {@code >= 0;} label for the block which starts the method */
+ private final int firstLabel;
- /**
- * {@code null-ok;} array of predecessors for each block, indexed by block
- * label
- */
- private IntList[] predecessors;
+ /**
+ * {@code null-ok;} array of predecessors for each block, indexed by block
+ * label
+ */
+ private IntList[] predecessors;
- /**
- * {@code null-ok;} the predecessors for the implicit "exit" block, that is
- * the labels for the blocks that return, if calculated
- */
- private IntList exitPredecessors;
+ /**
+ * {@code null-ok;} the predecessors for the implicit "exit" block, that is
+ * the labels for the blocks that return, if calculated
+ */
+ private IntList exitPredecessors;
- /**
- * Constructs an instance.
- *
- * @param blocks {@code non-null;} basic block list of the method
- * @param firstLabel {@code >= 0;} the label of the first block to execute
- */
- public RopMethod(BasicBlockList blocks, int firstLabel) {
- if (blocks == null) {
- throw new NullPointerException("blocks == null");
- }
-
- if (firstLabel < 0) {
- throw new IllegalArgumentException("firstLabel < 0");
- }
-
- this.blocks = blocks;
- this.firstLabel = firstLabel;
-
- this.predecessors = null;
- this.exitPredecessors = null;
+ /**
+ * Constructs an instance.
+ *
+ * @param blocks {@code non-null;} basic block list of the method
+ * @param firstLabel {@code >= 0;} the label of the first block to execute
+ */
+ public RopMethod(BasicBlockList blocks, int firstLabel) {
+ if (blocks == null) {
+ throw new NullPointerException("blocks == null");
}
- /**
- * Gets the basic block list for this method.
- *
- * @return {@code non-null;} the list
- */
- public BasicBlockList getBlocks() {
- return blocks;
+ if (firstLabel < 0) {
+ throw new IllegalArgumentException("firstLabel < 0");
}
- /**
- * Gets the label for the first block in the method that this list
- * represents.
- *
- * @return {@code >= 0;} the first-block label
- */
- public int getFirstLabel() {
- return firstLabel;
+ this.blocks = blocks;
+ this.firstLabel = firstLabel;
+
+ this.predecessors = null;
+ this.exitPredecessors = null;
+ }
+
+ /**
+ * Gets the basic block list for this method.
+ *
+ * @return {@code non-null;} the list
+ */
+ public BasicBlockList getBlocks() {
+ return blocks;
+ }
+
+ /**
+ * Gets the label for the first block in the method that this list
+ * represents.
+ *
+ * @return {@code >= 0;} the first-block label
+ */
+ public int getFirstLabel() {
+ return firstLabel;
+ }
+
+ /**
+ * Gets the predecessors associated with the given block. This throws
+ * an exception if there is no block with the given label.
+ *
+ * @param label {@code >= 0;} the label of the block in question
+ * @return {@code non-null;} the predecessors of that block
+ */
+ public IntList labelToPredecessors(int label) {
+ if (exitPredecessors == null) {
+ calcPredecessors();
}
- /**
- * Gets the predecessors associated with the given block. This throws
- * an exception if there is no block with the given label.
- *
- * @param label {@code >= 0;} the label of the block in question
- * @return {@code non-null;} the predecessors of that block
- */
- public IntList labelToPredecessors(int label) {
- if (exitPredecessors == null) {
- calcPredecessors();
- }
+ IntList result = predecessors[label];
- IntList result = predecessors[label];
-
- if (result == null) {
- throw new RuntimeException("no such block: " + Hex.u2(label));
- }
-
- return result;
+ if (result == null) {
+ throw new RuntimeException("no such block: " + Hex.u2(label));
}
- /**
- * Gets the exit predecessors for this instance.
- *
- * @return {@code non-null;} the exit predecessors
- */
- public IntList getExitPredecessors() {
- if (exitPredecessors == null) {
- calcPredecessors();
- }
+ return result;
+ }
- return exitPredecessors;
+ /**
+ * Gets the exit predecessors for this instance.
+ *
+ * @return {@code non-null;} the exit predecessors
+ */
+ public IntList getExitPredecessors() {
+ if (exitPredecessors == null) {
+ calcPredecessors();
}
+ return exitPredecessors;
+ }
- /**
- * Returns an instance that is identical to this one, except that
- * the registers in each instruction are offset by the given
- * amount.
- *
- * @param delta the amount to offset register numbers by
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public RopMethod withRegisterOffset(int delta) {
- RopMethod result = new RopMethod(blocks.withRegisterOffset(delta),
- firstLabel);
- if (exitPredecessors != null) {
- /*
- * The predecessors have been calculated. It's safe to
- * inject these into the new instance, since the
- * transformation being applied doesn't affect the
- * predecessors.
- */
- result.exitPredecessors = exitPredecessors;
- result.predecessors = predecessors;
- }
+ /**
+ * Returns an instance that is identical to this one, except that
+ * the registers in each instruction are offset by the given
+ * amount.
+ *
+ * @param delta the amount to offset register numbers by
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public RopMethod withRegisterOffset(int delta) {
+ RopMethod result = new RopMethod(blocks.withRegisterOffset(delta), firstLabel);
- return result;
+ if (exitPredecessors != null) {
+ /*
+ * The predecessors have been calculated. It's safe to
+ * inject these into the new instance, since the
+ * transformation being applied doesn't affect the
+ * predecessors.
+ */
+ result.exitPredecessors = exitPredecessors;
+ result.predecessors = predecessors;
}
- /**
- * Calculates the predecessor sets for each block as well as for the
- * exit.
+ return result;
+ }
+
+ /**
+ * Calculates the predecessor sets for each block as well as for the
+ * exit.
+ */
+ private void calcPredecessors() {
+ int maxLabel = blocks.getMaxLabel();
+ IntList[] predecessors = new IntList[maxLabel];
+ IntList exitPredecessors = new IntList(10);
+ int sz = blocks.size();
+
+ /*
+ * For each block, find its successors, and add the block's label to
+ * the successor's predecessors.
*/
- private void calcPredecessors() {
- int maxLabel = blocks.getMaxLabel();
- IntList[] predecessors = new IntList[maxLabel];
- IntList exitPredecessors = new IntList(10);
- int sz = blocks.size();
-
- /*
- * For each block, find its successors, and add the block's label to
- * the successor's predecessors.
- */
- for (int i = 0; i < sz; i++) {
- BasicBlock one = blocks.get(i);
- int label = one.getLabel();
- IntList successors = one.getSuccessors();
- int ssz = successors.size();
- if (ssz == 0) {
- // This block exits.
- exitPredecessors.add(label);
- } else {
- for (int j = 0; j < ssz; j++) {
- int succLabel = successors.get(j);
- IntList succPreds = predecessors[succLabel];
- if (succPreds == null) {
- succPreds = new IntList(10);
- predecessors[succLabel] = succPreds;
- }
- succPreds.add(label);
- }
- }
+ for (int i = 0; i < sz; i++) {
+ BasicBlock one = blocks.get(i);
+ int label = one.getLabel();
+ IntList successors = one.getSuccessors();
+ int ssz = successors.size();
+ if (ssz == 0) {
+ // This block exits.
+ exitPredecessors.add(label);
+ } else {
+ for (int j = 0; j < ssz; j++) {
+ int succLabel = successors.get(j);
+ IntList succPreds = predecessors[succLabel];
+ if (succPreds == null) {
+ succPreds = new IntList(10);
+ predecessors[succLabel] = succPreds;
+ }
+ succPreds.add(label);
}
-
- // Sort and immutablize all the predecessor lists.
- for (int i = 0; i < maxLabel; i++) {
- IntList preds = predecessors[i];
- if (preds != null) {
- preds.sort();
- preds.setImmutable();
- }
- }
-
- exitPredecessors.sort();
- exitPredecessors.setImmutable();
-
- /*
- * The start label might not ever have had any predecessors
- * added to it (probably doesn't, because of how Java gets
- * translated into rop form). So, check for this and rectify
- * the situation if required.
- */
- if (predecessors[firstLabel] == null) {
- predecessors[firstLabel] = IntList.EMPTY;
- }
-
- this.predecessors = predecessors;
- this.exitPredecessors = exitPredecessors;
+ }
}
+
+ // Sort and immutablize all the predecessor lists.
+ for (int i = 0; i < maxLabel; i++) {
+ IntList preds = predecessors[i];
+ if (preds != null) {
+ preds.sort();
+ preds.setImmutable();
+ }
+ }
+
+ exitPredecessors.sort();
+ exitPredecessors.setImmutable();
+
+ /*
+ * The start label might not ever have had any predecessors
+ * added to it (probably doesn't, because of how Java gets
+ * translated into rop form). So, check for this and rectify
+ * the situation if required.
+ */
+ if (predecessors[firstLabel] == null) {
+ predecessors[firstLabel] = IntList.EMPTY;
+ }
+
+ this.predecessors = predecessors;
+ this.exitPredecessors = exitPredecessors;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/Rops.java b/dx/src/com/android/jack/dx/rop/code/Rops.java
index 23deb8d..22ba56e 100644
--- a/dx/src/com/android/jack/dx/rop/code/Rops.java
+++ b/dx/src/com/android/jack/dx/rop/code/Rops.java
@@ -30,2061 +30,2110 @@
* Standard instances of {@link Rop}.
*/
public final class Rops {
- /** {@code nop()} */
- public static final Rop NOP =
- new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop");
+ /** {@code nop()} */
+ public static final Rop NOP = new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop");
- /** {@code r,x: int :: r = x;} */
- public static final Rop MOVE_INT =
- new Rop(RegOps.MOVE, Type.INT, StdTypeList.INT, "move-int");
+ /** {@code r,x: int :: r = x;} */
+ public static final Rop MOVE_INT = new Rop(RegOps.MOVE, Type.INT, StdTypeList.INT, "move-int");
- /** {@code r,x: long :: r = x;} */
- public static final Rop MOVE_LONG =
- new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long");
+ /** {@code r,x: long :: r = x;} */
+ public static final Rop MOVE_LONG =
+ new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long");
- /** {@code r,x: float :: r = x;} */
- public static final Rop MOVE_FLOAT =
- new Rop(RegOps.MOVE, Type.FLOAT, StdTypeList.FLOAT, "move-float");
+ /** {@code r,x: float :: r = x;} */
+ public static final Rop MOVE_FLOAT =
+ new Rop(RegOps.MOVE, Type.FLOAT, StdTypeList.FLOAT, "move-float");
- /** {@code r,x: double :: r = x;} */
- public static final Rop MOVE_DOUBLE =
- new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double");
+ /** {@code r,x: double :: r = x;} */
+ public static final Rop MOVE_DOUBLE =
+ new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double");
- /** {@code r,x: Object :: r = x;} */
- public static final Rop MOVE_OBJECT =
- new Rop(RegOps.MOVE, Type.OBJECT, StdTypeList.OBJECT, "move-object");
+ /** {@code r,x: Object :: r = x;} */
+ public static final Rop MOVE_OBJECT =
+ new Rop(RegOps.MOVE, Type.OBJECT, StdTypeList.OBJECT, "move-object");
- /**
- * {@code r,x: ReturnAddress :: r = x;}
- *
- * Note that this rop-form instruction has no dex-form equivilent and
- * must be removed before the dex conversion.
- */
- public static final Rop MOVE_RETURN_ADDRESS =
- new Rop(RegOps.MOVE, Type.RETURN_ADDRESS,
- StdTypeList.RETURN_ADDRESS, "move-return-address");
+ /**
+ * {@code r,x: ReturnAddress :: r = x;}
+ *
+ * Note that this rop-form instruction has no dex-form equivilent and
+ * must be removed before the dex conversion.
+ */
+ public static final Rop MOVE_RETURN_ADDRESS =
+ new Rop(RegOps.MOVE, Type.RETURN_ADDRESS, StdTypeList.RETURN_ADDRESS, "move-return-address");
- /** {@code r,param(x): int :: r = param(x);} */
- public static final Rop MOVE_PARAM_INT =
- new Rop(RegOps.MOVE_PARAM, Type.INT, StdTypeList.EMPTY,
- "move-param-int");
+ /** {@code r,param(x): int :: r = param(x);} */
+ public static final Rop MOVE_PARAM_INT =
+ new Rop(RegOps.MOVE_PARAM, Type.INT, StdTypeList.EMPTY, "move-param-int");
- /** {@code r,param(x): long :: r = param(x);} */
- public static final Rop MOVE_PARAM_LONG =
- new Rop(RegOps.MOVE_PARAM, Type.LONG, StdTypeList.EMPTY,
- "move-param-long");
+ /** {@code r,param(x): long :: r = param(x);} */
+ public static final Rop MOVE_PARAM_LONG =
+ new Rop(RegOps.MOVE_PARAM, Type.LONG, StdTypeList.EMPTY, "move-param-long");
- /** {@code r,param(x): float :: r = param(x);} */
- public static final Rop MOVE_PARAM_FLOAT =
- new Rop(RegOps.MOVE_PARAM, Type.FLOAT, StdTypeList.EMPTY,
- "move-param-float");
+ /** {@code r,param(x): float :: r = param(x);} */
+ public static final Rop MOVE_PARAM_FLOAT =
+ new Rop(RegOps.MOVE_PARAM, Type.FLOAT, StdTypeList.EMPTY, "move-param-float");
- /** {@code r,param(x): double :: r = param(x);} */
- public static final Rop MOVE_PARAM_DOUBLE =
- new Rop(RegOps.MOVE_PARAM, Type.DOUBLE, StdTypeList.EMPTY,
- "move-param-double");
+ /** {@code r,param(x): double :: r = param(x);} */
+ public static final Rop MOVE_PARAM_DOUBLE =
+ new Rop(RegOps.MOVE_PARAM, Type.DOUBLE, StdTypeList.EMPTY, "move-param-double");
- /** {@code r,param(x): Object :: r = param(x);} */
- public static final Rop MOVE_PARAM_OBJECT =
- new Rop(RegOps.MOVE_PARAM, Type.OBJECT, StdTypeList.EMPTY,
- "move-param-object");
+ /** {@code r,param(x): Object :: r = param(x);} */
+ public static final Rop MOVE_PARAM_OBJECT =
+ new Rop(RegOps.MOVE_PARAM, Type.OBJECT, StdTypeList.EMPTY, "move-param-object");
- /** {@code r, literal: int :: r = literal;} */
- public static final Rop CONST_INT =
- new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int");
+ /** {@code r, literal: int :: r = literal;} */
+ public static final Rop CONST_INT =
+ new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int");
- /** {@code r, literal: long :: r = literal;} */
- public static final Rop CONST_LONG =
- new Rop(RegOps.CONST, Type.LONG, StdTypeList.EMPTY, "const-long");
+ /** {@code r, literal: long :: r = literal;} */
+ public static final Rop CONST_LONG =
+ new Rop(RegOps.CONST, Type.LONG, StdTypeList.EMPTY, "const-long");
- /** {@code r, literal: float :: r = literal;} */
- public static final Rop CONST_FLOAT =
- new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float");
+ /** {@code r, literal: float :: r = literal;} */
+ public static final Rop CONST_FLOAT =
+ new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float");
- /** {@code r, literal: double :: r = literal;} */
- public static final Rop CONST_DOUBLE =
- new Rop(RegOps.CONST, Type.DOUBLE, StdTypeList.EMPTY, "const-double");
+ /** {@code r, literal: double :: r = literal;} */
+ public static final Rop CONST_DOUBLE =
+ new Rop(RegOps.CONST, Type.DOUBLE, StdTypeList.EMPTY, "const-double");
- /** {@code r, literal: Object :: r = literal;} */
- public static final Rop CONST_OBJECT =
- new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "const-object");
+ /** {@code r, literal: Object :: r = literal;} */
+ public static final Rop CONST_OBJECT =
+ new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY, Exceptions.LIST_Error, "const-object");
- /** {@code r, literal: Object :: r = literal;} */
- public static final Rop CONST_OBJECT_NOTHROW =
- new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
- "const-object-nothrow");
+ /** {@code r, literal: Object :: r = literal;} */
+ public static final Rop CONST_OBJECT_NOTHROW =
+ new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY, "const-object-nothrow");
- /** {@code goto label} */
- public static final Rop GOTO =
- new Rop(RegOps.GOTO, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_GOTO,
- "goto");
+ /** {@code goto label} */
+ public static final Rop GOTO =
+ new Rop(RegOps.GOTO, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_GOTO, "goto");
- /** {@code x: int :: if (x == 0) goto label} */
- public static final Rop IF_EQZ_INT =
- new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-eqz-int");
+ /** {@code x: int :: if (x == 0) goto label} */
+ public static final Rop IF_EQZ_INT =
+ new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-eqz-int");
- /** {@code x: int :: if (x != 0) goto label} */
- public static final Rop IF_NEZ_INT =
- new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-nez-int");
+ /** {@code x: int :: if (x != 0) goto label} */
+ public static final Rop IF_NEZ_INT =
+ new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-nez-int");
- /** {@code x: int :: if (x < 0) goto label} */
- public static final Rop IF_LTZ_INT =
- new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-ltz-int");
+ /** {@code x: int :: if (x < 0) goto label} */
+ public static final Rop IF_LTZ_INT =
+ new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-ltz-int");
- /** {@code x: int :: if (x >= 0) goto label} */
- public static final Rop IF_GEZ_INT =
- new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-gez-int");
+ /** {@code x: int :: if (x >= 0) goto label} */
+ public static final Rop IF_GEZ_INT =
+ new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-gez-int");
- /** {@code x: int :: if (x <= 0) goto label} */
- public static final Rop IF_LEZ_INT =
- new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-lez-int");
+ /** {@code x: int :: if (x <= 0) goto label} */
+ public static final Rop IF_LEZ_INT =
+ new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-lez-int");
- /** {@code x: int :: if (x > 0) goto label} */
- public static final Rop IF_GTZ_INT =
- new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
- "if-gtz-int");
+ /** {@code x: int :: if (x > 0) goto label} */
+ public static final Rop IF_GTZ_INT =
+ new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, "if-gtz-int");
- /** {@code x: Object :: if (x == null) goto label} */
- public static final Rop IF_EQZ_OBJECT =
- new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF,
- "if-eqz-object");
+ /** {@code x: Object :: if (x == null) goto label} */
+ public static final Rop IF_EQZ_OBJECT =
+ new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF, "if-eqz-object");
- /** {@code x: Object :: if (x != null) goto label} */
- public static final Rop IF_NEZ_OBJECT =
- new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF,
- "if-nez-object");
+ /** {@code x: Object :: if (x != null) goto label} */
+ public static final Rop IF_NEZ_OBJECT =
+ new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF, "if-nez-object");
- /** {@code x,y: int :: if (x == y) goto label} */
- public static final Rop IF_EQ_INT =
- new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-eq-int");
+ /** {@code x,y: int :: if (x == y) goto label} */
+ public static final Rop IF_EQ_INT =
+ new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-eq-int");
- /** {@code x,y: int :: if (x != y) goto label} */
- public static final Rop IF_NE_INT =
- new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-ne-int");
+ /** {@code x,y: int :: if (x != y) goto label} */
+ public static final Rop IF_NE_INT =
+ new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-ne-int");
- /** {@code x,y: int :: if (x < y) goto label} */
- public static final Rop IF_LT_INT =
- new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-lt-int");
+ /** {@code x,y: int :: if (x < y) goto label} */
+ public static final Rop IF_LT_INT =
+ new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-lt-int");
- /** {@code x,y: int :: if (x >= y) goto label} */
- public static final Rop IF_GE_INT =
- new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-ge-int");
+ /** {@code x,y: int :: if (x >= y) goto label} */
+ public static final Rop IF_GE_INT =
+ new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-ge-int");
- /** {@code x,y: int :: if (x <= y) goto label} */
- public static final Rop IF_LE_INT =
- new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-le-int");
+ /** {@code x,y: int :: if (x <= y) goto label} */
+ public static final Rop IF_LE_INT =
+ new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-le-int");
- /** {@code x,y: int :: if (x > y) goto label} */
- public static final Rop IF_GT_INT =
- new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
- "if-gt-int");
+ /** {@code x,y: int :: if (x > y) goto label} */
+ public static final Rop IF_GT_INT =
+ new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, "if-gt-int");
- /** {@code x,y: Object :: if (x == y) goto label} */
- public static final Rop IF_EQ_OBJECT =
- new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT_OBJECT,
- Rop.BRANCH_IF, "if-eq-object");
+ /** {@code x,y: Object :: if (x == y) goto label} */
+ public static final Rop IF_EQ_OBJECT =
+ new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT_OBJECT, Rop.BRANCH_IF, "if-eq-object");
- /** {@code x,y: Object :: if (x != y) goto label} */
- public static final Rop IF_NE_OBJECT =
- new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT_OBJECT,
- Rop.BRANCH_IF, "if-ne-object");
+ /** {@code x,y: Object :: if (x != y) goto label} */
+ public static final Rop IF_NE_OBJECT =
+ new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT_OBJECT, Rop.BRANCH_IF, "if-ne-object");
- /** {@code x: int :: goto switchtable[x]} */
- public static final Rop SWITCH =
- new Rop(RegOps.SWITCH, Type.VOID, StdTypeList.INT, Rop.BRANCH_SWITCH,
- "switch");
+ /** {@code x: int :: goto switchtable[x]} */
+ public static final Rop SWITCH =
+ new Rop(RegOps.SWITCH, Type.VOID, StdTypeList.INT, Rop.BRANCH_SWITCH, "switch");
- /** {@code r,x,y: int :: r = x + y;} */
- public static final Rop ADD_INT =
- new Rop(RegOps.ADD, Type.INT, StdTypeList.INT_INT, "add-int");
+ /** {@code r,x,y: int :: r = x + y;} */
+ public static final Rop ADD_INT = new Rop(RegOps.ADD, Type.INT, StdTypeList.INT_INT, "add-int");
- /** {@code r,x,y: long :: r = x + y;} */
- public static final Rop ADD_LONG =
- new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG_LONG, "add-long");
+ /** {@code r,x,y: long :: r = x + y;} */
+ public static final Rop ADD_LONG =
+ new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG_LONG, "add-long");
- /** {@code r,x,y: float :: r = x + y;} */
- public static final Rop ADD_FLOAT =
- new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "add-float");
+ /** {@code r,x,y: float :: r = x + y;} */
+ public static final Rop ADD_FLOAT =
+ new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "add-float");
- /** {@code r,x,y: double :: r = x + y;} */
- public static final Rop ADD_DOUBLE =
- new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
- Rop.BRANCH_NONE, "add-double");
+ /** {@code r,x,y: double :: r = x + y;} */
+ public static final Rop ADD_DOUBLE =
+ new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "add-double");
- /** {@code r,x,y: int :: r = x - y;} */
- public static final Rop SUB_INT =
- new Rop(RegOps.SUB, Type.INT, StdTypeList.INT_INT, "sub-int");
+ /** {@code r,x,y: int :: r = x - y;} */
+ public static final Rop SUB_INT = new Rop(RegOps.SUB, Type.INT, StdTypeList.INT_INT, "sub-int");
- /** {@code r,x,y: long :: r = x - y;} */
- public static final Rop SUB_LONG =
- new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG_LONG, "sub-long");
+ /** {@code r,x,y: long :: r = x - y;} */
+ public static final Rop SUB_LONG =
+ new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG_LONG, "sub-long");
- /** {@code r,x,y: float :: r = x - y;} */
- public static final Rop SUB_FLOAT =
- new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "sub-float");
+ /** {@code r,x,y: float :: r = x - y;} */
+ public static final Rop SUB_FLOAT =
+ new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "sub-float");
- /** {@code r,x,y: double :: r = x - y;} */
- public static final Rop SUB_DOUBLE =
- new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
- Rop.BRANCH_NONE, "sub-double");
+ /** {@code r,x,y: double :: r = x - y;} */
+ public static final Rop SUB_DOUBLE =
+ new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "sub-double");
- /** {@code r,x,y: int :: r = x * y;} */
- public static final Rop MUL_INT =
- new Rop(RegOps.MUL, Type.INT, StdTypeList.INT_INT, "mul-int");
+ /** {@code r,x,y: int :: r = x * y;} */
+ public static final Rop MUL_INT = new Rop(RegOps.MUL, Type.INT, StdTypeList.INT_INT, "mul-int");
- /** {@code r,x,y: long :: r = x * y;} */
- public static final Rop MUL_LONG =
- new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG_LONG, "mul-long");
+ /** {@code r,x,y: long :: r = x * y;} */
+ public static final Rop MUL_LONG =
+ new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG_LONG, "mul-long");
- /** {@code r,x,y: float :: r = x * y;} */
- public static final Rop MUL_FLOAT =
- new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "mul-float");
+ /** {@code r,x,y: float :: r = x * y;} */
+ public static final Rop MUL_FLOAT =
+ new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "mul-float");
- /** {@code r,x,y: double :: r = x * y;} */
- public static final Rop MUL_DOUBLE =
- new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
- Rop.BRANCH_NONE, "mul-double");
+ /** {@code r,x,y: double :: r = x * y;} */
+ public static final Rop MUL_DOUBLE =
+ new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "mul-double");
- /** {@code r,x,y: int :: r = x / y;} */
- public static final Rop DIV_INT =
- new Rop(RegOps.DIV, Type.INT, StdTypeList.INT_INT,
- Exceptions.LIST_Error_ArithmeticException, "div-int");
+ /** {@code r,x,y: int :: r = x / y;} */
+ public static final Rop DIV_INT = new Rop(RegOps.DIV, Type.INT, StdTypeList.INT_INT,
+ Exceptions.LIST_Error_ArithmeticException, "div-int");
- /** {@code r,x,y: long :: r = x / y;} */
- public static final Rop DIV_LONG =
- new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG_LONG,
- Exceptions.LIST_Error_ArithmeticException, "div-long");
+ /** {@code r,x,y: long :: r = x / y;} */
+ public static final Rop DIV_LONG = new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG_LONG,
+ Exceptions.LIST_Error_ArithmeticException, "div-long");
- /** {@code r,x,y: float :: r = x / y;} */
- public static final Rop DIV_FLOAT =
- new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "div-float");
+ /** {@code r,x,y: float :: r = x / y;} */
+ public static final Rop DIV_FLOAT =
+ new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "div-float");
- /** {@code r,x,y: double :: r = x / y;} */
- public static final Rop DIV_DOUBLE =
- new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
- "div-double");
+ /** {@code r,x,y: double :: r = x / y;} */
+ public static final Rop DIV_DOUBLE =
+ new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, "div-double");
- /** {@code r,x,y: int :: r = x % y;} */
- public static final Rop REM_INT =
- new Rop(RegOps.REM, Type.INT, StdTypeList.INT_INT,
- Exceptions.LIST_Error_ArithmeticException, "rem-int");
+ /** {@code r,x,y: int :: r = x % y;} */
+ public static final Rop REM_INT = new Rop(RegOps.REM, Type.INT, StdTypeList.INT_INT,
+ Exceptions.LIST_Error_ArithmeticException, "rem-int");
- /** {@code r,x,y: long :: r = x % y;} */
- public static final Rop REM_LONG =
- new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG_LONG,
- Exceptions.LIST_Error_ArithmeticException, "rem-long");
+ /** {@code r,x,y: long :: r = x % y;} */
+ public static final Rop REM_LONG = new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG_LONG,
+ Exceptions.LIST_Error_ArithmeticException, "rem-long");
- /** {@code r,x,y: float :: r = x % y;} */
- public static final Rop REM_FLOAT =
- new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "rem-float");
+ /** {@code r,x,y: float :: r = x % y;} */
+ public static final Rop REM_FLOAT =
+ new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "rem-float");
- /** {@code r,x,y: double :: r = x % y;} */
- public static final Rop REM_DOUBLE =
- new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
- "rem-double");
+ /** {@code r,x,y: double :: r = x % y;} */
+ public static final Rop REM_DOUBLE =
+ new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, "rem-double");
- /** {@code r,x: int :: r = -x;} */
- public static final Rop NEG_INT =
- new Rop(RegOps.NEG, Type.INT, StdTypeList.INT, "neg-int");
+ /** {@code r,x: int :: r = -x;} */
+ public static final Rop NEG_INT = new Rop(RegOps.NEG, Type.INT, StdTypeList.INT, "neg-int");
- /** {@code r,x: long :: r = -x;} */
- public static final Rop NEG_LONG =
- new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long");
+ /** {@code r,x: long :: r = -x;} */
+ public static final Rop NEG_LONG = new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long");
- /** {@code r,x: float :: r = -x;} */
- public static final Rop NEG_FLOAT =
- new Rop(RegOps.NEG, Type.FLOAT, StdTypeList.FLOAT, "neg-float");
+ /** {@code r,x: float :: r = -x;} */
+ public static final Rop NEG_FLOAT =
+ new Rop(RegOps.NEG, Type.FLOAT, StdTypeList.FLOAT, "neg-float");
- /** {@code r,x: double :: r = -x;} */
- public static final Rop NEG_DOUBLE =
- new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double");
+ /** {@code r,x: double :: r = -x;} */
+ public static final Rop NEG_DOUBLE =
+ new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double");
- /** {@code r,x,y: int :: r = x & y;} */
- public static final Rop AND_INT =
- new Rop(RegOps.AND, Type.INT, StdTypeList.INT_INT, "and-int");
+ /** {@code r,x,y: int :: r = x & y;} */
+ public static final Rop AND_INT = new Rop(RegOps.AND, Type.INT, StdTypeList.INT_INT, "and-int");
- /** {@code r,x,y: long :: r = x & y;} */
- public static final Rop AND_LONG =
- new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG_LONG, "and-long");
+ /** {@code r,x,y: long :: r = x & y;} */
+ public static final Rop AND_LONG =
+ new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG_LONG, "and-long");
- /** {@code r,x,y: int :: r = x | y;} */
- public static final Rop OR_INT =
- new Rop(RegOps.OR, Type.INT, StdTypeList.INT_INT, "or-int");
+ /** {@code r,x,y: int :: r = x | y;} */
+ public static final Rop OR_INT = new Rop(RegOps.OR, Type.INT, StdTypeList.INT_INT, "or-int");
- /** {@code r,x,y: long :: r = x | y;} */
- public static final Rop OR_LONG =
- new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG_LONG, "or-long");
+ /** {@code r,x,y: long :: r = x | y;} */
+ public static final Rop OR_LONG = new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG_LONG, "or-long");
- /** {@code r,x,y: int :: r = x ^ y;} */
- public static final Rop XOR_INT =
- new Rop(RegOps.XOR, Type.INT, StdTypeList.INT_INT, "xor-int");
+ /** {@code r,x,y: int :: r = x ^ y;} */
+ public static final Rop XOR_INT = new Rop(RegOps.XOR, Type.INT, StdTypeList.INT_INT, "xor-int");
- /** {@code r,x,y: long :: r = x ^ y;} */
- public static final Rop XOR_LONG =
- new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG_LONG, "xor-long");
+ /** {@code r,x,y: long :: r = x ^ y;} */
+ public static final Rop XOR_LONG =
+ new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG_LONG, "xor-long");
- /** {@code r,x,y: int :: r = x << y;} */
- public static final Rop SHL_INT =
- new Rop(RegOps.SHL, Type.INT, StdTypeList.INT_INT, "shl-int");
+ /** {@code r,x,y: int :: r = x << y;} */
+ public static final Rop SHL_INT = new Rop(RegOps.SHL, Type.INT, StdTypeList.INT_INT, "shl-int");
- /** {@code r,x: long; y: int :: r = x << y;} */
- public static final Rop SHL_LONG =
- new Rop(RegOps.SHL, Type.LONG, StdTypeList.LONG_INT, "shl-long");
+ /** {@code r,x: long; y: int :: r = x << y;} */
+ public static final Rop SHL_LONG =
+ new Rop(RegOps.SHL, Type.LONG, StdTypeList.LONG_INT, "shl-long");
- /** {@code r,x,y: int :: r = x >> y;} */
- public static final Rop SHR_INT =
- new Rop(RegOps.SHR, Type.INT, StdTypeList.INT_INT, "shr-int");
+ /** {@code r,x,y: int :: r = x >> y;} */
+ public static final Rop SHR_INT = new Rop(RegOps.SHR, Type.INT, StdTypeList.INT_INT, "shr-int");
- /** {@code r,x: long; y: int :: r = x >> y;} */
- public static final Rop SHR_LONG =
- new Rop(RegOps.SHR, Type.LONG, StdTypeList.LONG_INT, "shr-long");
+ /** {@code r,x: long; y: int :: r = x >> y;} */
+ public static final Rop SHR_LONG =
+ new Rop(RegOps.SHR, Type.LONG, StdTypeList.LONG_INT, "shr-long");
- /** {@code r,x,y: int :: r = x >>> y;} */
- public static final Rop USHR_INT =
- new Rop(RegOps.USHR, Type.INT, StdTypeList.INT_INT, "ushr-int");
+ /** {@code r,x,y: int :: r = x >>> y;} */
+ public static final Rop USHR_INT =
+ new Rop(RegOps.USHR, Type.INT, StdTypeList.INT_INT, "ushr-int");
- /** {@code r,x: long; y: int :: r = x >>> y;} */
- public static final Rop USHR_LONG =
- new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long");
+ /** {@code r,x: long; y: int :: r = x >>> y;} */
+ public static final Rop USHR_LONG =
+ new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long");
- /** {@code r,x: int :: r = ~x;} */
- public static final Rop NOT_INT =
- new Rop(RegOps.NOT, Type.INT, StdTypeList.INT, "not-int");
+ /** {@code r,x: int :: r = ~x;} */
+ public static final Rop NOT_INT = new Rop(RegOps.NOT, Type.INT, StdTypeList.INT, "not-int");
- /** {@code r,x: long :: r = ~x;} */
- public static final Rop NOT_LONG =
- new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long");
+ /** {@code r,x: long :: r = ~x;} */
+ public static final Rop NOT_LONG = new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long");
- /** {@code r,x,c: int :: r = x + c;} */
- public static final Rop ADD_CONST_INT =
- new Rop(RegOps.ADD, Type.INT, StdTypeList.INT, "add-const-int");
+ /** {@code r,x,c: int :: r = x + c;} */
+ public static final Rop ADD_CONST_INT =
+ new Rop(RegOps.ADD, Type.INT, StdTypeList.INT, "add-const-int");
- /** {@code r,x,c: long :: r = x + c;} */
- public static final Rop ADD_CONST_LONG =
- new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG, "add-const-long");
+ /** {@code r,x,c: long :: r = x + c;} */
+ public static final Rop ADD_CONST_LONG =
+ new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG, "add-const-long");
- /** {@code r,x,c: float :: r = x + c;} */
- public static final Rop ADD_CONST_FLOAT =
- new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT, "add-const-float");
+ /** {@code r,x,c: float :: r = x + c;} */
+ public static final Rop ADD_CONST_FLOAT =
+ new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT, "add-const-float");
- /** {@code r,x,c: double :: r = x + c;} */
- public static final Rop ADD_CONST_DOUBLE =
- new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE,
- "add-const-double");
+ /** {@code r,x,c: double :: r = x + c;} */
+ public static final Rop ADD_CONST_DOUBLE =
+ new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE, "add-const-double");
- /** {@code r,x,c: int :: r = x - c;} */
- public static final Rop SUB_CONST_INT =
- new Rop(RegOps.SUB, Type.INT, StdTypeList.INT, "sub-const-int");
+ /** {@code r,x,c: int :: r = x - c;} */
+ public static final Rop SUB_CONST_INT =
+ new Rop(RegOps.SUB, Type.INT, StdTypeList.INT, "sub-const-int");
- /** {@code r,x,c: long :: r = x - c;} */
- public static final Rop SUB_CONST_LONG =
- new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG, "sub-const-long");
+ /** {@code r,x,c: long :: r = x - c;} */
+ public static final Rop SUB_CONST_LONG =
+ new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG, "sub-const-long");
- /** {@code r,x,c: float :: r = x - c;} */
- public static final Rop SUB_CONST_FLOAT =
- new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT, "sub-const-float");
+ /** {@code r,x,c: float :: r = x - c;} */
+ public static final Rop SUB_CONST_FLOAT =
+ new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT, "sub-const-float");
- /** {@code r,x,c: double :: r = x - c;} */
- public static final Rop SUB_CONST_DOUBLE =
- new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE,
- "sub-const-double");
+ /** {@code r,x,c: double :: r = x - c;} */
+ public static final Rop SUB_CONST_DOUBLE =
+ new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE, "sub-const-double");
- /** {@code r,x,c: int :: r = x * c;} */
- public static final Rop MUL_CONST_INT =
- new Rop(RegOps.MUL, Type.INT, StdTypeList.INT, "mul-const-int");
+ /** {@code r,x,c: int :: r = x * c;} */
+ public static final Rop MUL_CONST_INT =
+ new Rop(RegOps.MUL, Type.INT, StdTypeList.INT, "mul-const-int");
- /** {@code r,x,c: long :: r = x * c;} */
- public static final Rop MUL_CONST_LONG =
- new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG, "mul-const-long");
+ /** {@code r,x,c: long :: r = x * c;} */
+ public static final Rop MUL_CONST_LONG =
+ new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG, "mul-const-long");
- /** {@code r,x,c: float :: r = x * c;} */
- public static final Rop MUL_CONST_FLOAT =
- new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT, "mul-const-float");
+ /** {@code r,x,c: float :: r = x * c;} */
+ public static final Rop MUL_CONST_FLOAT =
+ new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT, "mul-const-float");
- /** {@code r,x,c: double :: r = x * c;} */
- public static final Rop MUL_CONST_DOUBLE =
- new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE,
- "mul-const-double");
+ /** {@code r,x,c: double :: r = x * c;} */
+ public static final Rop MUL_CONST_DOUBLE =
+ new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE, "mul-const-double");
- /** {@code r,x,c: int :: r = x / c;} */
- public static final Rop DIV_CONST_INT =
- new Rop(RegOps.DIV, Type.INT, StdTypeList.INT,
- Exceptions.LIST_Error_ArithmeticException, "div-const-int");
+ /** {@code r,x,c: int :: r = x / c;} */
+ public static final Rop DIV_CONST_INT = new Rop(RegOps.DIV, Type.INT, StdTypeList.INT,
+ Exceptions.LIST_Error_ArithmeticException, "div-const-int");
- /** {@code r,x,c: long :: r = x / c;} */
- public static final Rop DIV_CONST_LONG =
- new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG,
- Exceptions.LIST_Error_ArithmeticException, "div-const-long");
+ /** {@code r,x,c: long :: r = x / c;} */
+ public static final Rop DIV_CONST_LONG = new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG,
+ Exceptions.LIST_Error_ArithmeticException, "div-const-long");
- /** {@code r,x,c: float :: r = x / c;} */
- public static final Rop DIV_CONST_FLOAT =
- new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT, "div-const-float");
+ /** {@code r,x,c: float :: r = x / c;} */
+ public static final Rop DIV_CONST_FLOAT =
+ new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT, "div-const-float");
- /** {@code r,x,c: double :: r = x / c;} */
- public static final Rop DIV_CONST_DOUBLE =
- new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE,
- "div-const-double");
+ /** {@code r,x,c: double :: r = x / c;} */
+ public static final Rop DIV_CONST_DOUBLE =
+ new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE, "div-const-double");
- /** {@code r,x,c: int :: r = x % c;} */
- public static final Rop REM_CONST_INT =
- new Rop(RegOps.REM, Type.INT, StdTypeList.INT,
- Exceptions.LIST_Error_ArithmeticException, "rem-const-int");
+ /** {@code r,x,c: int :: r = x % c;} */
+ public static final Rop REM_CONST_INT = new Rop(RegOps.REM, Type.INT, StdTypeList.INT,
+ Exceptions.LIST_Error_ArithmeticException, "rem-const-int");
- /** {@code r,x,c: long :: r = x % c;} */
- public static final Rop REM_CONST_LONG =
- new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG,
- Exceptions.LIST_Error_ArithmeticException, "rem-const-long");
+ /** {@code r,x,c: long :: r = x % c;} */
+ public static final Rop REM_CONST_LONG = new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG,
+ Exceptions.LIST_Error_ArithmeticException, "rem-const-long");
- /** {@code r,x,c: float :: r = x % c;} */
- public static final Rop REM_CONST_FLOAT =
- new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT, "rem-const-float");
+ /** {@code r,x,c: float :: r = x % c;} */
+ public static final Rop REM_CONST_FLOAT =
+ new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT, "rem-const-float");
- /** {@code r,x,c: double :: r = x % c;} */
- public static final Rop REM_CONST_DOUBLE =
- new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE,
- "rem-const-double");
+ /** {@code r,x,c: double :: r = x % c;} */
+ public static final Rop REM_CONST_DOUBLE =
+ new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE, "rem-const-double");
- /** {@code r,x,c: int :: r = x & c;} */
- public static final Rop AND_CONST_INT =
- new Rop(RegOps.AND, Type.INT, StdTypeList.INT, "and-const-int");
+ /** {@code r,x,c: int :: r = x & c;} */
+ public static final Rop AND_CONST_INT =
+ new Rop(RegOps.AND, Type.INT, StdTypeList.INT, "and-const-int");
- /** {@code r,x,c: long :: r = x & c;} */
- public static final Rop AND_CONST_LONG =
- new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG, "and-const-long");
+ /** {@code r,x,c: long :: r = x & c;} */
+ public static final Rop AND_CONST_LONG =
+ new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG, "and-const-long");
- /** {@code r,x,c: int :: r = x | c;} */
- public static final Rop OR_CONST_INT =
- new Rop(RegOps.OR, Type.INT, StdTypeList.INT, "or-const-int");
+ /** {@code r,x,c: int :: r = x | c;} */
+ public static final Rop OR_CONST_INT =
+ new Rop(RegOps.OR, Type.INT, StdTypeList.INT, "or-const-int");
- /** {@code r,x,c: long :: r = x | c;} */
- public static final Rop OR_CONST_LONG =
- new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG, "or-const-long");
+ /** {@code r,x,c: long :: r = x | c;} */
+ public static final Rop OR_CONST_LONG =
+ new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG, "or-const-long");
- /** {@code r,x,c: int :: r = x ^ c;} */
- public static final Rop XOR_CONST_INT =
- new Rop(RegOps.XOR, Type.INT, StdTypeList.INT, "xor-const-int");
+ /** {@code r,x,c: int :: r = x ^ c;} */
+ public static final Rop XOR_CONST_INT =
+ new Rop(RegOps.XOR, Type.INT, StdTypeList.INT, "xor-const-int");
- /** {@code r,x,c: long :: r = x ^ c;} */
- public static final Rop XOR_CONST_LONG =
- new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG, "xor-const-long");
+ /** {@code r,x,c: long :: r = x ^ c;} */
+ public static final Rop XOR_CONST_LONG =
+ new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG, "xor-const-long");
- /** {@code r,x,c: int :: r = x << c;} */
- public static final Rop SHL_CONST_INT =
- new Rop(RegOps.SHL, Type.INT, StdTypeList.INT, "shl-const-int");
+ /** {@code r,x,c: int :: r = x << c;} */
+ public static final Rop SHL_CONST_INT =
+ new Rop(RegOps.SHL, Type.INT, StdTypeList.INT, "shl-const-int");
- /** {@code r,x: long; c: int :: r = x << c;} */
- public static final Rop SHL_CONST_LONG =
- new Rop(RegOps.SHL, Type.LONG, StdTypeList.INT, "shl-const-long");
+ /** {@code r,x: long; c: int :: r = x << c;} */
+ public static final Rop SHL_CONST_LONG =
+ new Rop(RegOps.SHL, Type.LONG, StdTypeList.INT, "shl-const-long");
- /** {@code r,x,c: int :: r = x >> c;} */
- public static final Rop SHR_CONST_INT =
- new Rop(RegOps.SHR, Type.INT, StdTypeList.INT, "shr-const-int");
+ /** {@code r,x,c: int :: r = x >> c;} */
+ public static final Rop SHR_CONST_INT =
+ new Rop(RegOps.SHR, Type.INT, StdTypeList.INT, "shr-const-int");
- /** {@code r,x: long; c: int :: r = x >> c;} */
- public static final Rop SHR_CONST_LONG =
- new Rop(RegOps.SHR, Type.LONG, StdTypeList.INT, "shr-const-long");
+ /** {@code r,x: long; c: int :: r = x >> c;} */
+ public static final Rop SHR_CONST_LONG =
+ new Rop(RegOps.SHR, Type.LONG, StdTypeList.INT, "shr-const-long");
- /** {@code r,x,c: int :: r = x >>> c;} */
- public static final Rop USHR_CONST_INT =
- new Rop(RegOps.USHR, Type.INT, StdTypeList.INT, "ushr-const-int");
+ /** {@code r,x,c: int :: r = x >>> c;} */
+ public static final Rop USHR_CONST_INT =
+ new Rop(RegOps.USHR, Type.INT, StdTypeList.INT, "ushr-const-int");
- /** {@code r,x: long; c: int :: r = x >>> c;} */
- public static final Rop USHR_CONST_LONG =
- new Rop(RegOps.USHR, Type.LONG, StdTypeList.INT, "ushr-const-long");
+ /** {@code r,x: long; c: int :: r = x >>> c;} */
+ public static final Rop USHR_CONST_LONG =
+ new Rop(RegOps.USHR, Type.LONG, StdTypeList.INT, "ushr-const-long");
- /** {@code r: int; x,y: long :: r = cmp(x, y);} */
- public static final Rop CMPL_LONG =
- new Rop(RegOps.CMPL, Type.INT, StdTypeList.LONG_LONG, "cmpl-long");
+ /** {@code r: int; x,y: long :: r = cmp(x, y);} */
+ public static final Rop CMPL_LONG =
+ new Rop(RegOps.CMPL, Type.INT, StdTypeList.LONG_LONG, "cmpl-long");
- /** {@code r: int; x,y: float :: r = cmpl(x, y);} */
- public static final Rop CMPL_FLOAT =
- new Rop(RegOps.CMPL, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpl-float");
+ /** {@code r: int; x,y: float :: r = cmpl(x, y);} */
+ public static final Rop CMPL_FLOAT =
+ new Rop(RegOps.CMPL, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpl-float");
- /** {@code r: int; x,y: double :: r = cmpl(x, y);} */
- public static final Rop CMPL_DOUBLE =
- new Rop(RegOps.CMPL, Type.INT, StdTypeList.DOUBLE_DOUBLE,
- "cmpl-double");
+ /** {@code r: int; x,y: double :: r = cmpl(x, y);} */
+ public static final Rop CMPL_DOUBLE =
+ new Rop(RegOps.CMPL, Type.INT, StdTypeList.DOUBLE_DOUBLE, "cmpl-double");
- /** {@code r: int; x,y: float :: r = cmpg(x, y);} */
- public static final Rop CMPG_FLOAT =
- new Rop(RegOps.CMPG, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpg-float");
+ /** {@code r: int; x,y: float :: r = cmpg(x, y);} */
+ public static final Rop CMPG_FLOAT =
+ new Rop(RegOps.CMPG, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpg-float");
- /** {@code r: int; x,y: double :: r = cmpg(x, y);} */
- public static final Rop CMPG_DOUBLE =
- new Rop(RegOps.CMPG, Type.INT, StdTypeList.DOUBLE_DOUBLE,
- "cmpg-double");
+ /** {@code r: int; x,y: double :: r = cmpg(x, y);} */
+ public static final Rop CMPG_DOUBLE =
+ new Rop(RegOps.CMPG, Type.INT, StdTypeList.DOUBLE_DOUBLE, "cmpg-double");
- /** {@code r: int; x: long :: r = (int) x} */
- public static final Rop CONV_L2I =
- new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i");
+ /** {@code r: int; x: long :: r = (int) x} */
+ public static final Rop CONV_L2I = new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i");
- /** {@code r: int; x: float :: r = (int) x} */
- public static final Rop CONV_F2I =
- new Rop(RegOps.CONV, Type.INT, StdTypeList.FLOAT, "conv-f2i");
+ /** {@code r: int; x: float :: r = (int) x} */
+ public static final Rop CONV_F2I = new Rop(RegOps.CONV, Type.INT, StdTypeList.FLOAT, "conv-f2i");
- /** {@code r: int; x: double :: r = (int) x} */
- public static final Rop CONV_D2I =
- new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i");
+ /** {@code r: int; x: double :: r = (int) x} */
+ public static final Rop CONV_D2I = new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i");
- /** {@code r: long; x: int :: r = (long) x} */
- public static final Rop CONV_I2L =
- new Rop(RegOps.CONV, Type.LONG, StdTypeList.INT, "conv-i2l");
+ /** {@code r: long; x: int :: r = (long) x} */
+ public static final Rop CONV_I2L = new Rop(RegOps.CONV, Type.LONG, StdTypeList.INT, "conv-i2l");
- /** {@code r: long; x: float :: r = (long) x} */
- public static final Rop CONV_F2L =
- new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l");
+ /** {@code r: long; x: float :: r = (long) x} */
+ public static final Rop CONV_F2L = new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l");
- /** {@code r: long; x: double :: r = (long) x} */
- public static final Rop CONV_D2L =
- new Rop(RegOps.CONV, Type.LONG, StdTypeList.DOUBLE, "conv-d2l");
+ /** {@code r: long; x: double :: r = (long) x} */
+ public static final Rop CONV_D2L =
+ new Rop(RegOps.CONV, Type.LONG, StdTypeList.DOUBLE, "conv-d2l");
- /** {@code r: float; x: int :: r = (float) x} */
- public static final Rop CONV_I2F =
- new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f");
+ /** {@code r: float; x: int :: r = (float) x} */
+ public static final Rop CONV_I2F = new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f");
- /** {@code r: float; x: long :: r = (float) x} */
- public static final Rop CONV_L2F =
- new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.LONG, "conv-l2f");
+ /** {@code r: float; x: long :: r = (float) x} */
+ public static final Rop CONV_L2F = new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.LONG, "conv-l2f");
- /** {@code r: float; x: double :: r = (float) x} */
- public static final Rop CONV_D2F =
- new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f");
+ /** {@code r: float; x: double :: r = (float) x} */
+ public static final Rop CONV_D2F =
+ new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f");
- /** {@code r: double; x: int :: r = (double) x} */
- public static final Rop CONV_I2D =
- new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.INT, "conv-i2d");
+ /** {@code r: double; x: int :: r = (double) x} */
+ public static final Rop CONV_I2D = new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.INT, "conv-i2d");
- /** {@code r: double; x: long :: r = (double) x} */
- public static final Rop CONV_L2D =
- new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d");
+ /** {@code r: double; x: long :: r = (double) x} */
+ public static final Rop CONV_L2D =
+ new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d");
- /** {@code r: double; x: float :: r = (double) x} */
- public static final Rop CONV_F2D =
- new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.FLOAT, "conv-f2d");
+ /** {@code r: double; x: float :: r = (double) x} */
+ public static final Rop CONV_F2D =
+ new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.FLOAT, "conv-f2d");
- /**
- * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
- * convert int to byte)
- */
- public static final Rop TO_BYTE =
- new Rop(RegOps.TO_BYTE, Type.INT, StdTypeList.INT, "to-byte");
+ /**
+ * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
+ * convert int to byte)
+ */
+ public static final Rop TO_BYTE = new Rop(RegOps.TO_BYTE, Type.INT, StdTypeList.INT, "to-byte");
- /**
- * {@code r,x: int :: r = x & 0xffff} (Java-style
- * convert int to char)
- */
- public static final Rop TO_CHAR =
- new Rop(RegOps.TO_CHAR, Type.INT, StdTypeList.INT, "to-char");
+ /**
+ * {@code r,x: int :: r = x & 0xffff} (Java-style
+ * convert int to char)
+ */
+ public static final Rop TO_CHAR = new Rop(RegOps.TO_CHAR, Type.INT, StdTypeList.INT, "to-char");
- /**
- * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
- * convert int to short)
- */
- public static final Rop TO_SHORT =
- new Rop(RegOps.TO_SHORT, Type.INT, StdTypeList.INT, "to-short");
+ /**
+ * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
+ * convert int to short)
+ */
+ public static final Rop TO_SHORT =
+ new Rop(RegOps.TO_SHORT, Type.INT, StdTypeList.INT, "to-short");
- /** {@code return void} */
- public static final Rop RETURN_VOID =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN,
- "return-void");
+ /** {@code return void} */
+ public static final Rop RETURN_VOID =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN, "return-void");
- /** {@code x: int; return x} */
- public static final Rop RETURN_INT =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.INT, Rop.BRANCH_RETURN,
- "return-int");
+ /** {@code x: int; return x} */
+ public static final Rop RETURN_INT =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.INT, Rop.BRANCH_RETURN, "return-int");
- /** {@code x: long; return x} */
- public static final Rop RETURN_LONG =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN,
- "return-long");
+ /** {@code x: long; return x} */
+ public static final Rop RETURN_LONG =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN, "return-long");
- /** {@code x: float; return x} */
- public static final Rop RETURN_FLOAT =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.FLOAT, Rop.BRANCH_RETURN,
- "return-float");
+ /** {@code x: float; return x} */
+ public static final Rop RETURN_FLOAT =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.FLOAT, Rop.BRANCH_RETURN, "return-float");
- /** {@code x: double; return x} */
- public static final Rop RETURN_DOUBLE =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE,
- Rop.BRANCH_RETURN, "return-double");
+ /** {@code x: double; return x} */
+ public static final Rop RETURN_DOUBLE =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE, Rop.BRANCH_RETURN, "return-double");
- /** {@code x: Object; return x} */
- public static final Rop RETURN_OBJECT =
- new Rop(RegOps.RETURN, Type.VOID, StdTypeList.OBJECT,
- Rop.BRANCH_RETURN, "return-object");
+ /** {@code x: Object; return x} */
+ public static final Rop RETURN_OBJECT =
+ new Rop(RegOps.RETURN, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_RETURN, "return-object");
- /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
- public static final Rop ARRAY_LENGTH =
- new Rop(RegOps.ARRAY_LENGTH, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException, "array-length");
+ /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
+ public static final Rop ARRAY_LENGTH = new Rop(RegOps.ARRAY_LENGTH, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "array-length");
- /** {@code x: Throwable :: throw(x)} */
- public static final Rop THROW =
- new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE,
- StdTypeList.THROWABLE, "throw");
+ /** {@code x: Throwable :: throw(x)} */
+ public static final Rop THROW =
+ new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE, StdTypeList.THROWABLE, "throw");
- /** {@code x: Object :: monitorenter(x)} */
- public static final Rop MONITOR_ENTER =
- new Rop(RegOps.MONITOR_ENTER, Type.VOID, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException, "monitor-enter");
+ /** {@code x: Object :: monitorenter(x)} */
+ public static final Rop MONITOR_ENTER = new Rop(RegOps.MONITOR_ENTER, Type.VOID,
+ StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException, "monitor-enter");
- /** {@code x: Object :: monitorexit(x)} */
- public static final Rop MONITOR_EXIT =
- new Rop(RegOps.MONITOR_EXIT, Type.VOID, StdTypeList.OBJECT,
- Exceptions.LIST_Error_Null_IllegalMonitorStateException,
- "monitor-exit");
+ /** {@code x: Object :: monitorexit(x)} */
+ public static final Rop MONITOR_EXIT = new Rop(RegOps.MONITOR_EXIT, Type.VOID, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_Null_IllegalMonitorStateException, "monitor-exit");
- /** {@code r,y: int; x: int[] :: r = x[y]} */
- public static final Rop AGET_INT =
- new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-int");
+ /** {@code r,y: int; x: int[] :: r = x[y]} */
+ public static final Rop AGET_INT = new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-int");
- /** {@code r: long; x: long[]; y: int :: r = x[y]} */
- public static final Rop AGET_LONG =
- new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-long");
+ /** {@code r: long; x: long[]; y: int :: r = x[y]} */
+ public static final Rop AGET_LONG = new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-long");
- /** {@code r: float; x: float[]; y: int :: r = x[y]} */
- public static final Rop AGET_FLOAT =
- new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-float");
+ /** {@code r: float; x: float[]; y: int :: r = x[y]} */
+ public static final Rop AGET_FLOAT = new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-float");
- /** {@code r: double; x: double[]; y: int :: r = x[y]} */
- public static final Rop AGET_DOUBLE =
- new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-double");
+ /** {@code r: double; x: double[]; y: int :: r = x[y]} */
+ public static final Rop AGET_DOUBLE = new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-double");
- /** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
- public static final Rop AGET_OBJECT =
- new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-object");
+ /** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
+ public static final Rop AGET_OBJECT = new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-object");
- /** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
- public static final Rop AGET_BOOLEAN =
- new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-boolean");
+ /** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
+ public static final Rop AGET_BOOLEAN = new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-boolean");
- /** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
- public static final Rop AGET_BYTE =
- new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");
+ /** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
+ public static final Rop AGET_BYTE = new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");
- /** {@code r: char; x: char[]; y: int :: r = x[y]} */
- public static final Rop AGET_CHAR =
- new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");
+ /** {@code r: char; x: char[]; y: int :: r = x[y]} */
+ public static final Rop AGET_CHAR = new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");
- /** {@code r: short; x: short[]; y: int :: r = x[y]} */
- public static final Rop AGET_SHORT =
- new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aget-short");
+ /** {@code r: short; x: short[]; y: int :: r = x[y]} */
+ public static final Rop AGET_SHORT = new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-short");
- /** {@code x,z: int; y: int[] :: y[z] = x} */
- public static final Rop APUT_INT =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");
+ /** {@code x,z: int; y: int[] :: y[z] = x} */
+ public static final Rop APUT_INT = new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");
- /** {@code x: long; y: long[]; z: int :: y[z] = x} */
- public static final Rop APUT_LONG =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");
+ /** {@code x: long; y: long[]; z: int :: y[z] = x} */
+ public static final Rop APUT_LONG = new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");
- /** {@code x: float; y: float[]; z: int :: y[z] = x} */
- public static final Rop APUT_FLOAT =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.FLOAT_FLOATARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aput-float");
+ /** {@code x: float; y: float[]; z: int :: y[z] = x} */
+ public static final Rop APUT_FLOAT = new Rop(RegOps.APUT, Type.VOID,
+ StdTypeList.FLOAT_FLOATARR_INT, Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+ "aput-float");
- /** {@code x: double; y: double[]; z: int :: y[z] = x} */
- public static final Rop APUT_DOUBLE =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.DOUBLE_DOUBLEARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
- "aput-double");
+ /** {@code x: double; y: double[]; z: int :: y[z] = x} */
+ public static final Rop APUT_DOUBLE = new Rop(RegOps.APUT, Type.VOID,
+ StdTypeList.DOUBLE_DOUBLEARR_INT, Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+ "aput-double");
- /** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
- public static final Rop APUT_OBJECT =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.OBJECT_OBJECTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
- "aput-object");
+ /** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
+ public static final Rop APUT_OBJECT = new Rop(RegOps.APUT, Type.VOID,
+ StdTypeList.OBJECT_OBJECTARR_INT, Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+ "aput-object");
- /** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
- public static final Rop APUT_BOOLEAN =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BOOLEANARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
- "aput-boolean");
+ /** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
+ public static final Rop APUT_BOOLEAN = new Rop(RegOps.APUT, Type.VOID,
+ StdTypeList.INT_BOOLEANARR_INT, Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+ "aput-boolean");
- /** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
- public static final Rop APUT_BYTE =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");
+ /** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
+ public static final Rop APUT_BYTE = new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");
- /** {@code x: char; y: char[]; z: int :: y[z] = x} */
- public static final Rop APUT_CHAR =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");
+ /** {@code x: char; y: char[]; z: int :: y[z] = x} */
+ public static final Rop APUT_CHAR = new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");
- /** {@code x: short; y: short[]; z: int :: y[z] = x} */
- public static final Rop APUT_SHORT =
- new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT,
- Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
- "aput-short");
+ /** {@code x: short; y: short[]; z: int :: y[z] = x} */
+ public static final Rop APUT_SHORT = new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT,
+ Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-short");
- /**
- * {@code T: any non-array object type :: r =
- * alloc(T)} (allocate heap space for an object)
- */
- public static final Rop NEW_INSTANCE =
- new Rop(RegOps.NEW_INSTANCE, Type.OBJECT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "new-instance");
+ /**
+ * {@code T: any non-array object type :: r =
+ * alloc(T)} (allocate heap space for an object)
+ */
+ public static final Rop NEW_INSTANCE = new Rop(RegOps.NEW_INSTANCE, Type.OBJECT,
+ StdTypeList.EMPTY, Exceptions.LIST_Error, "new-instance");
- /** {@code r: int[]; x: int :: r = new int[x]} */
- public static final Rop NEW_ARRAY_INT =
- new Rop(RegOps.NEW_ARRAY, Type.INT_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-int");
+ /** {@code r: int[]; x: int :: r = new int[x]} */
+ public static final Rop NEW_ARRAY_INT = new Rop(RegOps.NEW_ARRAY, Type.INT_ARRAY, StdTypeList.INT,
+ Exceptions.LIST_Error_NegativeArraySizeException, "new-array-int");
- /** {@code r: long[]; x: int :: r = new long[x]} */
- public static final Rop NEW_ARRAY_LONG =
- new Rop(RegOps.NEW_ARRAY, Type.LONG_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-long");
+ /** {@code r: long[]; x: int :: r = new long[x]} */
+ public static final Rop NEW_ARRAY_LONG = new Rop(RegOps.NEW_ARRAY, Type.LONG_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-long");
- /** {@code r: float[]; x: int :: r = new float[x]} */
- public static final Rop NEW_ARRAY_FLOAT =
- new Rop(RegOps.NEW_ARRAY, Type.FLOAT_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-float");
+ /** {@code r: float[]; x: int :: r = new float[x]} */
+ public static final Rop NEW_ARRAY_FLOAT = new Rop(RegOps.NEW_ARRAY, Type.FLOAT_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-float");
- /** {@code r: double[]; x: int :: r = new double[x]} */
- public static final Rop NEW_ARRAY_DOUBLE =
- new Rop(RegOps.NEW_ARRAY, Type.DOUBLE_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-double");
+ /** {@code r: double[]; x: int :: r = new double[x]} */
+ public static final Rop NEW_ARRAY_DOUBLE = new Rop(RegOps.NEW_ARRAY, Type.DOUBLE_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-double");
- /** {@code r: boolean[]; x: int :: r = new boolean[x]} */
- public static final Rop NEW_ARRAY_BOOLEAN =
- new Rop(RegOps.NEW_ARRAY, Type.BOOLEAN_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-boolean");
+ /** {@code r: boolean[]; x: int :: r = new boolean[x]} */
+ public static final Rop NEW_ARRAY_BOOLEAN = new Rop(RegOps.NEW_ARRAY, Type.BOOLEAN_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-boolean");
- /** {@code r: byte[]; x: int :: r = new byte[x]} */
- public static final Rop NEW_ARRAY_BYTE =
- new Rop(RegOps.NEW_ARRAY, Type.BYTE_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-byte");
+ /** {@code r: byte[]; x: int :: r = new byte[x]} */
+ public static final Rop NEW_ARRAY_BYTE = new Rop(RegOps.NEW_ARRAY, Type.BYTE_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-byte");
- /** {@code r: char[]; x: int :: r = new char[x]} */
- public static final Rop NEW_ARRAY_CHAR =
- new Rop(RegOps.NEW_ARRAY, Type.CHAR_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-char");
+ /** {@code r: char[]; x: int :: r = new char[x]} */
+ public static final Rop NEW_ARRAY_CHAR = new Rop(RegOps.NEW_ARRAY, Type.CHAR_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-char");
- /** {@code r: short[]; x: int :: r = new short[x]} */
- public static final Rop NEW_ARRAY_SHORT =
- new Rop(RegOps.NEW_ARRAY, Type.SHORT_ARRAY, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-short");
+ /** {@code r: short[]; x: int :: r = new short[x]} */
+ public static final Rop NEW_ARRAY_SHORT = new Rop(RegOps.NEW_ARRAY, Type.SHORT_ARRAY,
+ StdTypeList.INT, Exceptions.LIST_Error_NegativeArraySizeException, "new-array-short");
- /**
- * {@code T: any non-array object type; x: Object :: (T) x} (can
- * throw {@code ClassCastException})
- */
- public static final Rop CHECK_CAST =
- new Rop(RegOps.CHECK_CAST, Type.VOID, StdTypeList.OBJECT,
- Exceptions.LIST_Error_ClassCastException, "check-cast");
+ /**
+ * {@code T: any non-array object type; x: Object :: (T) x} (can
+ * throw {@code ClassCastException})
+ */
+ public static final Rop CHECK_CAST = new Rop(RegOps.CHECK_CAST, Type.VOID, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_ClassCastException, "check-cast");
- /**
- * {@code T: any non-array object type; x: Object :: x instanceof
- * T}. Note: This is listed as throwing {@code Error}
- * explicitly because the op <i>can</i> throw, but there are no
- * other predefined exceptions for it.
- */
- public static final Rop INSTANCE_OF =
- new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error, "instance-of");
+ /**
+ * {@code T: any non-array object type; x: Object :: x instanceof
+ * T}. Note: This is listed as throwing {@code Error}
+ * explicitly because the op <i>can</i> throw, but there are no
+ * other predefined exceptions for it.
+ */
+ public static final Rop INSTANCE_OF = new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error, "instance-of");
- /**
- * {@code r: int; x: Object; f: instance field spec of
- * type int :: r = x.f}
- */
- public static final Rop GET_FIELD_INT =
- new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException, "get-field-int");
+ /**
+ * {@code r: int; x: Object; f: instance field spec of
+ * type int :: r = x.f}
+ */
+ public static final Rop GET_FIELD_INT = new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "get-field-int");
- /**
- * {@code r: long; x: Object; f: instance field spec of
- * type long :: r = x.f}
- */
- public static final Rop GET_FIELD_LONG =
- new Rop(RegOps.GET_FIELD, Type.LONG, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException, "get-field-long");
+ /**
+ * {@code r: long; x: Object; f: instance field spec of
+ * type long :: r = x.f}
+ */
+ public static final Rop GET_FIELD_LONG = new Rop(RegOps.GET_FIELD, Type.LONG, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "get-field-long");
- /**
- * {@code r: float; x: Object; f: instance field spec of
- * type float :: r = x.f}
- */
- public static final Rop GET_FIELD_FLOAT =
- new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-float");
+ /**
+ * {@code r: float; x: Object; f: instance field spec of
+ * type float :: r = x.f}
+ */
+ public static final Rop GET_FIELD_FLOAT = new Rop(RegOps.GET_FIELD, Type.FLOAT,
+ StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException, "get-field-float");
- /**
- * {@code r: double; x: Object; f: instance field spec of
- * type double :: r = x.f}
- */
- public static final Rop GET_FIELD_DOUBLE =
- new Rop(RegOps.GET_FIELD, Type.DOUBLE, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-double");
+ /**
+ * {@code r: double; x: Object; f: instance field spec of
+ * type double :: r = x.f}
+ */
+ public static final Rop GET_FIELD_DOUBLE = new Rop(RegOps.GET_FIELD, Type.DOUBLE,
+ StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException, "get-field-double");
- /**
- * {@code r: Object; x: Object; f: instance field spec of
- * type Object :: r = x.f}
- */
- public static final Rop GET_FIELD_OBJECT =
- new Rop(RegOps.GET_FIELD, Type.OBJECT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-object");
+ /**
+ * {@code r: Object; x: Object; f: instance field spec of
+ * type Object :: r = x.f}
+ */
+ public static final Rop GET_FIELD_OBJECT = new Rop(RegOps.GET_FIELD, Type.OBJECT,
+ StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException, "get-field-object");
- /**
- * {@code r: boolean; x: Object; f: instance field spec of
- * type boolean :: r = x.f}
- */
- public static final Rop GET_FIELD_BOOLEAN =
- new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-boolean");
+ /**
+ * {@code r: boolean; x: Object; f: instance field spec of
+ * type boolean :: r = x.f}
+ */
+ public static final Rop GET_FIELD_BOOLEAN = new Rop(RegOps.GET_FIELD, Type.INT,
+ StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException, "get-field-boolean");
- /**
- * {@code r: byte; x: Object; f: instance field spec of
- * type byte :: r = x.f}
- */
- public static final Rop GET_FIELD_BYTE =
- new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-byte");
+ /**
+ * {@code r: byte; x: Object; f: instance field spec of
+ * type byte :: r = x.f}
+ */
+ public static final Rop GET_FIELD_BYTE = new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "get-field-byte");
- /**
- * {@code r: char; x: Object; f: instance field spec of
- * type char :: r = x.f}
- */
- public static final Rop GET_FIELD_CHAR =
- new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-char");
+ /**
+ * {@code r: char; x: Object; f: instance field spec of
+ * type char :: r = x.f}
+ */
+ public static final Rop GET_FIELD_CHAR = new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "get-field-char");
- /**
- * {@code r: short; x: Object; f: instance field spec of
- * type short :: r = x.f}
- */
- public static final Rop GET_FIELD_SHORT =
- new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "get-field-short");
+ /**
+ * {@code r: short; x: Object; f: instance field spec of
+ * type short :: r = x.f}
+ */
+ public static final Rop GET_FIELD_SHORT = new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
+ Exceptions.LIST_Error_NullPointerException, "get-field-short");
- /** {@code r: int; f: static field spec of type int :: r = f} */
- public static final Rop GET_STATIC_INT =
- new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-static-int");
+ /** {@code r: int; f: static field spec of type int :: r = f} */
+ public static final Rop GET_STATIC_INT = new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
+ Exceptions.LIST_Error, "get-static-int");
- /** {@code r: long; f: static field spec of type long :: r = f} */
- public static final Rop GET_STATIC_LONG =
- new Rop(RegOps.GET_STATIC, Type.LONG, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-static-long");
+ /** {@code r: long; f: static field spec of type long :: r = f} */
+ public static final Rop GET_STATIC_LONG = new Rop(RegOps.GET_STATIC, Type.LONG, StdTypeList.EMPTY,
+ Exceptions.LIST_Error, "get-static-long");
- /** {@code r: float; f: static field spec of type float :: r = f} */
- public static final Rop GET_STATIC_FLOAT =
- new Rop(RegOps.GET_STATIC, Type.FLOAT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-static-float");
+ /** {@code r: float; f: static field spec of type float :: r = f} */
+ public static final Rop GET_STATIC_FLOAT = new Rop(RegOps.GET_STATIC, Type.FLOAT,
+ StdTypeList.EMPTY, Exceptions.LIST_Error, "get-static-float");
- /** {@code r: double; f: static field spec of type double :: r = f} */
- public static final Rop GET_STATIC_DOUBLE =
- new Rop(RegOps.GET_STATIC, Type.DOUBLE, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-static-double");
+ /** {@code r: double; f: static field spec of type double :: r = f} */
+ public static final Rop GET_STATIC_DOUBLE = new Rop(RegOps.GET_STATIC, Type.DOUBLE,
+ StdTypeList.EMPTY, Exceptions.LIST_Error, "get-static-double");
- /** {@code r: Object; f: static field spec of type Object :: r = f} */
- public static final Rop GET_STATIC_OBJECT =
- new Rop(RegOps.GET_STATIC, Type.OBJECT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-static-object");
+ /** {@code r: Object; f: static field spec of type Object :: r = f} */
+ public static final Rop GET_STATIC_OBJECT = new Rop(RegOps.GET_STATIC, Type.OBJECT,
+ StdTypeList.EMPTY, Exceptions.LIST_Error, "get-static-object");
- /** {@code r: boolean; f: static field spec of type boolean :: r = f} */
- public static final Rop GET_STATIC_BOOLEAN =
- new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-field-boolean");
+ /** {@code r: boolean; f: static field spec of type boolean :: r = f} */
+ public static final Rop GET_STATIC_BOOLEAN = new Rop(RegOps.GET_STATIC, Type.INT,
+ StdTypeList.EMPTY, Exceptions.LIST_Error, "get-field-boolean");
- /** {@code r: byte; f: static field spec of type byte :: r = f} */
- public static final Rop GET_STATIC_BYTE =
- new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-field-byte");
+ /** {@code r: byte; f: static field spec of type byte :: r = f} */
+ public static final Rop GET_STATIC_BYTE = new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
+ Exceptions.LIST_Error, "get-field-byte");
- /** {@code r: char; f: static field spec of type char :: r = f} */
- public static final Rop GET_STATIC_CHAR =
- new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-field-char");
+ /** {@code r: char; f: static field spec of type char :: r = f} */
+ public static final Rop GET_STATIC_CHAR = new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
+ Exceptions.LIST_Error, "get-field-char");
- /** {@code r: short; f: static field spec of type short :: r = f} */
- public static final Rop GET_STATIC_SHORT =
- new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
- Exceptions.LIST_Error, "get-field-short");
+ /** {@code r: short; f: static field spec of type short :: r = f} */
+ public static final Rop GET_STATIC_SHORT = new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
+ Exceptions.LIST_Error, "get-field-short");
- /**
- * {@code x: int; y: Object; f: instance field spec of type
- * int :: y.f = x}
- */
- public static final Rop PUT_FIELD_INT =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
- Exceptions.LIST_Error_NullPointerException, "put-field-int");
+ /**
+ * {@code x: int; y: Object; f: instance field spec of type
+ * int :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_INT = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.INT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-int");
- /**
- * {@code x: long; y: Object; f: instance field spec of type
- * long :: y.f = x}
- */
- public static final Rop PUT_FIELD_LONG =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.LONG_OBJECT,
- Exceptions.LIST_Error_NullPointerException, "put-field-long");
+ /**
+ * {@code x: long; y: Object; f: instance field spec of type
+ * long :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_LONG = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.LONG_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-long");
- /**
- * {@code x: float; y: Object; f: instance field spec of type
- * float :: y.f = x}
- */
- public static final Rop PUT_FIELD_FLOAT =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-float");
+ /**
+ * {@code x: float; y: Object; f: instance field spec of type
+ * float :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_FLOAT = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.FLOAT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-float");
- /**
- * {@code x: double; y: Object; f: instance field spec of type
- * double :: y.f = x}
- */
- public static final Rop PUT_FIELD_DOUBLE =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.DOUBLE_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-double");
+ /**
+ * {@code x: double; y: Object; f: instance field spec of type
+ * double :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_DOUBLE = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.DOUBLE_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-double");
- /**
- * {@code x: Object; y: Object; f: instance field spec of type
- * Object :: y.f = x}
- */
- public static final Rop PUT_FIELD_OBJECT =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.OBJECT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-object");
+ /**
+ * {@code x: Object; y: Object; f: instance field spec of type
+ * Object :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_OBJECT = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.OBJECT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-object");
- /**
- * {@code x: int; y: Object; f: instance field spec of type
- * boolean :: y.f = x}
- */
- public static final Rop PUT_FIELD_BOOLEAN =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-boolean");
+ /**
+ * {@code x: int; y: Object; f: instance field spec of type
+ * boolean :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_BOOLEAN = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.INT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-boolean");
- /**
- * {@code x: int; y: Object; f: instance field spec of type
- * byte :: y.f = x}
- */
- public static final Rop PUT_FIELD_BYTE =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-byte");
+ /**
+ * {@code x: int; y: Object; f: instance field spec of type
+ * byte :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_BYTE = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.INT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-byte");
- /**
- * {@code x: int; y: Object; f: instance field spec of type
- * char :: y.f = x}
- */
- public static final Rop PUT_FIELD_CHAR =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-char");
+ /**
+ * {@code x: int; y: Object; f: instance field spec of type
+ * char :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_CHAR = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.INT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-char");
- /**
- * {@code x: int; y: Object; f: instance field spec of type
- * short :: y.f = x}
- */
- public static final Rop PUT_FIELD_SHORT =
- new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
- Exceptions.LIST_Error_NullPointerException,
- "put-field-short");
+ /**
+ * {@code x: int; y: Object; f: instance field spec of type
+ * short :: y.f = x}
+ */
+ public static final Rop PUT_FIELD_SHORT = new Rop(RegOps.PUT_FIELD, Type.VOID,
+ StdTypeList.INT_OBJECT, Exceptions.LIST_Error_NullPointerException, "put-field-short");
- /** {@code f: static field spec of type int; x: int :: f = x} */
- public static final Rop PUT_STATIC_INT =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
- Exceptions.LIST_Error, "put-static-int");
+ /** {@code f: static field spec of type int; x: int :: f = x} */
+ public static final Rop PUT_STATIC_INT = new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
+ Exceptions.LIST_Error, "put-static-int");
- /** {@code f: static field spec of type long; x: long :: f = x} */
- public static final Rop PUT_STATIC_LONG =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.LONG,
- Exceptions.LIST_Error, "put-static-long");
+ /** {@code f: static field spec of type long; x: long :: f = x} */
+ public static final Rop PUT_STATIC_LONG = new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.LONG,
+ Exceptions.LIST_Error, "put-static-long");
- /** {@code f: static field spec of type float; x: float :: f = x} */
- public static final Rop PUT_STATIC_FLOAT =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.FLOAT,
- Exceptions.LIST_Error, "put-static-float");
+ /** {@code f: static field spec of type float; x: float :: f = x} */
+ public static final Rop PUT_STATIC_FLOAT = new Rop(RegOps.PUT_STATIC, Type.VOID,
+ StdTypeList.FLOAT, Exceptions.LIST_Error, "put-static-float");
- /** {@code f: static field spec of type double; x: double :: f = x} */
- public static final Rop PUT_STATIC_DOUBLE =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.DOUBLE,
- Exceptions.LIST_Error, "put-static-double");
+ /** {@code f: static field spec of type double; x: double :: f = x} */
+ public static final Rop PUT_STATIC_DOUBLE = new Rop(RegOps.PUT_STATIC, Type.VOID,
+ StdTypeList.DOUBLE, Exceptions.LIST_Error, "put-static-double");
- /** {@code f: static field spec of type Object; x: Object :: f = x} */
- public static final Rop PUT_STATIC_OBJECT =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.OBJECT,
- Exceptions.LIST_Error, "put-static-object");
+ /** {@code f: static field spec of type Object; x: Object :: f = x} */
+ public static final Rop PUT_STATIC_OBJECT = new Rop(RegOps.PUT_STATIC, Type.VOID,
+ StdTypeList.OBJECT, Exceptions.LIST_Error, "put-static-object");
- /**
- * {@code f: static field spec of type boolean; x: boolean :: f =
- * x}
- */
- public static final Rop PUT_STATIC_BOOLEAN =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
- Exceptions.LIST_Error, "put-static-boolean");
+ /**
+ * {@code f: static field spec of type boolean; x: boolean :: f =
+ * x}
+ */
+ public static final Rop PUT_STATIC_BOOLEAN = new Rop(RegOps.PUT_STATIC, Type.VOID,
+ StdTypeList.INT, Exceptions.LIST_Error, "put-static-boolean");
- /** {@code f: static field spec of type byte; x: byte :: f = x} */
- public static final Rop PUT_STATIC_BYTE =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
- Exceptions.LIST_Error, "put-static-byte");
+ /** {@code f: static field spec of type byte; x: byte :: f = x} */
+ public static final Rop PUT_STATIC_BYTE = new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
+ Exceptions.LIST_Error, "put-static-byte");
- /** {@code f: static field spec of type char; x: char :: f = x} */
- public static final Rop PUT_STATIC_CHAR =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
- Exceptions.LIST_Error, "put-static-char");
+ /** {@code f: static field spec of type char; x: char :: f = x} */
+ public static final Rop PUT_STATIC_CHAR = new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
+ Exceptions.LIST_Error, "put-static-char");
- /** {@code f: static field spec of type short; x: short :: f = x} */
- public static final Rop PUT_STATIC_SHORT =
- new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
- Exceptions.LIST_Error, "put-static-short");
+ /** {@code f: static field spec of type short; x: short :: f = x} */
+ public static final Rop PUT_STATIC_SHORT = new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
+ Exceptions.LIST_Error, "put-static-short");
- /** {@code x: Int :: local variable begins in x} */
- public static final Rop MARK_LOCAL_INT =
- new Rop (RegOps.MARK_LOCAL, Type.VOID,
- StdTypeList.INT, "mark-local-int");
+ /** {@code x: Int :: local variable begins in x} */
+ public static final Rop MARK_LOCAL_INT =
+ new Rop(RegOps.MARK_LOCAL, Type.VOID, StdTypeList.INT, "mark-local-int");
- /** {@code x: Long :: local variable begins in x} */
- public static final Rop MARK_LOCAL_LONG =
- new Rop (RegOps.MARK_LOCAL, Type.VOID,
- StdTypeList.LONG, "mark-local-long");
+ /** {@code x: Long :: local variable begins in x} */
+ public static final Rop MARK_LOCAL_LONG =
+ new Rop(RegOps.MARK_LOCAL, Type.VOID, StdTypeList.LONG, "mark-local-long");
- /** {@code x: Float :: local variable begins in x} */
- public static final Rop MARK_LOCAL_FLOAT =
- new Rop (RegOps.MARK_LOCAL, Type.VOID,
- StdTypeList.FLOAT, "mark-local-float");
+ /** {@code x: Float :: local variable begins in x} */
+ public static final Rop MARK_LOCAL_FLOAT =
+ new Rop(RegOps.MARK_LOCAL, Type.VOID, StdTypeList.FLOAT, "mark-local-float");
- /** {@code x: Double :: local variable begins in x} */
- public static final Rop MARK_LOCAL_DOUBLE =
- new Rop (RegOps.MARK_LOCAL, Type.VOID,
- StdTypeList.DOUBLE, "mark-local-double");
+ /** {@code x: Double :: local variable begins in x} */
+ public static final Rop MARK_LOCAL_DOUBLE =
+ new Rop(RegOps.MARK_LOCAL, Type.VOID, StdTypeList.DOUBLE, "mark-local-double");
- /** {@code x: Object :: local variable begins in x} */
- public static final Rop MARK_LOCAL_OBJECT =
- new Rop (RegOps.MARK_LOCAL, Type.VOID,
- StdTypeList.OBJECT, "mark-local-object");
+ /** {@code x: Object :: local variable begins in x} */
+ public static final Rop MARK_LOCAL_OBJECT =
+ new Rop(RegOps.MARK_LOCAL, Type.VOID, StdTypeList.OBJECT, "mark-local-object");
- /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
- public static final Rop FILL_ARRAY_DATA =
- new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY,
- "fill-array-data");
+ /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
+ public static final Rop FILL_ARRAY_DATA =
+ new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY, "fill-array-data");
- /**
- * Returns the appropriate rop for the given opcode, destination,
- * and sources. The result is typically, but not necessarily, a
- * shared instance.
- *
- * <p><b>Note:</b> This method does not do complete error checking on
- * its arguments, and so it may return an instance which seemed "right
- * enough" even though in actuality the passed arguments don't quite
- * match what is returned. TODO: Revisit this issue.</p>
- *
- * @param opcode the opcode
- * @param dest {@code non-null;} destination (result) type, or
- * {@link Type#VOID} if none
- * @param sources {@code non-null;} list of source types
- * @param cst {@code null-ok;} associated constant, if any
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop ropFor(int opcode, TypeBearer dest, TypeList sources,
- Constant cst) {
- switch (opcode) {
- case RegOps.NOP: return NOP;
- case RegOps.MOVE: return opMove(dest);
- case RegOps.MOVE_PARAM: return opMoveParam(dest);
- case RegOps.MOVE_EXCEPTION: return opMoveException(dest);
- case RegOps.CONST: return opConst(dest);
- case RegOps.GOTO: return GOTO;
- case RegOps.IF_EQ: return opIfEq(sources);
- case RegOps.IF_NE: return opIfNe(sources);
- case RegOps.IF_LT: return opIfLt(sources);
- case RegOps.IF_GE: return opIfGe(sources);
- case RegOps.IF_LE: return opIfLe(sources);
- case RegOps.IF_GT: return opIfGt(sources);
- case RegOps.SWITCH: return SWITCH;
- case RegOps.ADD: return opAdd(sources);
- case RegOps.SUB: return opSub(sources);
- case RegOps.MUL: return opMul(sources);
- case RegOps.DIV: return opDiv(sources);
- case RegOps.REM: return opRem(sources);
- case RegOps.NEG: return opNeg(dest);
- case RegOps.AND: return opAnd(sources);
- case RegOps.OR: return opOr(sources);
- case RegOps.XOR: return opXor(sources);
- case RegOps.SHL: return opShl(sources);
- case RegOps.SHR: return opShr(sources);
- case RegOps.USHR: return opUshr(sources);
- case RegOps.NOT: return opNot(dest);
- case RegOps.CMPL: return opCmpl(sources.getType(0));
- case RegOps.CMPG: return opCmpg(sources.getType(0));
- case RegOps.CONV: return opConv(dest, sources.getType(0));
- case RegOps.TO_BYTE: return TO_BYTE;
- case RegOps.TO_CHAR: return TO_CHAR;
- case RegOps.TO_SHORT: return TO_SHORT;
- case RegOps.RETURN: {
- if (sources.size() == 0) {
- return RETURN_VOID;
- }
- return opReturn(sources.getType(0));
- }
- case RegOps.ARRAY_LENGTH: return ARRAY_LENGTH;
- case RegOps.THROW: return THROW;
- case RegOps.MONITOR_ENTER: return MONITOR_ENTER;
- case RegOps.MONITOR_EXIT: return MONITOR_EXIT;
- case RegOps.AGET: {
- Type source = sources.getType(0);
- Type componentType;
- if (source == Type.KNOWN_NULL) {
- /*
- * Treat a known-null as an array of the expected
- * result type.
- */
- componentType = dest.getType();
- } else {
- componentType = source.getComponentType();
- }
- return opAget(componentType);
- }
- case RegOps.APUT: {
- Type source = sources.getType(1);
- Type componentType;
- if (source == Type.KNOWN_NULL) {
- /*
- * Treat a known-null as an array of the type being
- * stored.
- */
- componentType = sources.getType(0);
- } else {
- componentType = source.getComponentType();
- }
- return opAput(componentType);
- }
- case RegOps.NEW_INSTANCE: return NEW_INSTANCE;
- case RegOps.NEW_ARRAY: return opNewArray(dest.getType());
- case RegOps.CHECK_CAST: return CHECK_CAST;
- case RegOps.INSTANCE_OF: return INSTANCE_OF;
- case RegOps.GET_FIELD: return opGetField(dest);
- case RegOps.GET_STATIC: return opGetStatic(dest);
- case RegOps.PUT_FIELD: return opPutField(sources.getType(0));
- case RegOps.PUT_STATIC: return opPutStatic(sources.getType(0));
- case RegOps.INVOKE_STATIC: {
- return opInvokeStatic(((CstMethodRef) cst).getPrototype());
- }
- case RegOps.INVOKE_VIRTUAL: {
- CstBaseMethodRef cstMeth = (CstMethodRef) cst;
- Prototype meth = cstMeth.getPrototype();
- CstType definer = cstMeth.getDefiningClass();
- meth = meth.withFirstParameter(definer.getClassType());
- return opInvokeVirtual(meth);
- }
- case RegOps.INVOKE_SUPER: {
- CstBaseMethodRef cstMeth = (CstMethodRef) cst;
- Prototype meth = cstMeth.getPrototype();
- CstType definer = cstMeth.getDefiningClass();
- meth = meth.withFirstParameter(definer.getClassType());
- return opInvokeSuper(meth);
- }
- case RegOps.INVOKE_DIRECT: {
- CstBaseMethodRef cstMeth = (CstMethodRef) cst;
- Prototype meth = cstMeth.getPrototype();
- CstType definer = cstMeth.getDefiningClass();
- meth = meth.withFirstParameter(definer.getClassType());
- return opInvokeDirect(meth);
- }
- case RegOps.INVOKE_INTERFACE: {
- CstBaseMethodRef cstMeth = (CstMethodRef) cst;
- Prototype meth = cstMeth.getPrototype();
- CstType definer = cstMeth.getDefiningClass();
- meth = meth.withFirstParameter(definer.getClassType());
- return opInvokeInterface(meth);
- }
+ /**
+ * Returns the appropriate rop for the given opcode, destination,
+ * and sources. The result is typically, but not necessarily, a
+ * shared instance.
+ *
+ * <p><b>Note:</b> This method does not do complete error checking on
+ * its arguments, and so it may return an instance which seemed "right
+ * enough" even though in actuality the passed arguments don't quite
+ * match what is returned. TODO(dx team): Revisit this issue.</p>
+ *
+ * @param opcode the opcode
+ * @param dest {@code non-null;} destination (result) type, or
+ * {@link Type#VOID} if none
+ * @param sources {@code non-null;} list of source types
+ * @param cst {@code null-ok;} associated constant, if any
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop ropFor(int opcode, TypeBearer dest, TypeList sources, Constant cst) {
+ switch (opcode) {
+ case RegOps.NOP:
+ return NOP;
+ case RegOps.MOVE:
+ return opMove(dest);
+ case RegOps.MOVE_PARAM:
+ return opMoveParam(dest);
+ case RegOps.MOVE_EXCEPTION:
+ return opMoveException(dest);
+ case RegOps.CONST:
+ return opConst(dest);
+ case RegOps.GOTO:
+ return GOTO;
+ case RegOps.IF_EQ:
+ return opIfEq(sources);
+ case RegOps.IF_NE:
+ return opIfNe(sources);
+ case RegOps.IF_LT:
+ return opIfLt(sources);
+ case RegOps.IF_GE:
+ return opIfGe(sources);
+ case RegOps.IF_LE:
+ return opIfLe(sources);
+ case RegOps.IF_GT:
+ return opIfGt(sources);
+ case RegOps.SWITCH:
+ return SWITCH;
+ case RegOps.ADD:
+ return opAdd(sources);
+ case RegOps.SUB:
+ return opSub(sources);
+ case RegOps.MUL:
+ return opMul(sources);
+ case RegOps.DIV:
+ return opDiv(sources);
+ case RegOps.REM:
+ return opRem(sources);
+ case RegOps.NEG:
+ return opNeg(dest);
+ case RegOps.AND:
+ return opAnd(sources);
+ case RegOps.OR:
+ return opOr(sources);
+ case RegOps.XOR:
+ return opXor(sources);
+ case RegOps.SHL:
+ return opShl(sources);
+ case RegOps.SHR:
+ return opShr(sources);
+ case RegOps.USHR:
+ return opUshr(sources);
+ case RegOps.NOT:
+ return opNot(dest);
+ case RegOps.CMPL:
+ return opCmpl(sources.getType(0));
+ case RegOps.CMPG:
+ return opCmpg(sources.getType(0));
+ case RegOps.CONV:
+ return opConv(dest, sources.getType(0));
+ case RegOps.TO_BYTE:
+ return TO_BYTE;
+ case RegOps.TO_CHAR:
+ return TO_CHAR;
+ case RegOps.TO_SHORT:
+ return TO_SHORT;
+ case RegOps.RETURN: {
+ if (sources.size() == 0) {
+ return RETURN_VOID;
}
-
- throw new RuntimeException("unknown opcode " + RegOps.opName(opcode));
- }
-
- /**
- * Returns the appropriate {@code move} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being moved
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMove(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return MOVE_INT;
- case Type.BT_LONG: return MOVE_LONG;
- case Type.BT_FLOAT: return MOVE_FLOAT;
- case Type.BT_DOUBLE: return MOVE_DOUBLE;
- case Type.BT_OBJECT: return MOVE_OBJECT;
- case Type.BT_ADDR: return MOVE_RETURN_ADDRESS;
+ return opReturn(sources.getType(0));
+ }
+ case RegOps.ARRAY_LENGTH:
+ return ARRAY_LENGTH;
+ case RegOps.THROW:
+ return THROW;
+ case RegOps.MONITOR_ENTER:
+ return MONITOR_ENTER;
+ case RegOps.MONITOR_EXIT:
+ return MONITOR_EXIT;
+ case RegOps.AGET: {
+ Type source = sources.getType(0);
+ Type componentType;
+ if (source == Type.KNOWN_NULL) {
+ /*
+ * Treat a known-null as an array of the expected
+ * result type.
+ */
+ componentType = dest.getType();
+ } else {
+ componentType = source.getComponentType();
}
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code move-param} rop for the
- * given type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of value being moved
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMoveParam(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return MOVE_PARAM_INT;
- case Type.BT_LONG: return MOVE_PARAM_LONG;
- case Type.BT_FLOAT: return MOVE_PARAM_FLOAT;
- case Type.BT_DOUBLE: return MOVE_PARAM_DOUBLE;
- case Type.BT_OBJECT: return MOVE_PARAM_OBJECT;
+ return opAget(componentType);
+ }
+ case RegOps.APUT: {
+ Type source = sources.getType(1);
+ Type componentType;
+ if (source == Type.KNOWN_NULL) {
+ /*
+ * Treat a known-null as an array of the type being
+ * stored.
+ */
+ componentType = sources.getType(0);
+ } else {
+ componentType = source.getComponentType();
}
-
- return throwBadType(type);
+ return opAput(componentType);
+ }
+ case RegOps.NEW_INSTANCE:
+ return NEW_INSTANCE;
+ case RegOps.NEW_ARRAY:
+ return opNewArray(dest.getType());
+ case RegOps.CHECK_CAST:
+ return CHECK_CAST;
+ case RegOps.INSTANCE_OF:
+ return INSTANCE_OF;
+ case RegOps.GET_FIELD:
+ return opGetField(dest);
+ case RegOps.GET_STATIC:
+ return opGetStatic(dest);
+ case RegOps.PUT_FIELD:
+ return opPutField(sources.getType(0));
+ case RegOps.PUT_STATIC:
+ return opPutStatic(sources.getType(0));
+ case RegOps.INVOKE_STATIC: {
+ return opInvokeStatic(((CstMethodRef) cst).getPrototype());
+ }
+ case RegOps.INVOKE_VIRTUAL: {
+ CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+ Prototype meth = cstMeth.getPrototype();
+ CstType definer = cstMeth.getDefiningClass();
+ meth = meth.withFirstParameter(definer.getClassType());
+ return opInvokeVirtual(meth);
+ }
+ case RegOps.INVOKE_SUPER: {
+ CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+ Prototype meth = cstMeth.getPrototype();
+ CstType definer = cstMeth.getDefiningClass();
+ meth = meth.withFirstParameter(definer.getClassType());
+ return opInvokeSuper(meth);
+ }
+ case RegOps.INVOKE_DIRECT: {
+ CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+ Prototype meth = cstMeth.getPrototype();
+ CstType definer = cstMeth.getDefiningClass();
+ meth = meth.withFirstParameter(definer.getClassType());
+ return opInvokeDirect(meth);
+ }
+ case RegOps.INVOKE_INTERFACE: {
+ CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+ Prototype meth = cstMeth.getPrototype();
+ CstType definer = cstMeth.getDefiningClass();
+ meth = meth.withFirstParameter(definer.getClassType());
+ return opInvokeInterface(meth);
+ }
}
- /**
- * Returns the appropriate {@code move-exception} rop for the
- * given type. The result may be a shared instance.
- *
- * @param type {@code non-null;} type of the exception
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMoveException(TypeBearer type) {
- return new Rop(RegOps.MOVE_EXCEPTION, type.getType(),
- StdTypeList.EMPTY, (String) null);
+ throw new RuntimeException("unknown opcode " + RegOps.opName(opcode));
+ }
+
+ /**
+ * Returns the appropriate {@code move} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being moved
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMove(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return MOVE_INT;
+ case Type.BT_LONG:
+ return MOVE_LONG;
+ case Type.BT_FLOAT:
+ return MOVE_FLOAT;
+ case Type.BT_DOUBLE:
+ return MOVE_DOUBLE;
+ case Type.BT_OBJECT:
+ return MOVE_OBJECT;
+ case Type.BT_ADDR:
+ return MOVE_RETURN_ADDRESS;
}
- /**
- * Returns the appropriate {@code move-result} rop for the
- * given type. The result may be a shared instance.
- *
- * @param type {@code non-null;} type of the parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMoveResult(TypeBearer type) {
- return new Rop(RegOps.MOVE_RESULT, type.getType(),
- StdTypeList.EMPTY, (String) null);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code move-param} rop for the
+ * given type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being moved
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMoveParam(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return MOVE_PARAM_INT;
+ case Type.BT_LONG:
+ return MOVE_PARAM_LONG;
+ case Type.BT_FLOAT:
+ return MOVE_PARAM_FLOAT;
+ case Type.BT_DOUBLE:
+ return MOVE_PARAM_DOUBLE;
+ case Type.BT_OBJECT:
+ return MOVE_PARAM_OBJECT;
}
- /**
- * Returns the appropriate {@code move-result-pseudo} rop for the
- * given type. The result may be a shared instance.
- *
- * @param type {@code non-null;} type of the parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMoveResultPseudo(TypeBearer type) {
- return new Rop(RegOps.MOVE_RESULT_PSEUDO, type.getType(),
- StdTypeList.EMPTY, (String) null);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code move-exception} rop for the
+ * given type. The result may be a shared instance.
+ *
+ * @param type {@code non-null;} type of the exception
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMoveException(TypeBearer type) {
+ return new Rop(RegOps.MOVE_EXCEPTION, type.getType(), StdTypeList.EMPTY, (String) null);
+ }
+
+ /**
+ * Returns the appropriate {@code move-result} rop for the
+ * given type. The result may be a shared instance.
+ *
+ * @param type {@code non-null;} type of the parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMoveResult(TypeBearer type) {
+ return new Rop(RegOps.MOVE_RESULT, type.getType(), StdTypeList.EMPTY, (String) null);
+ }
+
+ /**
+ * Returns the appropriate {@code move-result-pseudo} rop for the
+ * given type. The result may be a shared instance.
+ *
+ * @param type {@code non-null;} type of the parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMoveResultPseudo(TypeBearer type) {
+ return new Rop(RegOps.MOVE_RESULT_PSEUDO, type.getType(), StdTypeList.EMPTY, (String) null);
+ }
+
+ /**
+ * Returns the appropriate {@code const} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of the constant
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opConst(TypeBearer type) {
+ if (type.getType() == Type.KNOWN_NULL) {
+ return CONST_OBJECT_NOTHROW;
}
- /**
- * Returns the appropriate {@code const} rop for the given
- * type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of the constant
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opConst(TypeBearer type) {
- if (type.getType() == Type.KNOWN_NULL) {
- return CONST_OBJECT_NOTHROW;
- }
-
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return CONST_INT;
- case Type.BT_LONG: return CONST_LONG;
- case Type.BT_FLOAT: return CONST_FLOAT;
- case Type.BT_DOUBLE: return CONST_DOUBLE;
- case Type.BT_OBJECT: return CONST_OBJECT;
- }
-
- return throwBadType(type);
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return CONST_INT;
+ case Type.BT_LONG:
+ return CONST_LONG;
+ case Type.BT_FLOAT:
+ return CONST_FLOAT;
+ case Type.BT_DOUBLE:
+ return CONST_DOUBLE;
+ case Type.BT_OBJECT:
+ return CONST_OBJECT;
}
- /**
- * Returns the appropriate {@code if-eq} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfEq(TypeList types) {
- return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT,
- IF_EQ_INT, IF_EQ_OBJECT);
- }
+ return throwBadType(type);
+ }
- /**
- * Returns the appropriate {@code if-ne} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfNe(TypeList types) {
- return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT,
- IF_NE_INT, IF_NE_OBJECT);
- }
+ /**
+ * Returns the appropriate {@code if-eq} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfEq(TypeList types) {
+ return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT, IF_EQ_INT, IF_EQ_OBJECT);
+ }
- /**
- * Returns the appropriate {@code if-lt} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfLt(TypeList types) {
- return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
- }
+ /**
+ * Returns the appropriate {@code if-ne} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfNe(TypeList types) {
+ return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT, IF_NE_INT, IF_NE_OBJECT);
+ }
- /**
- * Returns the appropriate {@code if-ge} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfGe(TypeList types) {
- return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
- }
+ /**
+ * Returns the appropriate {@code if-lt} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfLt(TypeList types) {
+ return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
+ }
- /**
- * Returns the appropriate {@code if-gt} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfGt(TypeList types) {
- return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
- }
+ /**
+ * Returns the appropriate {@code if-ge} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfGe(TypeList types) {
+ return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
+ }
- /**
- * Returns the appropriate {@code if-le} rop for the given
- * sources. The result is a shared instance.
- *
- * @param types {@code non-null;} source types
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opIfLe(TypeList types) {
- return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
- }
+ /**
+ * Returns the appropriate {@code if-gt} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfGt(TypeList types) {
+ return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
+ }
- /**
- * Helper for all the {@code if*}-related methods, which
- * checks types and picks one of the four variants, throwing if
- * there's a problem.
- *
- * @param types {@code non-null;} the types
- * @param intZ {@code non-null;} the int-to-0 comparison
- * @param objZ {@code null-ok;} the object-to-null comparison
- * @param intInt {@code non-null;} the int-to-int comparison
- * @param objObj {@code non-null;} the object-to-object comparison
- * @return {@code non-null;} the appropriate instance
- */
- private static Rop pickIf(TypeList types, Rop intZ, Rop objZ, Rop intInt,
- Rop objObj) {
- switch(types.size()) {
- case 1: {
- switch (types.getType(0).getBasicFrameType()) {
- case Type.BT_INT: {
- return intZ;
- }
- case Type.BT_OBJECT: {
- if (objZ != null) {
- return objZ;
- }
- }
- }
- break;
+ /**
+ * Returns the appropriate {@code if-le} rop for the given
+ * sources. The result is a shared instance.
+ *
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opIfLe(TypeList types) {
+ return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
+ }
+
+ /**
+ * Helper for all the {@code if*}-related methods, which
+ * checks types and picks one of the four variants, throwing if
+ * there's a problem.
+ *
+ * @param types {@code non-null;} the types
+ * @param intZ {@code non-null;} the int-to-0 comparison
+ * @param objZ {@code null-ok;} the object-to-null comparison
+ * @param intInt {@code non-null;} the int-to-int comparison
+ * @param objObj {@code non-null;} the object-to-object comparison
+ * @return {@code non-null;} the appropriate instance
+ */
+ private static Rop pickIf(TypeList types, Rop intZ, Rop objZ, Rop intInt, Rop objObj) {
+ switch (types.size()) {
+ case 1: {
+ switch (types.getType(0).getBasicFrameType()) {
+ case Type.BT_INT: {
+ return intZ;
+ }
+ case Type.BT_OBJECT: {
+ if (objZ != null) {
+ return objZ;
}
- case 2: {
- int bt = types.getType(0).getBasicFrameType();
- if (bt == types.getType(1).getBasicFrameType()) {
- switch (bt) {
- case Type.BT_INT: {
- return intInt;
- }
- case Type.BT_OBJECT: {
- if (objObj != null) {
- return objObj;
- }
- }
- }
- }
- break;
- }
+ }
}
-
- return throwBadTypes(types);
- }
-
- /**
- * Returns the appropriate {@code add} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opAdd(TypeList types) {
- return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG,
- ADD_CONST_FLOAT, ADD_CONST_DOUBLE, ADD_INT,
- ADD_LONG, ADD_FLOAT, ADD_DOUBLE);
- }
-
- /**
- * Returns the appropriate {@code sub} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opSub(TypeList types) {
- return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG,
- SUB_CONST_FLOAT, SUB_CONST_DOUBLE, SUB_INT,
- SUB_LONG, SUB_FLOAT, SUB_DOUBLE);
- }
-
- /**
- * Returns the appropriate {@code mul} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMul(TypeList types) {
- return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG,
- MUL_CONST_FLOAT, MUL_CONST_DOUBLE, MUL_INT,
- MUL_LONG, MUL_FLOAT, MUL_DOUBLE);
- }
-
- /**
- * Returns the appropriate {@code div} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opDiv(TypeList types) {
- return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG,
- DIV_CONST_FLOAT, DIV_CONST_DOUBLE, DIV_INT,
- DIV_LONG, DIV_FLOAT, DIV_DOUBLE);
- }
-
- /**
- * Returns the appropriate {@code rem} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opRem(TypeList types) {
- return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG,
- REM_CONST_FLOAT, REM_CONST_DOUBLE, REM_INT,
- REM_LONG, REM_FLOAT, REM_DOUBLE);
- }
-
- /**
- * Returns the appropriate {@code and} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opAnd(TypeList types) {
- return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null,
- AND_INT, AND_LONG, null, null);
- }
-
- /**
- * Returns the appropriate {@code or} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opOr(TypeList types) {
- return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null,
- OR_INT, OR_LONG, null, null);
- }
-
- /**
- * Returns the appropriate {@code xor} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opXor(TypeList types) {
- return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null,
- XOR_INT, XOR_LONG, null, null);
- }
-
- /**
- * Returns the appropriate {@code shl} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opShl(TypeList types) {
- return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null,
- SHL_INT, SHL_LONG, null, null);
- }
-
- /**
- * Returns the appropriate {@code shr} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opShr(TypeList types) {
- return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null,
- SHR_INT, SHR_LONG, null, null);
- }
-
- /**
- * Returns the appropriate {@code ushr} rop for the given
- * types. The result is a shared instance.
- *
- * @param types {@code non-null;} types of the sources
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opUshr(TypeList types) {
- return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null,
- USHR_INT, USHR_LONG, null, null);
- }
-
- /**
- * Returns the appropriate binary arithmetic rop for the given type
- * and arguments. The result is a shared instance.
- *
- * @param types {@code non-null;} sources of the operation
- * @param int1 {@code non-null;} the int-to-constant rop
- * @param long1 {@code non-null;} the long-to-constant rop
- * @param float1 {@code null-ok;} the float-to-constant rop, if any
- * @param double1 {@code null-ok;} the double-to-constant rop, if any
- * @param int2 {@code non-null;} the int-to-int rop
- * @param long2 {@code non-null;} the long-to-long or long-to-int rop
- * @param float2 {@code null-ok;} the float-to-float rop, if any
- * @param double2 {@code null-ok;} the double-to-double rop, if any
- * @return {@code non-null;} an appropriate instance
- */
- private static Rop pickBinaryOp(TypeList types, Rop int1, Rop long1,
- Rop float1, Rop double1, Rop int2,
- Rop long2, Rop float2, Rop double2) {
- int bt1 = types.getType(0).getBasicFrameType();
- Rop result = null;
-
- switch (types.size()) {
- case 1: {
- switch(bt1) {
- case Type.BT_INT: return int1;
- case Type.BT_LONG: return long1;
- case Type.BT_FLOAT: result = float1; break;
- case Type.BT_DOUBLE: result = double1; break;
- }
- break;
- }
- case 2: {
- switch(bt1) {
- case Type.BT_INT: return int2;
- case Type.BT_LONG: return long2;
- case Type.BT_FLOAT: result = float2; break;
- case Type.BT_DOUBLE: result = double2; break;
- }
- break;
- }
- }
-
- if (result == null) {
- return throwBadTypes(types);
- }
-
- return result;
- }
-
- /**
- * Returns the appropriate {@code neg} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being operated on
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opNeg(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return NEG_INT;
- case Type.BT_LONG: return NEG_LONG;
- case Type.BT_FLOAT: return NEG_FLOAT;
- case Type.BT_DOUBLE: return NEG_DOUBLE;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code not} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being operated on
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opNot(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return NOT_INT;
- case Type.BT_LONG: return NOT_LONG;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code cmpl} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being compared
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opCmpl(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_LONG: return CMPL_LONG;
- case Type.BT_FLOAT: return CMPL_FLOAT;
- case Type.BT_DOUBLE: return CMPL_DOUBLE;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code cmpg} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being compared
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opCmpg(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_FLOAT: return CMPG_FLOAT;
- case Type.BT_DOUBLE: return CMPG_DOUBLE;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code conv} rop for the given types. The
- * result is a shared instance.
- *
- * @param dest {@code non-null;} target value type
- * @param source {@code non-null;} source value type
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opConv(TypeBearer dest, TypeBearer source) {
- int dbt = dest.getBasicFrameType();
- switch (source.getBasicFrameType()) {
+ break;
+ }
+ case 2: {
+ int bt = types.getType(0).getBasicFrameType();
+ if (bt == types.getType(1).getBasicFrameType()) {
+ switch (bt) {
case Type.BT_INT: {
- switch (dbt) {
- case Type.BT_LONG: return CONV_I2L;
- case Type.BT_FLOAT: return CONV_I2F;
- case Type.BT_DOUBLE: return CONV_I2D;
- default: break;
- }
+ return intInt;
}
- case Type.BT_LONG: {
- switch (dbt) {
- case Type.BT_INT: return CONV_L2I;
- case Type.BT_FLOAT: return CONV_L2F;
- case Type.BT_DOUBLE: return CONV_L2D;
- default: break;
- }
- }
- case Type.BT_FLOAT: {
- switch (dbt) {
- case Type.BT_INT: return CONV_F2I;
- case Type.BT_LONG: return CONV_F2L;
- case Type.BT_DOUBLE: return CONV_F2D;
- default: break;
- }
- }
- case Type.BT_DOUBLE: {
- switch (dbt) {
- case Type.BT_INT: return CONV_D2I;
- case Type.BT_LONG: return CONV_D2L;
- case Type.BT_FLOAT: return CONV_D2F;
- default: break;
- }
- }
- }
-
- return throwBadTypes(StdTypeList.make(dest.getType(),
- source.getType()));
- }
-
- /**
- * Returns the appropriate {@code return} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} type of value being returned
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opReturn(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return RETURN_INT;
- case Type.BT_LONG: return RETURN_LONG;
- case Type.BT_FLOAT: return RETURN_FLOAT;
- case Type.BT_DOUBLE: return RETURN_DOUBLE;
- case Type.BT_OBJECT: return RETURN_OBJECT;
- case Type.BT_VOID: return RETURN_VOID;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code aget} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} element type of array being accessed
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opAget(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return AGET_INT;
- case Type.BT_LONG: return AGET_LONG;
- case Type.BT_FLOAT: return AGET_FLOAT;
- case Type.BT_DOUBLE: return AGET_DOUBLE;
- case Type.BT_OBJECT: return AGET_OBJECT;
- case Type.BT_BOOLEAN: return AGET_BOOLEAN;
- case Type.BT_BYTE: return AGET_BYTE;
- case Type.BT_CHAR: return AGET_CHAR;
- case Type.BT_SHORT: return AGET_SHORT;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code aput} rop for the given type. The
- * result is a shared instance.
- *
- * @param type {@code non-null;} element type of array being accessed
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opAput(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return APUT_INT;
- case Type.BT_LONG: return APUT_LONG;
- case Type.BT_FLOAT: return APUT_FLOAT;
- case Type.BT_DOUBLE: return APUT_DOUBLE;
- case Type.BT_OBJECT: return APUT_OBJECT;
- case Type.BT_BOOLEAN: return APUT_BOOLEAN;
- case Type.BT_BYTE: return APUT_BYTE;
- case Type.BT_CHAR: return APUT_CHAR;
- case Type.BT_SHORT: return APUT_SHORT;
- }
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code new-array} rop for the given
- * type. The result is a shared instance.
- *
- * @param arrayType {@code non-null;} array type of array being created
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opNewArray(TypeBearer arrayType) {
- Type type = arrayType.getType();
- Type elementType = type.getComponentType();
-
- switch (elementType.getBasicType()) {
- case Type.BT_INT: return NEW_ARRAY_INT;
- case Type.BT_LONG: return NEW_ARRAY_LONG;
- case Type.BT_FLOAT: return NEW_ARRAY_FLOAT;
- case Type.BT_DOUBLE: return NEW_ARRAY_DOUBLE;
- case Type.BT_BOOLEAN: return NEW_ARRAY_BOOLEAN;
- case Type.BT_BYTE: return NEW_ARRAY_BYTE;
- case Type.BT_CHAR: return NEW_ARRAY_CHAR;
- case Type.BT_SHORT: return NEW_ARRAY_SHORT;
case Type.BT_OBJECT: {
- return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT,
- Exceptions.LIST_Error_NegativeArraySizeException,
- "new-array-object");
+ if (objObj != null) {
+ return objObj;
+ }
}
+ }
}
-
- return throwBadType(type);
+ break;
+ }
}
- /**
- * Returns the appropriate {@code filled-new-array} rop for the given
- * type. The result may be a shared instance.
- *
- * @param arrayType {@code non-null;} type of array being created
- * @param count {@code >= 0;} number of elements that the array should have
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
- Type type = arrayType.getType();
- Type elementType = type.getComponentType();
+ return throwBadTypes(types);
+ }
- if (elementType.isCategory2()) {
- return throwBadType(arrayType);
+ /**
+ * Returns the appropriate {@code add} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opAdd(TypeList types) {
+ return pickBinaryOp(types,
+ ADD_CONST_INT,
+ ADD_CONST_LONG,
+ ADD_CONST_FLOAT,
+ ADD_CONST_DOUBLE,
+ ADD_INT,
+ ADD_LONG,
+ ADD_FLOAT,
+ ADD_DOUBLE);
+ }
+
+ /**
+ * Returns the appropriate {@code sub} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opSub(TypeList types) {
+ return pickBinaryOp(types,
+ SUB_CONST_INT,
+ SUB_CONST_LONG,
+ SUB_CONST_FLOAT,
+ SUB_CONST_DOUBLE,
+ SUB_INT,
+ SUB_LONG,
+ SUB_FLOAT,
+ SUB_DOUBLE);
+ }
+
+ /**
+ * Returns the appropriate {@code mul} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMul(TypeList types) {
+ return pickBinaryOp(types,
+ MUL_CONST_INT,
+ MUL_CONST_LONG,
+ MUL_CONST_FLOAT,
+ MUL_CONST_DOUBLE,
+ MUL_INT,
+ MUL_LONG,
+ MUL_FLOAT,
+ MUL_DOUBLE);
+ }
+
+ /**
+ * Returns the appropriate {@code div} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opDiv(TypeList types) {
+ return pickBinaryOp(types,
+ DIV_CONST_INT,
+ DIV_CONST_LONG,
+ DIV_CONST_FLOAT,
+ DIV_CONST_DOUBLE,
+ DIV_INT,
+ DIV_LONG,
+ DIV_FLOAT,
+ DIV_DOUBLE);
+ }
+
+ /**
+ * Returns the appropriate {@code rem} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opRem(TypeList types) {
+ return pickBinaryOp(types,
+ REM_CONST_INT,
+ REM_CONST_LONG,
+ REM_CONST_FLOAT,
+ REM_CONST_DOUBLE,
+ REM_INT,
+ REM_LONG,
+ REM_FLOAT,
+ REM_DOUBLE);
+ }
+
+ /**
+ * Returns the appropriate {@code and} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opAnd(TypeList types) {
+ return pickBinaryOp(types,
+ AND_CONST_INT,
+ AND_CONST_LONG,
+ null,
+ null,
+ AND_INT,
+ AND_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate {@code or} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opOr(TypeList types) {
+ return pickBinaryOp(types,
+ OR_CONST_INT,
+ OR_CONST_LONG,
+ null,
+ null,
+ OR_INT,
+ OR_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate {@code xor} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opXor(TypeList types) {
+ return pickBinaryOp(types,
+ XOR_CONST_INT,
+ XOR_CONST_LONG,
+ null,
+ null,
+ XOR_INT,
+ XOR_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate {@code shl} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opShl(TypeList types) {
+ return pickBinaryOp(types,
+ SHL_CONST_INT,
+ SHL_CONST_LONG,
+ null,
+ null,
+ SHL_INT,
+ SHL_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate {@code shr} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opShr(TypeList types) {
+ return pickBinaryOp(types,
+ SHR_CONST_INT,
+ SHR_CONST_LONG,
+ null,
+ null,
+ SHR_INT,
+ SHR_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate {@code ushr} rop for the given
+ * types. The result is a shared instance.
+ *
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opUshr(TypeList types) {
+ return pickBinaryOp(types,
+ USHR_CONST_INT,
+ USHR_CONST_LONG,
+ null,
+ null,
+ USHR_INT,
+ USHR_LONG,
+ null,
+ null);
+ }
+
+ /**
+ * Returns the appropriate binary arithmetic rop for the given type
+ * and arguments. The result is a shared instance.
+ *
+ * @param types {@code non-null;} sources of the operation
+ * @param int1 {@code non-null;} the int-to-constant rop
+ * @param long1 {@code non-null;} the long-to-constant rop
+ * @param float1 {@code null-ok;} the float-to-constant rop, if any
+ * @param double1 {@code null-ok;} the double-to-constant rop, if any
+ * @param int2 {@code non-null;} the int-to-int rop
+ * @param long2 {@code non-null;} the long-to-long or long-to-int rop
+ * @param float2 {@code null-ok;} the float-to-float rop, if any
+ * @param double2 {@code null-ok;} the double-to-double rop, if any
+ * @return {@code non-null;} an appropriate instance
+ */
+ private static Rop pickBinaryOp(TypeList types,
+ Rop int1,
+ Rop long1,
+ Rop float1,
+ Rop double1,
+ Rop int2,
+ Rop long2,
+ Rop float2,
+ Rop double2) {
+ int bt1 = types.getType(0).getBasicFrameType();
+ Rop result = null;
+
+ switch (types.size()) {
+ case 1: {
+ switch (bt1) {
+ case Type.BT_INT:
+ return int1;
+ case Type.BT_LONG:
+ return long1;
+ case Type.BT_FLOAT:
+ result = float1;
+ break;
+ case Type.BT_DOUBLE:
+ result = double1;
+ break;
}
-
- if (count < 0) {
- throw new IllegalArgumentException("count < 0");
+ break;
+ }
+ case 2: {
+ switch (bt1) {
+ case Type.BT_INT:
+ return int2;
+ case Type.BT_LONG:
+ return long2;
+ case Type.BT_FLOAT:
+ result = float2;
+ break;
+ case Type.BT_DOUBLE:
+ result = double2;
+ break;
}
+ break;
+ }
+ }
- StdTypeList sourceTypes = new StdTypeList(count);
+ if (result == null) {
+ return throwBadTypes(types);
+ }
- for (int i = 0; i < count; i++) {
- sourceTypes.set(i, elementType);
+ return result;
+ }
+
+ /**
+ * Returns the appropriate {@code neg} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being operated on
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opNeg(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return NEG_INT;
+ case Type.BT_LONG:
+ return NEG_LONG;
+ case Type.BT_FLOAT:
+ return NEG_FLOAT;
+ case Type.BT_DOUBLE:
+ return NEG_DOUBLE;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code not} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being operated on
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opNot(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return NOT_INT;
+ case Type.BT_LONG:
+ return NOT_LONG;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code cmpl} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being compared
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opCmpl(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_LONG:
+ return CMPL_LONG;
+ case Type.BT_FLOAT:
+ return CMPL_FLOAT;
+ case Type.BT_DOUBLE:
+ return CMPL_DOUBLE;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code cmpg} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being compared
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opCmpg(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_FLOAT:
+ return CMPG_FLOAT;
+ case Type.BT_DOUBLE:
+ return CMPG_DOUBLE;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code conv} rop for the given types. The
+ * result is a shared instance.
+ *
+ * @param dest {@code non-null;} target value type
+ * @param source {@code non-null;} source value type
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opConv(TypeBearer dest, TypeBearer source) {
+ int dbt = dest.getBasicFrameType();
+ switch (source.getBasicFrameType()) {
+ case Type.BT_INT: {
+ switch (dbt) {
+ case Type.BT_LONG:
+ return CONV_I2L;
+ case Type.BT_FLOAT:
+ return CONV_I2F;
+ case Type.BT_DOUBLE:
+ return CONV_I2D;
+ default:
+ break;
}
-
- // Note: The resulting rop is considered call-like.
- return new Rop(RegOps.FILLED_NEW_ARRAY,
- sourceTypes,
- Exceptions.LIST_Error);
- }
-
- /**
- * Returns the appropriate {@code get-field} rop for the given
- * type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of the field in question
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opGetField(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return GET_FIELD_INT;
- case Type.BT_LONG: return GET_FIELD_LONG;
- case Type.BT_FLOAT: return GET_FIELD_FLOAT;
- case Type.BT_DOUBLE: return GET_FIELD_DOUBLE;
- case Type.BT_OBJECT: return GET_FIELD_OBJECT;
- case Type.BT_BOOLEAN: return GET_FIELD_BOOLEAN;
- case Type.BT_BYTE: return GET_FIELD_BYTE;
- case Type.BT_CHAR: return GET_FIELD_CHAR;
- case Type.BT_SHORT: return GET_FIELD_SHORT;
+ break;
+ }
+ case Type.BT_LONG: {
+ switch (dbt) {
+ case Type.BT_INT:
+ return CONV_L2I;
+ case Type.BT_FLOAT:
+ return CONV_L2F;
+ case Type.BT_DOUBLE:
+ return CONV_L2D;
+ default:
+ break;
}
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code put-field} rop for the given
- * type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of the field in question
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opPutField(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return PUT_FIELD_INT;
- case Type.BT_LONG: return PUT_FIELD_LONG;
- case Type.BT_FLOAT: return PUT_FIELD_FLOAT;
- case Type.BT_DOUBLE: return PUT_FIELD_DOUBLE;
- case Type.BT_OBJECT: return PUT_FIELD_OBJECT;
- case Type.BT_BOOLEAN: return PUT_FIELD_BOOLEAN;
- case Type.BT_BYTE: return PUT_FIELD_BYTE;
- case Type.BT_CHAR: return PUT_FIELD_CHAR;
- case Type.BT_SHORT: return PUT_FIELD_SHORT;
+ break;
+ }
+ case Type.BT_FLOAT: {
+ switch (dbt) {
+ case Type.BT_INT:
+ return CONV_F2I;
+ case Type.BT_LONG:
+ return CONV_F2L;
+ case Type.BT_DOUBLE:
+ return CONV_F2D;
+ default:
+ break;
}
-
- return throwBadType(type);
- }
-
- /**
- * Returns the appropriate {@code get-static} rop for the given
- * type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of the field in question
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opGetStatic(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return GET_STATIC_INT;
- case Type.BT_LONG: return GET_STATIC_LONG;
- case Type.BT_FLOAT: return GET_STATIC_FLOAT;
- case Type.BT_DOUBLE: return GET_STATIC_DOUBLE;
- case Type.BT_OBJECT: return GET_STATIC_OBJECT;
- case Type.BT_BOOLEAN: return GET_STATIC_BOOLEAN;
- case Type.BT_BYTE: return GET_STATIC_BYTE;
- case Type.BT_CHAR: return GET_STATIC_CHAR;
- case Type.BT_SHORT: return GET_STATIC_SHORT;
+ break;
+ }
+ case Type.BT_DOUBLE: {
+ switch (dbt) {
+ case Type.BT_INT:
+ return CONV_D2I;
+ case Type.BT_LONG:
+ return CONV_D2L;
+ case Type.BT_FLOAT:
+ return CONV_D2F;
+ default:
+ break;
}
-
- return throwBadType(type);
+ }
}
- /**
- * Returns the appropriate {@code put-static} rop for the given
- * type. The result is a shared instance.
- *
- * @param type {@code non-null;} type of the field in question
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opPutStatic(TypeBearer type) {
- switch (type.getBasicType()) {
- case Type.BT_INT: return PUT_STATIC_INT;
- case Type.BT_LONG: return PUT_STATIC_LONG;
- case Type.BT_FLOAT: return PUT_STATIC_FLOAT;
- case Type.BT_DOUBLE: return PUT_STATIC_DOUBLE;
- case Type.BT_OBJECT: return PUT_STATIC_OBJECT;
- case Type.BT_BOOLEAN: return PUT_STATIC_BOOLEAN;
- case Type.BT_BYTE: return PUT_STATIC_BYTE;
- case Type.BT_CHAR: return PUT_STATIC_CHAR;
- case Type.BT_SHORT: return PUT_STATIC_SHORT;
- }
+ return throwBadTypes(StdTypeList.make(dest.getType(), source.getType()));
+ }
- return throwBadType(type);
+ /**
+ * Returns the appropriate {@code return} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being returned
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opReturn(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return RETURN_INT;
+ case Type.BT_LONG:
+ return RETURN_LONG;
+ case Type.BT_FLOAT:
+ return RETURN_FLOAT;
+ case Type.BT_DOUBLE:
+ return RETURN_DOUBLE;
+ case Type.BT_OBJECT:
+ return RETURN_OBJECT;
+ case Type.BT_VOID:
+ return RETURN_VOID;
}
- /**
- * Returns the appropriate {@code invoke-static} rop for the
- * given type. The result is typically a newly-allocated instance.
- *
- * @param meth {@code non-null;} descriptor of the method
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opInvokeStatic(Prototype meth) {
- return new Rop(RegOps.INVOKE_STATIC,
- meth.getParameterFrameTypes(),
- StdTypeList.THROWABLE);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code aget} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} element type of array being accessed
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opAget(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return AGET_INT;
+ case Type.BT_LONG:
+ return AGET_LONG;
+ case Type.BT_FLOAT:
+ return AGET_FLOAT;
+ case Type.BT_DOUBLE:
+ return AGET_DOUBLE;
+ case Type.BT_OBJECT:
+ return AGET_OBJECT;
+ case Type.BT_BOOLEAN:
+ return AGET_BOOLEAN;
+ case Type.BT_BYTE:
+ return AGET_BYTE;
+ case Type.BT_CHAR:
+ return AGET_CHAR;
+ case Type.BT_SHORT:
+ return AGET_SHORT;
}
- /**
- * Returns the appropriate {@code invoke-virtual} rop for the
- * given type. The result is typically a newly-allocated instance.
- *
- * @param meth {@code non-null;} descriptor of the method, including the
- * {@code this} parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opInvokeVirtual(Prototype meth) {
- return new Rop(RegOps.INVOKE_VIRTUAL,
- meth.getParameterFrameTypes(),
- StdTypeList.THROWABLE);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code aput} rop for the given type. The
+ * result is a shared instance.
+ *
+ * @param type {@code non-null;} element type of array being accessed
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opAput(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return APUT_INT;
+ case Type.BT_LONG:
+ return APUT_LONG;
+ case Type.BT_FLOAT:
+ return APUT_FLOAT;
+ case Type.BT_DOUBLE:
+ return APUT_DOUBLE;
+ case Type.BT_OBJECT:
+ return APUT_OBJECT;
+ case Type.BT_BOOLEAN:
+ return APUT_BOOLEAN;
+ case Type.BT_BYTE:
+ return APUT_BYTE;
+ case Type.BT_CHAR:
+ return APUT_CHAR;
+ case Type.BT_SHORT:
+ return APUT_SHORT;
}
- /**
- * Returns the appropriate {@code invoke-super} rop for the
- * given type. The result is typically a newly-allocated instance.
- *
- * @param meth {@code non-null;} descriptor of the method, including the
- * {@code this} parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opInvokeSuper(Prototype meth) {
- return new Rop(RegOps.INVOKE_SUPER,
- meth.getParameterFrameTypes(),
- StdTypeList.THROWABLE);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code new-array} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param arrayType {@code non-null;} array type of array being created
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opNewArray(TypeBearer arrayType) {
+ Type type = arrayType.getType();
+ Type elementType = type.getComponentType();
+
+ switch (elementType.getBasicType()) {
+ case Type.BT_INT:
+ return NEW_ARRAY_INT;
+ case Type.BT_LONG:
+ return NEW_ARRAY_LONG;
+ case Type.BT_FLOAT:
+ return NEW_ARRAY_FLOAT;
+ case Type.BT_DOUBLE:
+ return NEW_ARRAY_DOUBLE;
+ case Type.BT_BOOLEAN:
+ return NEW_ARRAY_BOOLEAN;
+ case Type.BT_BYTE:
+ return NEW_ARRAY_BYTE;
+ case Type.BT_CHAR:
+ return NEW_ARRAY_CHAR;
+ case Type.BT_SHORT:
+ return NEW_ARRAY_SHORT;
+ case Type.BT_OBJECT: {
+ return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT,
+ Exceptions.LIST_Error_NegativeArraySizeException, "new-array-object");
+ }
}
- /**
- * Returns the appropriate {@code invoke-direct} rop for the
- * given type. The result is typically a newly-allocated instance.
- *
- * @param meth {@code non-null;} descriptor of the method, including the
- * {@code this} parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opInvokeDirect(Prototype meth) {
- return new Rop(RegOps.INVOKE_DIRECT,
- meth.getParameterFrameTypes(),
- StdTypeList.THROWABLE);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code filled-new-array} rop for the given
+ * type. The result may be a shared instance.
+ *
+ * @param arrayType {@code non-null;} type of array being created
+ * @param count {@code >= 0;} number of elements that the array should have
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
+ Type type = arrayType.getType();
+ Type elementType = type.getComponentType();
+
+ if (elementType.isCategory2()) {
+ return throwBadType(arrayType);
}
- /**
- * Returns the appropriate {@code invoke-interface} rop for the
- * given type. The result is typically a newly-allocated instance.
- *
- * @param meth {@code non-null;} descriptor of the method, including the
- * {@code this} parameter
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opInvokeInterface(Prototype meth) {
- return new Rop(RegOps.INVOKE_INTERFACE,
- meth.getParameterFrameTypes(),
- StdTypeList.THROWABLE);
+ if (count < 0) {
+ throw new IllegalArgumentException("count < 0");
}
- /**
- * Returns the appropriate {@code mark-local} rop for the given type.
- * The result is a shared instance.
- *
- * @param type {@code non-null;} type of value being marked
- * @return {@code non-null;} an appropriate instance
- */
- public static Rop opMarkLocal(TypeBearer type) {
- switch (type.getBasicFrameType()) {
- case Type.BT_INT: return MARK_LOCAL_INT;
- case Type.BT_LONG: return MARK_LOCAL_LONG;
- case Type.BT_FLOAT: return MARK_LOCAL_FLOAT;
- case Type.BT_DOUBLE: return MARK_LOCAL_DOUBLE;
- case Type.BT_OBJECT: return MARK_LOCAL_OBJECT;
- }
+ StdTypeList sourceTypes = new StdTypeList(count);
- return throwBadType(type);
+ for (int i = 0; i < count; i++) {
+ sourceTypes.set(i, elementType);
}
- /**
- * This class is uninstantiable.
- */
- private Rops() {
- // This space intentionally left blank.
+ // Note: The resulting rop is considered call-like.
+ return new Rop(RegOps.FILLED_NEW_ARRAY, sourceTypes, Exceptions.LIST_Error);
+ }
+
+ /**
+ * Returns the appropriate {@code get-field} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opGetField(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return GET_FIELD_INT;
+ case Type.BT_LONG:
+ return GET_FIELD_LONG;
+ case Type.BT_FLOAT:
+ return GET_FIELD_FLOAT;
+ case Type.BT_DOUBLE:
+ return GET_FIELD_DOUBLE;
+ case Type.BT_OBJECT:
+ return GET_FIELD_OBJECT;
+ case Type.BT_BOOLEAN:
+ return GET_FIELD_BOOLEAN;
+ case Type.BT_BYTE:
+ return GET_FIELD_BYTE;
+ case Type.BT_CHAR:
+ return GET_FIELD_CHAR;
+ case Type.BT_SHORT:
+ return GET_FIELD_SHORT;
}
- /**
- * Throws the right exception to complain about a bogus type.
- *
- * @param type {@code non-null;} the bad type
- * @return never
- */
- private static Rop throwBadType(TypeBearer type) {
- throw new IllegalArgumentException("bad type: " + type);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code put-field} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opPutField(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return PUT_FIELD_INT;
+ case Type.BT_LONG:
+ return PUT_FIELD_LONG;
+ case Type.BT_FLOAT:
+ return PUT_FIELD_FLOAT;
+ case Type.BT_DOUBLE:
+ return PUT_FIELD_DOUBLE;
+ case Type.BT_OBJECT:
+ return PUT_FIELD_OBJECT;
+ case Type.BT_BOOLEAN:
+ return PUT_FIELD_BOOLEAN;
+ case Type.BT_BYTE:
+ return PUT_FIELD_BYTE;
+ case Type.BT_CHAR:
+ return PUT_FIELD_CHAR;
+ case Type.BT_SHORT:
+ return PUT_FIELD_SHORT;
}
- /**
- * Throws the right exception to complain about a bogus list of types.
- *
- * @param types {@code non-null;} the bad types
- * @return never
- */
- private static Rop throwBadTypes(TypeList types) {
- throw new IllegalArgumentException("bad types: " + types);
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code get-static} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opGetStatic(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return GET_STATIC_INT;
+ case Type.BT_LONG:
+ return GET_STATIC_LONG;
+ case Type.BT_FLOAT:
+ return GET_STATIC_FLOAT;
+ case Type.BT_DOUBLE:
+ return GET_STATIC_DOUBLE;
+ case Type.BT_OBJECT:
+ return GET_STATIC_OBJECT;
+ case Type.BT_BOOLEAN:
+ return GET_STATIC_BOOLEAN;
+ case Type.BT_BYTE:
+ return GET_STATIC_BYTE;
+ case Type.BT_CHAR:
+ return GET_STATIC_CHAR;
+ case Type.BT_SHORT:
+ return GET_STATIC_SHORT;
}
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code put-static} rop for the given
+ * type. The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opPutStatic(TypeBearer type) {
+ switch (type.getBasicType()) {
+ case Type.BT_INT:
+ return PUT_STATIC_INT;
+ case Type.BT_LONG:
+ return PUT_STATIC_LONG;
+ case Type.BT_FLOAT:
+ return PUT_STATIC_FLOAT;
+ case Type.BT_DOUBLE:
+ return PUT_STATIC_DOUBLE;
+ case Type.BT_OBJECT:
+ return PUT_STATIC_OBJECT;
+ case Type.BT_BOOLEAN:
+ return PUT_STATIC_BOOLEAN;
+ case Type.BT_BYTE:
+ return PUT_STATIC_BYTE;
+ case Type.BT_CHAR:
+ return PUT_STATIC_CHAR;
+ case Type.BT_SHORT:
+ return PUT_STATIC_SHORT;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * Returns the appropriate {@code invoke-static} rop for the
+ * given type. The result is typically a newly-allocated instance.
+ *
+ * @param meth {@code non-null;} descriptor of the method
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opInvokeStatic(Prototype meth) {
+ return new Rop(RegOps.INVOKE_STATIC, meth.getParameterFrameTypes(), StdTypeList.THROWABLE);
+ }
+
+ /**
+ * Returns the appropriate {@code invoke-virtual} rop for the
+ * given type. The result is typically a newly-allocated instance.
+ *
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opInvokeVirtual(Prototype meth) {
+ return new Rop(RegOps.INVOKE_VIRTUAL, meth.getParameterFrameTypes(), StdTypeList.THROWABLE);
+ }
+
+ /**
+ * Returns the appropriate {@code invoke-super} rop for the
+ * given type. The result is typically a newly-allocated instance.
+ *
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opInvokeSuper(Prototype meth) {
+ return new Rop(RegOps.INVOKE_SUPER, meth.getParameterFrameTypes(), StdTypeList.THROWABLE);
+ }
+
+ /**
+ * Returns the appropriate {@code invoke-direct} rop for the
+ * given type. The result is typically a newly-allocated instance.
+ *
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opInvokeDirect(Prototype meth) {
+ return new Rop(RegOps.INVOKE_DIRECT, meth.getParameterFrameTypes(), StdTypeList.THROWABLE);
+ }
+
+ /**
+ * Returns the appropriate {@code invoke-interface} rop for the
+ * given type. The result is typically a newly-allocated instance.
+ *
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opInvokeInterface(Prototype meth) {
+ return new Rop(RegOps.INVOKE_INTERFACE, meth.getParameterFrameTypes(), StdTypeList.THROWABLE);
+ }
+
+ /**
+ * Returns the appropriate {@code mark-local} rop for the given type.
+ * The result is a shared instance.
+ *
+ * @param type {@code non-null;} type of value being marked
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static Rop opMarkLocal(TypeBearer type) {
+ switch (type.getBasicFrameType()) {
+ case Type.BT_INT:
+ return MARK_LOCAL_INT;
+ case Type.BT_LONG:
+ return MARK_LOCAL_LONG;
+ case Type.BT_FLOAT:
+ return MARK_LOCAL_FLOAT;
+ case Type.BT_DOUBLE:
+ return MARK_LOCAL_DOUBLE;
+ case Type.BT_OBJECT:
+ return MARK_LOCAL_OBJECT;
+ }
+
+ return throwBadType(type);
+ }
+
+ /**
+ * This class is uninstantiable.
+ */
+ private Rops() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Throws the right exception to complain about a bogus type.
+ *
+ * @param type {@code non-null;} the bad type
+ * @return never
+ */
+ private static Rop throwBadType(TypeBearer type) {
+ throw new IllegalArgumentException("bad type: " + type);
+ }
+
+ /**
+ * Throws the right exception to complain about a bogus list of types.
+ *
+ * @param types {@code non-null;} the bad types
+ * @return never
+ */
+ private static Rop throwBadTypes(TypeList types) {
+ throw new IllegalArgumentException("bad types: " + types);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/SourcePosition.java b/dx/src/com/android/jack/dx/rop/code/SourcePosition.java
index 0c4c122..0aeea9a 100644
--- a/dx/src/com/android/jack/dx/rop/code/SourcePosition.java
+++ b/dx/src/com/android/jack/dx/rop/code/SourcePosition.java
@@ -24,145 +24,143 @@
* line number and original bytecode address.
*/
public final class SourcePosition {
- /** {@code non-null;} convenient "no information known" instance */
- public static final SourcePosition NO_INFO =
- new SourcePosition(null, -1, -1);
+ /** {@code non-null;} convenient "no information known" instance */
+ public static final SourcePosition NO_INFO = new SourcePosition(null, -1, -1);
- /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
- private final CstString sourceFile;
+ /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
+ private final CstString sourceFile;
- /**
- * {@code >= -1;} the bytecode address, or {@code -1} if that
- * information is unknown
- */
- private final int address;
+ /**
+ * {@code >= -1;} the bytecode address, or {@code -1} if that
+ * information is unknown
+ */
+ private final int address;
- /**
- * {@code >= -1;} the line number, or {@code -1} if that
- * information is unknown
- */
- private final int line;
+ /**
+ * {@code >= -1;} the line number, or {@code -1} if that
+ * information is unknown
+ */
+ private final int line;
- /**
- * Constructs an instance.
- *
- * @param sourceFile {@code null-ok;} name of the file of origin or
- * {@code null} if unknown
- * @param address {@code >= -1;} original bytecode address or {@code -1}
- * if unknown
- * @param line {@code >= -1;} original line number or {@code -1} if
- * unknown
- */
- public SourcePosition(CstString sourceFile, int address, int line) {
- if (address < -1) {
- throw new IllegalArgumentException("address < -1");
- }
-
- if (line < -1) {
- throw new IllegalArgumentException("line < -1");
- }
-
- this.sourceFile = sourceFile;
- this.address = address;
- this.line = line;
+ /**
+ * Constructs an instance.
+ *
+ * @param sourceFile {@code null-ok;} name of the file of origin or
+ * {@code null} if unknown
+ * @param address {@code >= -1;} original bytecode address or {@code -1}
+ * if unknown
+ * @param line {@code >= -1;} original line number or {@code -1} if
+ * unknown
+ */
+ public SourcePosition(CstString sourceFile, int address, int line) {
+ if (address < -1) {
+ throw new IllegalArgumentException("address < -1");
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(50);
-
- if (sourceFile != null) {
- sb.append(sourceFile.toHuman());
- sb.append(":");
- }
-
- if (line >= 0) {
- sb.append(line);
- }
-
- sb.append('@');
-
- if (address < 0) {
- sb.append("????");
- } else {
- sb.append(Hex.u2(address));
- }
-
- return sb.toString();
+ if (line < -1) {
+ throw new IllegalArgumentException("line < -1");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof SourcePosition)) {
- return false;
- }
+ this.sourceFile = sourceFile;
+ this.address = address;
+ this.line = line;
+ }
- if (this == other) {
- return true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(50);
- SourcePosition pos = (SourcePosition) other;
-
- return (address == pos.address) && sameLineAndFile(pos);
+ if (sourceFile != null) {
+ sb.append(sourceFile.toHuman());
+ sb.append(":");
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return sourceFile.hashCode() + address + line;
+ if (line >= 0) {
+ sb.append(line);
}
- /**
- * Returns whether the lines match between this instance and
- * the one given.
- *
- * @param other {@code non-null;} the instance to compare to
- * @return {@code true} iff the lines match
- */
- public boolean sameLine(SourcePosition other) {
- return (line == other.line);
+ sb.append('@');
+
+ if (address < 0) {
+ sb.append("????");
+ } else {
+ sb.append(Hex.u2(address));
}
- /**
- * Returns whether the lines and files match between this instance and
- * the one given.
- *
- * @param other {@code non-null;} the instance to compare to
- * @return {@code true} iff the lines and files match
- */
- public boolean sameLineAndFile(SourcePosition other) {
- return (line == other.line) &&
- ((sourceFile == other.sourceFile) ||
- ((sourceFile != null) && sourceFile.equals(other.sourceFile)));
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof SourcePosition)) {
+ return false;
}
- /**
- * Gets the source file, if known.
- *
- * @return {@code null-ok;} the source file or {@code null} if unknown
- */
- public CstString getSourceFile() {
- return sourceFile;
+ if (this == other) {
+ return true;
}
- /**
- * Gets the original bytecode address.
- *
- * @return {@code >= -1;} the address or {@code -1} if unknown
- */
- public int getAddress() {
- return address;
- }
+ SourcePosition pos = (SourcePosition) other;
- /**
- * Gets the original line number.
- *
- * @return {@code >= -1;} the original line number or {@code -1} if
- * unknown
- */
- public int getLine() {
- return line;
- }
+ return (address == pos.address) && sameLineAndFile(pos);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return sourceFile.hashCode() + address + line;
+ }
+
+ /**
+ * Returns whether the lines match between this instance and
+ * the one given.
+ *
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code true} iff the lines match
+ */
+ public boolean sameLine(SourcePosition other) {
+ return (line == other.line);
+ }
+
+ /**
+ * Returns whether the lines and files match between this instance and
+ * the one given.
+ *
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code true} iff the lines and files match
+ */
+ public boolean sameLineAndFile(SourcePosition other) {
+ return (line == other.line) && ((sourceFile == other.sourceFile)
+ || ((sourceFile != null) && sourceFile.equals(other.sourceFile)));
+ }
+
+ /**
+ * Gets the source file, if known.
+ *
+ * @return {@code null-ok;} the source file or {@code null} if unknown
+ */
+ public CstString getSourceFile() {
+ return sourceFile;
+ }
+
+ /**
+ * Gets the original bytecode address.
+ *
+ * @return {@code >= -1;} the address or {@code -1} if unknown
+ */
+ public int getAddress() {
+ return address;
+ }
+
+ /**
+ * Gets the original line number.
+ *
+ * @return {@code >= -1;} the original line number or {@code -1} if
+ * unknown
+ */
+ public int getLine() {
+ return line;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/SwitchInsn.java b/dx/src/com/android/jack/dx/rop/code/SwitchInsn.java
index a91b624..81e286b 100644
--- a/dx/src/com/android/jack/dx/rop/code/SwitchInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/SwitchInsn.java
@@ -24,96 +24,89 @@
/**
* Instruction which contains switch cases.
*/
-public final class SwitchInsn
- extends Insn {
- /** {@code non-null;} list of switch cases */
- private final IntList cases;
+public final class SwitchInsn extends Insn {
+ /** {@code non-null;} list of switch cases */
+ private final IntList cases;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param result {@code null-ok;} spec for the result, if any
- * @param sources {@code non-null;} specs for all the sources
- * @param cases {@code non-null;} list of switch cases
- */
- public SwitchInsn(Rop opcode, SourcePosition position, RegisterSpec result,
- RegisterSpecList sources, IntList cases) {
- super(opcode, position, result, sources);
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param result {@code null-ok;} spec for the result, if any
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cases {@code non-null;} list of switch cases
+ */
+ public SwitchInsn(Rop opcode, SourcePosition position, RegisterSpec result,
+ RegisterSpecList sources, IntList cases) {
+ super(opcode, position, result, sources);
- if (opcode.getBranchingness() != Rop.BRANCH_SWITCH) {
- throw new IllegalArgumentException("bogus branchingness");
- }
-
- if (cases == null) {
- throw new NullPointerException("cases == null");
- }
-
- this.cases = cases;
+ if (opcode.getBranchingness() != Rop.BRANCH_SWITCH) {
+ throw new IllegalArgumentException("bogus branchingness");
}
- /** {@inheritDoc} */
- @Override
- public String getInlineString() {
- return cases.toString();
+ if (cases == null) {
+ throw new NullPointerException("cases == null");
}
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return StdTypeList.EMPTY;
- }
+ this.cases = cases;
+ }
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitSwitchInsn(this);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String getInlineString() {
+ return cases.toString();
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- throw new UnsupportedOperationException("unsupported");
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return StdTypeList.EMPTY;
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new SwitchInsn(getOpcode(), getPosition(),
- getResult().withOffset(delta),
- getSources().withOffset(delta),
- cases);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitSwitchInsn(this);
+ }
- /**
- * {@inheritDoc}
- *
- * <p> SwitchInsn always compares false. The current use for this method
- * never encounters {@code SwitchInsn}s
- */
- @Override
- public boolean contentEquals(Insn b) {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ throw new UnsupportedOperationException("unsupported");
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new SwitchInsn(getOpcode(), getPosition(), getResult().withOffset(delta),
+ getSources().withOffset(delta), cases);
+ }
- return new SwitchInsn(getOpcode(), getPosition(),
- result,
- sources,
- cases);
- }
+ /**
+ * {@inheritDoc}
+ *
+ * <p> SwitchInsn always compares false. The current use for this method
+ * never encounters {@code SwitchInsn}s
+ */
+ @Override
+ public boolean contentEquals(Insn b) {
+ return false;
+ }
- /**
- * Gets the list of switch cases.
- *
- * @return {@code non-null;} the case list
- */
- public IntList getCases() {
- return cases;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
+
+ return new SwitchInsn(getOpcode(), getPosition(), result, sources, cases);
+ }
+
+ /**
+ * Gets the list of switch cases.
+ *
+ * @return {@code non-null;} the case list
+ */
+ public IntList getCases() {
+ return cases;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/ThrowingCstInsn.java b/dx/src/com/android/jack/dx/rop/code/ThrowingCstInsn.java
index aad2a03..b8c93e8 100644
--- a/dx/src/com/android/jack/dx/rop/code/ThrowingCstInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/ThrowingCstInsn.java
@@ -25,86 +25,77 @@
* Instruction which contains an explicit reference to a constant
* and which might throw an exception.
*/
-public final class ThrowingCstInsn
- extends CstInsn {
- /** {@code non-null;} list of exceptions caught */
- private final TypeList catches;
+public final class ThrowingCstInsn extends CstInsn {
+ /** {@code non-null;} list of exceptions caught */
+ private final TypeList catches;
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param sources {@code non-null;} specs for all the sources
- * @param catches {@code non-null;} list of exceptions caught
- * @param cst {@code non-null;} the constant
- */
- public ThrowingCstInsn(Rop opcode, SourcePosition position,
- RegisterSpecList sources,
- TypeList catches, Constant cst) {
- super(opcode, position, null, sources, cst);
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param catches {@code non-null;} list of exceptions caught
+ * @param cst {@code non-null;} the constant
+ */
+ public ThrowingCstInsn(Rop opcode, SourcePosition position, RegisterSpecList sources,
+ TypeList catches, Constant cst) {
+ super(opcode, position, null, sources, cst);
- if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
- throw new IllegalArgumentException("bogus branchingness");
- }
-
- if (catches == null) {
- throw new NullPointerException("catches == null");
- }
-
- this.catches = catches;
+ if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+ throw new IllegalArgumentException("bogus branchingness");
}
- /** {@inheritDoc} */
- @Override
- public String getInlineString() {
- Constant cst = getConstant();
- String constantString = cst.toHuman();
- if (cst instanceof CstString) {
- constantString = ((CstString) cst).toQuoted();
- }
- return constantString + " " + ThrowingInsn.toCatchString(catches);
+ if (catches == null) {
+ throw new NullPointerException("catches == null");
}
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return catches;
- }
+ this.catches = catches;
+ }
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitThrowingCstInsn(this);
+ /** {@inheritDoc} */
+ @Override
+ public String getInlineString() {
+ Constant cst = getConstant();
+ String constantString = cst.toHuman();
+ if (cst instanceof CstString) {
+ constantString = ((CstString) cst).toQuoted();
}
+ return constantString + " " + ThrowingInsn.toCatchString(catches);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- return new ThrowingCstInsn(getOpcode(), getPosition(),
- getSources(), catches.withAddedType(type),
- getConstant());
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return catches;
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new ThrowingCstInsn(getOpcode(), getPosition(),
- getSources().withOffset(delta),
- catches,
- getConstant());
- }
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitThrowingCstInsn(this);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ return new ThrowingCstInsn(getOpcode(), getPosition(), getSources(),
+ catches.withAddedType(type), getConstant());
+ }
- return new ThrowingCstInsn(getOpcode(), getPosition(),
- sources,
- catches,
- getConstant());
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new ThrowingCstInsn(getOpcode(), getPosition(), getSources().withOffset(delta), catches,
+ getConstant());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
+
+ return new ThrowingCstInsn(getOpcode(), getPosition(), sources, catches, getConstant());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/ThrowingInsn.java b/dx/src/com/android/jack/dx/rop/code/ThrowingInsn.java
index cc12194..21956cf 100644
--- a/dx/src/com/android/jack/dx/rop/code/ThrowingInsn.java
+++ b/dx/src/com/android/jack/dx/rop/code/ThrowingInsn.java
@@ -25,96 +25,88 @@
* the list of exceptions handled by this instruction, with the
* no-exception case appended as the final target.
*/
-public final class ThrowingInsn
- extends Insn {
- /** {@code non-null;} list of exceptions caught */
- private final TypeList catches;
+public final class ThrowingInsn extends Insn {
+ /** {@code non-null;} list of exceptions caught */
+ private final TypeList catches;
- /**
- * Gets the string form of a register spec list to be used as a catches
- * list.
- *
- * @param catches {@code non-null;} the catches list
- * @return {@code non-null;} the string form
- */
- public static String toCatchString(TypeList catches) {
- StringBuffer sb = new StringBuffer(100);
+ /**
+ * Gets the string form of a register spec list to be used as a catches
+ * list.
+ *
+ * @param catches {@code non-null;} the catches list
+ * @return {@code non-null;} the string form
+ */
+ public static String toCatchString(TypeList catches) {
+ StringBuffer sb = new StringBuffer(100);
- sb.append("catch");
+ sb.append("catch");
- int sz = catches.size();
- for (int i = 0; i < sz; i++) {
- sb.append(" ");
- sb.append(catches.getType(i).toHuman());
- }
-
- return sb.toString();
+ int sz = catches.size();
+ for (int i = 0; i < sz; i++) {
+ sb.append(" ");
+ sb.append(catches.getType(i).toHuman());
}
- /**
- * Constructs an instance.
- *
- * @param opcode {@code non-null;} the opcode
- * @param position {@code non-null;} source position
- * @param sources {@code non-null;} specs for all the sources
- * @param catches {@code non-null;} list of exceptions caught
- */
- public ThrowingInsn(Rop opcode, SourcePosition position,
- RegisterSpecList sources,
- TypeList catches) {
- super(opcode, position, null, sources);
+ return sb.toString();
+ }
- if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
- throw new IllegalArgumentException("bogus branchingness");
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param catches {@code non-null;} list of exceptions caught
+ */
+ public ThrowingInsn(Rop opcode, SourcePosition position, RegisterSpecList sources,
+ TypeList catches) {
+ super(opcode, position, null, sources);
- if (catches == null) {
- throw new NullPointerException("catches == null");
- }
-
- this.catches = catches;
+ if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+ throw new IllegalArgumentException("bogus branchingness");
}
- /** {@inheritDoc} */
- @Override
- public String getInlineString() {
- return toCatchString(catches);
+ if (catches == null) {
+ throw new NullPointerException("catches == null");
}
- /** {@inheritDoc} */
- @Override
- public TypeList getCatches() {
- return catches;
- }
+ this.catches = catches;
+ }
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor visitor) {
- visitor.visitThrowingInsn(this);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String getInlineString() {
+ return toCatchString(catches);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withAddedCatch(Type type) {
- return new ThrowingInsn(getOpcode(), getPosition(),
- getSources(), catches.withAddedType(type));
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList getCatches() {
+ return catches;
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withRegisterOffset(int delta) {
- return new ThrowingInsn(getOpcode(), getPosition(),
- getSources().withOffset(delta),
- catches);
- }
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visitThrowingInsn(this);
+ }
- /** {@inheritDoc} */
- @Override
- public Insn withNewRegisters(RegisterSpec result,
- RegisterSpecList sources) {
+ /** {@inheritDoc} */
+ @Override
+ public Insn withAddedCatch(Type type) {
+ return new ThrowingInsn(getOpcode(), getPosition(), getSources(), catches.withAddedType(type));
+ }
- return new ThrowingInsn(getOpcode(), getPosition(),
- sources,
- catches);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Insn withRegisterOffset(int delta) {
+ return new ThrowingInsn(getOpcode(), getPosition(), getSources().withOffset(delta), catches);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
+
+ return new ThrowingInsn(getOpcode(), getPosition(), sources, catches);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/code/TranslationAdvice.java b/dx/src/com/android/jack/dx/rop/code/TranslationAdvice.java
index 32936ba..af78386 100644
--- a/dx/src/com/android/jack/dx/rop/code/TranslationAdvice.java
+++ b/dx/src/com/android/jack/dx/rop/code/TranslationAdvice.java
@@ -23,40 +23,39 @@
* the early stage code be explicitly tied to the target.
*/
public interface TranslationAdvice {
- /**
- * Returns an indication of whether the target can directly represent an
- * instruction with the given opcode operating on the given arguments,
- * where the last source argument is used as a constant. (That is, the
- * last argument must have a type which indicates it is a known constant.)
- * The instruction associated must have exactly two sources.
- *
- * @param opcode {@code non-null;} the opcode
- * @param sourceA {@code non-null;} the first source
- * @param sourceB {@code non-null;} the second source
- * @return {@code true} iff the target can represent the operation
- * using a constant for the last argument
- */
- public boolean hasConstantOperation(Rop opcode,
- RegisterSpec sourceA, RegisterSpec sourceB);
+ /**
+ * Returns an indication of whether the target can directly represent an
+ * instruction with the given opcode operating on the given arguments,
+ * where the last source argument is used as a constant. (That is, the
+ * last argument must have a type which indicates it is a known constant.)
+ * The instruction associated must have exactly two sources.
+ *
+ * @param opcode {@code non-null;} the opcode
+ * @param sourceA {@code non-null;} the first source
+ * @param sourceB {@code non-null;} the second source
+ * @return {@code true} iff the target can represent the operation
+ * using a constant for the last argument
+ */
+ public boolean hasConstantOperation(Rop opcode, RegisterSpec sourceA, RegisterSpec sourceB);
- /**
- * Returns true if the translation target requires the sources of the
- * specified opcode to be in order and contiguous (eg, for an invoke-range)
- *
- * @param opcode {@code non-null;} opcode
- * @param sources {@code non-null;} source list
- * @return {@code true} iff the target requires the sources to be
- * in order and contiguous.
- */
- public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources);
+ /**
+ * Returns true if the translation target requires the sources of the
+ * specified opcode to be in order and contiguous (eg, for an invoke-range)
+ *
+ * @param opcode {@code non-null;} opcode
+ * @param sources {@code non-null;} source list
+ * @return {@code true} iff the target requires the sources to be
+ * in order and contiguous.
+ */
+ public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources);
- /**
- * Gets the maximum register width that can be represented optimally.
- * For example, Dex bytecode does not have instruction forms that take
- * register numbers larger than 15 for all instructions so
- * DexTranslationAdvice returns 15 here.
- *
- * @return register count noted above
- */
- public int getMaxOptimalRegisterCount();
+ /**
+ * Gets the maximum register width that can be represented optimally.
+ * For example, Dex bytecode does not have instruction forms that take
+ * register numbers larger than 15 for all instructions so
+ * DexTranslationAdvice returns 15 here.
+ *
+ * @return register count noted above
+ */
+ public int getMaxOptimalRegisterCount();
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/Constant.java b/dx/src/com/android/jack/dx/rop/cst/Constant.java
index 7c756e2..a0d572d 100644
--- a/dx/src/com/android/jack/dx/rop/cst/Constant.java
+++ b/dx/src/com/android/jack/dx/rop/cst/Constant.java
@@ -21,48 +21,48 @@
/**
* Base class for constants of all sorts.
*/
-public abstract class Constant
- implements ToHuman, Comparable<Constant> {
- /**
- * Returns {@code true} if this instance is a category-2 constant,
- * meaning it takes up two slots in the constant pool, or
- * {@code false} if this instance is category-1.
- *
- * @return {@code true} iff this instance is category-2
- */
- public abstract boolean isCategory2();
+public abstract class Constant implements ToHuman, Comparable<Constant> {
+ /**
+ * Returns {@code true} if this instance is a category-2 constant,
+ * meaning it takes up two slots in the constant pool, or
+ * {@code false} if this instance is category-1.
+ *
+ * @return {@code true} iff this instance is category-2
+ */
+ public abstract boolean isCategory2();
- /**
- * Returns the human name for the particular type of constant
- * this instance is.
- *
- * @return {@code non-null;} the name
- */
- public abstract String typeName();
+ /**
+ * Returns the human name for the particular type of constant
+ * this instance is.
+ *
+ * @return {@code non-null;} the name
+ */
+ public abstract String typeName();
- /**
- * {@inheritDoc}
- *
- * This compares in class-major and value-minor order.
- */
- public final int compareTo(Constant other) {
- Class clazz = getClass();
- Class otherClazz = other.getClass();
+ /**
+ * {@inheritDoc}
+ *
+ * This compares in class-major and value-minor order.
+ */
+ @Override
+ public final int compareTo(Constant other) {
+ Class<? extends Constant> clazz = getClass();
+ Class<? extends Constant> otherClazz = other.getClass();
- if (clazz != otherClazz) {
- return clazz.getName().compareTo(otherClazz.getName());
- }
-
- return compareTo0(other);
+ if (clazz != otherClazz) {
+ return clazz.getName().compareTo(otherClazz.getName());
}
- /**
- * Compare the values of this and another instance, which are guaranteed
- * to be of the same class. Subclasses must implement this.
- *
- * @param other {@code non-null;} the instance to compare to
- * @return {@code -1}, {@code 0}, or {@code 1}, as usual
- * for a comparison
- */
- protected abstract int compareTo0(Constant other);
+ return compareTo0(other);
+ }
+
+ /**
+ * Compare the values of this and another instance, which are guaranteed
+ * to be of the same class. Subclasses must implement this.
+ *
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code -1}, {@code 0}, or {@code 1}, as usual
+ * for a comparison
+ */
+ protected abstract int compareTo0(Constant other);
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/ConstantPool.java b/dx/src/com/android/jack/dx/rop/cst/ConstantPool.java
index 218f3c4..c1099fe 100644
--- a/dx/src/com/android/jack/dx/rop/cst/ConstantPool.java
+++ b/dx/src/com/android/jack/dx/rop/cst/ConstantPool.java
@@ -21,50 +21,50 @@
* {@link Constant} objects.
*/
public interface ConstantPool {
- /**
- * Get the "size" of the constant pool. This corresponds to the
- * class file field {@code constant_pool_count}, and is in fact
- * always at least one more than the actual size of the constant pool,
- * as element {@code 0} is always invalid.
- *
- * @return {@code >= 1;} the size
- */
- public int size();
+ /**
+ * Get the "size" of the constant pool. This corresponds to the
+ * class file field {@code constant_pool_count}, and is in fact
+ * always at least one more than the actual size of the constant pool,
+ * as element {@code 0} is always invalid.
+ *
+ * @return {@code >= 1;} the size
+ */
+ public int size();
- /**
- * Get the {@code n}th entry in the constant pool, which must
- * be valid.
- *
- * @param n {@code n >= 0, n < size();} the constant pool index
- * @return {@code non-null;} the corresponding entry
- * @throws IllegalArgumentException thrown if {@code n} is
- * in-range but invalid
- */
- public Constant get(int n);
+ /**
+ * Get the {@code n}th entry in the constant pool, which must
+ * be valid.
+ *
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code non-null;} the corresponding entry
+ * @throws IllegalArgumentException thrown if {@code n} is
+ * in-range but invalid
+ */
+ public Constant get(int n);
- /**
- * Get the {@code n}th entry in the constant pool, which must
- * be valid unless {@code n == 0}, in which case {@code null}
- * is returned.
- *
- * @param n {@code n >= 0, n < size();} the constant pool index
- * @return {@code null-ok;} the corresponding entry, if {@code n != 0}
- * @throws IllegalArgumentException thrown if {@code n} is
- * in-range and non-zero but invalid
- */
- public Constant get0Ok(int n);
+ /**
+ * Get the {@code n}th entry in the constant pool, which must
+ * be valid unless {@code n == 0}, in which case {@code null}
+ * is returned.
+ *
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code null-ok;} the corresponding entry, if {@code n != 0}
+ * @throws IllegalArgumentException thrown if {@code n} is
+ * in-range and non-zero but invalid
+ */
+ public Constant get0Ok(int n);
- /**
- * Get the {@code n}th entry in the constant pool, or
- * {@code null} if the index is in-range but invalid. In
- * particular, {@code null} is returned for index {@code 0}
- * as well as the index after any entry which is defined to take up
- * two slots (that is, {@code Long} and {@code Double}
- * entries).
- *
- * @param n {@code n >= 0, n < size();} the constant pool index
- * @return {@code null-ok;} the corresponding entry, or {@code null} if
- * the index is in-range but invalid
- */
- public Constant getOrNull(int n);
+ /**
+ * Get the {@code n}th entry in the constant pool, or
+ * {@code null} if the index is in-range but invalid. In
+ * particular, {@code null} is returned for index {@code 0}
+ * as well as the index after any entry which is defined to take up
+ * two slots (that is, {@code Long} and {@code Double}
+ * entries).
+ *
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code null-ok;} the corresponding entry, or {@code null} if
+ * the index is in-range but invalid
+ */
+ public Constant getOrNull(int n);
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstAnnotation.java b/dx/src/com/android/jack/dx/rop/cst/CstAnnotation.java
index 84dd61f..87a97ca 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstAnnotation.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstAnnotation.java
@@ -22,75 +22,76 @@
* Constant type that represents an annotation.
*/
public final class CstAnnotation extends Constant {
- /** {@code non-null;} the actual annotation */
- private final Annotation annotation;
+ /** {@code non-null;} the actual annotation */
+ private final Annotation annotation;
- /**
- * Constructs an instance.
- *
- * @param annotation {@code non-null;} the annotation to hold
- */
- public CstAnnotation(Annotation annotation) {
- if (annotation == null) {
- throw new NullPointerException("annotation == null");
- }
-
- annotation.throwIfMutable();
-
- this.annotation = annotation;
+ /**
+ * Constructs an instance.
+ *
+ * @param annotation {@code non-null;} the annotation to hold
+ */
+ public CstAnnotation(Annotation annotation) {
+ if (annotation == null) {
+ throw new NullPointerException("annotation == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (! (other instanceof CstAnnotation)) {
- return false;
- }
+ annotation.throwIfMutable();
- return annotation.equals(((CstAnnotation) other).annotation);
+ this.annotation = annotation;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstAnnotation)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return annotation.hashCode();
- }
+ return annotation.equals(((CstAnnotation) other).annotation);
+ }
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- return annotation.compareTo(((CstAnnotation) other).annotation);
- }
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return annotation.hashCode();
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return annotation.toString();
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ return annotation.compareTo(((CstAnnotation) other).annotation);
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "annotation";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return annotation.toString();
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "annotation";
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return annotation.toString();
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
- /**
- * Get the underlying annotation.
- *
- * @return {@code non-null;} the annotation
- */
- public Annotation getAnnotation() {
- return annotation;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return annotation.toString();
+ }
+
+ /**
+ * Get the underlying annotation.
+ *
+ * @return {@code non-null;} the annotation
+ */
+ public Annotation getAnnotation() {
+ return annotation;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstArray.java b/dx/src/com/android/jack/dx/rop/cst/CstArray.java
index 080bb69..4d1c745 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstArray.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstArray.java
@@ -16,144 +16,144 @@
package com.android.jack.dx.rop.cst;
-import com.android.jack.dx.rop.type.Type;
import com.android.jack.dx.util.FixedSizeList;
/**
* Constant type to represent a fixed array of other constants.
*/
public final class CstArray extends Constant {
- /** {@code non-null;} the actual list of contents */
- private final List list;
+ /** {@code non-null;} the actual list of contents */
+ private final List list;
+ /**
+ * Constructs an instance.
+ *
+ * @param list {@code non-null;} the actual list of contents
+ */
+ public CstArray(List list) {
+ if (list == null) {
+ throw new NullPointerException("list == null");
+ }
+
+ list.throwIfMutable();
+
+ this.list = list;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstArray)) {
+ return false;
+ }
+
+ return list.equals(((CstArray) other).list);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return list.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ return list.compareTo(((CstArray) other).list);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return list.toString("array{", ", ", "}");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "array";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return list.toHuman("{", ", ", "}");
+ }
+
+ /**
+ * Get the underlying list.
+ *
+ * @return {@code non-null;} the list
+ */
+ public List getList() {
+ return list;
+ }
+
+ /**
+ * List of {@link Constant} instances.
+ */
+ public static final class List extends FixedSizeList implements Comparable<List> {
/**
- * Constructs an instance.
+ * Constructs an instance. All indices initially contain
+ * {@code null}.
*
- * @param list {@code non-null;} the actual list of contents
+ * @param size the size of the list
*/
- public CstArray(List list) {
- if (list == null) {
- throw new NullPointerException("list == null");
+ public List(int size) {
+ super(size);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(List other) {
+ int thisSize = size();
+ int otherSize = other.size();
+ int compareSize = (thisSize < otherSize) ? thisSize : otherSize;
+
+ for (int i = 0; i < compareSize; i++) {
+ Constant thisItem = (Constant) get0(i);
+ Constant otherItem = (Constant) other.get0(i);
+ int compare = thisItem.compareTo(otherItem);
+ if (compare != 0) {
+ return compare;
}
+ }
- list.throwIfMutable();
+ if (thisSize < otherSize) {
+ return -1;
+ } else if (thisSize > otherSize) {
+ return 1;
+ }
- this.list = list;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (! (other instanceof CstArray)) {
- return false;
- }
-
- return list.equals(((CstArray) other).list);
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return list.hashCode();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- return list.compareTo(((CstArray) other).list);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return list.toString("array{", ", ", "}");
- }
-
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "array";
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return list.toHuman("{", ", ", "}");
+ return 0;
}
/**
- * Get the underlying list.
+ * Gets the element at the given index. It is an error to call
+ * this with the index for an element which was never set; if you
+ * do that, this will throw {@code NullPointerException}.
*
- * @return {@code non-null;} the list
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
- public List getList() {
- return list;
+ public Constant get(int n) {
+ return (Constant) get0(n);
}
/**
- * List of {@link Constant} instances.
+ * Sets the element at the given index.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param a {@code null-ok;} the element to set at {@code n}
*/
- public static final class List
- extends FixedSizeList implements Comparable<List> {
- /**
- * Constructs an instance. All indices initially contain
- * {@code null}.
- *
- * @param size the size of the list
- */
- public List(int size) {
- super(size);
- }
-
- /** {@inheritDoc} */
- public int compareTo(List other) {
- int thisSize = size();
- int otherSize = other.size();
- int compareSize = (thisSize < otherSize) ? thisSize : otherSize;
-
- for (int i = 0; i < compareSize; i++) {
- Constant thisItem = (Constant) get0(i);
- Constant otherItem = (Constant) other.get0(i);
- int compare = thisItem.compareTo(otherItem);
- if (compare != 0) {
- return compare;
- }
- }
-
- if (thisSize < otherSize) {
- return -1;
- } else if (thisSize > otherSize) {
- return 1;
- }
-
- return 0;
- }
-
- /**
- * Gets the element at the given index. It is an error to call
- * this with the index for an element which was never set; if you
- * do that, this will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which index
- * @return {@code non-null;} element at that index
- */
- public Constant get(int n) {
- return (Constant) get0(n);
- }
-
- /**
- * Sets the element at the given index.
- *
- * @param n {@code >= 0, < size();} which index
- * @param a {@code null-ok;} the element to set at {@code n}
- */
- public void set(int n, Constant a) {
- set0(n, a);
- }
+ public void set(int n, Constant a) {
+ set0(n, a);
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/jack/dx/rop/cst/CstBaseMethodRef.java
index fedb208..1ba7d88 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstBaseMethodRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstBaseMethodRef.java
@@ -18,134 +18,133 @@
import com.android.jack.dx.rop.type.Prototype;
import com.android.jack.dx.rop.type.Type;
-import com.android.jack.dx.rop.type.TypeBearer;
/**
* Base class for constants of "methodish" type.
*
- * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type
+ * <p><b>Note:</b> As a {@code TypeBearer}, this class bears the return type
* of the method.</p>
*/
-public abstract class CstBaseMethodRef
- extends CstMemberRef {
- /** {@code non-null;} the raw prototype for this method */
- private final Prototype prototype;
+public abstract class CstBaseMethodRef extends CstMemberRef {
+ /** {@code non-null;} the raw prototype for this method */
+ private final Prototype prototype;
- /**
- * {@code null-ok;} the prototype for this method taken to be an instance
- * method, or {@code null} if not yet calculated
- */
- private Prototype instancePrototype;
+ /**
+ * {@code null-ok;} the prototype for this method taken to be an instance
+ * method, or {@code null} if not yet calculated
+ */
+ private Prototype instancePrototype;
- /**
- * Constructs an instance.
- *
- * @param definingClass {@code non-null;} the type of the defining class
- * @param nat {@code non-null;} the name-and-type
- */
- /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) {
- super(definingClass, nat);
+ /**
+ * Constructs an instance.
+ *
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
+ */
+ /*package*/CstBaseMethodRef(CstType definingClass, CstNat nat) {
+ super(definingClass, nat);
- String descriptor = getNat().getDescriptor().getString();
- this.prototype = Prototype.intern(descriptor);
- this.instancePrototype = null;
+ String descriptor = getNat().getDescriptor().getString();
+ this.prototype = Prototype.intern(descriptor);
+ this.instancePrototype = null;
+ }
+
+ /**
+ * Gets the raw prototype of this method. This doesn't include a
+ * {@code this} argument.
+ *
+ * @return {@code non-null;} the method prototype
+ */
+ public final Prototype getPrototype() {
+ return prototype;
+ }
+
+ /**
+ * Gets the prototype of this method as either a
+ * {@code static} or instance method. In the case of a
+ * {@code static} method, this is the same as the raw
+ * prototype. In the case of an instance method, this has an
+ * appropriately-typed {@code this} argument as the first
+ * one.
+ *
+ * @param isStatic whether the method should be considered static
+ * @return {@code non-null;} the method prototype
+ */
+ public final Prototype getPrototype(boolean isStatic) {
+ if (isStatic) {
+ return prototype;
+ } else {
+ if (instancePrototype == null) {
+ Type thisType = getDefiningClass().getClassType();
+ instancePrototype = prototype.withFirstParameter(thisType);
+ }
+ return instancePrototype;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected final int compareTo0(Constant other) {
+ int cmp = super.compareTo0(other);
+
+ if (cmp != 0) {
+ return cmp;
}
- /**
- * Gets the raw prototype of this method. This doesn't include a
- * {@code this} argument.
- *
- * @return {@code non-null;} the method prototype
- */
- public final Prototype getPrototype() {
- return prototype;
- }
+ CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
+ return prototype.compareTo(otherMethod.prototype);
+ }
- /**
- * Gets the prototype of this method as either a
- * {@code static} or instance method. In the case of a
- * {@code static} method, this is the same as the raw
- * prototype. In the case of an instance method, this has an
- * appropriately-typed {@code this} argument as the first
- * one.
- *
- * @param isStatic whether the method should be considered static
- * @return {@code non-null;} the method prototype
- */
- public final Prototype getPrototype(boolean isStatic) {
- if (isStatic) {
- return prototype;
- } else {
- if (instancePrototype == null) {
- Type thisType = getDefiningClass().getClassType();
- instancePrototype = prototype.withFirstParameter(thisType);
- }
- return instancePrototype;
- }
- }
+ /**
+ * {@inheritDoc}
+ *
+ * In this case, this method returns the <i>return type</i> of this method.
+ *
+ * @return {@code non-null;} the method's return type
+ */
+ @Override
+ public final Type getType() {
+ return prototype.getReturnType();
+ }
- /** {@inheritDoc} */
- @Override
- protected final int compareTo0(Constant other) {
- int cmp = super.compareTo0(other);
+ /**
+ * Gets the number of words of parameters required by this
+ * method's descriptor. Since instances of this class have no way
+ * to know if they will be used in a {@code static} or
+ * instance context, one has to indicate this explicitly as an
+ * argument. This method is just a convenient shorthand for
+ * {@code getPrototype().getParameterTypes().getWordCount()},
+ * plus {@code 1} if the method is to be treated as an
+ * instance method.
+ *
+ * @param isStatic whether the method should be considered static
+ * @return {@code >= 0;} the argument word count
+ */
+ public final int getParameterWordCount(boolean isStatic) {
+ return getPrototype(isStatic).getParameterTypes().getWordCount();
+ }
- if (cmp != 0) {
- return cmp;
- }
+ /**
+ * Gets whether this is a reference to an instance initialization
+ * method. This is just a convenient shorthand for
+ * {@code getNat().isInstanceInit()}.
+ *
+ * @return {@code true} iff this is a reference to an
+ * instance initialization method
+ */
+ public final boolean isInstanceInit() {
+ return getNat().isInstanceInit();
+ }
- CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
- return prototype.compareTo(otherMethod.prototype);
- }
-
- /**
- * {@inheritDoc}
- *
- * In this case, this method returns the <i>return type</i> of this method.
- *
- * @return {@code non-null;} the method's return type
- */
- public final Type getType() {
- return prototype.getReturnType();
- }
-
- /**
- * Gets the number of words of parameters required by this
- * method's descriptor. Since instances of this class have no way
- * to know if they will be used in a {@code static} or
- * instance context, one has to indicate this explicitly as an
- * argument. This method is just a convenient shorthand for
- * {@code getPrototype().getParameterTypes().getWordCount()},
- * plus {@code 1} if the method is to be treated as an
- * instance method.
- *
- * @param isStatic whether the method should be considered static
- * @return {@code >= 0;} the argument word count
- */
- public final int getParameterWordCount(boolean isStatic) {
- return getPrototype(isStatic).getParameterTypes().getWordCount();
- }
-
- /**
- * Gets whether this is a reference to an instance initialization
- * method. This is just a convenient shorthand for
- * {@code getNat().isInstanceInit()}.
- *
- * @return {@code true} iff this is a reference to an
- * instance initialization method
- */
- public final boolean isInstanceInit() {
- return getNat().isInstanceInit();
- }
-
- /**
- * Gets whether this is a reference to a class initialization
- * method. This is just a convenient shorthand for
- * {@code getNat().isClassInit()}.
- *
- * @return {@code true} iff this is a reference to an
- * instance initialization method
- */
- public final boolean isClassInit() {
- return getNat().isClassInit();
- }
+ /**
+ * Gets whether this is a reference to a class initialization
+ * method. This is just a convenient shorthand for
+ * {@code getNat().isClassInit()}.
+ *
+ * @return {@code true} iff this is a reference to an
+ * instance initialization method
+ */
+ public final boolean isClassInit() {
+ return getNat().isClassInit();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstBoolean.java b/dx/src/com/android/jack/dx/rop/cst/CstBoolean.java
index 81a0e27..ad4a063 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstBoolean.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstBoolean.java
@@ -21,79 +21,80 @@
/**
* Constants of type {@code boolean}.
*/
-public final class CstBoolean
- extends CstLiteral32 {
- /** {@code non-null;} instance representing {@code false} */
- public static final CstBoolean VALUE_FALSE = new CstBoolean(false);
+public final class CstBoolean extends CstLiteral32 {
+ /** {@code non-null;} instance representing {@code false} */
+ public static final CstBoolean VALUE_FALSE = new CstBoolean(false);
- /** {@code non-null;} instance representing {@code true} */
- public static final CstBoolean VALUE_TRUE = new CstBoolean(true);
+ /** {@code non-null;} instance representing {@code true} */
+ public static final CstBoolean VALUE_TRUE = new CstBoolean(true);
- /**
- * Makes an instance for the given value. This will return an
- * already-allocated instance.
- *
- * @param value the {@code boolean} value
- * @return {@code non-null;} the appropriate instance
- */
- public static CstBoolean make(boolean value) {
- return value ? VALUE_TRUE : VALUE_FALSE;
+ /**
+ * Makes an instance for the given value. This will return an
+ * already-allocated instance.
+ *
+ * @param value the {@code boolean} value
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstBoolean make(boolean value) {
+ return value ? VALUE_TRUE : VALUE_FALSE;
+ }
+
+ /**
+ * Makes an instance for the given {@code int} value. This
+ * will return an already-allocated instance.
+ *
+ * @param value must be either {@code 0} or {@code 1}
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstBoolean make(int value) {
+ if (value == 0) {
+ return VALUE_FALSE;
+ } else if (value == 1) {
+ return VALUE_TRUE;
+ } else {
+ throw new IllegalArgumentException("bogus value: " + value);
}
+ }
- /**
- * Makes an instance for the given {@code int} value. This
- * will return an already-allocated instance.
- *
- * @param value must be either {@code 0} or {@code 1}
- * @return {@code non-null;} the appropriate instance
- */
- public static CstBoolean make(int value) {
- if (value == 0) {
- return VALUE_FALSE;
- } else if (value == 1) {
- return VALUE_TRUE;
- } else {
- throw new IllegalArgumentException("bogus value: " + value);
- }
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code boolean} value
+ */
+ private CstBoolean(boolean value) {
+ super(value ? 1 : 0);
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code boolean} value
- */
- private CstBoolean(boolean value) {
- super(value ? 1 : 0);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return getValue() ? "boolean{true}" : "boolean{false}";
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return getValue() ? "boolean{true}" : "boolean{false}";
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.BOOLEAN;
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.BOOLEAN;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "boolean";
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "boolean";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return getValue() ? "true" : "false";
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return getValue() ? "true" : "false";
- }
-
- /**
- * Gets the {@code boolean} value.
- *
- * @return the value
- */
- public boolean getValue() {
- return (getIntBits() == 0) ? false : true;
- }
+ /**
+ * Gets the {@code boolean} value.
+ *
+ * @return the value
+ */
+ public boolean getValue() {
+ return (getIntBits() == 0) ? false : true;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstByte.java b/dx/src/com/android/jack/dx/rop/cst/CstByte.java
index 5ab4188..f92bfd0 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstByte.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstByte.java
@@ -22,78 +22,78 @@
/**
* Constants of type {@code byte}.
*/
-public final class CstByte
- extends CstLiteral32 {
- /** {@code non-null;} the value {@code 0} as an instance of this class */
- public static final CstByte VALUE_0 = make((byte) 0);
+public final class CstByte extends CstLiteral32 {
+ /** {@code non-null;} the value {@code 0} as an instance of this class */
+ public static final CstByte VALUE_0 = make((byte) 0);
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param value the {@code byte} value
- */
- public static CstByte make(byte value) {
- return new CstByte(value);
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param value the {@code byte} value
+ */
+ public static CstByte make(byte value) {
+ return new CstByte(value);
+ }
+
+ /**
+ * Makes an instance for the given {@code int} value. This
+ * may (but does not necessarily) return an already-allocated
+ * instance.
+ *
+ * @param value the value, which must be in range for a {@code byte}
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstByte make(int value) {
+ byte cast = (byte) value;
+
+ if (cast != value) {
+ throw new IllegalArgumentException("bogus byte value: " + value);
}
- /**
- * Makes an instance for the given {@code int} value. This
- * may (but does not necessarily) return an already-allocated
- * instance.
- *
- * @param value the value, which must be in range for a {@code byte}
- * @return {@code non-null;} the appropriate instance
- */
- public static CstByte make(int value) {
- byte cast = (byte) value;
+ return make(cast);
+ }
- if (cast != value) {
- throw new IllegalArgumentException("bogus byte value: " +
- value);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code byte} value
+ */
+ private CstByte(byte value) {
+ super(value);
+ }
- return make(cast);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int value = getIntBits();
+ return "byte{0x" + Hex.u1(value) + " / " + value + '}';
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code byte} value
- */
- private CstByte(byte value) {
- super(value);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.BYTE;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int value = getIntBits();
- return "byte{0x" + Hex.u1(value) + " / " + value + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "byte";
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.BYTE;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Integer.toString(getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "byte";
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return Integer.toString(getIntBits());
- }
-
- /**
- * Gets the {@code byte} value.
- *
- * @return the value
- */
- public byte getValue() {
- return (byte) getIntBits();
- }
+ /**
+ * Gets the {@code byte} value.
+ *
+ * @return the value
+ */
+ public byte getValue() {
+ return (byte) getIntBits();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstChar.java b/dx/src/com/android/jack/dx/rop/cst/CstChar.java
index b4cd303..3804542 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstChar.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstChar.java
@@ -22,78 +22,78 @@
/**
* Constants of type {@code char}.
*/
-public final class CstChar
- extends CstLiteral32 {
- /** {@code non-null;} the value {@code 0} as an instance of this class */
- public static final CstChar VALUE_0 = make((char) 0);
+public final class CstChar extends CstLiteral32 {
+ /** {@code non-null;} the value {@code 0} as an instance of this class */
+ public static final CstChar VALUE_0 = make((char) 0);
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param value the {@code char} value
- */
- public static CstChar make(char value) {
- return new CstChar(value);
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param value the {@code char} value
+ */
+ public static CstChar make(char value) {
+ return new CstChar(value);
+ }
+
+ /**
+ * Makes an instance for the given {@code int} value. This
+ * may (but does not necessarily) return an already-allocated
+ * instance.
+ *
+ * @param value the value, which must be in range for a {@code char}
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstChar make(int value) {
+ char cast = (char) value;
+
+ if (cast != value) {
+ throw new IllegalArgumentException("bogus char value: " + value);
}
- /**
- * Makes an instance for the given {@code int} value. This
- * may (but does not necessarily) return an already-allocated
- * instance.
- *
- * @param value the value, which must be in range for a {@code char}
- * @return {@code non-null;} the appropriate instance
- */
- public static CstChar make(int value) {
- char cast = (char) value;
+ return make(cast);
+ }
- if (cast != value) {
- throw new IllegalArgumentException("bogus char value: " +
- value);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code char} value
+ */
+ private CstChar(char value) {
+ super(value);
+ }
- return make(cast);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int value = getIntBits();
+ return "char{0x" + Hex.u2(value) + " / " + value + '}';
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code char} value
- */
- private CstChar(char value) {
- super(value);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.CHAR;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int value = getIntBits();
- return "char{0x" + Hex.u2(value) + " / " + value + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "char";
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.CHAR;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Integer.toString(getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "char";
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return Integer.toString(getIntBits());
- }
-
- /**
- * Gets the {@code char} value.
- *
- * @return the value
- */
- public char getValue() {
- return (char) getIntBits();
- }
+ /**
+ * Gets the {@code char} value.
+ *
+ * @return the value
+ */
+ public char getValue() {
+ return (char) getIntBits();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstDouble.java b/dx/src/com/android/jack/dx/rop/cst/CstDouble.java
index c000e6a..46d4c72 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstDouble.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstDouble.java
@@ -22,69 +22,67 @@
/**
* Constants of type {@code CONSTANT_Double_info}.
*/
-public final class CstDouble
- extends CstLiteral64 {
- /** {@code non-null;} instance representing {@code 0} */
- public static final CstDouble VALUE_0 =
- new CstDouble(Double.doubleToLongBits(0.0));
+public final class CstDouble extends CstLiteral64 {
+ /** {@code non-null;} instance representing {@code 0} */
+ public static final CstDouble VALUE_0 = new CstDouble(Double.doubleToLongBits(0.0));
- /** {@code non-null;} instance representing {@code 1} */
- public static final CstDouble VALUE_1 =
- new CstDouble(Double.doubleToLongBits(1.0));
+ /** {@code non-null;} instance representing {@code 1} */
+ public static final CstDouble VALUE_1 = new CstDouble(Double.doubleToLongBits(1.0));
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param bits the {@code double} value as {@code long} bits
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param bits the {@code double} value as {@code long} bits
+ */
+ public static CstDouble make(long bits) {
+ /*
+ * Note: Javadoc notwithstanding, this implementation always
+ * allocates.
*/
- public static CstDouble make(long bits) {
- /*
- * Note: Javadoc notwithstanding, this implementation always
- * allocates.
- */
- return new CstDouble(bits);
- }
+ return new CstDouble(bits);
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param bits the {@code double} value as {@code long} bits
- */
- private CstDouble(long bits) {
- super(bits);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param bits the {@code double} value as {@code long} bits
+ */
+ private CstDouble(long bits) {
+ super(bits);
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- long bits = getLongBits();
- return "double{0x" + Hex.u8(bits) + " / " +
- Double.longBitsToDouble(bits) + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ long bits = getLongBits();
+ return "double{0x" + Hex.u8(bits) + " / " + Double.longBitsToDouble(bits) + '}';
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.DOUBLE;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.DOUBLE;
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "double";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "double";
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return Double.toString(Double.longBitsToDouble(getLongBits()));
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Double.toString(Double.longBitsToDouble(getLongBits()));
+ }
- /**
- * Gets the {@code double} value.
- *
- * @return the value
- */
- public double getValue() {
- return Double.longBitsToDouble(getLongBits());
- }
+ /**
+ * Gets the {@code double} value.
+ *
+ * @return the value
+ */
+ public double getValue() {
+ return Double.longBitsToDouble(getLongBits());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/jack/dx/rop/cst/CstEnumRef.java
index 9be4634..b2528e2 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstEnumRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstEnumRef.java
@@ -23,46 +23,47 @@
* value of an enumerated type.
*/
public final class CstEnumRef extends CstMemberRef {
- /** {@code null-ok;} the corresponding field ref, lazily initialized */
- private CstFieldRef fieldRef;
+ /** {@code null-ok;} the corresponding field ref, lazily initialized */
+ private CstFieldRef fieldRef;
- /**
- * Constructs an instance.
- *
- * @param nat {@code non-null;} the name-and-type; the defining class is derived
- * from this
- */
- public CstEnumRef(CstNat nat) {
- super(new CstType(nat.getFieldType()), nat);
+ /**
+ * Constructs an instance.
+ *
+ * @param nat {@code non-null;} the name-and-type; the defining class is derived
+ * from this
+ */
+ public CstEnumRef(CstNat nat) {
+ super(new CstType(nat.getFieldType()), nat);
- fieldRef = null;
+ fieldRef = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "enum";
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <b>Note:</b> This returns the enumerated type.
+ */
+ @Override
+ public Type getType() {
+ return getDefiningClass().getClassType();
+ }
+
+ /**
+ * Get a {@link CstFieldRef} that corresponds with this instance.
+ *
+ * @return {@code non-null;} the corresponding field reference
+ */
+ public CstFieldRef getFieldRef() {
+ if (fieldRef == null) {
+ fieldRef = new CstFieldRef(getDefiningClass(), getNat());
}
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "enum";
- }
-
- /**
- * {@inheritDoc}
- *
- * <b>Note:</b> This returns the enumerated type.
- */
- public Type getType() {
- return getDefiningClass().getClassType();
- }
-
- /**
- * Get a {@link CstFieldRef} that corresponds with this instance.
- *
- * @return {@code non-null;} the corresponding field reference
- */
- public CstFieldRef getFieldRef() {
- if (fieldRef == null) {
- fieldRef = new CstFieldRef(getDefiningClass(), getNat());
- }
-
- return fieldRef;
- }
+ return fieldRef;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/jack/dx/rop/cst/CstFieldRef.java
index 76e7f25..3121114 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstFieldRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstFieldRef.java
@@ -22,58 +22,58 @@
* Constants of type {@code CONSTANT_Fieldref_info}.
*/
public final class CstFieldRef extends CstMemberRef {
- /**
- * Returns an instance of this class that represents the static
- * field which should hold the class corresponding to a given
- * primitive type. For example, if given {@link Type#INT}, this
- * method returns an instance corresponding to the field
- * {@code java.lang.Integer.TYPE}.
- *
- * @param primitiveType {@code non-null;} the primitive type
- * @return {@code non-null;} the corresponding static field
- */
- public static CstFieldRef forPrimitiveType(Type primitiveType) {
- return new CstFieldRef(CstType.forBoxedPrimitiveType(primitiveType),
- CstNat.PRIMITIVE_TYPE_NAT);
+ /**
+ * Returns an instance of this class that represents the static
+ * field which should hold the class corresponding to a given
+ * primitive type. For example, if given {@link Type#INT}, this
+ * method returns an instance corresponding to the field
+ * {@code java.lang.Integer.TYPE}.
+ *
+ * @param primitiveType {@code non-null;} the primitive type
+ * @return {@code non-null;} the corresponding static field
+ */
+ public static CstFieldRef forPrimitiveType(Type primitiveType) {
+ return new CstFieldRef(CstType.forBoxedPrimitiveType(primitiveType), CstNat.PRIMITIVE_TYPE_NAT);
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
+ */
+ public CstFieldRef(CstType definingClass, CstNat nat) {
+ super(definingClass, nat);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "field";
+ }
+
+ /**
+ * Returns the type of this field.
+ *
+ * @return {@code non-null;} the field's type
+ */
+ @Override
+ public Type getType() {
+ return getNat().getFieldType();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ int cmp = super.compareTo0(other);
+
+ if (cmp != 0) {
+ return cmp;
}
- /**
- * Constructs an instance.
- *
- * @param definingClass {@code non-null;} the type of the defining class
- * @param nat {@code non-null;} the name-and-type
- */
- public CstFieldRef(CstType definingClass, CstNat nat) {
- super(definingClass, nat);
- }
-
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "field";
- }
-
- /**
- * Returns the type of this field.
- *
- * @return {@code non-null;} the field's type
- */
- public Type getType() {
- return getNat().getFieldType();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- int cmp = super.compareTo0(other);
-
- if (cmp != 0) {
- return cmp;
- }
-
- CstFieldRef otherField = (CstFieldRef) other;
- CstString thisDescriptor = getNat().getDescriptor();
- CstString otherDescriptor = otherField.getNat().getDescriptor();
- return thisDescriptor.compareTo(otherDescriptor);
- }
+ CstFieldRef otherField = (CstFieldRef) other;
+ CstString thisDescriptor = getNat().getDescriptor();
+ CstString otherDescriptor = otherField.getNat().getDescriptor();
+ return thisDescriptor.compareTo(otherDescriptor);
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstFloat.java b/dx/src/com/android/jack/dx/rop/cst/CstFloat.java
index e257fae..b599ae4 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstFloat.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstFloat.java
@@ -22,70 +22,70 @@
/**
* Constants of type {@code CONSTANT_Float_info}.
*/
-public final class CstFloat
- extends CstLiteral32 {
- /** {@code non-null;} instance representing {@code 0} */
- public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f));
+public final class CstFloat extends CstLiteral32 {
+ /** {@code non-null;} instance representing {@code 0} */
+ public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f));
- /** {@code non-null;} instance representing {@code 1} */
- public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f));
+ /** {@code non-null;} instance representing {@code 1} */
+ public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f));
- /** {@code non-null;} instance representing {@code 2} */
- public static final CstFloat VALUE_2 = make(Float.floatToIntBits(2.0f));
+ /** {@code non-null;} instance representing {@code 2} */
+ public static final CstFloat VALUE_2 = make(Float.floatToIntBits(2.0f));
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param bits the {@code float} value as {@code int} bits
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param bits the {@code float} value as {@code int} bits
+ */
+ public static CstFloat make(int bits) {
+ /*
+ * Note: Javadoc notwithstanding, this implementation always
+ * allocates.
*/
- public static CstFloat make(int bits) {
- /*
- * Note: Javadoc notwithstanding, this implementation always
- * allocates.
- */
- return new CstFloat(bits);
- }
+ return new CstFloat(bits);
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param bits the {@code float} value as {@code int} bits
- */
- private CstFloat(int bits) {
- super(bits);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param bits the {@code float} value as {@code int} bits
+ */
+ private CstFloat(int bits) {
+ super(bits);
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int bits = getIntBits();
- return "float{0x" + Hex.u4(bits) + " / " +
- Float.intBitsToFloat(bits) + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int bits = getIntBits();
+ return "float{0x" + Hex.u4(bits) + " / " + Float.intBitsToFloat(bits) + '}';
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.FLOAT;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.FLOAT;
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "float";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "float";
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return Float.toString(Float.intBitsToFloat(getIntBits()));
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Float.toString(Float.intBitsToFloat(getIntBits()));
+ }
- /**
- * Gets the {@code float} value.
- *
- * @return the value
- */
- public float getValue() {
- return Float.intBitsToFloat(getIntBits());
- }
+ /**
+ * Gets the {@code float} value.
+ *
+ * @return the value
+ */
+ public float getValue() {
+ return Float.intBitsToFloat(getIntBits());
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstIndexMap.java b/dx/src/com/android/jack/dx/rop/cst/CstIndexMap.java
index 3d84830..9a5d55e 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstIndexMap.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstIndexMap.java
@@ -15,13 +15,13 @@
*/
package com.android.jack.dx.rop.cst;
+import com.android.jack.dx.dex.file.DexFile;
+import com.android.jack.dx.dex.file.IndexedItem;
+
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import com.android.jack.dx.dex.file.DexFile;
-import com.android.jack.dx.dex.file.IndexedItem;
-
/**
* Maps {@link TypedConstant} index offsets from a dex file to those into another.
*/
@@ -38,8 +38,7 @@
new HashMap<Integer, CstBaseMethodRef>();
/** Mapping between index and {@link CstFieldRef} value of a dex file.*/
- private final Map<Integer, CstFieldRef> fieldsIndexMap =
- new HashMap<Integer, CstFieldRef>();
+ private final Map<Integer, CstFieldRef> fieldsIndexMap = new HashMap<Integer, CstFieldRef>();
/**
* Keeps string mapping of a dex file.
@@ -47,10 +46,9 @@
* @param cstString The string.
*/
public void addStringMapping(int index, CstString cstString) {
- Integer key = new Integer (index);
+ Integer key = new Integer(index);
assert index >= 0;
- assert stringsIndexMap.get(key) == null
- || stringsIndexMap.get(key).compareTo(cstString) == 0;
+ assert stringsIndexMap.get(key) == null || stringsIndexMap.get(key).compareTo(cstString) == 0;
if (!stringsIndexMap.containsKey(key)) {
stringsIndexMap.put(key, cstString);
@@ -63,10 +61,9 @@
* @param cstType The type.
*/
public void addTypeMapping(int index, CstType cstType) {
- Integer key = new Integer (index);
+ Integer key = new Integer(index);
assert index >= 0;
- assert typesIndexMap.get(key) == null
- || typesIndexMap.get(key).compareTo(cstType) == 0;
+ assert typesIndexMap.get(key) == null || typesIndexMap.get(key).compareTo(cstType) == 0;
if (!typesIndexMap.containsKey(key)) {
typesIndexMap.put(key, cstType);
@@ -79,10 +76,9 @@
* @param methodRef The method.
*/
public void addMethodMapping(int index, CstBaseMethodRef methodRef) {
- Integer key = new Integer (index);
+ Integer key = new Integer(index);
assert index >= 0;
- assert methodsIndexMap.get(key) == null
- || methodsIndexMap.get(key).compareTo(methodRef) == 0;
+ assert methodsIndexMap.get(key) == null || methodsIndexMap.get(key).compareTo(methodRef) == 0;
if (!methodsIndexMap.containsKey(key)) {
methodsIndexMap.put(key, methodRef);
@@ -95,10 +91,9 @@
* @param fieldRef The Field.
*/
public void addFieldMapping(int index, CstFieldRef fieldRef) {
- Integer key = new Integer (index);
+ Integer key = new Integer(index);
assert index >= 0;
- assert fieldsIndexMap.get(key) == null
- || fieldsIndexMap.get(key).compareTo(fieldRef) == 0;
+ assert fieldsIndexMap.get(key) == null || fieldsIndexMap.get(key).compareTo(fieldRef) == 0;
if (!fieldsIndexMap.containsKey(key)) {
fieldsIndexMap.put(key, fieldRef);
@@ -109,7 +104,7 @@
* Merge all {@link TypedConstant} of one dex file into another.
* @param dex The dex file where values are merged.
*/
- public void mergeConstantsIntoDexFile(DexFile dex) {
+ public void mergeConstantsIntoDexFile(DexFile dex) {
for (CstString cst : stringsIndexMap.values()) {
dex.getStringIds().intern(cst);
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstInteger.java b/dx/src/com/android/jack/dx/rop/cst/CstInteger.java
index 10ae236..e6ee29a 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstInteger.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstInteger.java
@@ -22,95 +22,96 @@
/**
* Constants of type {@code CONSTANT_Integer_info}.
*/
-public final class CstInteger
- extends CstLiteral32 {
- /** {@code non-null;} array of cached instances */
- private static final CstInteger[] cache = new CstInteger[511];
+public final class CstInteger extends CstLiteral32 {
+ /** {@code non-null;} array of cached instances */
+ private static final CstInteger[] cache = new CstInteger[511];
- /** {@code non-null;} instance representing {@code -1} */
- public static final CstInteger VALUE_M1 = make(-1);
+ /** {@code non-null;} instance representing {@code -1} */
+ public static final CstInteger VALUE_M1 = make(-1);
- /** {@code non-null;} instance representing {@code 0} */
- public static final CstInteger VALUE_0 = make(0);
+ /** {@code non-null;} instance representing {@code 0} */
+ public static final CstInteger VALUE_0 = make(0);
- /** {@code non-null;} instance representing {@code 1} */
- public static final CstInteger VALUE_1 = make(1);
+ /** {@code non-null;} instance representing {@code 1} */
+ public static final CstInteger VALUE_1 = make(1);
- /** {@code non-null;} instance representing {@code 2} */
- public static final CstInteger VALUE_2 = make(2);
+ /** {@code non-null;} instance representing {@code 2} */
+ public static final CstInteger VALUE_2 = make(2);
- /** {@code non-null;} instance representing {@code 3} */
- public static final CstInteger VALUE_3 = make(3);
+ /** {@code non-null;} instance representing {@code 3} */
+ public static final CstInteger VALUE_3 = make(3);
- /** {@code non-null;} instance representing {@code 4} */
- public static final CstInteger VALUE_4 = make(4);
+ /** {@code non-null;} instance representing {@code 4} */
+ public static final CstInteger VALUE_4 = make(4);
- /** {@code non-null;} instance representing {@code 5} */
- public static final CstInteger VALUE_5 = make(5);
+ /** {@code non-null;} instance representing {@code 5} */
+ public static final CstInteger VALUE_5 = make(5);
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param value the {@code int} value
- * @return {@code non-null;} the appropriate instance
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param value the {@code int} value
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstInteger make(int value) {
+ /*
+ * Note: No need to synchronize, since we don't make any sort
+ * of guarantee about ==, and it's okay to overwrite existing
+ * entries too.
*/
- public static CstInteger make(int value) {
- /*
- * Note: No need to synchronize, since we don't make any sort
- * of guarantee about ==, and it's okay to overwrite existing
- * entries too.
- */
- int idx = (value & 0x7fffffff) % cache.length;
- CstInteger obj = cache[idx];
+ int idx = (value & 0x7fffffff) % cache.length;
+ CstInteger obj = cache[idx];
- if ((obj != null) && (obj.getValue() == value)) {
- return obj;
- }
-
- obj = new CstInteger(value);
- cache[idx] = obj;
- return obj;
+ if ((obj != null) && (obj.getValue() == value)) {
+ return obj;
}
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code int} value
- */
- private CstInteger(int value) {
- super(value);
- }
+ obj = new CstInteger(value);
+ cache[idx] = obj;
+ return obj;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int value = getIntBits();
- return "int{0x" + Hex.u4(value) + " / " + value + '}';
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code int} value
+ */
+ private CstInteger(int value) {
+ super(value);
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.INT;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int value = getIntBits();
+ return "int{0x" + Hex.u4(value) + " / " + value + '}';
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "int";
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.INT;
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return Integer.toString(getIntBits());
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "int";
+ }
- /**
- * Gets the {@code int} value.
- *
- * @return the value
- */
- public int getValue() {
- return getIntBits();
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Integer.toString(getIntBits());
+ }
+
+ /**
+ * Gets the {@code int} value.
+ *
+ * @return the value
+ */
+ public int getValue() {
+ return getIntBits();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/jack/dx/rop/cst/CstInterfaceMethodRef.java
index 66c3dd6..7aef26a 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstInterfaceMethodRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstInterfaceMethodRef.java
@@ -19,42 +19,41 @@
/**
* Constants of type {@code CONSTANT_InterfaceMethodref_info}.
*/
-public final class CstInterfaceMethodRef
- extends CstBaseMethodRef {
- /**
- * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
- * instance, if calculated
- */
- private CstMethodRef methodRef;
+public final class CstInterfaceMethodRef extends CstBaseMethodRef {
+ /**
+ * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
+ * instance, if calculated
+ */
+ private CstMethodRef methodRef;
- /**
- * Constructs an instance.
- *
- * @param definingClass {@code non-null;} the type of the defining class
- * @param nat {@code non-null;} the name-and-type
- */
- public CstInterfaceMethodRef(CstType definingClass, CstNat nat) {
- super(definingClass, nat);
- methodRef = null;
+ /**
+ * Constructs an instance.
+ *
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
+ */
+ public CstInterfaceMethodRef(CstType definingClass, CstNat nat) {
+ super(definingClass, nat);
+ methodRef = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "ifaceMethod";
+ }
+
+ /**
+ * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
+ * this instance.
+ *
+ * @return {@code non-null;} an appropriate instance
+ */
+ public CstMethodRef toMethodRef() {
+ if (methodRef == null) {
+ methodRef = new CstMethodRef(getDefiningClass(), getNat());
}
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "ifaceMethod";
- }
-
- /**
- * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
- * this instance.
- *
- * @return {@code non-null;} an appropriate instance
- */
- public CstMethodRef toMethodRef() {
- if (methodRef == null) {
- methodRef = new CstMethodRef(getDefiningClass(), getNat());
- }
-
- return methodRef;
- }
+ return methodRef;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/jack/dx/rop/cst/CstKnownNull.java
index fe471f3..a7b6355 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstKnownNull.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstKnownNull.java
@@ -22,89 +22,91 @@
* Constant type to represent a known-{@code null} value.
*/
public final class CstKnownNull extends CstLiteralBits {
- /** {@code non-null;} unique instance of this class */
- public static final CstKnownNull THE_ONE = new CstKnownNull();
+ /** {@code non-null;} unique instance of this class */
+ public static final CstKnownNull THE_ONE = new CstKnownNull();
- /**
- * Constructs an instance. This class is not publicly instantiable. Use
- * {@link #THE_ONE}.
- */
- private CstKnownNull() {
- // This space intentionally left blank.
- }
+ /**
+ * Constructs an instance. This class is not publicly instantiable. Use
+ * {@link #THE_ONE}.
+ */
+ private CstKnownNull() {
+ // This space intentionally left blank.
+ }
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- return (other instanceof CstKnownNull);
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ return (other instanceof CstKnownNull);
+ }
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return 0x4466757a;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return 0x4466757a;
+ }
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- return 0;
- }
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ return 0;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return "known-null";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "known-null";
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.KNOWN_NULL;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.KNOWN_NULL;
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "known-null";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "known-null";
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return "null";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return "null";
+ }
- /** {@inheritDoc} */
- @Override
- public boolean fitsInInt() {
- // See comment in getIntBits().
- return true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean fitsInInt() {
+ // See comment in getIntBits().
+ return true;
+ }
- /**
- * {@inheritDoc}
- *
- * As "literal bits," a known-null is always represented as the
- * number zero.
- */
- @Override
- public int getIntBits() {
- return 0;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * As "literal bits," a known-null is always represented as the
+ * number zero.
+ */
+ @Override
+ public int getIntBits() {
+ return 0;
+ }
- /**
- * {@inheritDoc}
- *
- * As "literal bits," a known-null is always represented as the
- * number zero.
- */
- @Override
- public long getLongBits() {
- return 0;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * As "literal bits," a known-null is always represented as the
+ * number zero.
+ */
+ @Override
+ public long getLongBits() {
+ return 0;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/jack/dx/rop/cst/CstLiteral32.java
index 488c015..8e2cec2 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstLiteral32.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstLiteral32.java
@@ -19,69 +19,67 @@
/**
* Constants which are literal 32-bit values of some sort.
*/
-public abstract class CstLiteral32
- extends CstLiteralBits {
- /** the value as {@code int} bits */
- private final int bits;
+public abstract class CstLiteral32 extends CstLiteralBits {
+ /** the value as {@code int} bits */
+ private final int bits;
- /**
- * Constructs an instance.
- *
- * @param bits the value as {@code int} bits
- */
- /*package*/ CstLiteral32(int bits) {
- this.bits = bits;
+ /**
+ * Constructs an instance.
+ *
+ * @param bits the value as {@code int} bits
+ */
+ /*package*/CstLiteral32(int bits) {
+ this.bits = bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final boolean equals(Object other) {
+ return (other != null) && (getClass() == other.getClass())
+ && bits == ((CstLiteral32) other).bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int hashCode() {
+ return bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ int otherBits = ((CstLiteral32) other).bits;
+
+ if (bits < otherBits) {
+ return -1;
+ } else if (bits > otherBits) {
+ return 1;
+ } else {
+ return 0;
}
+ }
- /** {@inheritDoc} */
- @Override
- public final boolean equals(Object other) {
- return (other != null) &&
- (getClass() == other.getClass()) &&
- bits == ((CstLiteral32) other).bits;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isCategory2() {
+ return false;
+ }
- /** {@inheritDoc} */
- @Override
- public final int hashCode() {
- return bits;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean fitsInInt() {
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- int otherBits = ((CstLiteral32) other).bits;
+ /** {@inheritDoc} */
+ @Override
+ public final int getIntBits() {
+ return bits;
+ }
- if (bits < otherBits) {
- return -1;
- } else if (bits > otherBits) {
- return 1;
- } else {
- return 0;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public final boolean isCategory2() {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public final boolean fitsInInt() {
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public final int getIntBits() {
- return bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public final long getLongBits() {
- return (long) bits;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final long getLongBits() {
+ return bits;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/jack/dx/rop/cst/CstLiteral64.java
index e72b089..1c3e976 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstLiteral64.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstLiteral64.java
@@ -19,69 +19,67 @@
/**
* Constants which are literal 64-bit values of some sort.
*/
-public abstract class CstLiteral64
- extends CstLiteralBits {
- /** the value as {@code long} bits */
- private final long bits;
+public abstract class CstLiteral64 extends CstLiteralBits {
+ /** the value as {@code long} bits */
+ private final long bits;
- /**
- * Constructs an instance.
- *
- * @param bits the value as {@code long} bits
- */
- /*package*/ CstLiteral64(long bits) {
- this.bits = bits;
+ /**
+ * Constructs an instance.
+ *
+ * @param bits the value as {@code long} bits
+ */
+ /*package*/CstLiteral64(long bits) {
+ this.bits = bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final boolean equals(Object other) {
+ return (other != null) && (getClass() == other.getClass())
+ && bits == ((CstLiteral64) other).bits;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final int hashCode() {
+ return (int) bits ^ (int) (bits >> 32);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ long otherBits = ((CstLiteral64) other).bits;
+
+ if (bits < otherBits) {
+ return -1;
+ } else if (bits > otherBits) {
+ return 1;
+ } else {
+ return 0;
}
+ }
- /** {@inheritDoc} */
- @Override
- public final boolean equals(Object other) {
- return (other != null) &&
- (getClass() == other.getClass()) &&
- bits == ((CstLiteral64) other).bits;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isCategory2() {
+ return true;
+ }
- /** {@inheritDoc} */
- @Override
- public final int hashCode() {
- return (int) bits ^ (int) (bits >> 32);
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean fitsInInt() {
+ return (int) bits == bits;
+ }
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- long otherBits = ((CstLiteral64) other).bits;
+ /** {@inheritDoc} */
+ @Override
+ public final int getIntBits() {
+ return (int) bits;
+ }
- if (bits < otherBits) {
- return -1;
- } else if (bits > otherBits) {
- return 1;
- } else {
- return 0;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public final boolean isCategory2() {
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public final boolean fitsInInt() {
- return (int) bits == bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public final int getIntBits() {
- return (int) bits;
- }
-
- /** {@inheritDoc} */
- @Override
- public final long getLongBits() {
- return bits;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final long getLongBits() {
+ return bits;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/jack/dx/rop/cst/CstLiteralBits.java
index 0615aa7..4b8ead6 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstLiteralBits.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstLiteralBits.java
@@ -19,64 +19,63 @@
/**
* Constants which are literal bitwise values of some sort.
*/
-public abstract class CstLiteralBits
- extends TypedConstant {
- /**
- * Returns whether or not this instance's value may be accurately
- * represented as an {@code int}. The rule is that if there
- * is an {@code int} which may be sign-extended to yield this
- * instance's value, then this method returns {@code true}.
- * Otherwise, it returns {@code false}.
- *
- * @return {@code true} iff this instance fits in an {@code int}
- */
- public abstract boolean fitsInInt();
+public abstract class CstLiteralBits extends TypedConstant {
+ /**
+ * Returns whether or not this instance's value may be accurately
+ * represented as an {@code int}. The rule is that if there
+ * is an {@code int} which may be sign-extended to yield this
+ * instance's value, then this method returns {@code true}.
+ * Otherwise, it returns {@code false}.
+ *
+ * @return {@code true} iff this instance fits in an {@code int}
+ */
+ public abstract boolean fitsInInt();
- /**
- * Gets the value as {@code int} bits. If this instance contains
- * more bits than fit in an {@code int}, then this returns only
- * the low-order bits.
- *
- * @return the bits
- */
- public abstract int getIntBits();
+ /**
+ * Gets the value as {@code int} bits. If this instance contains
+ * more bits than fit in an {@code int}, then this returns only
+ * the low-order bits.
+ *
+ * @return the bits
+ */
+ public abstract int getIntBits();
- /**
- * Gets the value as {@code long} bits. If this instance contains
- * fewer bits than fit in a {@code long}, then the result of this
- * method is the sign extension of the value.
- *
- * @return the bits
- */
- public abstract long getLongBits();
+ /**
+ * Gets the value as {@code long} bits. If this instance contains
+ * fewer bits than fit in a {@code long}, then the result of this
+ * method is the sign extension of the value.
+ *
+ * @return the bits
+ */
+ public abstract long getLongBits();
- /**
- * Returns true if this value can fit in 16 bits with sign-extension.
- *
- * @return true if the sign-extended lower 16 bits are the same as
- * the value.
- */
- public boolean fitsIn16Bits() {
- if (! fitsInInt()) {
- return false;
- }
-
- int bits = getIntBits();
- return (short) bits == bits;
+ /**
+ * Returns true if this value can fit in 16 bits with sign-extension.
+ *
+ * @return true if the sign-extended lower 16 bits are the same as
+ * the value.
+ */
+ public boolean fitsIn16Bits() {
+ if (!fitsInInt()) {
+ return false;
}
- /**
- * Returns true if this value can fit in 8 bits with sign-extension.
- *
- * @return true if the sign-extended lower 8 bits are the same as
- * the value.
- */
- public boolean fitsIn8Bits() {
- if (! fitsInInt()) {
- return false;
- }
+ int bits = getIntBits();
+ return (short) bits == bits;
+ }
- int bits = getIntBits();
- return (byte) bits == bits;
+ /**
+ * Returns true if this value can fit in 8 bits with sign-extension.
+ *
+ * @return true if the sign-extended lower 8 bits are the same as
+ * the value.
+ */
+ public boolean fitsIn8Bits() {
+ if (!fitsInInt()) {
+ return false;
}
+
+ int bits = getIntBits();
+ return (byte) bits == bits;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstLong.java b/dx/src/com/android/jack/dx/rop/cst/CstLong.java
index 58c2b9b..6265566 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstLong.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstLong.java
@@ -22,66 +22,67 @@
/**
* Constants of type {@code CONSTANT_Long_info}.
*/
-public final class CstLong
- extends CstLiteral64 {
- /** {@code non-null;} instance representing {@code 0} */
- public static final CstLong VALUE_0 = make(0);
+public final class CstLong extends CstLiteral64 {
+ /** {@code non-null;} instance representing {@code 0} */
+ public static final CstLong VALUE_0 = make(0);
- /** {@code non-null;} instance representing {@code 1} */
- public static final CstLong VALUE_1 = make(1);
+ /** {@code non-null;} instance representing {@code 1} */
+ public static final CstLong VALUE_1 = make(1);
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param value the {@code long} value
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param value the {@code long} value
+ */
+ public static CstLong make(long value) {
+ /*
+ * Note: Javadoc notwithstanding, this implementation always
+ * allocates.
*/
- public static CstLong make(long value) {
- /*
- * Note: Javadoc notwithstanding, this implementation always
- * allocates.
- */
- return new CstLong(value);
- }
+ return new CstLong(value);
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code long} value
- */
- private CstLong(long value) {
- super(value);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code long} value
+ */
+ private CstLong(long value) {
+ super(value);
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- long value = getLongBits();
- return "long{0x" + Hex.u8(value) + " / " + value + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ long value = getLongBits();
+ return "long{0x" + Hex.u8(value) + " / " + value + '}';
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.LONG;
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.LONG;
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "long";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "long";
+ }
- /** {@inheritDoc} */
- public String toHuman() {
- return Long.toString(getLongBits());
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Long.toString(getLongBits());
+ }
- /**
- * Gets the {@code long} value.
- *
- * @return the value
- */
- public long getValue() {
- return getLongBits();
- }
+ /**
+ * Gets the {@code long} value.
+ *
+ * @return the value
+ */
+ public long getValue() {
+ return getLongBits();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/jack/dx/rop/cst/CstMemberRef.java
index 3415946..2b36a7d 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstMemberRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstMemberRef.java
@@ -20,103 +20,103 @@
* Constants of type {@code CONSTANT_*ref_info}.
*/
public abstract class CstMemberRef extends TypedConstant {
- /** {@code non-null;} the type of the defining class */
- private final CstType definingClass;
+ /** {@code non-null;} the type of the defining class */
+ private final CstType definingClass;
- /** {@code non-null;} the name-and-type */
- private final CstNat nat;
+ /** {@code non-null;} the name-and-type */
+ private final CstNat nat;
- /**
- * Constructs an instance.
- *
- * @param definingClass {@code non-null;} the type of the defining class
- * @param nat {@code non-null;} the name-and-type
- */
- /*package*/ CstMemberRef(CstType definingClass, CstNat nat) {
- if (definingClass == null) {
- throw new NullPointerException("definingClass == null");
- }
-
- if (nat == null) {
- throw new NullPointerException("nat == null");
- }
-
- this.definingClass = definingClass;
- this.nat = nat;
+ /**
+ * Constructs an instance.
+ *
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
+ */
+ /*package*/CstMemberRef(CstType definingClass, CstNat nat) {
+ if (definingClass == null) {
+ throw new NullPointerException("definingClass == null");
}
- /** {@inheritDoc} */
- @Override
- public final boolean equals(Object other) {
- if ((other == null) || (getClass() != other.getClass())) {
- return false;
- }
-
- CstMemberRef otherRef = (CstMemberRef) other;
- return definingClass.equals(otherRef.definingClass) &&
- nat.equals(otherRef.nat);
+ if (nat == null) {
+ throw new NullPointerException("nat == null");
}
- /** {@inheritDoc} */
- @Override
- public final int hashCode() {
- return (definingClass.hashCode() * 31) ^ nat.hashCode();
+ this.definingClass = definingClass;
+ this.nat = nat;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final boolean equals(Object other) {
+ if ((other == null) || (getClass() != other.getClass())) {
+ return false;
}
- /**
- * {@inheritDoc}
- *
- * <p><b>Note:</b> This implementation just compares the defining
- * class and name, and it is up to subclasses to compare the rest
- * after calling {@code super.compareTo0()}.</p>
- */
- @Override
- protected int compareTo0(Constant other) {
- CstMemberRef otherMember = (CstMemberRef) other;
- int cmp = definingClass.compareTo(otherMember.definingClass);
+ CstMemberRef otherRef = (CstMemberRef) other;
+ return definingClass.equals(otherRef.definingClass) && nat.equals(otherRef.nat);
+ }
- if (cmp != 0) {
- return cmp;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final int hashCode() {
+ return (definingClass.hashCode() * 31) ^ nat.hashCode();
+ }
- CstString thisName = nat.getName();
- CstString otherName = otherMember.nat.getName();
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b> This implementation just compares the defining
+ * class and name, and it is up to subclasses to compare the rest
+ * after calling {@code super.compareTo0()}.</p>
+ */
+ @Override
+ protected int compareTo0(Constant other) {
+ CstMemberRef otherMember = (CstMemberRef) other;
+ int cmp = definingClass.compareTo(otherMember.definingClass);
- return thisName.compareTo(otherName);
+ if (cmp != 0) {
+ return cmp;
}
- /** {@inheritDoc} */
- @Override
- public final String toString() {
- return typeName() + '{' + toHuman() + '}';
- }
+ CstString thisName = nat.getName();
+ CstString otherName = otherMember.nat.getName();
- /** {@inheritDoc} */
- @Override
- public final boolean isCategory2() {
- return false;
- }
+ return thisName.compareTo(otherName);
+ }
- /** {@inheritDoc} */
- public final String toHuman() {
- return definingClass.toHuman() + '.' + nat.toHuman();
- }
+ /** {@inheritDoc} */
+ @Override
+ public final String toString() {
+ return typeName() + '{' + toHuman() + '}';
+ }
- /**
- * Gets the type of the defining class.
- *
- * @return {@code non-null;} the type of defining class
- */
- public final CstType getDefiningClass() {
- return definingClass;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isCategory2() {
+ return false;
+ }
- /**
- * Gets the defining name-and-type.
- *
- * @return {@code non-null;} the name-and-type
- */
- public final CstNat getNat() {
- return nat;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final String toHuman() {
+ return definingClass.toHuman() + '.' + nat.toHuman();
+ }
+
+ /**
+ * Gets the type of the defining class.
+ *
+ * @return {@code non-null;} the type of defining class
+ */
+ public final CstType getDefiningClass() {
+ return definingClass;
+ }
+
+ /**
+ * Gets the defining name-and-type.
+ *
+ * @return {@code non-null;} the name-and-type
+ */
+ public final CstNat getNat() {
+ return nat;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstMethodRef.java b/dx/src/com/android/jack/dx/rop/cst/CstMethodRef.java
index 3b6d2a4..f28e050 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstMethodRef.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstMethodRef.java
@@ -19,21 +19,20 @@
/**
* Constants of type {@code CONSTANT_Methodref_info}.
*/
-public final class CstMethodRef
- extends CstBaseMethodRef {
- /**
- * Constructs an instance.
- *
- * @param definingClass {@code non-null;} the type of the defining class
- * @param nat {@code non-null;} the name-and-type
- */
- public CstMethodRef(CstType definingClass, CstNat nat) {
- super(definingClass, nat);
- }
+public final class CstMethodRef extends CstBaseMethodRef {
+ /**
+ * Constructs an instance.
+ *
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
+ */
+ public CstMethodRef(CstType definingClass, CstNat nat) {
+ super(definingClass, nat);
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "method";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "method";
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstNat.java b/dx/src/com/android/jack/dx/rop/cst/CstNat.java
index 75c521e..6abdbb7 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstNat.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstNat.java
@@ -22,149 +22,148 @@
* Constants of type {@code CONSTANT_NameAndType_info}.
*/
public final class CstNat extends Constant {
- /**
- * {@code non-null;} the instance for name {@code TYPE} and descriptor
- * {@code java.lang.Class}, which is useful when dealing with
- * wrapped primitives
- */
- public static final CstNat PRIMITIVE_TYPE_NAT =
- new CstNat(new CstString("TYPE"),
- new CstString("Ljava/lang/Class;"));
+ /**
+ * {@code non-null;} the instance for name {@code TYPE} and descriptor
+ * {@code java.lang.Class}, which is useful when dealing with
+ * wrapped primitives
+ */
+ public static final CstNat PRIMITIVE_TYPE_NAT =
+ new CstNat(new CstString("TYPE"), new CstString("Ljava/lang/Class;"));
- /** {@code non-null;} the name */
- private final CstString name;
+ /** {@code non-null;} the name */
+ private final CstString name;
- /** {@code non-null;} the descriptor (type) */
- private final CstString descriptor;
+ /** {@code non-null;} the descriptor (type) */
+ private final CstString descriptor;
- /**
- * Constructs an instance.
- *
- * @param name {@code non-null;} the name
- * @param descriptor {@code non-null;} the descriptor
- */
- public CstNat(CstString name, CstString descriptor) {
- if (name == null) {
- throw new NullPointerException("name == null");
- }
-
- if (descriptor == null) {
- throw new NullPointerException("descriptor == null");
- }
-
- this.name = name;
- this.descriptor = descriptor;
+ /**
+ * Constructs an instance.
+ *
+ * @param name {@code non-null;} the name
+ * @param descriptor {@code non-null;} the descriptor
+ */
+ public CstNat(CstString name, CstString descriptor) {
+ if (name == null) {
+ throw new NullPointerException("name == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof CstNat)) {
- return false;
- }
-
- CstNat otherNat = (CstNat) other;
- return name.equals(otherNat.name) &&
- descriptor.equals(otherNat.descriptor);
+ if (descriptor == null) {
+ throw new NullPointerException("descriptor == null");
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return (name.hashCode() * 31) ^ descriptor.hashCode();
+ this.name = name;
+ this.descriptor = descriptor;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstNat)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- CstNat otherNat = (CstNat) other;
- int cmp = name.compareTo(otherNat.name);
+ CstNat otherNat = (CstNat) other;
+ return name.equals(otherNat.name) && descriptor.equals(otherNat.descriptor);
+ }
- if (cmp != 0) {
- return cmp;
- }
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return (name.hashCode() * 31) ^ descriptor.hashCode();
+ }
- return descriptor.compareTo(otherNat.descriptor);
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ CstNat otherNat = (CstNat) other;
+ int cmp = name.compareTo(otherNat.name);
+
+ if (cmp != 0) {
+ return cmp;
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return "nat{" + toHuman() + '}';
- }
+ return descriptor.compareTo(otherNat.descriptor);
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "nat";
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "nat{" + toHuman() + '}';
+ }
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "nat";
+ }
- /**
- * Gets the name.
- *
- * @return {@code non-null;} the name
- */
- public CstString getName() {
- return name;
- }
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
- /**
- * Gets the descriptor.
- *
- * @return {@code non-null;} the descriptor
- */
- public CstString getDescriptor() {
- return descriptor;
- }
+ /**
+ * Gets the name.
+ *
+ * @return {@code non-null;} the name
+ */
+ public CstString getName() {
+ return name;
+ }
- /**
- * Returns an unadorned but human-readable version of the name-and-type
- * value.
- *
- * @return {@code non-null;} the human form
- */
- public String toHuman() {
- return name.toHuman() + ':' + descriptor.toHuman();
- }
+ /**
+ * Gets the descriptor.
+ *
+ * @return {@code non-null;} the descriptor
+ */
+ public CstString getDescriptor() {
+ return descriptor;
+ }
- /**
- * Gets the field type corresponding to this instance's descriptor.
- * This method is only valid to call if the descriptor in fact describes
- * a field (and not a method).
- *
- * @return {@code non-null;} the field type
- */
- public Type getFieldType() {
- return Type.intern(descriptor.getString());
- }
+ /**
+ * Returns an unadorned but human-readable version of the name-and-type
+ * value.
+ *
+ * @return {@code non-null;} the human form
+ */
+ @Override
+ public String toHuman() {
+ return name.toHuman() + ':' + descriptor.toHuman();
+ }
- /**
- * Gets whether this instance has the name of a standard instance
- * initialization method. This is just a convenient shorthand for
- * {@code getName().getString().equals("<init>")}.
- *
- * @return {@code true} iff this is a reference to an
- * instance initialization method
- */
- public final boolean isInstanceInit() {
- return name.getString().equals("<init>");
- }
+ /**
+ * Gets the field type corresponding to this instance's descriptor.
+ * This method is only valid to call if the descriptor in fact describes
+ * a field (and not a method).
+ *
+ * @return {@code non-null;} the field type
+ */
+ public Type getFieldType() {
+ return Type.intern(descriptor.getString());
+ }
- /**
- * Gets whether this instance has the name of a standard class
- * initialization method. This is just a convenient shorthand for
- * {@code getName().getString().equals("<clinit>")}.
- *
- * @return {@code true} iff this is a reference to an
- * instance initialization method
- */
- public final boolean isClassInit() {
- return name.getString().equals("<clinit>");
- }
+ /**
+ * Gets whether this instance has the name of a standard instance
+ * initialization method. This is just a convenient shorthand for
+ * {@code getName().getString().equals("<init>")}.
+ *
+ * @return {@code true} iff this is a reference to an
+ * instance initialization method
+ */
+ public final boolean isInstanceInit() {
+ return name.getString().equals("<init>");
+ }
+
+ /**
+ * Gets whether this instance has the name of a standard class
+ * initialization method. This is just a convenient shorthand for
+ * {@code getName().getString().equals("<clinit>")}.
+ *
+ * @return {@code true} iff this is a reference to an
+ * instance initialization method
+ */
+ public final boolean isClassInit() {
+ return name.getString().equals("<clinit>");
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstShort.java b/dx/src/com/android/jack/dx/rop/cst/CstShort.java
index 688ae6d..3038c91 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstShort.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstShort.java
@@ -22,79 +22,79 @@
/**
* Constants of type {@code short}.
*/
-public final class CstShort
- extends CstLiteral32 {
- /** {@code non-null;} the value {@code 0} as an instance of this class */
- public static final CstShort VALUE_0 = make((short) 0);
+public final class CstShort extends CstLiteral32 {
+ /** {@code non-null;} the value {@code 0} as an instance of this class */
+ public static final CstShort VALUE_0 = make((short) 0);
- /**
- * Makes an instance for the given value. This may (but does not
- * necessarily) return an already-allocated instance.
- *
- * @param value the {@code short} value
- * @return {@code non-null;} the appropriate instance
- */
- public static CstShort make(short value) {
- return new CstShort(value);
+ /**
+ * Makes an instance for the given value. This may (but does not
+ * necessarily) return an already-allocated instance.
+ *
+ * @param value the {@code short} value
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstShort make(short value) {
+ return new CstShort(value);
+ }
+
+ /**
+ * Makes an instance for the given {@code int} value. This
+ * may (but does not necessarily) return an already-allocated
+ * instance.
+ *
+ * @param value the value, which must be in range for a {@code short}
+ * @return {@code non-null;} the appropriate instance
+ */
+ public static CstShort make(int value) {
+ short cast = (short) value;
+
+ if (cast != value) {
+ throw new IllegalArgumentException("bogus short value: " + value);
}
- /**
- * Makes an instance for the given {@code int} value. This
- * may (but does not necessarily) return an already-allocated
- * instance.
- *
- * @param value the value, which must be in range for a {@code short}
- * @return {@code non-null;} the appropriate instance
- */
- public static CstShort make(int value) {
- short cast = (short) value;
+ return make(cast);
+ }
- if (cast != value) {
- throw new IllegalArgumentException("bogus short value: " +
- value);
- }
+ /**
+ * Constructs an instance. This constructor is private; use {@link #make}.
+ *
+ * @param value the {@code short} value
+ */
+ private CstShort(short value) {
+ super(value);
+ }
- return make(cast);
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ int value = getIntBits();
+ return "short{0x" + Hex.u2(value) + " / " + value + '}';
+ }
- /**
- * Constructs an instance. This constructor is private; use {@link #make}.
- *
- * @param value the {@code short} value
- */
- private CstShort(short value) {
- super(value);
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.SHORT;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- int value = getIntBits();
- return "short{0x" + Hex.u2(value) + " / " + value + '}';
- }
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "short";
+ }
- /** {@inheritDoc} */
- public Type getType() {
- return Type.SHORT;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return Integer.toString(getIntBits());
+ }
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "short";
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return Integer.toString(getIntBits());
- }
-
- /**
- * Gets the {@code short} value.
- *
- * @return the value
- */
- public short getValue() {
- return (short) getIntBits();
- }
+ /**
+ * Gets the {@code short} value.
+ *
+ * @return the value
+ */
+ public short getValue() {
+ return (short) getIntBits();
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstString.java b/dx/src/com/android/jack/dx/rop/cst/CstString.java
index 42cf62d..94d547c 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstString.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstString.java
@@ -24,352 +24,364 @@
* Constants of type {@code CONSTANT_Utf8_info} or {@code CONSTANT_String_info}.
*/
public final class CstString extends TypedConstant {
- /**
- * {@code non-null;} instance representing {@code ""}, that is, the
- * empty string
- */
- public static final CstString EMPTY_STRING = new CstString("");
+ /**
+ * {@code non-null;} instance representing {@code ""}, that is, the
+ * empty string
+ */
+ public static final CstString EMPTY_STRING = new CstString("");
- /** {@code non-null;} the UTF-8 value as a string */
- private final String string;
+ /** {@code non-null;} the UTF-8 value as a string */
+ private final String string;
- /** {@code non-null;} the UTF-8 value as bytes */
- private final ByteArray bytes;
+ /** {@code non-null;} the UTF-8 value as bytes */
+ private final ByteArray bytes;
- /**
- * Converts a string into its MUTF-8 form. MUTF-8 differs from normal UTF-8
- * in the handling of character '\0' and surrogate pairs.
- *
- * @param string {@code non-null;} the string to convert
- * @return {@code non-null;} the UTF-8 bytes for it
- */
- public static byte[] stringToUtf8Bytes(String string) {
- int len = string.length();
- byte[] bytes = new byte[len * 3]; // Avoid having to reallocate.
- int outAt = 0;
+ /**
+ * Converts a string into its MUTF-8 form. MUTF-8 differs from normal UTF-8
+ * in the handling of character '\0' and surrogate pairs.
+ *
+ * @param string {@code non-null;} the string to convert
+ * @return {@code non-null;} the UTF-8 bytes for it
+ */
+ public static byte[] stringToUtf8Bytes(String string) {
+ int len = string.length();
+ byte[] bytes = new byte[len * 3]; // Avoid having to reallocate.
+ int outAt = 0;
- for (int i = 0; i < len; i++) {
- char c = string.charAt(i);
- if ((c != 0) && (c < 0x80)) {
- bytes[outAt] = (byte) c;
- outAt++;
- } else if (c < 0x800) {
- bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0);
- bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80);
- outAt += 2;
- } else {
- bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0);
- bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80);
- bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80);
- outAt += 3;
+ for (int i = 0; i < len; i++) {
+ char c = string.charAt(i);
+ if ((c != 0) && (c < 0x80)) {
+ bytes[outAt] = (byte) c;
+ outAt++;
+ } else if (c < 0x800) {
+ bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0);
+ bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80);
+ outAt += 2;
+ } else {
+ bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0);
+ bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80);
+ bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80);
+ outAt += 3;
+ }
+ }
+
+ byte[] result = new byte[outAt];
+ System.arraycopy(bytes, 0, result, 0, outAt);
+ return result;
+ }
+
+ /**
+ * Converts an array of UTF-8 bytes into a string.
+ *
+ * @param bytes {@code non-null;} the bytes to convert
+ * @return {@code non-null;} the converted string
+ */
+ public static String utf8BytesToString(ByteArray bytes) {
+ int length = bytes.size();
+ char[] chars = new char[length]; // This is sized to avoid a realloc.
+ int outAt = 0;
+
+ for (int at = 0; length > 0; /*at*/) {
+ int v0 = bytes.getUnsignedByte(at);
+ char out;
+ switch (v0 >> 4) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07: {
+ // 0XXXXXXX -- single-byte encoding
+ length--;
+ if (v0 == 0) {
+ // A single zero byte is illegal.
+ return throwBadUtf8(v0, at);
+ }
+ out = (char) v0;
+ at++;
+ break;
+ }
+ case 0x0c:
+ case 0x0d: {
+ // 110XXXXX -- two-byte encoding
+ length -= 2;
+ if (length < 0) {
+ return throwBadUtf8(v0, at);
+ }
+ int v1 = bytes.getUnsignedByte(at + 1);
+ if ((v1 & 0xc0) != 0x80) {
+ return throwBadUtf8(v1, at + 1);
+ }
+ int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f);
+ if ((value != 0) && (value < 0x80)) {
+ /*
+ * This should have been represented with
+ * one-byte encoding.
+ */
+ return throwBadUtf8(v1, at + 1);
+ }
+ out = (char) value;
+ at += 2;
+ break;
+ }
+ case 0x0e: {
+ // 1110XXXX -- three-byte encoding
+ length -= 3;
+ if (length < 0) {
+ return throwBadUtf8(v0, at);
+ }
+ int v1 = bytes.getUnsignedByte(at + 1);
+ if ((v1 & 0xc0) != 0x80) {
+ return throwBadUtf8(v1, at + 1);
+ }
+ int v2 = bytes.getUnsignedByte(at + 2);
+ if ((v1 & 0xc0) != 0x80) {
+ return throwBadUtf8(v2, at + 2);
+ }
+ int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | (v2 & 0x3f);
+ if (value < 0x800) {
+ /*
+ * This should have been represented with one- or
+ * two-byte encoding.
+ */
+ return throwBadUtf8(v2, at + 2);
+ }
+ out = (char) value;
+ at += 3;
+ break;
+ }
+ default: {
+ // 10XXXXXX, 1111XXXX -- illegal
+ return throwBadUtf8(v0, at);
+ }
+ }
+ chars[outAt] = out;
+ outAt++;
+ }
+
+ return new String(chars, 0, outAt);
+ }
+
+ /**
+ * Helper for {@link #utf8BytesToString}, which throws the right
+ * exception for a bogus utf-8 byte.
+ *
+ * @param value the byte value
+ * @param offset the file offset
+ * @return never
+ * @throws IllegalArgumentException always thrown
+ */
+ private static String throwBadUtf8(int value, int offset) {
+ throw new IllegalArgumentException(
+ "bad utf-8 byte " + Hex.u1(value) + " at offset " + Hex.u4(offset));
+ }
+
+ /**
+ * Constructs an instance from a {@code String}.
+ *
+ * @param string {@code non-null;} the UTF-8 value as a string
+ */
+ public CstString(String string) {
+ if (string == null) {
+ throw new NullPointerException("string == null");
+ }
+
+ this.string = string.intern();
+ this.bytes = new ByteArray(stringToUtf8Bytes(string));
+ }
+
+ /**
+ * Constructs an instance from some UTF-8 bytes.
+ *
+ * @param bytes {@code non-null;} array of the UTF-8 bytes
+ */
+ public CstString(ByteArray bytes) {
+ if (bytes == null) {
+ throw new NullPointerException("bytes == null");
+ }
+
+ this.bytes = bytes;
+ this.string = utf8BytesToString(bytes).intern();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstString)) {
+ return false;
+ }
+
+ return string.equals(((CstString) other).string);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return string.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ return string.compareTo(((CstString) other).string);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "string{\"" + toHuman() + "\"}";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "utf8";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ int len = string.length();
+ StringBuilder sb = new StringBuilder(len * 3 / 2);
+
+ for (int i = 0; i < len; i++) {
+ char c = string.charAt(i);
+ if ((c >= ' ') && (c < 0x7f)) {
+ if ((c == '\'') || (c == '\"') || (c == '\\')) {
+ sb.append('\\');
+ }
+ sb.append(c);
+ } else if (c <= 0x7f) {
+ switch (c) {
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ default: {
+ /*
+ * Represent the character as an octal escape.
+ * If the next character is a valid octal
+ * digit, disambiguate by using the
+ * three-digit form.
+ */
+ char nextChar = (i < (len - 1)) ? string.charAt(i + 1) : 0;
+ boolean displayZero = (nextChar >= '0') && (nextChar <= '7');
+ sb.append('\\');
+ for (int shift = 6; shift >= 0; shift -= 3) {
+ char outChar = (char) (((c >> shift) & 7) + '0');
+ if ((outChar != '0') || displayZero) {
+ sb.append(outChar);
+ displayZero = true;
+ }
}
- }
-
- byte[] result = new byte[outAt];
- System.arraycopy(bytes, 0, result, 0, outAt);
- return result;
- }
-
- /**
- * Converts an array of UTF-8 bytes into a string.
- *
- * @param bytes {@code non-null;} the bytes to convert
- * @return {@code non-null;} the converted string
- */
- public static String utf8BytesToString(ByteArray bytes) {
- int length = bytes.size();
- char[] chars = new char[length]; // This is sized to avoid a realloc.
- int outAt = 0;
-
- for (int at = 0; length > 0; /*at*/) {
- int v0 = bytes.getUnsignedByte(at);
- char out;
- switch (v0 >> 4) {
- case 0x00: case 0x01: case 0x02: case 0x03:
- case 0x04: case 0x05: case 0x06: case 0x07: {
- // 0XXXXXXX -- single-byte encoding
- length--;
- if (v0 == 0) {
- // A single zero byte is illegal.
- return throwBadUtf8(v0, at);
- }
- out = (char) v0;
- at++;
- break;
- }
- case 0x0c: case 0x0d: {
- // 110XXXXX -- two-byte encoding
- length -= 2;
- if (length < 0) {
- return throwBadUtf8(v0, at);
- }
- int v1 = bytes.getUnsignedByte(at + 1);
- if ((v1 & 0xc0) != 0x80) {
- return throwBadUtf8(v1, at + 1);
- }
- int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f);
- if ((value != 0) && (value < 0x80)) {
- /*
- * This should have been represented with
- * one-byte encoding.
- */
- return throwBadUtf8(v1, at + 1);
- }
- out = (char) value;
- at += 2;
- break;
- }
- case 0x0e: {
- // 1110XXXX -- three-byte encoding
- length -= 3;
- if (length < 0) {
- return throwBadUtf8(v0, at);
- }
- int v1 = bytes.getUnsignedByte(at + 1);
- if ((v1 & 0xc0) != 0x80) {
- return throwBadUtf8(v1, at + 1);
- }
- int v2 = bytes.getUnsignedByte(at + 2);
- if ((v1 & 0xc0) != 0x80) {
- return throwBadUtf8(v2, at + 2);
- }
- int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) |
- (v2 & 0x3f);
- if (value < 0x800) {
- /*
- * This should have been represented with one- or
- * two-byte encoding.
- */
- return throwBadUtf8(v2, at + 2);
- }
- out = (char) value;
- at += 3;
- break;
- }
- default: {
- // 10XXXXXX, 1111XXXX -- illegal
- return throwBadUtf8(v0, at);
- }
+ if (!displayZero) {
+ // Ironic edge case: The original value was 0.
+ sb.append('0');
}
- chars[outAt] = out;
- outAt++;
+ break;
+ }
}
-
- return new String(chars, 0, outAt);
+ } else {
+ sb.append("\\u");
+ sb.append(Character.forDigit(c >> 12, 16));
+ sb.append(Character.forDigit((c >> 8) & 0x0f, 16));
+ sb.append(Character.forDigit((c >> 4) & 0x0f, 16));
+ sb.append(Character.forDigit(c & 0x0f, 16));
+ }
}
- /**
- * Helper for {@link #utf8BytesToString}, which throws the right
- * exception for a bogus utf-8 byte.
- *
- * @param value the byte value
- * @param offset the file offset
- * @return never
- * @throws IllegalArgumentException always thrown
- */
- private static String throwBadUtf8(int value, int offset) {
- throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) +
- " at offset " + Hex.u4(offset));
+ return sb.toString();
+ }
+
+ /**
+ * Gets the value as a human-oriented string, surrounded by double
+ * quotes.
+ *
+ * @return {@code non-null;} the quoted string
+ */
+ public String toQuoted() {
+ return '\"' + toHuman() + '\"';
+ }
+
+ /**
+ * Gets the value as a human-oriented string, surrounded by double
+ * quotes, but ellipsizes the result if it is longer than the given
+ * maximum length
+ *
+ * @param maxLength {@code >= 5;} the maximum length of the string to return
+ * @return {@code non-null;} the quoted string
+ */
+ public String toQuoted(int maxLength) {
+ String string = toHuman();
+ int length = string.length();
+ String ellipses;
+
+ if (length <= (maxLength - 2)) {
+ ellipses = "";
+ } else {
+ string = string.substring(0, maxLength - 5);
+ ellipses = "...";
}
- /**
- * Constructs an instance from a {@code String}.
- *
- * @param string {@code non-null;} the UTF-8 value as a string
- */
- public CstString(String string) {
- if (string == null) {
- throw new NullPointerException("string == null");
- }
+ return '\"' + string + ellipses + '\"';
+ }
- this.string = string.intern();
- this.bytes = new ByteArray(stringToUtf8Bytes(string));
- }
+ /**
+ * Gets the UTF-8 value as a string.
+ * The returned string is always already interned.
+ *
+ * @return {@code non-null;} the UTF-8 value as a string
+ */
+ public String getString() {
+ return string;
+ }
- /**
- * Constructs an instance from some UTF-8 bytes.
- *
- * @param bytes {@code non-null;} array of the UTF-8 bytes
- */
- public CstString(ByteArray bytes) {
- if (bytes == null) {
- throw new NullPointerException("bytes == null");
- }
+ /**
+ * Gets the UTF-8 value as UTF-8 encoded bytes.
+ *
+ * @return {@code non-null;} an array of the UTF-8 bytes
+ */
+ public ByteArray getBytes() {
+ return bytes;
+ }
- this.bytes = bytes;
- this.string = utf8BytesToString(bytes).intern();
- }
+ /**
+ * Gets the size of this instance as UTF-8 code points. That is,
+ * get the number of bytes in the UTF-8 encoding of this instance.
+ *
+ * @return {@code >= 0;} the UTF-8 size
+ */
+ public int getUtf8Size() {
+ return bytes.size();
+ }
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof CstString)) {
- return false;
- }
+ /**
+ * Gets the size of this instance as UTF-16 code points. That is,
+ * get the number of 16-bit chars in the UTF-16 encoding of this
+ * instance. This is the same as the {@code length} of the
+ * Java {@code String} representation of this instance.
+ *
+ * @return {@code >= 0;} the UTF-16 size
+ */
+ public int getUtf16Size() {
+ return string.length();
+ }
- return string.equals(((CstString) other).string);
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return string.hashCode();
- }
-
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- return string.compareTo(((CstString) other).string);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return "string{\"" + toHuman() + "\"}";
- }
-
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "utf8";
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- int len = string.length();
- StringBuilder sb = new StringBuilder(len * 3 / 2);
-
- for (int i = 0; i < len; i++) {
- char c = string.charAt(i);
- if ((c >= ' ') && (c < 0x7f)) {
- if ((c == '\'') || (c == '\"') || (c == '\\')) {
- sb.append('\\');
- }
- sb.append(c);
- } else if (c <= 0x7f) {
- switch (c) {
- case '\n': sb.append("\\n"); break;
- case '\r': sb.append("\\r"); break;
- case '\t': sb.append("\\t"); break;
- default: {
- /*
- * Represent the character as an octal escape.
- * If the next character is a valid octal
- * digit, disambiguate by using the
- * three-digit form.
- */
- char nextChar =
- (i < (len - 1)) ? string.charAt(i + 1) : 0;
- boolean displayZero =
- (nextChar >= '0') && (nextChar <= '7');
- sb.append('\\');
- for (int shift = 6; shift >= 0; shift -= 3) {
- char outChar = (char) (((c >> shift) & 7) + '0');
- if ((outChar != '0') || displayZero) {
- sb.append(outChar);
- displayZero = true;
- }
- }
- if (! displayZero) {
- // Ironic edge case: The original value was 0.
- sb.append('0');
- }
- break;
- }
- }
- } else {
- sb.append("\\u");
- sb.append(Character.forDigit(c >> 12, 16));
- sb.append(Character.forDigit((c >> 8) & 0x0f, 16));
- sb.append(Character.forDigit((c >> 4) & 0x0f, 16));
- sb.append(Character.forDigit(c & 0x0f, 16));
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Gets the value as a human-oriented string, surrounded by double
- * quotes.
- *
- * @return {@code non-null;} the quoted string
- */
- public String toQuoted() {
- return '\"' + toHuman() + '\"';
- }
-
- /**
- * Gets the value as a human-oriented string, surrounded by double
- * quotes, but ellipsizes the result if it is longer than the given
- * maximum length
- *
- * @param maxLength {@code >= 5;} the maximum length of the string to return
- * @return {@code non-null;} the quoted string
- */
- public String toQuoted(int maxLength) {
- String string = toHuman();
- int length = string.length();
- String ellipses;
-
- if (length <= (maxLength - 2)) {
- ellipses = "";
- } else {
- string = string.substring(0, maxLength - 5);
- ellipses = "...";
- }
-
- return '\"' + string + ellipses + '\"';
- }
-
- /**
- * Gets the UTF-8 value as a string.
- * The returned string is always already interned.
- *
- * @return {@code non-null;} the UTF-8 value as a string
- */
- public String getString() {
- return string;
- }
-
- /**
- * Gets the UTF-8 value as UTF-8 encoded bytes.
- *
- * @return {@code non-null;} an array of the UTF-8 bytes
- */
- public ByteArray getBytes() {
- return bytes;
- }
-
- /**
- * Gets the size of this instance as UTF-8 code points. That is,
- * get the number of bytes in the UTF-8 encoding of this instance.
- *
- * @return {@code >= 0;} the UTF-8 size
- */
- public int getUtf8Size() {
- return bytes.size();
- }
-
- /**
- * Gets the size of this instance as UTF-16 code points. That is,
- * get the number of 16-bit chars in the UTF-16 encoding of this
- * instance. This is the same as the {@code length} of the
- * Java {@code String} representation of this instance.
- *
- * @return {@code >= 0;} the UTF-16 size
- */
- public int getUtf16Size() {
- return string.length();
- }
-
- public Type getType() {
- return Type.STRING;
- }
+ @Override
+ public Type getType() {
+ return Type.STRING;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/CstType.java b/dx/src/com/android/jack/dx/rop/cst/CstType.java
index 26d5a07..4ef8ad5 100644
--- a/dx/src/com/android/jack/dx/rop/cst/CstType.java
+++ b/dx/src/com/android/jack/dx/rop/cst/CstType.java
@@ -24,227 +24,236 @@
* Constants that represent an arbitrary type (reference or primitive).
*/
public final class CstType extends TypedConstant {
- /** {@code non-null;} map of interned types */
- private static final HashMap<Type, CstType> interns =
- new HashMap<Type, CstType>(100);
+ /** {@code non-null;} map of interned types */
+ private static final HashMap<Type, CstType> interns = new HashMap<Type, CstType>(100);
- /** {@code non-null;} instance corresponding to the class {@code Object} */
- public static final CstType OBJECT = intern(Type.OBJECT);
+ /** {@code non-null;} instance corresponding to the class {@code Object} */
+ public static final CstType OBJECT = intern(Type.OBJECT);
- /** {@code non-null;} instance corresponding to the class {@code Boolean} */
- public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Boolean} */
+ public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Byte} */
- public static final CstType BYTE = intern(Type.BYTE_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Byte} */
+ public static final CstType BYTE = intern(Type.BYTE_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Character} */
- public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Character} */
+ public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Double} */
- public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Double} */
+ public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Float} */
- public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Float} */
+ public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Long} */
- public static final CstType LONG = intern(Type.LONG_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Long} */
+ public static final CstType LONG = intern(Type.LONG_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Integer} */
- public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Integer} */
+ public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Short} */
- public static final CstType SHORT = intern(Type.SHORT_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Short} */
+ public static final CstType SHORT = intern(Type.SHORT_CLASS);
- /** {@code non-null;} instance corresponding to the class {@code Void} */
- public static final CstType VOID = intern(Type.VOID_CLASS);
+ /** {@code non-null;} instance corresponding to the class {@code Void} */
+ public static final CstType VOID = intern(Type.VOID_CLASS);
- /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
- public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
+ public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code byte[]} */
- public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code byte[]} */
+ public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code char[]} */
- public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code char[]} */
+ public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code double[]} */
- public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code double[]} */
+ public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code float[]} */
- public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code float[]} */
+ public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code long[]} */
- public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code long[]} */
+ public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code int[]} */
- public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code int[]} */
+ public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
- /** {@code non-null;} instance corresponding to the type {@code short[]} */
- public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
+ /** {@code non-null;} instance corresponding to the type {@code short[]} */
+ public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
- /** {@code non-null;} the underlying type */
- private final Type type;
+ /** {@code non-null;} the underlying type */
+ private final Type type;
- /**
- * {@code null-ok;} the type descriptor corresponding to this instance, if
- * calculated
- */
- private CstString descriptor;
+ /**
+ * {@code null-ok;} the type descriptor corresponding to this instance, if
+ * calculated
+ */
+ private CstString descriptor;
- /**
- * Returns an instance of this class that represents the wrapper
- * class corresponding to a given primitive type. For example, if
- * given {@link Type#INT}, this method returns the class reference
- * {@code java.lang.Integer}.
- *
- * @param primitiveType {@code non-null;} the primitive type
- * @return {@code non-null;} the corresponding wrapper class
- */
- public static CstType forBoxedPrimitiveType(Type primitiveType) {
- switch (primitiveType.getBasicType()) {
- case Type.BT_BOOLEAN: return BOOLEAN;
- case Type.BT_BYTE: return BYTE;
- case Type.BT_CHAR: return CHARACTER;
- case Type.BT_DOUBLE: return DOUBLE;
- case Type.BT_FLOAT: return FLOAT;
- case Type.BT_INT: return INTEGER;
- case Type.BT_LONG: return LONG;
- case Type.BT_SHORT: return SHORT;
- case Type.BT_VOID: return VOID;
- }
-
- throw new IllegalArgumentException("not primitive: " + primitiveType);
+ /**
+ * Returns an instance of this class that represents the wrapper
+ * class corresponding to a given primitive type. For example, if
+ * given {@link Type#INT}, this method returns the class reference
+ * {@code java.lang.Integer}.
+ *
+ * @param primitiveType {@code non-null;} the primitive type
+ * @return {@code non-null;} the corresponding wrapper class
+ */
+ public static CstType forBoxedPrimitiveType(Type primitiveType) {
+ switch (primitiveType.getBasicType()) {
+ case Type.BT_BOOLEAN:
+ return BOOLEAN;
+ case Type.BT_BYTE:
+ return BYTE;
+ case Type.BT_CHAR:
+ return CHARACTER;
+ case Type.BT_DOUBLE:
+ return DOUBLE;
+ case Type.BT_FLOAT:
+ return FLOAT;
+ case Type.BT_INT:
+ return INTEGER;
+ case Type.BT_LONG:
+ return LONG;
+ case Type.BT_SHORT:
+ return SHORT;
+ case Type.BT_VOID:
+ return VOID;
}
- /**
- * Returns an interned instance of this class for the given type.
- *
- * @param type {@code non-null;} the underlying type
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static CstType intern(Type type) {
- synchronized (interns) {
- CstType cst = interns.get(type);
+ throw new IllegalArgumentException("not primitive: " + primitiveType);
+ }
- if (cst == null) {
- cst = new CstType(type);
- interns.put(type, cst);
- }
+ /**
+ * Returns an interned instance of this class for the given type.
+ *
+ * @param type {@code non-null;} the underlying type
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static CstType intern(Type type) {
+ synchronized (interns) {
+ CstType cst = interns.get(type);
- return cst;
- }
+ if (cst == null) {
+ cst = new CstType(type);
+ interns.put(type, cst);
+ }
+
+ return cst;
+ }
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param type {@code non-null;} the underlying type
+ */
+ public CstType(Type type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
}
- /**
- * Constructs an instance.
- *
- * @param type {@code non-null;} the underlying type
- */
- public CstType(Type type) {
- if (type == null) {
- throw new NullPointerException("type == null");
- }
-
- if (type == type.KNOWN_NULL) {
- throw new UnsupportedOperationException(
- "KNOWN_NULL is not representable");
- }
-
- this.type = type;
- this.descriptor = null;
+ if (type == Type.KNOWN_NULL) {
+ throw new UnsupportedOperationException("KNOWN_NULL is not representable");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof CstType)) {
- return false;
- }
+ this.type = type;
+ this.descriptor = null;
+ }
- return type == ((CstType) other).type;
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstType)) {
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return type.hashCode();
+ return type == ((CstType) other).type;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ String thisDescriptor = type.getDescriptor();
+ String otherDescriptor = ((CstType) other).type.getDescriptor();
+ return thisDescriptor.compareTo(otherDescriptor);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "type{" + toHuman() + '}';
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return Type.CLASS;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "type";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return type.toHuman();
+ }
+
+ /**
+ * Gets the underlying type (as opposed to the type corresponding
+ * to this instance as a constant, which is always
+ * {@code Class}).
+ *
+ * @return {@code non-null;} the type corresponding to the name
+ */
+ public Type getClassType() {
+ return type;
+ }
+
+ /**
+ * Gets the type descriptor for this instance.
+ *
+ * @return {@code non-null;} the descriptor
+ */
+ public CstString getDescriptor() {
+ if (descriptor == null) {
+ descriptor = new CstString(type.getDescriptor());
}
- /** {@inheritDoc} */
- @Override
- protected int compareTo0(Constant other) {
- String thisDescriptor = type.getDescriptor();
- String otherDescriptor = ((CstType) other).type.getDescriptor();
- return thisDescriptor.compareTo(otherDescriptor);
- }
+ return descriptor;
+ }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return "type{" + toHuman() + '}';
+ /**
+ * Returns a human readable package name for this type, like "java.util".
+ * If this is an array type, this returns the package name of the array's
+ * component type. If this is a primitive type, this returns "default".
+ */
+ public String getPackageName() {
+ // descriptor is a string like "[[Ljava/util/String;"
+ String descriptor = getDescriptor().getString();
+ int lastSlash = descriptor.lastIndexOf('/');
+ int lastLeftSquare = descriptor.lastIndexOf('['); // -1 unless this is an array
+ if (lastSlash == -1) {
+ return "default";
+ } else {
+ // +2 to skip the '[' and the 'L' prefix
+ return descriptor.substring(lastLeftSquare + 2, lastSlash).replace('/', '.');
}
-
- /** {@inheritDoc} */
- public Type getType() {
- return Type.CLASS;
- }
-
- /** {@inheritDoc} */
- @Override
- public String typeName() {
- return "type";
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isCategory2() {
- return false;
- }
-
- /** {@inheritDoc} */
- public String toHuman() {
- return type.toHuman();
- }
-
- /**
- * Gets the underlying type (as opposed to the type corresponding
- * to this instance as a constant, which is always
- * {@code Class}).
- *
- * @return {@code non-null;} the type corresponding to the name
- */
- public Type getClassType() {
- return type;
- }
-
- /**
- * Gets the type descriptor for this instance.
- *
- * @return {@code non-null;} the descriptor
- */
- public CstString getDescriptor() {
- if (descriptor == null) {
- descriptor = new CstString(type.getDescriptor());
- }
-
- return descriptor;
- }
-
- /**
- * Returns a human readable package name for this type, like "java.util".
- * If this is an array type, this returns the package name of the array's
- * component type. If this is a primitive type, this returns "default".
- */
- public String getPackageName() {
- // descriptor is a string like "[[Ljava/util/String;"
- String descriptor = getDescriptor().getString();
- int lastSlash = descriptor.lastIndexOf('/');
- int lastLeftSquare = descriptor.lastIndexOf('['); // -1 unless this is an array
- if (lastSlash == -1) {
- return "default";
- } else {
- // +2 to skip the '[' and the 'L' prefix
- return descriptor.substring(lastLeftSquare + 2, lastSlash).replace('/', '.');
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/StdConstantPool.java b/dx/src/com/android/jack/dx/rop/cst/StdConstantPool.java
index ab16a2e..3036484 100644
--- a/dx/src/com/android/jack/dx/rop/cst/StdConstantPool.java
+++ b/dx/src/com/android/jack/dx/rop/cst/StdConstantPool.java
@@ -24,116 +24,117 @@
* Standard implementation of {@link ConstantPool}, which directly stores
* an array of {@link Constant} objects and can be made immutable.
*/
-public final class StdConstantPool
- extends MutabilityControl implements ConstantPool {
- /** {@code non-null;} array of entries */
- private final Constant[] entries;
+public final class StdConstantPool extends MutabilityControl implements ConstantPool {
+ /** {@code non-null;} array of entries */
+ private final Constant[] entries;
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the pool; this corresponds to the
- * class file field {@code constant_pool_count}, and is in fact
- * always at least one more than the actual size of the constant pool,
- * as element {@code 0} is always invalid.
- */
- public StdConstantPool(int size) {
- super(size > 1);
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the pool; this corresponds to the
+ * class file field {@code constant_pool_count}, and is in fact
+ * always at least one more than the actual size of the constant pool,
+ * as element {@code 0} is always invalid.
+ */
+ public StdConstantPool(int size) {
+ super(size > 1);
- if (size < 1) {
- throw new IllegalArgumentException("size < 1");
- }
-
- entries = new Constant[size];
+ if (size < 1) {
+ throw new IllegalArgumentException("size < 1");
}
- /** {@inheritDoc} */
- public int size() {
- return entries.length;
+ entries = new Constant[size];
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int size() {
+ return entries.length;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Constant getOrNull(int n) {
+ try {
+ return entries[n];
+ } catch (IndexOutOfBoundsException ex) {
+ // Translate the exception.
+ return throwInvalid(n);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Constant get0Ok(int n) {
+ if (n == 0) {
+ return null;
}
- /** {@inheritDoc} */
- public Constant getOrNull(int n) {
- try {
- return entries[n];
- } catch (IndexOutOfBoundsException ex) {
- // Translate the exception.
- return throwInvalid(n);
- }
+ return get(n);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Constant get(int n) {
+ try {
+ Constant result = entries[n];
+
+ if (result == null) {
+ throwInvalid(n);
+ }
+
+ return result;
+ } catch (IndexOutOfBoundsException ex) {
+ // Translate the exception.
+ return throwInvalid(n);
+ }
+ }
+
+ /**
+ * Sets the entry at the given index.
+ *
+ * @param n {@code >= 1, < size();} which entry
+ * @param cst {@code null-ok;} the constant to store
+ */
+ public void set(int n, Constant cst) {
+ throwIfImmutable();
+
+ boolean cat2 = (cst != null) && cst.isCategory2();
+
+ if (n < 1) {
+ throw new IllegalArgumentException("n < 1");
}
- /** {@inheritDoc} */
- public Constant get0Ok(int n) {
- if (n == 0) {
- return null;
- }
-
- return get(n);
+ if (cat2) {
+ // Storing a category-2 entry nulls out the next index.
+ if (n == (entries.length - 1)) {
+ throw new IllegalArgumentException("(n == size - 1) && " + "cst.isCategory2()");
+ }
+ entries[n + 1] = null;
}
- /** {@inheritDoc} */
- public Constant get(int n) {
- try {
- Constant result = entries[n];
-
- if (result == null) {
- throwInvalid(n);
- }
-
- return result;
- } catch (IndexOutOfBoundsException ex) {
- // Translate the exception.
- return throwInvalid(n);
- }
+ if ((cst != null) && (entries[n] == null)) {
+ /*
+ * Overwriting the second half of a category-2 entry nulls out
+ * the first half.
+ */
+ Constant prev = entries[n - 1];
+ if ((prev != null) && prev.isCategory2()) {
+ entries[n - 1] = null;
+ }
}
- /**
- * Sets the entry at the given index.
- *
- * @param n {@code >= 1, < size();} which entry
- * @param cst {@code null-ok;} the constant to store
- */
- public void set(int n, Constant cst) {
- throwIfImmutable();
+ entries[n] = cst;
+ }
- boolean cat2 = (cst != null) && cst.isCategory2();
-
- if (n < 1) {
- throw new IllegalArgumentException("n < 1");
- }
-
- if (cat2) {
- // Storing a category-2 entry nulls out the next index.
- if (n == (entries.length - 1)) {
- throw new IllegalArgumentException("(n == size - 1) && " +
- "cst.isCategory2()");
- }
- entries[n + 1] = null;
- }
-
- if ((cst != null) && (entries[n] == null)) {
- /*
- * Overwriting the second half of a category-2 entry nulls out
- * the first half.
- */
- Constant prev = entries[n - 1];
- if ((prev != null) && prev.isCategory2()) {
- entries[n - 1] = null;
- }
- }
-
- entries[n] = cst;
- }
-
- /**
- * Throws the right exception for an invalid cpi.
- *
- * @param idx the bad cpi
- * @return never
- * @throws ExceptionWithContext always thrown
- */
- private static Constant throwInvalid(int idx) {
- throw new ExceptionWithContext("invalid constant pool index " +
- Hex.u2(idx));
- }
+ /**
+ * Throws the right exception for an invalid cpi.
+ *
+ * @param idx the bad cpi
+ * @return never
+ * @throws ExceptionWithContext always thrown
+ */
+ private static Constant throwInvalid(int idx) {
+ throw new ExceptionWithContext("invalid constant pool index " + Hex.u2(idx));
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/TypedConstant.java b/dx/src/com/android/jack/dx/rop/cst/TypedConstant.java
index b7b236e..2e44b28 100644
--- a/dx/src/com/android/jack/dx/rop/cst/TypedConstant.java
+++ b/dx/src/com/android/jack/dx/rop/cst/TypedConstant.java
@@ -21,29 +21,32 @@
/**
* Base class for constants which implement {@link TypeBearer}.
*/
-public abstract class TypedConstant
- extends Constant implements TypeBearer {
- /**
- * {@inheritDoc}
- *
- * This implementation always returns {@code this}.
- */
- public final TypeBearer getFrameType() {
- return this;
- }
+public abstract class TypedConstant extends Constant implements TypeBearer {
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation always returns {@code this}.
+ */
+ @Override
+ public final TypeBearer getFrameType() {
+ return this;
+ }
- /** {@inheritDoc} */
- public final int getBasicType() {
- return getType().getBasicType();
- }
+ /** {@inheritDoc} */
+ @Override
+ public final int getBasicType() {
+ return getType().getBasicType();
+ }
- /** {@inheritDoc} */
- public final int getBasicFrameType() {
- return getType().getBasicFrameType();
- }
+ /** {@inheritDoc} */
+ @Override
+ public final int getBasicFrameType() {
+ return getType().getBasicFrameType();
+ }
- /** {@inheritDoc} */
- public final boolean isConstant() {
- return true;
- }
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isConstant() {
+ return true;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/cst/Zeroes.java b/dx/src/com/android/jack/dx/rop/cst/Zeroes.java
index 00842cb..2550ec0 100644
--- a/dx/src/com/android/jack/dx/rop/cst/Zeroes.java
+++ b/dx/src/com/android/jack/dx/rop/cst/Zeroes.java
@@ -22,34 +22,42 @@
* Utility for turning types into zeroes.
*/
public final class Zeroes {
- /**
- * This class is uninstantiable.
- */
- private Zeroes() {
- // This space intentionally left blank.
- }
+ /**
+ * This class is uninstantiable.
+ */
+ private Zeroes() {
+ // This space intentionally left blank.
+ }
- /**
- * Gets the "zero" (or {@code null}) value for the given type.
- *
- * @param type {@code non-null;} the type in question
- * @return {@code non-null;} its "zero" value
- */
- public static Constant zeroFor(Type type) {
- switch (type.getBasicType()) {
- case Type.BT_BOOLEAN: return CstBoolean.VALUE_FALSE;
- case Type.BT_BYTE: return CstByte.VALUE_0;
- case Type.BT_CHAR: return CstChar.VALUE_0;
- case Type.BT_DOUBLE: return CstDouble.VALUE_0;
- case Type.BT_FLOAT: return CstFloat.VALUE_0;
- case Type.BT_INT: return CstInteger.VALUE_0;
- case Type.BT_LONG: return CstLong.VALUE_0;
- case Type.BT_SHORT: return CstShort.VALUE_0;
- case Type.BT_OBJECT: return CstKnownNull.THE_ONE;
- default: {
- throw new UnsupportedOperationException("no zero for type: " +
- type.toHuman());
- }
- }
+ /**
+ * Gets the "zero" (or {@code null}) value for the given type.
+ *
+ * @param type {@code non-null;} the type in question
+ * @return {@code non-null;} its "zero" value
+ */
+ public static Constant zeroFor(Type type) {
+ switch (type.getBasicType()) {
+ case Type.BT_BOOLEAN:
+ return CstBoolean.VALUE_FALSE;
+ case Type.BT_BYTE:
+ return CstByte.VALUE_0;
+ case Type.BT_CHAR:
+ return CstChar.VALUE_0;
+ case Type.BT_DOUBLE:
+ return CstDouble.VALUE_0;
+ case Type.BT_FLOAT:
+ return CstFloat.VALUE_0;
+ case Type.BT_INT:
+ return CstInteger.VALUE_0;
+ case Type.BT_LONG:
+ return CstLong.VALUE_0;
+ case Type.BT_SHORT:
+ return CstShort.VALUE_0;
+ case Type.BT_OBJECT:
+ return CstKnownNull.THE_ONE;
+ default: {
+ throw new UnsupportedOperationException("no zero for type: " + type.toHuman());
+ }
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/type/Prototype.java b/dx/src/com/android/jack/dx/rop/type/Prototype.java
index 547f1ca..ed4e46c 100644
--- a/dx/src/com/android/jack/dx/rop/type/Prototype.java
+++ b/dx/src/com/android/jack/dx/rop/type/Prototype.java
@@ -24,377 +24,374 @@
* using {@code ==}.
*/
public final class Prototype implements Comparable<Prototype> {
- /** {@code non-null;} intern table mapping string descriptors to instances */
- private static final HashMap<String, Prototype> internTable =
- new HashMap<String, Prototype>(500);
+ /** {@code non-null;} intern table mapping string descriptors to instances */
+ private static final HashMap<String, Prototype> internTable = new HashMap<String, Prototype>(500);
- /** {@code non-null;} method descriptor */
- private final String descriptor;
+ /** {@code non-null;} method descriptor */
+ private final String descriptor;
- /** {@code non-null;} return type */
- private final Type returnType;
+ /** {@code non-null;} return type */
+ private final Type returnType;
- /** {@code non-null;} list of parameter types */
- private final StdTypeList parameterTypes;
+ /** {@code non-null;} list of parameter types */
+ private final StdTypeList parameterTypes;
- /** {@code null-ok;} list of parameter frame types, if calculated */
- private StdTypeList parameterFrameTypes;
+ /** {@code null-ok;} list of parameter frame types, if calculated */
+ private StdTypeList parameterFrameTypes;
- /**
- * Returns the unique instance corresponding to the
- * given method descriptor. See vmspec-2 sec4.3.3 for details on the
- * field descriptor syntax.
- *
- * @param descriptor {@code non-null;} the descriptor
- * @return {@code non-null;} the corresponding instance
- * @throws IllegalArgumentException thrown if the descriptor has
- * invalid syntax
+ /**
+ * Returns the unique instance corresponding to the
+ * given method descriptor. See vmspec-2 sec4.3.3 for details on the
+ * field descriptor syntax.
+ *
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
+ * @throws IllegalArgumentException thrown if the descriptor has
+ * invalid syntax
+ */
+ public static Prototype intern(String descriptor) {
+ if (descriptor == null) {
+ throw new NullPointerException("descriptor == null");
+ }
+
+ Prototype result;
+ synchronized (internTable) {
+ result = internTable.get(descriptor);
+ }
+ if (result != null) {
+ return result;
+ }
+
+ Type[] params = makeParameterArray(descriptor);
+ int paramCount = 0;
+ int at = 1;
+
+ for (;;) {
+ int startAt = at;
+ char c = descriptor.charAt(at);
+ if (c == ')') {
+ at++;
+ break;
+ }
+
+ // Skip array markers.
+ while (c == '[') {
+ at++;
+ c = descriptor.charAt(at);
+ }
+
+ if (c == 'L') {
+ // It looks like the start of a class name; find the end.
+ int endAt = descriptor.indexOf(';', at);
+ if (endAt == -1) {
+ throw new IllegalArgumentException("bad descriptor");
+ }
+ at = endAt + 1;
+ } else {
+ at++;
+ }
+
+ params[paramCount] = Type.intern(descriptor.substring(startAt, at));
+ paramCount++;
+ }
+
+ Type returnType = Type.internReturnType(descriptor.substring(at));
+ StdTypeList parameterTypes = new StdTypeList(paramCount);
+
+ for (int i = 0; i < paramCount; i++) {
+ parameterTypes.set(i, params[i]);
+ }
+
+ result = new Prototype(descriptor, returnType, parameterTypes);
+ return putIntern(result);
+ }
+
+ /**
+ * Helper for {@link #intern} which returns an empty array to
+ * populate with parsed parameter types, and which also ensures
+ * that there is a '(' at the start of the descriptor and a
+ * single ')' somewhere before the end.
+ *
+ * @param descriptor {@code non-null;} the descriptor string
+ * @return {@code non-null;} array large enough to hold all parsed parameter
+ * types, but which is likely actually larger than needed
+ */
+ private static Type[] makeParameterArray(String descriptor) {
+ int length = descriptor.length();
+
+ if (descriptor.charAt(0) != '(') {
+ throw new IllegalArgumentException("bad descriptor");
+ }
+
+ /*
+ * This is a cheesy way to establish an upper bound on the
+ * number of parameters: Just count capital letters.
*/
- public static Prototype intern(String descriptor) {
- if (descriptor == null) {
- throw new NullPointerException("descriptor == null");
- }
-
- Prototype result;
- synchronized (internTable) {
- result = internTable.get(descriptor);
- }
- if (result != null) {
- return result;
- }
-
- Type[] params = makeParameterArray(descriptor);
- int paramCount = 0;
- int at = 1;
-
- for (;;) {
- int startAt = at;
- char c = descriptor.charAt(at);
- if (c == ')') {
- at++;
- break;
- }
-
- // Skip array markers.
- while (c == '[') {
- at++;
- c = descriptor.charAt(at);
- }
-
- if (c == 'L') {
- // It looks like the start of a class name; find the end.
- int endAt = descriptor.indexOf(';', at);
- if (endAt == -1) {
- throw new IllegalArgumentException("bad descriptor");
- }
- at = endAt + 1;
- } else {
- at++;
- }
-
- params[paramCount] =
- Type.intern(descriptor.substring(startAt, at));
- paramCount++;
- }
-
- Type returnType = Type.internReturnType(descriptor.substring(at));
- StdTypeList parameterTypes = new StdTypeList(paramCount);
-
- for (int i = 0; i < paramCount; i++) {
- parameterTypes.set(i, params[i]);
- }
-
- result = new Prototype(descriptor, returnType, parameterTypes);
- return putIntern(result);
+ int closeAt = 0;
+ int maxParams = 0;
+ for (int i = 1; i < length; i++) {
+ char c = descriptor.charAt(i);
+ if (c == ')') {
+ closeAt = i;
+ break;
+ }
+ if ((c >= 'A') && (c <= 'Z')) {
+ maxParams++;
+ }
}
- /**
- * Helper for {@link #intern} which returns an empty array to
- * populate with parsed parameter types, and which also ensures
- * that there is a '(' at the start of the descriptor and a
- * single ')' somewhere before the end.
- *
- * @param descriptor {@code non-null;} the descriptor string
- * @return {@code non-null;} array large enough to hold all parsed parameter
- * types, but which is likely actually larger than needed
+ if ((closeAt == 0) || (closeAt == (length - 1))) {
+ throw new IllegalArgumentException("bad descriptor");
+ }
+
+ if (descriptor.indexOf(')', closeAt + 1) != -1) {
+ throw new IllegalArgumentException("bad descriptor");
+ }
+
+ return new Type[maxParams];
+ }
+
+ /**
+ * Interns an instance, adding to the descriptor as necessary based
+ * on the given definer, name, and flags. For example, an init
+ * method has an uninitialized object of type {@code definer}
+ * as its first argument.
+ *
+ * @param descriptor {@code non-null;} the descriptor string
+ * @param definer {@code non-null;} class the method is defined on
+ * @param isStatic whether this is a static method
+ * @param isInit whether this is an init method
+ * @return {@code non-null;} the interned instance
+ */
+ public static Prototype intern(String descriptor, Type definer, boolean isStatic,
+ boolean isInit) {
+ Prototype base = intern(descriptor);
+
+ if (isStatic) {
+ return base;
+ }
+
+ if (isInit) {
+ definer = definer.asUninitialized(Integer.MAX_VALUE);
+ }
+
+ return base.withFirstParameter(definer);
+ }
+
+ /**
+ * Interns an instance which consists of the given number of
+ * {@code int}s along with the given return type
+ *
+ * @param returnType {@code non-null;} the return type
+ * @param count {@code > 0;} the number of elements in the prototype
+ * @return {@code non-null;} the interned instance
+ */
+ public static Prototype internInts(Type returnType, int count) {
+ // Make the descriptor...
+
+ StringBuffer sb = new StringBuffer(100);
+
+ sb.append('(');
+
+ for (int i = 0; i < count; i++) {
+ sb.append('I');
+ }
+
+ sb.append(')');
+ sb.append(returnType.getDescriptor());
+
+ // ...and intern it.
+ return intern(sb.toString());
+ }
+
+ /**
+ * Constructs an instance. This is a private constructor; use one
+ * of the public static methods to get instances.
+ *
+ * @param descriptor {@code non-null;} the descriptor string
+ */
+ private Prototype(String descriptor, Type returnType, StdTypeList parameterTypes) {
+ if (descriptor == null) {
+ throw new NullPointerException("descriptor == null");
+ }
+
+ if (returnType == null) {
+ throw new NullPointerException("returnType == null");
+ }
+
+ if (parameterTypes == null) {
+ throw new NullPointerException("parameterTypes == null");
+ }
+
+ this.descriptor = descriptor;
+ this.returnType = returnType;
+ this.parameterTypes = parameterTypes;
+ this.parameterFrameTypes = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ /*
+ * Since externally-visible instances are interned, this
+ * check helps weed out some easy cases.
+ */
+ return true;
+ }
+
+ if (!(other instanceof Prototype)) {
+ return false;
+ }
+
+ return descriptor.equals(((Prototype) other).descriptor);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return descriptor.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Prototype other) {
+ if (this == other) {
+ return 0;
+ }
+
+ /*
+ * The return type is the major order, and then args in order,
+ * and then the shorter list comes first (similar to string
+ * sorting).
*/
- private static Type[] makeParameterArray(String descriptor) {
- int length = descriptor.length();
- if (descriptor.charAt(0) != '(') {
- throw new IllegalArgumentException("bad descriptor");
- }
+int result = returnType.compareTo(other.returnType);
- /*
- * This is a cheesy way to establish an upper bound on the
- * number of parameters: Just count capital letters.
- */
- int closeAt = 0;
- int maxParams = 0;
- for (int i = 1; i < length; i++) {
- char c = descriptor.charAt(i);
- if (c == ')') {
- closeAt = i;
- break;
- }
- if ((c >= 'A') && (c <= 'Z')) {
- maxParams++;
- }
- }
-
- if ((closeAt == 0) || (closeAt == (length - 1))) {
- throw new IllegalArgumentException("bad descriptor");
- }
-
- if (descriptor.indexOf(')', closeAt + 1) != -1) {
- throw new IllegalArgumentException("bad descriptor");
- }
-
- return new Type[maxParams];
+ if (result != 0) {
+ return result;
}
- /**
- * Interns an instance, adding to the descriptor as necessary based
- * on the given definer, name, and flags. For example, an init
- * method has an uninitialized object of type {@code definer}
- * as its first argument.
- *
- * @param descriptor {@code non-null;} the descriptor string
- * @param definer {@code non-null;} class the method is defined on
- * @param isStatic whether this is a static method
- * @param isInit whether this is an init method
- * @return {@code non-null;} the interned instance
- */
- public static Prototype intern(String descriptor, Type definer,
- boolean isStatic, boolean isInit) {
- Prototype base = intern(descriptor);
+ int thisSize = parameterTypes.size();
+ int otherSize = other.parameterTypes.size();
+ int size = Math.min(thisSize, otherSize);
- if (isStatic) {
- return base;
- }
+ for (int i = 0; i < size; i++) {
+ Type thisType = parameterTypes.get(i);
+ Type otherType = other.parameterTypes.get(i);
- if (isInit) {
- definer = definer.asUninitialized(Integer.MAX_VALUE);
- }
+ result = thisType.compareTo(otherType);
- return base.withFirstParameter(definer);
+ if (result != 0) {
+ return result;
+ }
}
- /**
- * Interns an instance which consists of the given number of
- * {@code int}s along with the given return type
- *
- * @param returnType {@code non-null;} the return type
- * @param count {@code > 0;} the number of elements in the prototype
- * @return {@code non-null;} the interned instance
- */
- public static Prototype internInts(Type returnType, int count) {
- // Make the descriptor...
+ if (thisSize < otherSize) {
+ return -1;
+ } else if (thisSize > otherSize) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
- StringBuffer sb = new StringBuffer(100);
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return descriptor;
+ }
- sb.append('(');
+ /**
+ * Gets the descriptor string.
+ *
+ * @return {@code non-null;} the descriptor
+ */
+ public String getDescriptor() {
+ return descriptor;
+ }
- for (int i = 0; i < count; i++) {
- sb.append('I');
+ /**
+ * Gets the return type.
+ *
+ * @return {@code non-null;} the return type
+ */
+ public Type getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * Gets the list of parameter types.
+ *
+ * @return {@code non-null;} the list of parameter types
+ */
+ public StdTypeList getParameterTypes() {
+ return parameterTypes;
+ }
+
+ /**
+ * Gets the list of frame types corresponding to the list of parameter
+ * types. The difference between the two lists (if any) is that all
+ * "intlike" types (see {@link Type#isIntlike}) are replaced by
+ * {@link Type#INT}.
+ *
+ * @return {@code non-null;} the list of parameter frame types
+ */
+ public StdTypeList getParameterFrameTypes() {
+ if (parameterFrameTypes == null) {
+ int sz = parameterTypes.size();
+ StdTypeList list = new StdTypeList(sz);
+ boolean any = false;
+ for (int i = 0; i < sz; i++) {
+ Type one = parameterTypes.get(i);
+ if (one.isIntlike()) {
+ any = true;
+ one = Type.INT;
}
-
- sb.append(')');
- sb.append(returnType.getDescriptor());
-
- // ...and intern it.
- return intern(sb.toString());
+ list.set(i, one);
+ }
+ parameterFrameTypes = any ? list : parameterTypes;
}
- /**
- * Constructs an instance. This is a private constructor; use one
- * of the public static methods to get instances.
- *
- * @param descriptor {@code non-null;} the descriptor string
- */
- private Prototype(String descriptor, Type returnType,
- StdTypeList parameterTypes) {
- if (descriptor == null) {
- throw new NullPointerException("descriptor == null");
- }
+ return parameterFrameTypes;
+ }
- if (returnType == null) {
- throw new NullPointerException("returnType == null");
- }
+ /**
+ * Returns a new interned instance, which is the same as this instance,
+ * except that it has an additional parameter prepended to the original's
+ * argument list.
+ *
+ * @param param {@code non-null;} the new first parameter
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public Prototype withFirstParameter(Type param) {
+ String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
+ StdTypeList newParams = parameterTypes.withFirst(param);
- if (parameterTypes == null) {
- throw new NullPointerException("parameterTypes == null");
- }
+ newParams.setImmutable();
- this.descriptor = descriptor;
- this.returnType = returnType;
- this.parameterTypes = parameterTypes;
- this.parameterFrameTypes = null;
+ Prototype result = new Prototype(newDesc, returnType, newParams);
+
+ return putIntern(result);
+ }
+
+ /**
+ * Puts the given instance in the intern table if it's not already
+ * there. If a conflicting value is already in the table, then leave it.
+ * Return the interned value.
+ *
+ * @param desc {@code non-null;} instance to make interned
+ * @return {@code non-null;} the actual interned object
+ */
+ private static Prototype putIntern(Prototype desc) {
+ synchronized (internTable) {
+ String descriptor = desc.getDescriptor();
+ Prototype already = internTable.get(descriptor);
+ if (already != null) {
+ return already;
+ }
+ internTable.put(descriptor, desc);
+ return desc;
}
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- /*
- * Since externally-visible instances are interned, this
- * check helps weed out some easy cases.
- */
- return true;
- }
-
- if (!(other instanceof Prototype)) {
- return false;
- }
-
- return descriptor.equals(((Prototype) other).descriptor);
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return descriptor.hashCode();
- }
-
- /** {@inheritDoc} */
- public int compareTo(Prototype other) {
- if (this == other) {
- return 0;
- }
-
- /*
- * The return type is the major order, and then args in order,
- * and then the shorter list comes first (similar to string
- * sorting).
- */
-
- int result = returnType.compareTo(other.returnType);
-
- if (result != 0) {
- return result;
- }
-
- int thisSize = parameterTypes.size();
- int otherSize = other.parameterTypes.size();
- int size = Math.min(thisSize, otherSize);
-
- for (int i = 0; i < size; i++) {
- Type thisType = parameterTypes.get(i);
- Type otherType = other.parameterTypes.get(i);
-
- result = thisType.compareTo(otherType);
-
- if (result != 0) {
- return result;
- }
- }
-
- if (thisSize < otherSize) {
- return -1;
- } else if (thisSize > otherSize) {
- return 1;
- } else {
- return 0;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return descriptor;
- }
-
- /**
- * Gets the descriptor string.
- *
- * @return {@code non-null;} the descriptor
- */
- public String getDescriptor() {
- return descriptor;
- }
-
- /**
- * Gets the return type.
- *
- * @return {@code non-null;} the return type
- */
- public Type getReturnType() {
- return returnType;
- }
-
- /**
- * Gets the list of parameter types.
- *
- * @return {@code non-null;} the list of parameter types
- */
- public StdTypeList getParameterTypes() {
- return parameterTypes;
- }
-
- /**
- * Gets the list of frame types corresponding to the list of parameter
- * types. The difference between the two lists (if any) is that all
- * "intlike" types (see {@link Type#isIntlike}) are replaced by
- * {@link Type#INT}.
- *
- * @return {@code non-null;} the list of parameter frame types
- */
- public StdTypeList getParameterFrameTypes() {
- if (parameterFrameTypes == null) {
- int sz = parameterTypes.size();
- StdTypeList list = new StdTypeList(sz);
- boolean any = false;
- for (int i = 0; i < sz; i++) {
- Type one = parameterTypes.get(i);
- if (one.isIntlike()) {
- any = true;
- one = Type.INT;
- }
- list.set(i, one);
- }
- parameterFrameTypes = any ? list : parameterTypes;
- }
-
- return parameterFrameTypes;
- }
-
- /**
- * Returns a new interned instance, which is the same as this instance,
- * except that it has an additional parameter prepended to the original's
- * argument list.
- *
- * @param param {@code non-null;} the new first parameter
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public Prototype withFirstParameter(Type param) {
- String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
- StdTypeList newParams = parameterTypes.withFirst(param);
-
- newParams.setImmutable();
-
- Prototype result =
- new Prototype(newDesc, returnType, newParams);
-
- return putIntern(result);
- }
-
- /**
- * Puts the given instance in the intern table if it's not already
- * there. If a conflicting value is already in the table, then leave it.
- * Return the interned value.
- *
- * @param desc {@code non-null;} instance to make interned
- * @return {@code non-null;} the actual interned object
- */
- private static Prototype putIntern(Prototype desc) {
- synchronized (internTable) {
- String descriptor = desc.getDescriptor();
- Prototype already = internTable.get(descriptor);
- if (already != null) {
- return already;
- }
- internTable.put(descriptor, desc);
- return desc;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/type/StdTypeList.java b/dx/src/com/android/jack/dx/rop/type/StdTypeList.java
index fe8242e..c4b5c4a 100644
--- a/dx/src/com/android/jack/dx/rop/type/StdTypeList.java
+++ b/dx/src/com/android/jack/dx/rop/type/StdTypeList.java
@@ -21,387 +21,367 @@
/**
* Standard implementation of {@link TypeList}.
*/
-public final class StdTypeList
- extends FixedSizeList implements TypeList {
- /** {@code non-null;} no-element instance */
- public static final StdTypeList EMPTY = new StdTypeList(0);
+public final class StdTypeList extends FixedSizeList implements TypeList {
+ /** {@code non-null;} no-element instance */
+ public static final StdTypeList EMPTY = new StdTypeList(0);
- /** {@code non-null;} the list {@code [int]} */
- public static final StdTypeList INT = StdTypeList.make(Type.INT);
+ /** {@code non-null;} the list {@code [int]} */
+ public static final StdTypeList INT = StdTypeList.make(Type.INT);
- /** {@code non-null;} the list {@code [long]} */
- public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
+ /** {@code non-null;} the list {@code [long]} */
+ public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
- /** {@code non-null;} the list {@code [float]} */
- public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
+ /** {@code non-null;} the list {@code [float]} */
+ public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
- /** {@code non-null;} the list {@code [double]} */
- public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
+ /** {@code non-null;} the list {@code [double]} */
+ public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
- /** {@code non-null;} the list {@code [Object]} */
- public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
+ /** {@code non-null;} the list {@code [Object]} */
+ public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
- /** {@code non-null;} the list {@code [ReturnAddress]} */
- public static final StdTypeList RETURN_ADDRESS
- = StdTypeList.make(Type.RETURN_ADDRESS);
+ /** {@code non-null;} the list {@code [ReturnAddress]} */
+ public static final StdTypeList RETURN_ADDRESS = StdTypeList.make(Type.RETURN_ADDRESS);
- /** {@code non-null;} the list {@code [Throwable]} */
- public static final StdTypeList THROWABLE =
- StdTypeList.make(Type.THROWABLE);
+ /** {@code non-null;} the list {@code [Throwable]} */
+ public static final StdTypeList THROWABLE = StdTypeList.make(Type.THROWABLE);
- /** {@code non-null;} the list {@code [int, int]} */
- public static final StdTypeList INT_INT =
- StdTypeList.make(Type.INT, Type.INT);
+ /** {@code non-null;} the list {@code [int, int]} */
+ public static final StdTypeList INT_INT = StdTypeList.make(Type.INT, Type.INT);
- /** {@code non-null;} the list {@code [long, long]} */
- public static final StdTypeList LONG_LONG =
- StdTypeList.make(Type.LONG, Type.LONG);
+ /** {@code non-null;} the list {@code [long, long]} */
+ public static final StdTypeList LONG_LONG = StdTypeList.make(Type.LONG, Type.LONG);
- /** {@code non-null;} the list {@code [float, float]} */
- public static final StdTypeList FLOAT_FLOAT =
- StdTypeList.make(Type.FLOAT, Type.FLOAT);
+ /** {@code non-null;} the list {@code [float, float]} */
+ public static final StdTypeList FLOAT_FLOAT = StdTypeList.make(Type.FLOAT, Type.FLOAT);
- /** {@code non-null;} the list {@code [double, double]} */
- public static final StdTypeList DOUBLE_DOUBLE =
- StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
+ /** {@code non-null;} the list {@code [double, double]} */
+ public static final StdTypeList DOUBLE_DOUBLE = StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
- /** {@code non-null;} the list {@code [Object, Object]} */
- public static final StdTypeList OBJECT_OBJECT =
- StdTypeList.make(Type.OBJECT, Type.OBJECT);
+ /** {@code non-null;} the list {@code [Object, Object]} */
+ public static final StdTypeList OBJECT_OBJECT = StdTypeList.make(Type.OBJECT, Type.OBJECT);
- /** {@code non-null;} the list {@code [int, Object]} */
- public static final StdTypeList INT_OBJECT =
- StdTypeList.make(Type.INT, Type.OBJECT);
+ /** {@code non-null;} the list {@code [int, Object]} */
+ public static final StdTypeList INT_OBJECT = StdTypeList.make(Type.INT, Type.OBJECT);
- /** {@code non-null;} the list {@code [long, Object]} */
- public static final StdTypeList LONG_OBJECT =
- StdTypeList.make(Type.LONG, Type.OBJECT);
+ /** {@code non-null;} the list {@code [long, Object]} */
+ public static final StdTypeList LONG_OBJECT = StdTypeList.make(Type.LONG, Type.OBJECT);
- /** {@code non-null;} the list {@code [float, Object]} */
- public static final StdTypeList FLOAT_OBJECT =
- StdTypeList.make(Type.FLOAT, Type.OBJECT);
+ /** {@code non-null;} the list {@code [float, Object]} */
+ public static final StdTypeList FLOAT_OBJECT = StdTypeList.make(Type.FLOAT, Type.OBJECT);
- /** {@code non-null;} the list {@code [double, Object]} */
- public static final StdTypeList DOUBLE_OBJECT =
- StdTypeList.make(Type.DOUBLE, Type.OBJECT);
+ /** {@code non-null;} the list {@code [double, Object]} */
+ public static final StdTypeList DOUBLE_OBJECT = StdTypeList.make(Type.DOUBLE, Type.OBJECT);
- /** {@code non-null;} the list {@code [long, int]} */
- public static final StdTypeList LONG_INT =
- StdTypeList.make(Type.LONG, Type.INT);
+ /** {@code non-null;} the list {@code [long, int]} */
+ public static final StdTypeList LONG_INT = StdTypeList.make(Type.LONG, Type.INT);
- /** {@code non-null;} the list {@code [int[], int]} */
- public static final StdTypeList INTARR_INT =
- StdTypeList.make(Type.INT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int[], int]} */
+ public static final StdTypeList INTARR_INT = StdTypeList.make(Type.INT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [long[], int]} */
- public static final StdTypeList LONGARR_INT =
- StdTypeList.make(Type.LONG_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [long[], int]} */
+ public static final StdTypeList LONGARR_INT = StdTypeList.make(Type.LONG_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [float[], int]} */
- public static final StdTypeList FLOATARR_INT =
- StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [float[], int]} */
+ public static final StdTypeList FLOATARR_INT = StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [double[], int]} */
- public static final StdTypeList DOUBLEARR_INT =
- StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [double[], int]} */
+ public static final StdTypeList DOUBLEARR_INT = StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [Object[], int]} */
- public static final StdTypeList OBJECTARR_INT =
- StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [Object[], int]} */
+ public static final StdTypeList OBJECTARR_INT = StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [boolean[], int]} */
- public static final StdTypeList BOOLEANARR_INT =
- StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [boolean[], int]} */
+ public static final StdTypeList BOOLEANARR_INT = StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [byte[], int]} */
- public static final StdTypeList BYTEARR_INT =
- StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [byte[], int]} */
+ public static final StdTypeList BYTEARR_INT = StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [char[], int]} */
- public static final StdTypeList CHARARR_INT =
- StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [char[], int]} */
+ public static final StdTypeList CHARARR_INT = StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [short[], int]} */
- public static final StdTypeList SHORTARR_INT =
- StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [short[], int]} */
+ public static final StdTypeList SHORTARR_INT = StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [int, int[], int]} */
- public static final StdTypeList INT_INTARR_INT =
- StdTypeList.make(Type.INT, Type.INT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int, int[], int]} */
+ public static final StdTypeList INT_INTARR_INT =
+ StdTypeList.make(Type.INT, Type.INT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [long, long[], int]} */
- public static final StdTypeList LONG_LONGARR_INT =
- StdTypeList.make(Type.LONG, Type.LONG_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [long, long[], int]} */
+ public static final StdTypeList LONG_LONGARR_INT =
+ StdTypeList.make(Type.LONG, Type.LONG_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [float, float[], int]} */
- public static final StdTypeList FLOAT_FLOATARR_INT =
- StdTypeList.make(Type.FLOAT, Type.FLOAT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [float, float[], int]} */
+ public static final StdTypeList FLOAT_FLOATARR_INT =
+ StdTypeList.make(Type.FLOAT, Type.FLOAT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [double, double[], int]} */
- public static final StdTypeList DOUBLE_DOUBLEARR_INT =
- StdTypeList.make(Type.DOUBLE, Type.DOUBLE_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [double, double[], int]} */
+ public static final StdTypeList DOUBLE_DOUBLEARR_INT =
+ StdTypeList.make(Type.DOUBLE, Type.DOUBLE_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [Object, Object[], int]} */
- public static final StdTypeList OBJECT_OBJECTARR_INT =
- StdTypeList.make(Type.OBJECT, Type.OBJECT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [Object, Object[], int]} */
+ public static final StdTypeList OBJECT_OBJECTARR_INT =
+ StdTypeList.make(Type.OBJECT, Type.OBJECT_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [int, boolean[], int]} */
- public static final StdTypeList INT_BOOLEANARR_INT =
- StdTypeList.make(Type.INT, Type.BOOLEAN_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int, boolean[], int]} */
+ public static final StdTypeList INT_BOOLEANARR_INT =
+ StdTypeList.make(Type.INT, Type.BOOLEAN_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [int, byte[], int]} */
- public static final StdTypeList INT_BYTEARR_INT =
- StdTypeList.make(Type.INT, Type.BYTE_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int, byte[], int]} */
+ public static final StdTypeList INT_BYTEARR_INT =
+ StdTypeList.make(Type.INT, Type.BYTE_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [int, char[], int]} */
- public static final StdTypeList INT_CHARARR_INT =
- StdTypeList.make(Type.INT, Type.CHAR_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int, char[], int]} */
+ public static final StdTypeList INT_CHARARR_INT =
+ StdTypeList.make(Type.INT, Type.CHAR_ARRAY, Type.INT);
- /** {@code non-null;} the list {@code [int, short[], int]} */
- public static final StdTypeList INT_SHORTARR_INT =
- StdTypeList.make(Type.INT, Type.SHORT_ARRAY, Type.INT);
+ /** {@code non-null;} the list {@code [int, short[], int]} */
+ public static final StdTypeList INT_SHORTARR_INT =
+ StdTypeList.make(Type.INT, Type.SHORT_ARRAY, Type.INT);
- /**
- * Makes a single-element instance.
- *
- * @param type {@code non-null;} the element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static StdTypeList make(Type type) {
- StdTypeList result = new StdTypeList(1);
- result.set(0, type);
- return result;
+ /**
+ * Makes a single-element instance.
+ *
+ * @param type {@code non-null;} the element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static StdTypeList make(Type type) {
+ StdTypeList result = new StdTypeList(1);
+ result.set(0, type);
+ return result;
+ }
+
+ /**
+ * Makes a two-element instance.
+ *
+ * @param type0 {@code non-null;} the first element
+ * @param type1 {@code non-null;} the second element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static StdTypeList make(Type type0, Type type1) {
+ StdTypeList result = new StdTypeList(2);
+ result.set(0, type0);
+ result.set(1, type1);
+ return result;
+ }
+
+ /**
+ * Makes a three-element instance.
+ *
+ * @param type0 {@code non-null;} the first element
+ * @param type1 {@code non-null;} the second element
+ * @param type2 {@code non-null;} the third element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static StdTypeList make(Type type0, Type type1, Type type2) {
+ StdTypeList result = new StdTypeList(3);
+ result.set(0, type0);
+ result.set(1, type1);
+ result.set(2, type2);
+ return result;
+ }
+
+ /**
+ * Makes a four-element instance.
+ *
+ * @param type0 {@code non-null;} the first element
+ * @param type1 {@code non-null;} the second element
+ * @param type2 {@code non-null;} the third element
+ * @param type3 {@code non-null;} the fourth element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static StdTypeList make(Type type0, Type type1, Type type2, Type type3) {
+ StdTypeList result = new StdTypeList(4);
+ result.set(0, type0);
+ result.set(1, type1);
+ result.set(2, type2);
+ result.set(3, type3);
+ return result;
+ }
+
+ /**
+ * Returns the given list as a comma-separated list of human forms. This
+ * is a static method so as to work on arbitrary {@link TypeList}
+ * instances.
+ *
+ * @param list {@code non-null;} the list to convert
+ * @return {@code non-null;} the human form
+ */
+ public static String toHuman(TypeList list) {
+ int size = list.size();
+
+ if (size == 0) {
+ return "<empty>";
}
- /**
- * Makes a two-element instance.
- *
- * @param type0 {@code non-null;} the first element
- * @param type1 {@code non-null;} the second element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static StdTypeList make(Type type0, Type type1) {
- StdTypeList result = new StdTypeList(2);
- result.set(0, type0);
- result.set(1, type1);
- return result;
+ StringBuffer sb = new StringBuffer(100);
+
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(list.getType(i).toHuman());
}
- /**
- * Makes a three-element instance.
- *
- * @param type0 {@code non-null;} the first element
- * @param type1 {@code non-null;} the second element
- * @param type2 {@code non-null;} the third element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static StdTypeList make(Type type0, Type type1, Type type2) {
- StdTypeList result = new StdTypeList(3);
- result.set(0, type0);
- result.set(1, type1);
- result.set(2, type2);
- return result;
+ return sb.toString();
+ }
+
+ /**
+ * Returns a hashcode of the contents of the given list. This
+ * is a static method so as to work on arbitrary {@link TypeList}
+ * instances.
+ *
+ * @param list {@code non-null;} the list to inspect
+ * @return {@code non-null;} the hash code
+ */
+ public static int hashContents(TypeList list) {
+ int size = list.size();
+ int hash = 0;
+
+ for (int i = 0; i < size; i++) {
+ hash = (hash * 31) + list.getType(i).hashCode();
}
- /**
- * Makes a four-element instance.
- *
- * @param type0 {@code non-null;} the first element
- * @param type1 {@code non-null;} the second element
- * @param type2 {@code non-null;} the third element
- * @param type3 {@code non-null;} the fourth element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static StdTypeList make(Type type0, Type type1, Type type2,
- Type type3) {
- StdTypeList result = new StdTypeList(4);
- result.set(0, type0);
- result.set(1, type1);
- result.set(2, type2);
- result.set(3, type3);
- return result;
+ return hash;
+ }
+
+ /**
+ * Compares the contents of the given two instances for equality. This
+ * is a static method so as to work on arbitrary {@link TypeList}
+ * instances.
+ *
+ * @param list1 {@code non-null;} one list to compare
+ * @param list2 {@code non-null;} another list to compare
+ * @return whether the two lists contain corresponding equal elements
+ */
+ public static boolean equalContents(TypeList list1, TypeList list2) {
+ int size = list1.size();
+
+ if (list2.size() != size) {
+ return false;
}
- /**
- * Returns the given list as a comma-separated list of human forms. This
- * is a static method so as to work on arbitrary {@link TypeList}
- * instances.
- *
- * @param list {@code non-null;} the list to convert
- * @return {@code non-null;} the human form
- */
- public static String toHuman(TypeList list) {
- int size = list.size();
-
- if (size == 0) {
- return "<empty>";
- }
-
- StringBuffer sb = new StringBuffer(100);
-
- for (int i = 0; i < size; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(list.getType(i).toHuman());
- }
-
- return sb.toString();
+ for (int i = 0; i < size; i++) {
+ if (!list1.getType(i).equals(list2.getType(i))) {
+ return false;
+ }
}
- /**
- * Returns a hashcode of the contents of the given list. This
- * is a static method so as to work on arbitrary {@link TypeList}
- * instances.
- *
- * @param list {@code non-null;} the list to inspect
- * @return {@code non-null;} the hash code
- */
- public static int hashContents(TypeList list) {
- int size = list.size();
- int hash = 0;
+ return true;
+ }
- for (int i = 0; i < size; i++) {
- hash = (hash * 31) + list.getType(i).hashCode();
- }
+ /**
+ * Compares the contents of the given two instances for ordering. This
+ * is a static method so as to work on arbitrary {@link TypeList}
+ * instances.
+ *
+ * @param list1 {@code non-null;} one list to compare
+ * @param list2 {@code non-null;} another list to compare
+ * @return the order of the two lists
+ */
+ public static int compareContents(TypeList list1, TypeList list2) {
+ int size1 = list1.size();
+ int size2 = list2.size();
+ int size = Math.min(size1, size2);
- return hash;
+ for (int i = 0; i < size; i++) {
+ int comparison = list1.getType(i).compareTo(list2.getType(i));
+ if (comparison != 0) {
+ return comparison;
+ }
}
- /**
- * Compares the contents of the given two instances for equality. This
- * is a static method so as to work on arbitrary {@link TypeList}
- * instances.
- *
- * @param list1 {@code non-null;} one list to compare
- * @param list2 {@code non-null;} another list to compare
- * @return whether the two lists contain corresponding equal elements
- */
- public static boolean equalContents(TypeList list1, TypeList list2) {
- int size = list1.size();
+ if (size1 == size2) {
+ return 0;
+ } else if (size1 < size2) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
- if (list2.size() != size) {
- return false;
- }
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public StdTypeList(int size) {
+ super(size);
+ }
- for (int i = 0; i < size; i++) {
- if (! list1.getType(i).equals(list2.getType(i))) {
- return false;
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public Type getType(int n) {
+ return get(n);
+ }
- return true;
+ /** {@inheritDoc} */
+ @Override
+ public int getWordCount() {
+ int sz = size();
+ int result = 0;
+
+ for (int i = 0; i < sz; i++) {
+ result += get(i).getCategory();
}
- /**
- * Compares the contents of the given two instances for ordering. This
- * is a static method so as to work on arbitrary {@link TypeList}
- * instances.
- *
- * @param list1 {@code non-null;} one list to compare
- * @param list2 {@code non-null;} another list to compare
- * @return the order of the two lists
- */
- public static int compareContents(TypeList list1, TypeList list2) {
- int size1 = list1.size();
- int size2 = list2.size();
- int size = Math.min(size1, size2);
+ return result;
+ }
- for (int i = 0; i < size; i++) {
- int comparison = list1.getType(i).compareTo(list2.getType(i));
- if (comparison != 0) {
- return comparison;
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public TypeList withAddedType(Type type) {
+ int sz = size();
+ StdTypeList result = new StdTypeList(sz + 1);
- if (size1 == size2) {
- return 0;
- } else if (size1 < size2) {
- return -1;
- } else {
- return 1;
- }
+ for (int i = 0; i < sz; i++) {
+ result.set0(i, get0(i));
}
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public StdTypeList(int size) {
- super(size);
+ result.set(sz, type);
+ result.setImmutable();
+ return result;
+ }
+
+ /**
+ * Gets the indicated element. It is an error to call this with the
+ * index for an element which was never set; if you do that, this
+ * will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
+ */
+ public Type get(int n) {
+ return (Type) get0(n);
+ }
+
+ /**
+ * Sets the type at the given index.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @param type {@code non-null;} the type to store
+ */
+ public void set(int n, Type type) {
+ set0(n, type);
+ }
+
+ /**
+ * Returns a new instance, which is the same as this instance,
+ * except that it has an additional type prepended to the
+ * original.
+ *
+ * @param type {@code non-null;} the new first element
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public StdTypeList withFirst(Type type) {
+ int sz = size();
+ StdTypeList result = new StdTypeList(sz + 1);
+
+ result.set0(0, type);
+ for (int i = 0; i < sz; i++) {
+ result.set0(i + 1, getOrNull0(i));
}
- /** {@inheritDoc} */
- public Type getType(int n) {
- return get(n);
- }
-
- /** {@inheritDoc} */
- public int getWordCount() {
- int sz = size();
- int result = 0;
-
- for (int i = 0; i < sz; i++) {
- result += get(i).getCategory();
- }
-
- return result;
- }
-
- /** {@inheritDoc} */
- public TypeList withAddedType(Type type) {
- int sz = size();
- StdTypeList result = new StdTypeList(sz + 1);
-
- for (int i = 0; i < sz; i++) {
- result.set0(i, get0(i));
- }
-
- result.set(sz, type);
- result.setImmutable();
- return result;
- }
-
- /**
- * Gets the indicated element. It is an error to call this with the
- * index for an element which was never set; if you do that, this
- * will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which element
- * @return {@code non-null;} the indicated element
- */
- public Type get(int n) {
- return (Type) get0(n);
- }
-
- /**
- * Sets the type at the given index.
- *
- * @param n {@code >= 0, < size();} which element
- * @param type {@code non-null;} the type to store
- */
- public void set(int n, Type type) {
- set0(n, type);
- }
-
- /**
- * Returns a new instance, which is the same as this instance,
- * except that it has an additional type prepended to the
- * original.
- *
- * @param type {@code non-null;} the new first element
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public StdTypeList withFirst(Type type) {
- int sz = size();
- StdTypeList result = new StdTypeList(sz + 1);
-
- result.set0(0, type);
- for (int i = 0; i < sz; i++) {
- result.set0(i + 1, getOrNull0(i));
- }
-
- return result;
- }
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/type/Type.java b/dx/src/com/android/jack/dx/rop/type/Type.java
index 2b8d0a8..c6ea1fd 100644
--- a/dx/src/com/android/jack/dx/rop/type/Type.java
+++ b/dx/src/com/android/jack/dx/rop/type/Type.java
@@ -27,836 +27,844 @@
* other using {@code ==}.
*/
public final class Type implements TypeBearer, Comparable<Type> {
- /**
- * {@code non-null;} intern table mapping string descriptors to
- * instances
+ /**
+ * {@code non-null;} intern table mapping string descriptors to
+ * instances
+ */
+ private static final HashMap<String, Type> internTable = new HashMap<String, Type>(500);
+
+ /** basic type constant for {@code void} */
+ public static final int BT_VOID = 0;
+
+ /** basic type constant for {@code boolean} */
+ public static final int BT_BOOLEAN = 1;
+
+ /** basic type constant for {@code byte} */
+ public static final int BT_BYTE = 2;
+
+ /** basic type constant for {@code char} */
+ public static final int BT_CHAR = 3;
+
+ /** basic type constant for {@code double} */
+ public static final int BT_DOUBLE = 4;
+
+ /** basic type constant for {@code float} */
+ public static final int BT_FLOAT = 5;
+
+ /** basic type constant for {@code int} */
+ public static final int BT_INT = 6;
+
+ /** basic type constant for {@code long} */
+ public static final int BT_LONG = 7;
+
+ /** basic type constant for {@code short} */
+ public static final int BT_SHORT = 8;
+
+ /** basic type constant for {@code Object} */
+ public static final int BT_OBJECT = 9;
+
+ /** basic type constant for a return address */
+ public static final int BT_ADDR = 10;
+
+ /** count of basic type constants */
+ public static final int BT_COUNT = 11;
+
+ /** {@code non-null;} instance representing {@code boolean} */
+ public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
+
+ /** {@code non-null;} instance representing {@code byte} */
+ public static final Type BYTE = new Type("B", BT_BYTE);
+
+ /** {@code non-null;} instance representing {@code char} */
+ public static final Type CHAR = new Type("C", BT_CHAR);
+
+ /** {@code non-null;} instance representing {@code double} */
+ public static final Type DOUBLE = new Type("D", BT_DOUBLE);
+
+ /** {@code non-null;} instance representing {@code float} */
+ public static final Type FLOAT = new Type("F", BT_FLOAT);
+
+ /** {@code non-null;} instance representing {@code int} */
+ public static final Type INT = new Type("I", BT_INT);
+
+ /** {@code non-null;} instance representing {@code long} */
+ public static final Type LONG = new Type("J", BT_LONG);
+
+ /** {@code non-null;} instance representing {@code short} */
+ public static final Type SHORT = new Type("S", BT_SHORT);
+
+ /** {@code non-null;} instance representing {@code void} */
+ public static final Type VOID = new Type("V", BT_VOID);
+
+ /** {@code non-null;} instance representing a known-{@code null} */
+ public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
+
+ /** {@code non-null;} instance representing a subroutine return address */
+ public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
+
+ static {
+ /*
+ * Put all the primitive types into the intern table. This needs
+ * to happen before the array types below get interned.
*/
- private static final HashMap<String, Type> internTable =
- new HashMap<String, Type>(500);
+ putIntern(BOOLEAN);
+ putIntern(BYTE);
+ putIntern(CHAR);
+ putIntern(DOUBLE);
+ putIntern(FLOAT);
+ putIntern(INT);
+ putIntern(LONG);
+ putIntern(SHORT);
+ /*
+ * Note: VOID isn't put in the intern table, since it's special and
+ * shouldn't be found by a normal call to intern().
+ */
+ }
- /** basic type constant for {@code void} */
- public static final int BT_VOID = 0;
+ /**
+ * {@code non-null;} instance representing
+ * {@code java.lang.annotation.Annotation}
+ */
+ public static final Type ANNOTATION = intern("Ljava/lang/annotation/Annotation;");
- /** basic type constant for {@code boolean} */
- public static final int BT_BOOLEAN = 1;
+ /** {@code non-null;} instance representing {@code java.lang.Class} */
+ public static final Type CLASS = intern("Ljava/lang/Class;");
- /** basic type constant for {@code byte} */
- public static final int BT_BYTE = 2;
+ /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
+ public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
- /** basic type constant for {@code char} */
- public static final int BT_CHAR = 3;
+ /** {@code non-null;} instance representing {@code java.lang.Object} */
+ public static final Type OBJECT = intern("Ljava/lang/Object;");
- /** basic type constant for {@code double} */
- public static final int BT_DOUBLE = 4;
+ /** {@code non-null;} instance representing {@code java.io.Serializable} */
+ public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
- /** basic type constant for {@code float} */
- public static final int BT_FLOAT = 5;
+ /** {@code non-null;} instance representing {@code java.lang.String} */
+ public static final Type STRING = intern("Ljava/lang/String;");
- /** basic type constant for {@code int} */
- public static final int BT_INT = 6;
+ /** {@code non-null;} instance representing {@code java.lang.Throwable} */
+ public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
- /** basic type constant for {@code long} */
- public static final int BT_LONG = 7;
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Boolean}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
- /** basic type constant for {@code short} */
- public static final int BT_SHORT = 8;
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Byte}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
- /** basic type constant for {@code Object} */
- public static final int BT_OBJECT = 9;
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Character}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
- /** basic type constant for a return address */
- public static final int BT_ADDR = 10;
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Double}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
- /** count of basic type constants */
- public static final int BT_COUNT = 11;
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Float}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
- /** {@code non-null;} instance representing {@code boolean} */
- public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Integer}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
- /** {@code non-null;} instance representing {@code byte} */
- public static final Type BYTE = new Type("B", BT_BYTE);
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Long}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
- /** {@code non-null;} instance representing {@code char} */
- public static final Type CHAR = new Type("C", BT_CHAR);
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Short}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
- /** {@code non-null;} instance representing {@code double} */
- public static final Type DOUBLE = new Type("D", BT_DOUBLE);
+ /**
+ * {@code non-null;} instance representing {@code java.lang.Void}; the
+ * suffix on the name helps disambiguate this from the instance
+ * representing a primitive type
+ */
+ public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
- /** {@code non-null;} instance representing {@code float} */
- public static final Type FLOAT = new Type("F", BT_FLOAT);
+ /** {@code non-null;} instance representing {@code boolean[]} */
+ public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
- /** {@code non-null;} instance representing {@code int} */
- public static final Type INT = new Type("I", BT_INT);
+ /** {@code non-null;} instance representing {@code byte[]} */
+ public static final Type BYTE_ARRAY = BYTE.getArrayType();
- /** {@code non-null;} instance representing {@code long} */
- public static final Type LONG = new Type("J", BT_LONG);
+ /** {@code non-null;} instance representing {@code char[]} */
+ public static final Type CHAR_ARRAY = CHAR.getArrayType();
- /** {@code non-null;} instance representing {@code short} */
- public static final Type SHORT = new Type("S", BT_SHORT);
+ /** {@code non-null;} instance representing {@code double[]} */
+ public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
- /** {@code non-null;} instance representing {@code void} */
- public static final Type VOID = new Type("V", BT_VOID);
+ /** {@code non-null;} instance representing {@code float[]} */
+ public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
- /** {@code non-null;} instance representing a known-{@code null} */
- public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
+ /** {@code non-null;} instance representing {@code int[]} */
+ public static final Type INT_ARRAY = INT.getArrayType();
- /** {@code non-null;} instance representing a subroutine return address */
- public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
+ /** {@code non-null;} instance representing {@code long[]} */
+ public static final Type LONG_ARRAY = LONG.getArrayType();
- static {
- /*
- * Put all the primitive types into the intern table. This needs
- * to happen before the array types below get interned.
- */
- putIntern(BOOLEAN);
- putIntern(BYTE);
- putIntern(CHAR);
- putIntern(DOUBLE);
- putIntern(FLOAT);
- putIntern(INT);
- putIntern(LONG);
- putIntern(SHORT);
- /*
- * Note: VOID isn't put in the intern table, since it's special and
- * shouldn't be found by a normal call to intern().
- */
+ /** {@code non-null;} instance representing {@code Object[]} */
+ public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
+
+ /** {@code non-null;} instance representing {@code short[]} */
+ public static final Type SHORT_ARRAY = SHORT.getArrayType();
+
+ /** {@code non-null;} field descriptor for the type */
+ private final String descriptor;
+
+ /**
+ * basic type corresponding to this type; one of the
+ * {@code BT_*} constants
+ */
+ private final int basicType;
+
+ /**
+ * {@code >= -1;} for an uninitialized type, bytecode index that this
+ * instance was allocated at; {@code Integer.MAX_VALUE} if it
+ * was an incoming uninitialized instance; {@code -1} if this
+ * is an <i>inititialized</i> instance
+ */
+ private final int newAt;
+
+ /**
+ * {@code null-ok;} the internal-form class name corresponding to
+ * this type, if calculated; only valid if {@code this} is a
+ * reference type and additionally not a return address
+ */
+ private String className;
+
+ /**
+ * {@code null-ok;} the type corresponding to an array of this type, if
+ * calculated
+ */
+ private Type arrayType;
+
+ /**
+ * {@code null-ok;} the type corresponding to elements of this type, if
+ * calculated; only valid if {@code this} is an array type
+ */
+ private Type componentType;
+
+ /**
+ * {@code null-ok;} the type corresponding to the initialized version of
+ * this type, if this instance is in fact an uninitialized type
+ */
+ private Type initializedType;
+
+ /**
+ * Returns the unique instance corresponding to the type with the
+ * given descriptor. See vmspec-2 sec4.3.2 for details on the
+ * field descriptor syntax. This method does <i>not</i> allow
+ * {@code "V"} (that is, type {@code void}) as a valid
+ * descriptor.
+ *
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
+ * @throws IllegalArgumentException thrown if the descriptor has
+ * invalid syntax
+ */
+ public static Type intern(String descriptor) {
+ Type result;
+ synchronized (internTable) {
+ result = internTable.get(descriptor);
+ }
+ if (result != null) {
+ return result;
}
- /**
- * {@code non-null;} instance representing
- * {@code java.lang.annotation.Annotation}
+ char firstChar;
+ try {
+ firstChar = descriptor.charAt(0);
+ } catch (IndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("descriptor is empty");
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("descriptor == null");
+ }
+
+ if (firstChar == '[') {
+ /*
+ * Recursively strip away array markers to get at the underlying
+ * type, and build back on to form the result.
+ */
+ result = intern(descriptor.substring(1));
+ return result.getArrayType();
+ }
+
+ /*
+ * If the first character isn't '[' and it wasn't found in the
+ * intern cache, then it had better be the descriptor for a class.
*/
- public static final Type ANNOTATION =
- intern("Ljava/lang/annotation/Annotation;");
- /** {@code non-null;} instance representing {@code java.lang.Class} */
- public static final Type CLASS = intern("Ljava/lang/Class;");
+int length = descriptor.length();
+ if ((firstChar != 'L') || (descriptor.charAt(length - 1) != ';')) {
+ throw new IllegalArgumentException("bad descriptor: " + descriptor);
+ }
- /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
- public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
-
- /** {@code non-null;} instance representing {@code java.lang.Object} */
- public static final Type OBJECT = intern("Ljava/lang/Object;");
-
- /** {@code non-null;} instance representing {@code java.io.Serializable} */
- public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
-
- /** {@code non-null;} instance representing {@code java.lang.String} */
- public static final Type STRING = intern("Ljava/lang/String;");
-
- /** {@code non-null;} instance representing {@code java.lang.Throwable} */
- public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Boolean}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
+ /*
+ * Validate the characters of the class name itself. Note that
+ * vmspec-2 does not have a coherent definition for valid
+ * internal-form class names, and the definition here is fairly
+ * liberal: A name is considered valid as long as it doesn't
+ * contain any of '[' ';' '.' '(' ')', and it has no more than one
+ * '/' in a row, and no '/' at either end.
*/
- public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
- /**
- * {@code non-null;} instance representing {@code java.lang.Byte}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Character}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Double}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Float}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Integer}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Long}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Short}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
-
- /**
- * {@code non-null;} instance representing {@code java.lang.Void}; the
- * suffix on the name helps disambiguate this from the instance
- * representing a primitive type
- */
- public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
-
- /** {@code non-null;} instance representing {@code boolean[]} */
- public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
-
- /** {@code non-null;} instance representing {@code byte[]} */
- public static final Type BYTE_ARRAY = BYTE.getArrayType();
-
- /** {@code non-null;} instance representing {@code char[]} */
- public static final Type CHAR_ARRAY = CHAR.getArrayType();
-
- /** {@code non-null;} instance representing {@code double[]} */
- public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
-
- /** {@code non-null;} instance representing {@code float[]} */
- public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
-
- /** {@code non-null;} instance representing {@code int[]} */
- public static final Type INT_ARRAY = INT.getArrayType();
-
- /** {@code non-null;} instance representing {@code long[]} */
- public static final Type LONG_ARRAY = LONG.getArrayType();
-
- /** {@code non-null;} instance representing {@code Object[]} */
- public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
-
- /** {@code non-null;} instance representing {@code short[]} */
- public static final Type SHORT_ARRAY = SHORT.getArrayType();
-
- /** {@code non-null;} field descriptor for the type */
- private final String descriptor;
-
- /**
- * basic type corresponding to this type; one of the
- * {@code BT_*} constants
- */
- private final int basicType;
-
- /**
- * {@code >= -1;} for an uninitialized type, bytecode index that this
- * instance was allocated at; {@code Integer.MAX_VALUE} if it
- * was an incoming uninitialized instance; {@code -1} if this
- * is an <i>inititialized</i> instance
- */
- private final int newAt;
-
- /**
- * {@code null-ok;} the internal-form class name corresponding to
- * this type, if calculated; only valid if {@code this} is a
- * reference type and additionally not a return address
- */
- private String className;
-
- /**
- * {@code null-ok;} the type corresponding to an array of this type, if
- * calculated
- */
- private Type arrayType;
-
- /**
- * {@code null-ok;} the type corresponding to elements of this type, if
- * calculated; only valid if {@code this} is an array type
- */
- private Type componentType;
-
- /**
- * {@code null-ok;} the type corresponding to the initialized version of
- * this type, if this instance is in fact an uninitialized type
- */
- private Type initializedType;
-
- /**
- * Returns the unique instance corresponding to the type with the
- * given descriptor. See vmspec-2 sec4.3.2 for details on the
- * field descriptor syntax. This method does <i>not</i> allow
- * {@code "V"} (that is, type {@code void}) as a valid
- * descriptor.
- *
- * @param descriptor {@code non-null;} the descriptor
- * @return {@code non-null;} the corresponding instance
- * @throws IllegalArgumentException thrown if the descriptor has
- * invalid syntax
- */
- public static Type intern(String descriptor) {
- Type result;
- synchronized (internTable) {
- result = internTable.get(descriptor);
+int limit = (length - 1); // Skip the final ';'.
+ for (int i = 1; i < limit; i++) {
+ char c = descriptor.charAt(i);
+ switch (c) {
+ case '[':
+ case ';':
+ case '.':
+ case '(':
+ case ')': {
+ throw new IllegalArgumentException("bad descriptor: " + descriptor);
}
- if (result != null) {
- return result;
- }
-
- char firstChar;
- try {
- firstChar = descriptor.charAt(0);
- } catch (IndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("descriptor is empty");
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("descriptor == null");
- }
-
- if (firstChar == '[') {
- /*
- * Recursively strip away array markers to get at the underlying
- * type, and build back on to form the result.
- */
- result = intern(descriptor.substring(1));
- return result.getArrayType();
- }
-
- /*
- * If the first character isn't '[' and it wasn't found in the
- * intern cache, then it had better be the descriptor for a class.
- */
-
- int length = descriptor.length();
- if ((firstChar != 'L') ||
- (descriptor.charAt(length - 1) != ';')) {
+ case '/': {
+ if ((i == 1) || (i == (length - 1)) || (descriptor.charAt(i - 1) == '/')) {
throw new IllegalArgumentException("bad descriptor: " + descriptor);
+ }
+ break;
}
-
- /*
- * Validate the characters of the class name itself. Note that
- * vmspec-2 does not have a coherent definition for valid
- * internal-form class names, and the definition here is fairly
- * liberal: A name is considered valid as long as it doesn't
- * contain any of '[' ';' '.' '(' ')', and it has no more than one
- * '/' in a row, and no '/' at either end.
- */
-
- int limit = (length - 1); // Skip the final ';'.
- for (int i = 1; i < limit; i++) {
- char c = descriptor.charAt(i);
- switch (c) {
- case '[':
- case ';':
- case '.':
- case '(':
- case ')': {
- throw new IllegalArgumentException("bad descriptor: " + descriptor);
- }
- case '/': {
- if ((i == 1) ||
- (i == (length - 1)) ||
- (descriptor.charAt(i - 1) == '/')) {
- throw new IllegalArgumentException("bad descriptor: " + descriptor);
- }
- break;
- }
- }
- }
-
- result = new Type(descriptor, BT_OBJECT);
- return putIntern(result);
+ }
}
- /**
- * Returns the unique instance corresponding to the type with the
- * given descriptor, allowing {@code "V"} to return the type
- * for {@code void}. Other than that one caveat, this method
- * is identical to {@link #intern}.
- *
- * @param descriptor {@code non-null;} the descriptor
- * @return {@code non-null;} the corresponding instance
- * @throws IllegalArgumentException thrown if the descriptor has
- * invalid syntax
- */
- public static Type internReturnType(String descriptor) {
- try {
- if (descriptor.equals("V")) {
- // This is the one special case where void may be returned.
- return VOID;
- }
- } catch (NullPointerException ex) {
- // Elucidate the exception.
- throw new NullPointerException("descriptor == null");
- }
+ result = new Type(descriptor, BT_OBJECT);
+ return putIntern(result);
+ }
- return intern(descriptor);
+ /**
+ * Returns the unique instance corresponding to the type with the
+ * given descriptor, allowing {@code "V"} to return the type
+ * for {@code void}. Other than that one caveat, this method
+ * is identical to {@link #intern}.
+ *
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
+ * @throws IllegalArgumentException thrown if the descriptor has
+ * invalid syntax
+ */
+ public static Type internReturnType(String descriptor) {
+ try {
+ if (descriptor.equals("V")) {
+ // This is the one special case where void may be returned.
+ return VOID;
+ }
+ } catch (NullPointerException ex) {
+ // Elucidate the exception.
+ throw new NullPointerException("descriptor == null");
}
- /**
- * Returns the unique instance corresponding to the type of the
- * class with the given name. Calling this method is equivalent to
- * calling {@code intern(name)} if {@code name} begins
- * with {@code "["} and calling {@code intern("L" + name + ";")}
- * in all other cases.
- *
- * @param name {@code non-null;} the name of the class whose type
- * is desired
- * @return {@code non-null;} the corresponding type
- * @throws IllegalArgumentException thrown if the name has
- * invalid syntax
- */
- public static Type internClassName(String name) {
- if (name == null) {
- throw new NullPointerException("name == null");
- }
+ return intern(descriptor);
+ }
- if (name.startsWith("[")) {
- return intern(name);
- }
-
- return intern('L' + name + ';');
+ /**
+ * Returns the unique instance corresponding to the type of the
+ * class with the given name. Calling this method is equivalent to
+ * calling {@code intern(name)} if {@code name} begins
+ * with {@code "["} and calling {@code intern("L" + name + ";")}
+ * in all other cases.
+ *
+ * @param name {@code non-null;} the name of the class whose type
+ * is desired
+ * @return {@code non-null;} the corresponding type
+ * @throws IllegalArgumentException thrown if the name has
+ * invalid syntax
+ */
+ public static Type internClassName(String name) {
+ if (name == null) {
+ throw new NullPointerException("name == null");
}
- /**
- * Constructs an instance corresponding to an "uninitialized type."
- * This is a private constructor; use one of the public static
- * methods to get instances.
- *
- * @param descriptor {@code non-null;} the field descriptor for the type
- * @param basicType basic type corresponding to this type; one of the
- * {@code BT_*} constants
- * @param newAt {@code >= -1;} allocation bytecode index
- */
- private Type(String descriptor, int basicType, int newAt) {
- if (descriptor == null) {
- throw new NullPointerException("descriptor == null");
- }
-
- if ((basicType < 0) || (basicType >= BT_COUNT)) {
- throw new IllegalArgumentException("bad basicType");
- }
-
- if (newAt < -1) {
- throw new IllegalArgumentException("newAt < -1");
- }
-
- this.descriptor = descriptor;
- this.basicType = basicType;
- this.newAt = newAt;
- this.arrayType = null;
- this.componentType = null;
- this.initializedType = null;
+ if (name.startsWith("[")) {
+ return intern(name);
}
- /**
- * Constructs an instance corresponding to an "initialized type."
- * This is a private constructor; use one of the public static
- * methods to get instances.
- *
- * @param descriptor {@code non-null;} the field descriptor for the type
- * @param basicType basic type corresponding to this type; one of the
- * {@code BT_*} constants
- */
- private Type(String descriptor, int basicType) {
- this(descriptor, basicType, -1);
+ return intern('L' + name + ';');
+ }
+
+ /**
+ * Constructs an instance corresponding to an "uninitialized type."
+ * This is a private constructor; use one of the public static
+ * methods to get instances.
+ *
+ * @param descriptor {@code non-null;} the field descriptor for the type
+ * @param basicType basic type corresponding to this type; one of the
+ * {@code BT_*} constants
+ * @param newAt {@code >= -1;} allocation bytecode index
+ */
+ private Type(String descriptor, int basicType, int newAt) {
+ if (descriptor == null) {
+ throw new NullPointerException("descriptor == null");
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- /*
- * Since externally-visible types are interned, this check
- * helps weed out some easy cases.
- */
- return true;
- }
-
- if (!(other instanceof Type)) {
- return false;
- }
-
- return descriptor.equals(((Type) other).descriptor);
+ if ((basicType < 0) || (basicType >= BT_COUNT)) {
+ throw new IllegalArgumentException("bad basicType");
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return descriptor.hashCode();
+ if (newAt < -1) {
+ throw new IllegalArgumentException("newAt < -1");
}
- /** {@inheritDoc} */
- public int compareTo(Type other) {
- return descriptor.compareTo(other.descriptor);
+ this.descriptor = descriptor;
+ this.basicType = basicType;
+ this.newAt = newAt;
+ this.arrayType = null;
+ this.componentType = null;
+ this.initializedType = null;
+ }
+
+ /**
+ * Constructs an instance corresponding to an "initialized type."
+ * This is a private constructor; use one of the public static
+ * methods to get instances.
+ *
+ * @param descriptor {@code non-null;} the field descriptor for the type
+ * @param basicType basic type corresponding to this type; one of the
+ * {@code BT_*} constants
+ */
+ private Type(String descriptor, int basicType) {
+ this(descriptor, basicType, -1);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ /*
+ * Since externally-visible types are interned, this check
+ * helps weed out some easy cases.
+ */
+ return true;
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
+ if (!(other instanceof Type)) {
+ return false;
+ }
+
+ return descriptor.equals(((Type) other).descriptor);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return descriptor.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int compareTo(Type other) {
+ return descriptor.compareTo(other.descriptor);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return descriptor;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ switch (basicType) {
+ case BT_VOID:
+ return "void";
+ case BT_BOOLEAN:
+ return "boolean";
+ case BT_BYTE:
+ return "byte";
+ case BT_CHAR:
+ return "char";
+ case BT_DOUBLE:
+ return "double";
+ case BT_FLOAT:
+ return "float";
+ case BT_INT:
+ return "int";
+ case BT_LONG:
+ return "long";
+ case BT_SHORT:
+ return "short";
+ case BT_OBJECT:
+ break;
+ default:
return descriptor;
}
- /** {@inheritDoc} */
- public String toHuman() {
- switch (basicType) {
- case BT_VOID: return "void";
- case BT_BOOLEAN: return "boolean";
- case BT_BYTE: return "byte";
- case BT_CHAR: return "char";
- case BT_DOUBLE: return "double";
- case BT_FLOAT: return "float";
- case BT_INT: return "int";
- case BT_LONG: return "long";
- case BT_SHORT: return "short";
- case BT_OBJECT: break;
- default: return descriptor;
- }
-
- if (isArray()) {
- return getComponentType().toHuman() + "[]";
- }
-
- // Remove the "L...;" around the type and convert "/" to ".".
- return getClassName().replace("/", ".");
+ if (isArray()) {
+ return getComponentType().toHuman() + "[]";
}
- /** {@inheritDoc} */
- public Type getType() {
- return this;
+ // Remove the "L...;" around the type and convert "/" to ".".
+ return getClassName().replace("/", ".");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Type getType() {
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Type getFrameType() {
+ switch (basicType) {
+ case BT_BOOLEAN:
+ case BT_BYTE:
+ case BT_CHAR:
+ case BT_INT:
+ case BT_SHORT: {
+ return INT;
+ }
}
- /** {@inheritDoc} */
- public Type getFrameType() {
- switch (basicType) {
- case BT_BOOLEAN:
- case BT_BYTE:
- case BT_CHAR:
- case BT_INT:
- case BT_SHORT: {
- return INT;
- }
- }
+ return this;
+ }
- return this;
+ /** {@inheritDoc} */
+ @Override
+ public int getBasicType() {
+ return basicType;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getBasicFrameType() {
+ switch (basicType) {
+ case BT_BOOLEAN:
+ case BT_BYTE:
+ case BT_CHAR:
+ case BT_INT:
+ case BT_SHORT: {
+ return BT_INT;
+ }
}
- /** {@inheritDoc} */
- public int getBasicType() {
- return basicType;
+ return basicType;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isConstant() {
+ return false;
+ }
+
+ /**
+ * Gets the descriptor.
+ *
+ * @return {@code non-null;} the descriptor
+ */
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ /**
+ * Gets the name of the class this type corresponds to, in internal
+ * form. This method is only valid if this instance is for a
+ * normal reference type (that is, a reference type and
+ * additionally not a return address).
+ *
+ * @return {@code non-null;} the internal-form class name
+ */
+ public String getClassName() {
+ if (className == null) {
+ if (!isReference()) {
+ throw new IllegalArgumentException("not an object type: " + descriptor);
+ }
+
+ if (descriptor.charAt(0) == '[') {
+ className = descriptor;
+ } else {
+ className = descriptor.substring(1, descriptor.length() - 1);
+ }
}
- /** {@inheritDoc} */
- public int getBasicFrameType() {
- switch (basicType) {
- case BT_BOOLEAN:
- case BT_BYTE:
- case BT_CHAR:
- case BT_INT:
- case BT_SHORT: {
- return BT_INT;
- }
- }
+ return className;
+ }
- return basicType;
+ /**
+ * Gets the category. Most instances are category 1. {@code long}
+ * and {@code double} are the only category 2 types.
+ *
+ * @see #isCategory1
+ * @see #isCategory2
+ * @return the category
+ */
+ public int getCategory() {
+ switch (basicType) {
+ case BT_LONG:
+ case BT_DOUBLE: {
+ return 2;
+ }
}
- /** {@inheritDoc} */
- public boolean isConstant() {
+ return 1;
+ }
+
+ /**
+ * Returns whether or not this is a category 1 type.
+ *
+ * @see #getCategory
+ * @see #isCategory2
+ * @return whether or not this is a category 1 type
+ */
+ public boolean isCategory1() {
+ switch (basicType) {
+ case BT_LONG:
+ case BT_DOUBLE: {
return false;
+ }
}
- /**
- * Gets the descriptor.
- *
- * @return {@code non-null;} the descriptor
- */
- public String getDescriptor() {
- return descriptor;
- }
+ return true;
+ }
- /**
- * Gets the name of the class this type corresponds to, in internal
- * form. This method is only valid if this instance is for a
- * normal reference type (that is, a reference type and
- * additionally not a return address).
- *
- * @return {@code non-null;} the internal-form class name
- */
- public String getClassName() {
- if (className == null) {
- if (!isReference()) {
- throw new IllegalArgumentException("not an object type: " +
- descriptor);
- }
-
- if (descriptor.charAt(0) == '[') {
- className = descriptor;
- } else {
- className = descriptor.substring(1, descriptor.length() - 1);
- }
- }
-
- return className;
- }
-
- /**
- * Gets the category. Most instances are category 1. {@code long}
- * and {@code double} are the only category 2 types.
- *
- * @see #isCategory1
- * @see #isCategory2
- * @return the category
- */
- public int getCategory() {
- switch (basicType) {
- case BT_LONG:
- case BT_DOUBLE: {
- return 2;
- }
- }
-
- return 1;
- }
-
- /**
- * Returns whether or not this is a category 1 type.
- *
- * @see #getCategory
- * @see #isCategory2
- * @return whether or not this is a category 1 type
- */
- public boolean isCategory1() {
- switch (basicType) {
- case BT_LONG:
- case BT_DOUBLE: {
- return false;
- }
- }
-
+ /**
+ * Returns whether or not this is a category 2 type.
+ *
+ * @see #getCategory
+ * @see #isCategory1
+ * @return whether or not this is a category 2 type
+ */
+ public boolean isCategory2() {
+ switch (basicType) {
+ case BT_LONG:
+ case BT_DOUBLE: {
return true;
+ }
}
- /**
- * Returns whether or not this is a category 2 type.
- *
- * @see #getCategory
- * @see #isCategory1
- * @return whether or not this is a category 2 type
+ return false;
+ }
+
+ /**
+ * Gets whether this type is "intlike." An intlike type is one which, when
+ * placed on a stack or in a local, is automatically converted to an
+ * {@code int}.
+ *
+ * @return whether this type is "intlike"
+ */
+ public boolean isIntlike() {
+ switch (basicType) {
+ case BT_BOOLEAN:
+ case BT_BYTE:
+ case BT_CHAR:
+ case BT_INT:
+ case BT_SHORT: {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets whether this type is a primitive type. All types are either
+ * primitive or reference types.
+ *
+ * @return whether this type is primitive
+ */
+ public boolean isPrimitive() {
+ switch (basicType) {
+ case BT_BOOLEAN:
+ case BT_BYTE:
+ case BT_CHAR:
+ case BT_DOUBLE:
+ case BT_FLOAT:
+ case BT_INT:
+ case BT_LONG:
+ case BT_SHORT:
+ case BT_VOID: {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets whether this type is a normal reference type. A normal
+ * reference type is a reference type that is not a return
+ * address. This method is just convenient shorthand for
+ * {@code getBasicType() == Type.BT_OBJECT}.
+ *
+ * @return whether this type is a normal reference type
+ */
+ public boolean isReference() {
+ return (basicType == BT_OBJECT);
+ }
+
+ /**
+ * Gets whether this type is an array type. If this method returns
+ * {@code true}, then it is safe to use {@link #getComponentType}
+ * to determine the component type.
+ *
+ * @return whether this type is an array type
+ */
+ public boolean isArray() {
+ return (descriptor.charAt(0) == '[');
+ }
+
+ /**
+ * Gets whether this type is an array type or is a known-null, and
+ * hence is compatible with array types.
+ *
+ * @return whether this type is an array type
+ */
+ public boolean isArrayOrKnownNull() {
+ return isArray() || equals(KNOWN_NULL);
+ }
+
+ /**
+ * Gets whether this type represents an uninitialized instance. An
+ * uninitialized instance is what one gets back from the {@code new}
+ * opcode, and remains uninitialized until a valid constructor is
+ * invoked on it.
+ *
+ * @return whether this type is "uninitialized"
+ */
+ public boolean isUninitialized() {
+ return (newAt >= 0);
+ }
+
+ /**
+ * Gets the bytecode index at which this uninitialized type was
+ * allocated. This returns {@code Integer.MAX_VALUE} if this
+ * type is an uninitialized incoming parameter (i.e., the
+ * {@code this} of an {@code <init>} method) or
+ * {@code -1} if this type is in fact <i>initialized</i>.
+ *
+ * @return {@code >= -1;} the allocation bytecode index
+ */
+ public int getNewAt() {
+ return newAt;
+ }
+
+ /**
+ * Gets the initialized type corresponding to this instance, but only
+ * if this instance is in fact an uninitialized object type.
+ *
+ * @return {@code non-null;} the initialized type
+ */
+ public Type getInitializedType() {
+ if (initializedType == null) {
+ throw new IllegalArgumentException("initialized type: " + descriptor);
+ }
+
+ return initializedType;
+ }
+
+ /**
+ * Gets the type corresponding to an array of this type.
+ *
+ * @return {@code non-null;} the array type
+ */
+ public Type getArrayType() {
+ if (arrayType == null) {
+ arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
+ }
+
+ return arrayType;
+ }
+
+ /**
+ * Gets the component type of this type. This method is only valid on
+ * array types.
+ *
+ * @return {@code non-null;} the component type
+ */
+ public Type getComponentType() {
+ if (componentType == null) {
+ if (descriptor.charAt(0) != '[') {
+ throw new IllegalArgumentException("not an array type: " + descriptor);
+ }
+ componentType = intern(descriptor.substring(1));
+ }
+
+ return componentType;
+ }
+
+ /**
+ * Returns a new interned instance which is identical to this one, except
+ * it is indicated as uninitialized and allocated at the given bytecode
+ * index. This instance must be an initialized object type.
+ *
+ * @param newAt {@code >= 0;} the allocation bytecode index
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public Type asUninitialized(int newAt) {
+ if (newAt < 0) {
+ throw new IllegalArgumentException("newAt < 0");
+ }
+
+ if (!isReference()) {
+ throw new IllegalArgumentException("not a reference type: " + descriptor);
+ }
+
+ if (isUninitialized()) {
+ /*
+ * Dealing with uninitialized types as a starting point is
+ * a pain, and it's not clear that it'd ever be used, so
+ * just disallow it.
+ */
+ throw new IllegalArgumentException("already uninitialized: " + descriptor);
+ }
+
+ /*
+ * Create a new descriptor that is unique and shouldn't conflict
+ * with "normal" type descriptors
*/
- public boolean isCategory2() {
- switch (basicType) {
- case BT_LONG:
- case BT_DOUBLE: {
- return true;
- }
- }
+ String newDesc = 'N' + Hex.u2(newAt) + descriptor;
+ Type result = new Type(newDesc, BT_OBJECT, newAt);
+ result.initializedType = this;
+ return putIntern(result);
+ }
- return false;
+ /**
+ * Puts the given instance in the intern table if it's not already
+ * there. If a conflicting value is already in the table, then leave it.
+ * Return the interned value.
+ *
+ * @param type {@code non-null;} instance to make interned
+ * @return {@code non-null;} the actual interned object
+ */
+ private static Type putIntern(Type type) {
+ synchronized (internTable) {
+ String descriptor = type.getDescriptor();
+ Type already = internTable.get(descriptor);
+ if (already != null) {
+ return already;
+ }
+ internTable.put(descriptor, type);
+ return type;
}
-
- /**
- * Gets whether this type is "intlike." An intlike type is one which, when
- * placed on a stack or in a local, is automatically converted to an
- * {@code int}.
- *
- * @return whether this type is "intlike"
- */
- public boolean isIntlike() {
- switch (basicType) {
- case BT_BOOLEAN:
- case BT_BYTE:
- case BT_CHAR:
- case BT_INT:
- case BT_SHORT: {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Gets whether this type is a primitive type. All types are either
- * primitive or reference types.
- *
- * @return whether this type is primitive
- */
- public boolean isPrimitive() {
- switch (basicType) {
- case BT_BOOLEAN:
- case BT_BYTE:
- case BT_CHAR:
- case BT_DOUBLE:
- case BT_FLOAT:
- case BT_INT:
- case BT_LONG:
- case BT_SHORT:
- case BT_VOID: {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Gets whether this type is a normal reference type. A normal
- * reference type is a reference type that is not a return
- * address. This method is just convenient shorthand for
- * {@code getBasicType() == Type.BT_OBJECT}.
- *
- * @return whether this type is a normal reference type
- */
- public boolean isReference() {
- return (basicType == BT_OBJECT);
- }
-
- /**
- * Gets whether this type is an array type. If this method returns
- * {@code true}, then it is safe to use {@link #getComponentType}
- * to determine the component type.
- *
- * @return whether this type is an array type
- */
- public boolean isArray() {
- return (descriptor.charAt(0) == '[');
- }
-
- /**
- * Gets whether this type is an array type or is a known-null, and
- * hence is compatible with array types.
- *
- * @return whether this type is an array type
- */
- public boolean isArrayOrKnownNull() {
- return isArray() || equals(KNOWN_NULL);
- }
-
- /**
- * Gets whether this type represents an uninitialized instance. An
- * uninitialized instance is what one gets back from the {@code new}
- * opcode, and remains uninitialized until a valid constructor is
- * invoked on it.
- *
- * @return whether this type is "uninitialized"
- */
- public boolean isUninitialized() {
- return (newAt >= 0);
- }
-
- /**
- * Gets the bytecode index at which this uninitialized type was
- * allocated. This returns {@code Integer.MAX_VALUE} if this
- * type is an uninitialized incoming parameter (i.e., the
- * {@code this} of an {@code <init>} method) or
- * {@code -1} if this type is in fact <i>initialized</i>.
- *
- * @return {@code >= -1;} the allocation bytecode index
- */
- public int getNewAt() {
- return newAt;
- }
-
- /**
- * Gets the initialized type corresponding to this instance, but only
- * if this instance is in fact an uninitialized object type.
- *
- * @return {@code non-null;} the initialized type
- */
- public Type getInitializedType() {
- if (initializedType == null) {
- throw new IllegalArgumentException("initialized type: " +
- descriptor);
- }
-
- return initializedType;
- }
-
- /**
- * Gets the type corresponding to an array of this type.
- *
- * @return {@code non-null;} the array type
- */
- public Type getArrayType() {
- if (arrayType == null) {
- arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
- }
-
- return arrayType;
- }
-
- /**
- * Gets the component type of this type. This method is only valid on
- * array types.
- *
- * @return {@code non-null;} the component type
- */
- public Type getComponentType() {
- if (componentType == null) {
- if (descriptor.charAt(0) != '[') {
- throw new IllegalArgumentException("not an array type: " +
- descriptor);
- }
- componentType = intern(descriptor.substring(1));
- }
-
- return componentType;
- }
-
- /**
- * Returns a new interned instance which is identical to this one, except
- * it is indicated as uninitialized and allocated at the given bytecode
- * index. This instance must be an initialized object type.
- *
- * @param newAt {@code >= 0;} the allocation bytecode index
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public Type asUninitialized(int newAt) {
- if (newAt < 0) {
- throw new IllegalArgumentException("newAt < 0");
- }
-
- if (!isReference()) {
- throw new IllegalArgumentException("not a reference type: " +
- descriptor);
- }
-
- if (isUninitialized()) {
- /*
- * Dealing with uninitialized types as a starting point is
- * a pain, and it's not clear that it'd ever be used, so
- * just disallow it.
- */
- throw new IllegalArgumentException("already uninitialized: " +
- descriptor);
- }
-
- /*
- * Create a new descriptor that is unique and shouldn't conflict
- * with "normal" type descriptors
- */
- String newDesc = 'N' + Hex.u2(newAt) + descriptor;
- Type result = new Type(newDesc, BT_OBJECT, newAt);
- result.initializedType = this;
- return putIntern(result);
- }
-
- /**
- * Puts the given instance in the intern table if it's not already
- * there. If a conflicting value is already in the table, then leave it.
- * Return the interned value.
- *
- * @param type {@code non-null;} instance to make interned
- * @return {@code non-null;} the actual interned object
- */
- private static Type putIntern(Type type) {
- synchronized (internTable) {
- String descriptor = type.getDescriptor();
- Type already = internTable.get(descriptor);
- if (already != null) {
- return already;
- }
- internTable.put(descriptor, type);
- return type;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/rop/type/TypeBearer.java b/dx/src/com/android/jack/dx/rop/type/TypeBearer.java
index 012814e..448e0e9 100644
--- a/dx/src/com/android/jack/dx/rop/type/TypeBearer.java
+++ b/dx/src/com/android/jack/dx/rop/type/TypeBearer.java
@@ -21,54 +21,53 @@
/**
* Object which has an associated type, possibly itself.
*/
-public interface TypeBearer
- extends ToHuman {
- /**
- * Gets the type associated with this instance.
- *
- * @return {@code non-null;} the type
- */
- public Type getType();
+public interface TypeBearer extends ToHuman {
+ /**
+ * Gets the type associated with this instance.
+ *
+ * @return {@code non-null;} the type
+ */
+ public Type getType();
- /**
- * Gets the frame type corresponding to this type. This method returns
- * {@code this}, except if {@link Type#isIntlike} on the underlying
- * type returns {@code true} but the underlying type is not in
- * fact {@link Type#INT}, in which case this method returns an instance
- * whose underlying type <i>is</i> {@code INT}.
- *
- * @return {@code non-null;} the frame type for this instance
- */
- public TypeBearer getFrameType();
+ /**
+ * Gets the frame type corresponding to this type. This method returns
+ * {@code this}, except if {@link Type#isIntlike} on the underlying
+ * type returns {@code true} but the underlying type is not in
+ * fact {@link Type#INT}, in which case this method returns an instance
+ * whose underlying type <i>is</i> {@code INT}.
+ *
+ * @return {@code non-null;} the frame type for this instance
+ */
+ public TypeBearer getFrameType();
- /**
- * Gets the basic type corresponding to this instance.
- *
- * @return the basic type; one of the {@code BT_*} constants
- * defined by {@link Type}
- */
- public int getBasicType();
+ /**
+ * Gets the basic type corresponding to this instance.
+ *
+ * @return the basic type; one of the {@code BT_*} constants
+ * defined by {@link Type}
+ */
+ public int getBasicType();
- /**
- * Gets the basic type corresponding to this instance's frame type. This
- * is equivalent to {@code getFrameType().getBasicType()}, and
- * is the same as calling {@code getFrameType()} unless this
- * instance is an int-like type, in which case this method returns
- * {@code BT_INT}.
- *
- * @see #getBasicType
- * @see #getFrameType
- *
- * @return the basic frame type; one of the {@code BT_*} constants
- * defined by {@link Type}
- */
- public int getBasicFrameType();
+ /**
+ * Gets the basic type corresponding to this instance's frame type. This
+ * is equivalent to {@code getFrameType().getBasicType()}, and
+ * is the same as calling {@code getFrameType()} unless this
+ * instance is an int-like type, in which case this method returns
+ * {@code BT_INT}.
+ *
+ * @see #getBasicType
+ * @see #getFrameType
+ *
+ * @return the basic frame type; one of the {@code BT_*} constants
+ * defined by {@link Type}
+ */
+ public int getBasicFrameType();
- /**
- * Returns whether this instance represents a constant value.
- *
- * @return {@code true} if this instance represents a constant value
- * and {@code false} if not
- */
- public boolean isConstant();
+ /**
+ * Returns whether this instance represents a constant value.
+ *
+ * @return {@code true} if this instance represents a constant value
+ * and {@code false} if not
+ */
+ public boolean isConstant();
}
diff --git a/dx/src/com/android/jack/dx/rop/type/TypeList.java b/dx/src/com/android/jack/dx/rop/type/TypeList.java
index 825d881..48cc50a 100644
--- a/dx/src/com/android/jack/dx/rop/type/TypeList.java
+++ b/dx/src/com/android/jack/dx/rop/type/TypeList.java
@@ -20,50 +20,50 @@
* List of {@link Type} instances (or of things that contain types).
*/
public interface TypeList {
- /**
- * Returns whether this instance is mutable. Note that the
- * {@code TypeList} interface itself doesn't provide any
- * means of mutation, but that doesn't mean that there isn't an
- * extra-interface way of mutating an instance.
- *
- * @return {@code true} if this instance is mutable or
- * {@code false} if it is immutable
- */
- public boolean isMutable();
+ /**
+ * Returns whether this instance is mutable. Note that the
+ * {@code TypeList} interface itself doesn't provide any
+ * means of mutation, but that doesn't mean that there isn't an
+ * extra-interface way of mutating an instance.
+ *
+ * @return {@code true} if this instance is mutable or
+ * {@code false} if it is immutable
+ */
+ public boolean isMutable();
- /**
- * Gets the size of this list.
- *
- * @return {@code >= 0;} the size
- */
- public int size();
+ /**
+ * Gets the size of this list.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int size();
- /**
- * Gets the indicated element. It is an error to call this with the
- * index for an element which was never set; if you do that, this
- * will throw {@code NullPointerException}.
- *
- * @param n {@code >= 0, < size();} which element
- * @return {@code non-null;} the indicated element
- */
- public Type getType(int n);
+ /**
+ * Gets the indicated element. It is an error to call this with the
+ * index for an element which was never set; if you do that, this
+ * will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
+ */
+ public Type getType(int n);
- /**
- * Gets the number of 32-bit words required to hold instances of
- * all the elements of this list. This is a sum of the widths (categories)
- * of all the elements.
- *
- * @return {@code >= 0;} the required number of words
- */
- public int getWordCount();
+ /**
+ * Gets the number of 32-bit words required to hold instances of
+ * all the elements of this list. This is a sum of the widths (categories)
+ * of all the elements.
+ *
+ * @return {@code >= 0;} the required number of words
+ */
+ public int getWordCount();
- /**
- * Returns a new instance which is identical to this one, except that
- * the given item is appended to the end and it is guaranteed to be
- * immutable.
- *
- * @param type {@code non-null;} item to append
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public TypeList withAddedType(Type type);
+ /**
+ * Returns a new instance which is identical to this one, except that
+ * the given item is appended to the end and it is guaranteed to be
+ * immutable.
+ *
+ * @param type {@code non-null;} item to append
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public TypeList withAddedType(Type type);
}
diff --git a/dx/src/com/android/jack/dx/ssa/BasicRegisterMapper.java b/dx/src/com/android/jack/dx/ssa/BasicRegisterMapper.java
index f9bdb2f..7093355 100644
--- a/dx/src/com/android/jack/dx/ssa/BasicRegisterMapper.java
+++ b/dx/src/com/android/jack/dx/ssa/BasicRegisterMapper.java
@@ -17,7 +17,6 @@
package com.android.jack.dx.ssa;
import com.android.jack.dx.rop.code.RegisterSpec;
-import com.android.jack.dx.rop.code.RegisterSpecList;
import com.android.jack.dx.util.IntList;
/**
@@ -25,105 +24,105 @@
* each mapping built up individually and added via addMapping()
*/
public class BasicRegisterMapper extends RegisterMapper {
- /** indexed by old register, containing new name */
- private IntList oldToNew;
+ /** indexed by old register, containing new name */
+ private IntList oldToNew;
- /** running count of used registers in new namespace */
- private int runningCountNewRegisters;
+ /** running count of used registers in new namespace */
+ private int runningCountNewRegisters;
- /**
- * Creates a new OneToOneRegisterMapper.
- *
- * @param countOldRegisters the number of registers in the old name space
- */
- public BasicRegisterMapper(int countOldRegisters) {
- oldToNew = new IntList(countOldRegisters);
+ /**
+ * Creates a new OneToOneRegisterMapper.
+ *
+ * @param countOldRegisters the number of registers in the old name space
+ */
+ public BasicRegisterMapper(int countOldRegisters) {
+ oldToNew = new IntList(countOldRegisters);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getNewRegisterCount() {
+ return runningCountNewRegisters;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec == null) {
+ return null;
}
- /** {@inheritDoc} */
- @Override
- public int getNewRegisterCount() {
- return runningCountNewRegisters;
+ int newReg;
+ try {
+ newReg = oldToNew.get(registerSpec.getReg());
+ } catch (IndexOutOfBoundsException ex) {
+ newReg = -1;
}
- /** {@inheritDoc} */
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec == null) {
- return null;
- }
-
- int newReg;
- try {
- newReg = oldToNew.get(registerSpec.getReg());
- } catch (IndexOutOfBoundsException ex) {
- newReg = -1;
- }
-
- if (newReg < 0) {
- throw new RuntimeException("no mapping specified for register");
- }
-
- return registerSpec.withReg(newReg);
+ if (newReg < 0) {
+ throw new RuntimeException("no mapping specified for register");
}
- /**
- * Returns the new-namespace mapping for the specified
- * old-namespace register, or -1 if one exists.
- *
- * @param oldReg {@code >= 0;} old-namespace register
- * @return new-namespace register or -1 if none
- */
- public int oldToNew(int oldReg) {
- if (oldReg >= oldToNew.size()) {
- return -1;
- }
+ return registerSpec.withReg(newReg);
+ }
- return oldToNew.get(oldReg);
+ /**
+ * Returns the new-namespace mapping for the specified
+ * old-namespace register, or -1 if one exists.
+ *
+ * @param oldReg {@code >= 0;} old-namespace register
+ * @return new-namespace register or -1 if none
+ */
+ public int oldToNew(int oldReg) {
+ if (oldReg >= oldToNew.size()) {
+ return -1;
}
- /** {@inheritDoc} */
- public String toHuman() {
- StringBuilder sb = new StringBuilder();
+ return oldToNew.get(oldReg);
+ }
- sb.append("Old\tNew\n");
- int sz = oldToNew.size();
+ /** {@inheritDoc} */
+ public String toHuman() {
+ StringBuilder sb = new StringBuilder();
- for (int i = 0; i < sz; i++) {
- sb.append(i);
- sb.append('\t');
- sb.append(oldToNew.get(i));
- sb.append('\n');
- }
+ sb.append("Old\tNew\n");
+ int sz = oldToNew.size();
- sb.append("new reg count:");
-
- sb.append(runningCountNewRegisters);
- sb.append('\n');
-
- return sb.toString();
+ for (int i = 0; i < sz; i++) {
+ sb.append(i);
+ sb.append('\t');
+ sb.append(oldToNew.get(i));
+ sb.append('\n');
}
- /**
- * Adds a mapping to the mapper. If oldReg has already been mapped,
- * overwrites previous mapping with new mapping.
- *
- * @param oldReg {@code >= 0;} old register
- * @param newReg {@code >= 0;} new register
- * @param category {@code 1..2;} width of reg
- */
- public void addMapping(int oldReg, int newReg, int category) {
- if (oldReg >= oldToNew.size()) {
- // expand the array as necessary
- for (int i = oldReg - oldToNew.size(); i >= 0; i--) {
- oldToNew.add(-1);
- }
- }
+ sb.append("new reg count:");
- oldToNew.set(oldReg, newReg);
+ sb.append(runningCountNewRegisters);
+ sb.append('\n');
- if (runningCountNewRegisters < (newReg + category)) {
- runningCountNewRegisters = newReg + category;
- }
+ return sb.toString();
+ }
+
+ /**
+ * Adds a mapping to the mapper. If oldReg has already been mapped,
+ * overwrites previous mapping with new mapping.
+ *
+ * @param oldReg {@code >= 0;} old register
+ * @param newReg {@code >= 0;} new register
+ * @param category {@code 1..2;} width of reg
+ */
+ public void addMapping(int oldReg, int newReg, int category) {
+ if (oldReg >= oldToNew.size()) {
+ // expand the array as necessary
+ for (int i = oldReg - oldToNew.size(); i >= 0; i--) {
+ oldToNew.add(-1);
+ }
}
+
+ oldToNew.set(oldReg, newReg);
+
+ if (runningCountNewRegisters < (newReg + category)) {
+ runningCountNewRegisters = newReg + category;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/ConstCollector.java b/dx/src/com/android/jack/dx/ssa/ConstCollector.java
index ee12cb4..aa73c2a 100644
--- a/dx/src/com/android/jack/dx/ssa/ConstCollector.java
+++ b/dx/src/com/android/jack/dx/ssa/ConstCollector.java
@@ -45,356 +45,340 @@
* insn size by about 3%.
*/
public class ConstCollector {
- /** Maximum constants to collect per method. Puts cap on reg use */
- private static final int MAX_COLLECTED_CONSTANTS = 5;
+ /** Maximum constants to collect per method. Puts cap on reg use */
+ private static final int MAX_COLLECTED_CONSTANTS = 5;
- /**
- * Also collect string consts, although they can throw exceptions.
- * This is off now because it just doesn't seem to gain a whole lot.
- * TODO if you turn this on, you must change SsaInsn.hasSideEffect()
- * to return false for const-string insns whose exceptions are not
- * caught in the current method.
- */
- private static boolean COLLECT_STRINGS = false;
+ /**
+ * Also collect string consts, although they can throw exceptions.
+ * This is off now because it just doesn't seem to gain a whole lot.
+ * TODO(dx team) if you turn this on, you must change SsaInsn.hasSideEffect()
+ * to return false for const-string insns whose exceptions are not
+ * caught in the current method.
+ */
+ private static boolean collectStrings = false;
- /**
- * If true, allow one local var to be involved with a collected const.
- * Turned off because it mostly just inserts more moves.
- */
- private static boolean COLLECT_ONE_LOCAL = false;
+ /**
+ * If true, allow one local var to be involved with a collected const.
+ * Turned off because it mostly just inserts more moves.
+ */
+ private static final boolean COLLECT_ONE_LOCAL = false;
- /** method we're processing */
- private final SsaMethod ssaMeth;
+ /** method we're processing */
+ private final SsaMethod ssaMeth;
- /**
- * Processes a method.
- *
- * @param ssaMethod {@code non-null;} method to process
- */
- public static void process(SsaMethod ssaMethod) {
- ConstCollector cc = new ConstCollector(ssaMethod);
- cc.run();
+ /**
+ * Processes a method.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ ConstCollector cc = new ConstCollector(ssaMethod);
+ cc.run();
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
+ private ConstCollector(SsaMethod ssaMethod) {
+ this.ssaMeth = ssaMethod;
+ }
+
+ /**
+ * Applies the optimization.
+ */
+ private void run() {
+ int regSz = ssaMeth.getRegCount();
+
+ ArrayList<TypedConstant> constantList = getConstsSortedByCountUse();
+
+ int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);
+
+ SsaBasicBlock start = ssaMeth.getEntryBlock();
+
+ // Constant to new register containing the constant
+ HashMap<TypedConstant, RegisterSpec> newRegs =
+ new HashMap<TypedConstant, RegisterSpec>(toCollect);
+
+ for (int i = 0; i < toCollect; i++) {
+ TypedConstant cst = constantList.get(i);
+ RegisterSpec result = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);
+
+ Rop constRop = Rops.opConst(cst);
+
+ if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
+ start.addInsnToHead(new PlainCstInsn(Rops.opConst(cst), SourcePosition.NO_INFO, result,
+ RegisterSpecList.EMPTY, cst));
+ } else {
+ // We need two new basic blocks along with the new insn
+ SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
+ SsaBasicBlock successorBlock = entryBlock.getPrimarySuccessor();
+
+ // Insert a block containing the const insn.
+ SsaBasicBlock constBlock = entryBlock.insertNewSuccessor(successorBlock);
+
+ constBlock.replaceLastInsn(new ThrowingCstInsn(constRop, SourcePosition.NO_INFO,
+ RegisterSpecList.EMPTY, StdTypeList.EMPTY, cst));
+
+ // Insert a block containing the move-result-pseudo insn.
+
+ SsaBasicBlock resultBlock = constBlock.insertNewSuccessor(successorBlock);
+ PlainInsn insn = new PlainInsn(Rops.opMoveResultPseudo(result.getTypeBearer()),
+ SourcePosition.NO_INFO, result, RegisterSpecList.EMPTY);
+
+ resultBlock.addInsnToHead(insn);
+ }
+
+ newRegs.put(cst, result);
}
- /**
- * Constructs an instance.
- *
- * @param ssaMethod {@code non-null;} method to process
+ updateConstUses(newRegs, regSz);
+ }
+
+ /**
+ * Gets all of the collectable constant values used in this method,
+ * sorted by most used first. Skips non-collectable consts, such as
+ * non-string object constants
+ *
+ * @return {@code non-null;} list of constants in most-to-least used order
+ */
+ private ArrayList<TypedConstant> getConstsSortedByCountUse() {
+ int regSz = ssaMeth.getRegCount();
+
+ final HashMap<TypedConstant, Integer> countUses = new HashMap<TypedConstant, Integer>();
+
+ /*
+ * Each collected constant can be used by just one local
+ * (used only if COLLECT_ONE_LOCAL is true).
*/
- private ConstCollector(SsaMethod ssaMethod) {
- this.ssaMeth = ssaMethod;
- }
+ final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();
- /**
- * Applies the optimization.
- */
- private void run() {
- int regSz = ssaMeth.getRegCount();
+ // Count how many times each const value is used.
+ for (int i = 0; i < regSz; i++) {
+ SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
- ArrayList<TypedConstant> constantList
- = getConstsSortedByCountUse();
+ if (insn == null || insn.getOpcode() == null) {
+ continue;
+ }
- int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);
+ RegisterSpec result = insn.getResult();
+ TypeBearer typeBearer = result.getTypeBearer();
- SsaBasicBlock start = ssaMeth.getEntryBlock();
+ if (!typeBearer.isConstant()) {
+ continue;
+ }
- // Constant to new register containing the constant
- HashMap<TypedConstant, RegisterSpec> newRegs
- = new HashMap<TypedConstant, RegisterSpec> (toCollect);
+ TypedConstant cst = (TypedConstant) typeBearer;
- for (int i = 0; i < toCollect; i++) {
- TypedConstant cst = constantList.get(i);
- RegisterSpec result
- = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);
+ // Find defining instruction for move-result-pseudo instructions
+ if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+ int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+ ArrayList<SsaInsn> predInsns;
+ predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+ insn = predInsns.get(predInsns.size() - 1);
+ }
- Rop constRop = Rops.opConst(cst);
-
- if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
- start.addInsnToHead(
- new PlainCstInsn(Rops.opConst(cst),
- SourcePosition.NO_INFO, result,
- RegisterSpecList.EMPTY, cst));
- } else {
- // We need two new basic blocks along with the new insn
- SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
- SsaBasicBlock successorBlock
- = entryBlock.getPrimarySuccessor();
-
- // Insert a block containing the const insn.
- SsaBasicBlock constBlock
- = entryBlock.insertNewSuccessor(successorBlock);
-
- constBlock.replaceLastInsn(
- new ThrowingCstInsn(constRop, SourcePosition.NO_INFO,
- RegisterSpecList.EMPTY,
- StdTypeList.EMPTY, cst));
-
- // Insert a block containing the move-result-pseudo insn.
-
- SsaBasicBlock resultBlock
- = constBlock.insertNewSuccessor(successorBlock);
- PlainInsn insn
- = new PlainInsn(
- Rops.opMoveResultPseudo(result.getTypeBearer()),
- SourcePosition.NO_INFO,
- result, RegisterSpecList.EMPTY);
-
- resultBlock.addInsnToHead(insn);
- }
-
- newRegs.put(cst, result);
- }
-
- updateConstUses(newRegs, regSz);
- }
-
- /**
- * Gets all of the collectable constant values used in this method,
- * sorted by most used first. Skips non-collectable consts, such as
- * non-string object constants
- *
- * @return {@code non-null;} list of constants in most-to-least used order
- */
- private ArrayList<TypedConstant> getConstsSortedByCountUse() {
- int regSz = ssaMeth.getRegCount();
-
- final HashMap<TypedConstant, Integer> countUses
- = new HashMap<TypedConstant, Integer>();
-
+ if (insn.canThrow()) {
/*
- * Each collected constant can be used by just one local
- * (used only if COLLECT_ONE_LOCAL is true).
+ * Don't move anything other than strings -- the risk
+ * of changing where an exception is thrown is too high.
*/
- final HashSet<TypedConstant> usedByLocal
- = new HashSet<TypedConstant>();
-
- // Count how many times each const value is used.
- for (int i = 0; i < regSz; i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
-
- if (insn == null || insn.getOpcode() == null) continue;
-
- RegisterSpec result = insn.getResult();
- TypeBearer typeBearer = result.getTypeBearer();
-
- if (!typeBearer.isConstant()) continue;
-
- TypedConstant cst = (TypedConstant) typeBearer;
-
- // Find defining instruction for move-result-pseudo instructions
- if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
- int pred = insn.getBlock().getPredecessors().nextSetBit(0);
- ArrayList<SsaInsn> predInsns;
- predInsns = ssaMeth.getBlocks().get(pred).getInsns();
- insn = predInsns.get(predInsns.size()-1);
- }
-
- if (insn.canThrow()) {
- /*
- * Don't move anything other than strings -- the risk
- * of changing where an exception is thrown is too high.
- */
- if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
- continue;
- }
- /*
- * We can't move any throwable const whose throw will be
- * caught, so don't count them.
- */
- if (insn.getBlock().getSuccessors().cardinality() > 1) {
- continue;
- }
- }
-
- /*
- * TODO: Might be nice to try and figure out which local
- * wins most when collected.
- */
- if (ssaMeth.isRegALocal(result)) {
- if (!COLLECT_ONE_LOCAL) {
- continue;
- } else {
- if (usedByLocal.contains(cst)) {
- // Count one local usage only.
- continue;
- } else {
- usedByLocal.add(cst);
- }
- }
- }
-
- Integer has = countUses.get(cst);
- if (has == null) {
- countUses.put(cst, 1);
- } else {
- countUses.put(cst, has + 1);
- }
+ if (!(cst instanceof CstString) || !collectStrings) {
+ continue;
}
-
- // Collect constants that have been reused.
- ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
- for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
- if (entry.getValue() > 1) {
- constantList.add(entry.getKey());
- }
- }
-
- // Sort by use, with most used at the beginning of the list.
- Collections.sort(constantList, new Comparator<Constant>() {
- public int compare(Constant a, Constant b) {
- int ret;
- ret = countUses.get(b) - countUses.get(a);
-
- if (ret == 0) {
- /*
- * Provide sorting determinisim for constants with same
- * usage count.
- */
- ret = a.compareTo(b);
- }
-
- return ret;
- }
-
- @Override
- public boolean equals (Object obj) {
- return obj == this;
- }
- });
-
- return constantList;
- }
-
- /**
- * Inserts mark-locals if necessary when changing a register. If
- * the definition of {@code origReg} is associated with a local
- * variable, then insert a mark-local for {@code newReg} just below
- * it. We expect the definition of {@code origReg} to ultimately
- * be removed by the dead code eliminator
- *
- * @param origReg {@code non-null;} original register
- * @param newReg {@code non-null;} new register that will replace
- * {@code origReg}
- */
- private void fixLocalAssignment(RegisterSpec origReg,
- RegisterSpec newReg) {
- for (SsaInsn use : ssaMeth.getUseListForRegister(origReg.getReg())) {
- RegisterSpec localAssignment = use.getLocalAssignment();
- if (localAssignment == null) {
- continue;
- }
-
- if (use.getResult() == null) {
- /*
- * This is a mark-local. it will be updated when all uses
- * are updated.
- */
- continue;
- }
-
- LocalItem local = localAssignment.getLocalItem();
-
- // Un-associate original use.
- use.setResultLocal(null);
-
- // Now add a mark-local to the new reg immediately after.
- newReg = newReg.withLocalItem(local);
-
- SsaInsn newInsn
- = SsaInsn.makeFromRop(
- new PlainInsn(Rops.opMarkLocal(newReg),
- SourcePosition.NO_INFO, null,
- RegisterSpecList.make(newReg)),
- use.getBlock());
-
- ArrayList<SsaInsn> insns = use.getBlock().getInsns();
-
- insns.add(insns.indexOf(use) + 1, newInsn);
- }
- }
-
- /**
- * Updates all uses of various consts to use the values in the newly
- * assigned registers.
- *
- * @param newRegs {@code non-null;} mapping between constant and new reg
- * @param origRegCount {@code >=0;} original SSA reg count, not including
- * newly added constant regs
- */
- private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs,
- int origRegCount) {
-
/*
- * set of constants associated with a local variable; used
- * only if COLLECT_ONE_LOCAL is true.
+ * We can't move any throwable const whose throw will be
+ * caught, so don't count them.
*/
- final HashSet<TypedConstant> usedByLocal
- = new HashSet<TypedConstant>();
-
- final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
-
- for (int i = 0; i < origRegCount; i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
-
- if (insn == null) {
- continue;
- }
-
- final RegisterSpec origReg = insn.getResult();
- TypeBearer typeBearer = insn.getResult().getTypeBearer();
-
- if (!typeBearer.isConstant()) continue;
-
- TypedConstant cst = (TypedConstant) typeBearer;
- final RegisterSpec newReg = newRegs.get(cst);
-
- if (newReg == null) {
- continue;
- }
-
- if (ssaMeth.isRegALocal(origReg)) {
- if (!COLLECT_ONE_LOCAL) {
- continue;
- } else {
- /*
- * TODO: If the same local gets the same cst
- * multiple times, it would be nice to reuse the
- * register.
- */
- if (usedByLocal.contains(cst)) {
- continue;
- } else {
- usedByLocal.add(cst);
- fixLocalAssignment(origReg, newRegs.get(cst));
- }
- }
- }
-
- // maps an original const register to the new collected register
- RegisterMapper mapper = new RegisterMapper() {
- @Override
- public int getNewRegisterCount() {
- return ssaMeth.getRegCount();
- }
-
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec.getReg() == origReg.getReg()) {
- return newReg.withLocalItem(
- registerSpec.getLocalItem());
- }
-
- return registerSpec;
- }
- };
-
- for (SsaInsn use : useList[origReg.getReg()]) {
- if (use.canThrow()
- && use.getBlock().getSuccessors().cardinality() > 1) {
- continue;
- }
- use.mapSourceRegisters(mapper);
- }
+ if (insn.getBlock().getSuccessors().cardinality() > 1) {
+ continue;
}
+ }
+
+ /*
+ * TODO(dx team): Might be nice to try and figure out which local
+ * wins most when collected.
+ */
+ if (ssaMeth.isRegALocal(result)) {
+ if (!COLLECT_ONE_LOCAL) {
+ continue;
+ } else {
+ if (usedByLocal.contains(cst)) {
+ // Count one local usage only.
+ continue;
+ } else {
+ usedByLocal.add(cst);
+ }
+ }
+ }
+
+ Integer has = countUses.get(cst);
+ if (has == null) {
+ countUses.put(cst, 1);
+ } else {
+ countUses.put(cst, has + 1);
+ }
}
+
+ // Collect constants that have been reused.
+ ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
+ for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
+ if (entry.getValue() > 1) {
+ constantList.add(entry.getKey());
+ }
+ }
+
+ // Sort by use, with most used at the beginning of the list.
+ Collections.sort(constantList, new Comparator<Constant>() {
+ @Override
+ public int compare(Constant a, Constant b) {
+ int ret;
+ ret = countUses.get(b) - countUses.get(a);
+
+ if (ret == 0) {
+ /*
+ * Provide sorting determinisim for constants with same
+ * usage count.
+ */
+ ret = a.compareTo(b);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+ });
+
+ return constantList;
+ }
+
+ /**
+ * Inserts mark-locals if necessary when changing a register. If
+ * the definition of {@code origReg} is associated with a local
+ * variable, then insert a mark-local for {@code newReg} just below
+ * it. We expect the definition of {@code origReg} to ultimately
+ * be removed by the dead code eliminator
+ *
+ * @param origReg {@code non-null;} original register
+ * @param newReg {@code non-null;} new register that will replace
+ * {@code origReg}
+ */
+ private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) {
+ for (SsaInsn use : ssaMeth.getUseListForRegister(origReg.getReg())) {
+ RegisterSpec localAssignment = use.getLocalAssignment();
+ if (localAssignment == null) {
+ continue;
+ }
+
+ if (use.getResult() == null) {
+ /*
+ * This is a mark-local. it will be updated when all uses
+ * are updated.
+ */
+ continue;
+ }
+
+ LocalItem local = localAssignment.getLocalItem();
+
+ // Un-associate original use.
+ use.setResultLocal(null);
+
+ // Now add a mark-local to the new reg immediately after.
+ newReg = newReg.withLocalItem(local);
+
+ SsaInsn newInsn = SsaInsn.makeFromRop(new PlainInsn(Rops.opMarkLocal(newReg),
+ SourcePosition.NO_INFO, null, RegisterSpecList.make(newReg)), use.getBlock());
+
+ ArrayList<SsaInsn> insns = use.getBlock().getInsns();
+
+ insns.add(insns.indexOf(use) + 1, newInsn);
+ }
+ }
+
+ /**
+ * Updates all uses of various consts to use the values in the newly
+ * assigned registers.
+ *
+ * @param newRegs {@code non-null;} mapping between constant and new reg
+ * @param origRegCount {@code >=0;} original SSA reg count, not including
+ * newly added constant regs
+ */
+ private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs, int origRegCount) {
+
+ /*
+ * set of constants associated with a local variable; used
+ * only if COLLECT_ONE_LOCAL is true.
+ */
+ final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();
+
+ final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
+
+ for (int i = 0; i < origRegCount; i++) {
+ SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+
+ if (insn == null) {
+ continue;
+ }
+
+ final RegisterSpec origReg = insn.getResult();
+ TypeBearer typeBearer = insn.getResult().getTypeBearer();
+
+ if (!typeBearer.isConstant()) {
+ continue;
+ }
+
+ TypedConstant cst = (TypedConstant) typeBearer;
+ final RegisterSpec newReg = newRegs.get(cst);
+
+ if (newReg == null) {
+ continue;
+ }
+
+ if (ssaMeth.isRegALocal(origReg)) {
+ if (!COLLECT_ONE_LOCAL) {
+ continue;
+ } else {
+ /*
+ * TODO(dx team): If the same local gets the same cst
+ * multiple times, it would be nice to reuse the
+ * register.
+ */
+ if (usedByLocal.contains(cst)) {
+ continue;
+ } else {
+ usedByLocal.add(cst);
+ fixLocalAssignment(origReg, newRegs.get(cst));
+ }
+ }
+ }
+
+ // maps an original const register to the new collected register
+ RegisterMapper mapper = new RegisterMapper() {
+ @Override
+ public int getNewRegisterCount() {
+ return ssaMeth.getRegCount();
+ }
+
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec.getReg() == origReg.getReg()) {
+ return newReg.withLocalItem(registerSpec.getLocalItem());
+ }
+
+ return registerSpec;
+ }
+ };
+
+ for (SsaInsn use : useList[origReg.getReg()]) {
+ if (use.canThrow() && use.getBlock().getSuccessors().cardinality() > 1) {
+ continue;
+ }
+ use.mapSourceRegisters(mapper);
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/DeadCodeRemover.java b/dx/src/com/android/jack/dx/ssa/DeadCodeRemover.java
index 70c0005..27040cf 100644
--- a/dx/src/com/android/jack/dx/ssa/DeadCodeRemover.java
+++ b/dx/src/com/android/jack/dx/ssa/DeadCodeRemover.java
@@ -16,14 +16,8 @@
package com.android.jack.dx.ssa;
-import com.android.jack.dx.rop.code.Insn;
-import com.android.jack.dx.rop.code.PlainInsn;
-import com.android.jack.dx.rop.code.RegOps;
import com.android.jack.dx.rop.code.RegisterSpec;
import com.android.jack.dx.rop.code.RegisterSpecList;
-import com.android.jack.dx.rop.code.Rop;
-import com.android.jack.dx.rop.code.Rops;
-import com.android.jack.dx.rop.code.SourcePosition;
import java.util.ArrayList;
import java.util.BitSet;
@@ -32,241 +26,244 @@
/**
* A variation on Appel Algorithm 19.12 "Dead code elimination in SSA form".
*
- * TODO this algorithm is more efficient if run in reverse from exit
+ * TODO(dx team) this algorithm is more efficient if run in reverse from exit
* block to entry block.
*/
public class DeadCodeRemover {
- /** method we're processing */
- private final SsaMethod ssaMeth;
+ /** method we're processing */
+ private final SsaMethod ssaMeth;
- /** ssaMeth.getRegCount() */
- private final int regCount;
+ /** ssaMeth.getRegCount() */
+ private final int regCount;
- /**
- * indexed by register: whether reg should be examined
- * (does it correspond to a no-side-effect insn?)
- */
- private final BitSet worklist;
+ /**
+ * indexed by register: whether reg should be examined
+ * (does it correspond to a no-side-effect insn?)
+ */
+ private final BitSet worklist;
- /** use list indexed by register; modified during operation */
- private final ArrayList<SsaInsn>[] useList;
+ /** use list indexed by register; modified during operation */
+ private final ArrayList<SsaInsn>[] useList;
- /**
- * Process a method with the dead-code remver
- *
- * @param ssaMethod method to process
- */
- public static void process(SsaMethod ssaMethod) {
- DeadCodeRemover dc = new DeadCodeRemover(ssaMethod);
- dc.run();
- }
+ /**
+ * Process a method with the dead-code remver
+ *
+ * @param ssaMethod method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ DeadCodeRemover dc = new DeadCodeRemover(ssaMethod);
+ dc.run();
+ }
- /**
- * Constructs an instance.
- *
- * @param ssaMethod method to process
- */
- private DeadCodeRemover(SsaMethod ssaMethod) {
- this.ssaMeth = ssaMethod;
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMethod method to process
+ */
+ private DeadCodeRemover(SsaMethod ssaMethod) {
+ this.ssaMeth = ssaMethod;
- regCount = ssaMethod.getRegCount();
- worklist = new BitSet(regCount);
- useList = ssaMeth.getUseListCopy();
- }
+ regCount = ssaMethod.getRegCount();
+ worklist = new BitSet(regCount);
+ useList = ssaMeth.getUseListCopy();
+ }
- /**
- * Runs the dead code remover.
- */
- private void run() {
- pruneDeadInstructions();
+ /**
+ * Runs the dead code remover.
+ */
+ private void run() {
+ pruneDeadInstructions();
- HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
- ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
+ ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
- int regV;
+ int regV;
- while ( 0 <= (regV = worklist.nextSetBit(0)) ) {
- worklist.clear(regV);
+ while (0 <= (regV = worklist.nextSetBit(0))) {
+ worklist.clear(regV);
- if (useList[regV].size() == 0
- || isCircularNoSideEffect(regV, null)) {
+ if (useList[regV].size() == 0 || isCircularNoSideEffect(regV, null)) {
- SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV);
+ SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV);
- // This insn has already been deleted.
- if (deletedInsns.contains(insnS)) {
- continue;
- }
-
- RegisterSpecList sources = insnS.getSources();
-
- int sz = sources.size();
- for (int i = 0; i < sz; i++) {
- // Delete this insn from all usage lists.
- RegisterSpec source = sources.get(i);
- useList[source.getReg()].remove(insnS);
-
- if (!hasSideEffect(
- ssaMeth.getDefinitionForRegister(
- source.getReg()))) {
- /*
- * Only registers whose definition has no side effect
- * should be added back to the worklist.
- */
- worklist.set(source.getReg());
- }
- }
-
- // Schedule this insn for later deletion.
- deletedInsns.add(insnS);
- }
+ // This insn has already been deleted.
+ if (deletedInsns.contains(insnS)) {
+ continue;
}
- ssaMeth.deleteInsns(deletedInsns);
- }
+ RegisterSpecList sources = insnS.getSources();
- /**
- * Removes all instructions from every unreachable block.
- */
- private void pruneDeadInstructions() {
- HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+ int sz = sources.size();
+ for (int i = 0; i < sz; i++) {
+ // Delete this insn from all usage lists.
+ RegisterSpec source = sources.get(i);
+ useList[source.getReg()].remove(insnS);
- ssaMeth.computeReachability();
-
- for (SsaBasicBlock block : ssaMeth.getBlocks()) {
- if (block.isReachable()) continue;
-
- // Prune instructions from unreachable blocks
- for (int i = 0; i < block.getInsns().size(); i++) {
- SsaInsn insn = block.getInsns().get(i);
- RegisterSpecList sources = insn.getSources();
- int sourcesSize = sources.size();
-
- // Delete this instruction completely if it has sources
- if (sourcesSize != 0) {
- deletedInsns.add(insn);
- }
-
- // Delete this instruction from all usage lists.
- for (int j = 0; j < sourcesSize; j++) {
- RegisterSpec source = sources.get(j);
- useList[source.getReg()].remove(insn);
- }
-
- // Remove this instruction result from the sources of any phis
- RegisterSpec result = insn.getResult();
- if (result == null) continue;
- for (SsaInsn use : useList[result.getReg()]) {
- if (use instanceof PhiInsn) {
- PhiInsn phiUse = (PhiInsn) use;
- phiUse.removePhiRegister(result);
- }
- }
- }
- }
-
- ssaMeth.deleteInsns(deletedInsns);
- }
-
- /**
- * Returns true if the only uses of this register form a circle of
- * operations with no side effects.
- *
- * @param regV register to examine
- * @param set a set of registers that we've already determined
- * are only used as sources in operations with no side effect or null
- * if this is the first recursion
- * @return true if usage is circular without side effect
- */
- private boolean isCircularNoSideEffect(int regV, BitSet set) {
- if ((set != null) && set.get(regV)) {
- return true;
- }
-
- for (SsaInsn use : useList[regV]) {
- if (hasSideEffect(use)) {
- return false;
- }
- }
-
- if (set == null) {
- set = new BitSet(regCount);
- }
-
- // This register is only used in operations that have no side effect.
- set.set(regV);
-
- for (SsaInsn use : useList[regV]) {
- RegisterSpec result = use.getResult();
-
- if (result == null
- || !isCircularNoSideEffect(result.getReg(), set)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns true if this insn has a side-effect. Returns true
- * if the insn is null for reasons stated in the code block.
- *
- * @param insn {@code null-ok;} instruction in question
- * @return true if it has a side-effect
- */
- private static boolean hasSideEffect(SsaInsn insn) {
- if (insn == null) {
- /* While false would seem to make more sense here, true
- * prevents us from adding this back to a worklist unnecessarally.
+ if (!hasSideEffect(ssaMeth.getDefinitionForRegister(source.getReg()))) {
+ /*
+ * Only registers whose definition has no side effect
+ * should be added back to the worklist.
*/
- return true;
+ worklist.set(source.getReg());
+ }
}
- return insn.hasSideEffect();
+ // Schedule this insn for later deletion.
+ deletedInsns.add(insnS);
+ }
}
+ ssaMeth.deleteInsns(deletedInsns);
+ }
+
+ /**
+ * Removes all instructions from every unreachable block.
+ */
+ private void pruneDeadInstructions() {
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+ ssaMeth.computeReachability();
+
+ for (SsaBasicBlock block : ssaMeth.getBlocks()) {
+ if (block.isReachable()) {
+ continue;
+ }
+
+ // Prune instructions from unreachable blocks
+ for (int i = 0; i < block.getInsns().size(); i++) {
+ SsaInsn insn = block.getInsns().get(i);
+ RegisterSpecList sources = insn.getSources();
+ int sourcesSize = sources.size();
+
+ // Delete this instruction completely if it has sources
+ if (sourcesSize != 0) {
+ deletedInsns.add(insn);
+ }
+
+ // Delete this instruction from all usage lists.
+ for (int j = 0; j < sourcesSize; j++) {
+ RegisterSpec source = sources.get(j);
+ useList[source.getReg()].remove(insn);
+ }
+
+ // Remove this instruction result from the sources of any phis
+ RegisterSpec result = insn.getResult();
+ if (result == null) {
+ continue;
+ }
+ for (SsaInsn use : useList[result.getReg()]) {
+ if (use instanceof PhiInsn) {
+ PhiInsn phiUse = (PhiInsn) use;
+ phiUse.removePhiRegister(result);
+ }
+ }
+ }
+ }
+
+ ssaMeth.deleteInsns(deletedInsns);
+ }
+
+ /**
+ * Returns true if the only uses of this register form a circle of
+ * operations with no side effects.
+ *
+ * @param regV register to examine
+ * @param set a set of registers that we've already determined
+ * are only used as sources in operations with no side effect or null
+ * if this is the first recursion
+ * @return true if usage is circular without side effect
+ */
+ private boolean isCircularNoSideEffect(int regV, BitSet set) {
+ if ((set != null) && set.get(regV)) {
+ return true;
+ }
+
+ for (SsaInsn use : useList[regV]) {
+ if (hasSideEffect(use)) {
+ return false;
+ }
+ }
+
+ if (set == null) {
+ set = new BitSet(regCount);
+ }
+
+ // This register is only used in operations that have no side effect.
+ set.set(regV);
+
+ for (SsaInsn use : useList[regV]) {
+ RegisterSpec result = use.getResult();
+
+ if (result == null || !isCircularNoSideEffect(result.getReg(), set)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if this insn has a side-effect. Returns true
+ * if the insn is null for reasons stated in the code block.
+ *
+ * @param insn {@code null-ok;} instruction in question
+ * @return true if it has a side-effect
+ */
+ private static boolean hasSideEffect(SsaInsn insn) {
+ if (insn == null) {
+ /* While false would seem to make more sense here, true
+ * prevents us from adding this back to a worklist unnecessarally.
+ */
+ return true;
+ }
+
+ return insn.hasSideEffect();
+ }
+
+ /**
+ * A callback class used to build up the initial worklist of
+ * registers defined by an instruction with no side effect.
+ */
+ private static class NoSideEffectVisitor implements SsaInsn.Visitor {
+ BitSet noSideEffectRegs;
+
/**
- * A callback class used to build up the initial worklist of
- * registers defined by an instruction with no side effect.
+ * Passes in data structures that will be filled out after
+ * ssaMeth.forEachInsn() is called with this instance.
+ *
+ * @param noSideEffectRegs to-build bitset of regs that are
+ * results of regs with no side effects
*/
- static private class NoSideEffectVisitor implements SsaInsn.Visitor {
- BitSet noSideEffectRegs;
-
- /**
- * Passes in data structures that will be filled out after
- * ssaMeth.forEachInsn() is called with this instance.
- *
- * @param noSideEffectRegs to-build bitset of regs that are
- * results of regs with no side effects
- */
- public NoSideEffectVisitor(BitSet noSideEffectRegs) {
- this.noSideEffectRegs = noSideEffectRegs;
- }
-
- /** {@inheritDoc} */
- public void visitMoveInsn (NormalSsaInsn insn) {
- // If we're tracking local vars, some moves have side effects.
- if (!hasSideEffect(insn)) {
- noSideEffectRegs.set(insn.getResult().getReg());
- }
- }
-
- /** {@inheritDoc} */
- public void visitPhiInsn (PhiInsn phi) {
- // If we're tracking local vars, then some phis have side effects.
- if (!hasSideEffect(phi)) {
- noSideEffectRegs.set(phi.getResult().getReg());
- }
- }
-
- /** {@inheritDoc} */
- public void visitNonMoveInsn (NormalSsaInsn insn) {
- RegisterSpec result = insn.getResult();
- if (!hasSideEffect(insn) && result != null) {
- noSideEffectRegs.set(result.getReg());
- }
- }
+ public NoSideEffectVisitor(BitSet noSideEffectRegs) {
+ this.noSideEffectRegs = noSideEffectRegs;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ // If we're tracking local vars, some moves have side effects.
+ if (!hasSideEffect(insn)) {
+ noSideEffectRegs.set(insn.getResult().getReg());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPhiInsn(PhiInsn phi) {
+ // If we're tracking local vars, then some phis have side effects.
+ if (!hasSideEffect(phi)) {
+ noSideEffectRegs.set(phi.getResult().getReg());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ RegisterSpec result = insn.getResult();
+ if (!hasSideEffect(insn) && result != null) {
+ noSideEffectRegs.set(result.getReg());
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/DomFront.java b/dx/src/com/android/jack/dx/ssa/DomFront.java
index 9e67f46..5a599ff 100644
--- a/dx/src/com/android/jack/dx/ssa/DomFront.java
+++ b/dx/src/com/android/jack/dx/ssa/DomFront.java
@@ -16,12 +16,9 @@
package com.android.jack.dx.ssa;
-import com.android.jack.dx.util.BitIntSet;
import com.android.jack.dx.util.IntSet;
-import com.android.jack.dx.util.ListIntSet;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.BitSet;
/**
@@ -30,175 +27,172 @@
* Harvey, and Kennedy; transliterated to Java.
*/
public class DomFront {
- /** local debug flag */
- private static boolean DEBUG = false;
+ /** local debug flag */
+ private static final boolean DEBUG = false;
- /** {@code non-null;} method being processed */
- private final SsaMethod meth;
+ /** {@code non-null;} method being processed */
+ private final SsaMethod meth;
- private final ArrayList<SsaBasicBlock> nodes;
+ private final ArrayList<SsaBasicBlock> nodes;
- private final DomInfo[] domInfos;
+ private final DomInfo[] domInfos;
+ /**
+ * Dominance-frontier information for a single basic block.
+ */
+ public static class DomInfo {
/**
- * Dominance-frontier information for a single basic block.
+ * {@code null-ok;} the dominance frontier set indexed by
+ * block index
*/
- public static class DomInfo {
- /**
- * {@code null-ok;} the dominance frontier set indexed by
- * block index
- */
- public IntSet dominanceFrontiers;
+ public IntSet dominanceFrontiers;
- /** {@code >= 0 after run();} the index of the immediate dominator */
- public int idom = -1;
+ /** {@code >= 0 after run();} the index of the immediate dominator */
+ public int idom = -1;
+ }
+
+ /**
+ * Constructs instance. Call {@link DomFront#run} to process.
+ *
+ * @param meth {@code non-null;} method to process
+ */
+ public DomFront(SsaMethod meth) {
+ this.meth = meth;
+ nodes = meth.getBlocks();
+
+ int szNodes = nodes.size();
+ domInfos = new DomInfo[szNodes];
+
+ for (int i = 0; i < szNodes; i++) {
+ domInfos[i] = new DomInfo();
+ }
+ }
+
+ /**
+ * Calculates the dominance frontier information for the method.
+ *
+ * @return {@code non-null;} an array of DomInfo structures
+ */
+ public DomInfo[] run() {
+ int szNodes = nodes.size();
+
+ if (DEBUG) {
+ for (int i = 0; i < szNodes; i++) {
+ SsaBasicBlock node = nodes.get(i);
+ System.out.println("pred[" + i + "]: " + node.getPredecessors());
+ }
}
- /**
- * Constructs instance. Call {@link DomFront#run} to process.
- *
- * @param meth {@code non-null;} method to process
- */
- public DomFront(SsaMethod meth) {
- this.meth = meth;
- nodes = meth.getBlocks();
+ Dominators.make(meth, domInfos, false);
- int szNodes = nodes.size();
- domInfos = new DomInfo[szNodes];
+ if (DEBUG) {
+ for (int i = 0; i < szNodes; i++) {
+ DomInfo info = domInfos[i];
+ System.out.println("idom[" + i + "]: " + info.idom);
+ }
+ }
- for (int i = 0; i < szNodes; i++) {
- domInfos[i] = new DomInfo();
+ buildDomTree();
+
+ if (DEBUG) {
+ debugPrintDomChildren();
+ }
+
+ for (int i = 0; i < szNodes; i++) {
+ domInfos[i].dominanceFrontiers = SetFactory.makeDomFrontSet(szNodes);
+ }
+
+ calcDomFronts();
+
+ if (DEBUG) {
+ for (int i = 0; i < szNodes; i++) {
+ System.out.println("df[" + i + "]: " + domInfos[i].dominanceFrontiers);
+ }
+ }
+
+ return domInfos;
+ }
+
+ private void debugPrintDomChildren() {
+ int szNodes = nodes.size();
+
+ for (int i = 0; i < szNodes; i++) {
+ SsaBasicBlock node = nodes.get(i);
+ StringBuffer sb = new StringBuffer();
+
+ sb.append('{');
+ boolean comma = false;
+ for (SsaBasicBlock child : node.getDomChildren()) {
+ if (comma) {
+ sb.append(',');
}
+ sb.append(child);
+ comma = true;
+ }
+ sb.append('}');
+
+ System.out.println("domChildren[" + node + "]: " + sb);
}
+ }
- /**
- * Calculates the dominance frontier information for the method.
- *
- * @return {@code non-null;} an array of DomInfo structures
- */
- public DomInfo[] run() {
- int szNodes = nodes.size();
+ /**
+ * The dominators algorithm leaves us knowing who the immediate dominator
+ * is for each node. This sweeps the node list and builds the proper
+ * dominance tree.
+ */
+ private void buildDomTree() {
+ int szNodes = nodes.size();
- if (DEBUG) {
- for (int i = 0; i < szNodes; i++) {
- SsaBasicBlock node = nodes.get(i);
- System.out.println("pred[" + i + "]: "
- + node.getPredecessors());
+ for (int i = 0; i < szNodes; i++) {
+ DomInfo info = domInfos[i];
+
+ if (info.idom == -1) {
+ continue;
+ }
+
+ SsaBasicBlock domParent = nodes.get(info.idom);
+ domParent.addDomChild(nodes.get(i));
+ }
+ }
+
+ /**
+ * Calculates the dominance-frontier set.
+ * from "A Simple, Fast Dominance Algorithm" by Cooper,
+ * Harvey, and Kennedy; transliterated to Java.
+ */
+ private void calcDomFronts() {
+ int szNodes = nodes.size();
+
+ for (int b = 0; b < szNodes; b++) {
+ SsaBasicBlock nb = nodes.get(b);
+ DomInfo nbInfo = domInfos[b];
+ BitSet pred = nb.getPredecessors();
+
+ if (pred.cardinality() > 1) {
+ for (int i = pred.nextSetBit(0); i >= 0; i = pred.nextSetBit(i + 1)) {
+
+ for (int runnerIndex = i; runnerIndex != nbInfo.idom; /* empty */) {
+ /*
+ * We can stop if we hit a block we already
+ * added label to, since we must be at a part
+ * of the dom tree we have seen before.
+ */
+ if (runnerIndex == -1) {
+ break;
}
- }
- Dominators methDom = Dominators.make(meth, domInfos, false);
+ DomInfo runnerInfo = domInfos[runnerIndex];
- if (DEBUG) {
- for (int i = 0; i < szNodes; i++) {
- DomInfo info = domInfos[i];
- System.out.println("idom[" + i + "]: "
- + info.idom);
+ if (runnerInfo.dominanceFrontiers.has(b)) {
+ break;
}
+
+ // Add b to runner's dominance frontier set.
+ runnerInfo.dominanceFrontiers.add(b);
+ runnerIndex = runnerInfo.idom;
+ }
}
-
- buildDomTree();
-
- if (DEBUG) {
- debugPrintDomChildren();
- }
-
- for (int i = 0; i < szNodes; i++) {
- domInfos[i].dominanceFrontiers
- = SetFactory.makeDomFrontSet(szNodes);
- }
-
- calcDomFronts();
-
- if (DEBUG) {
- for (int i = 0; i < szNodes; i++) {
- System.out.println("df[" + i + "]: "
- + domInfos[i].dominanceFrontiers);
- }
- }
-
- return domInfos;
+ }
}
-
- private void debugPrintDomChildren() {
- int szNodes = nodes.size();
-
- for (int i = 0; i < szNodes; i++) {
- SsaBasicBlock node = nodes.get(i);
- StringBuffer sb = new StringBuffer();
-
- sb.append('{');
- boolean comma = false;
- for (SsaBasicBlock child : node.getDomChildren()) {
- if (comma) {
- sb.append(',');
- }
- sb.append(child);
- comma = true;
- }
- sb.append('}');
-
- System.out.println("domChildren[" + node + "]: "
- + sb);
- }
- }
-
- /**
- * The dominators algorithm leaves us knowing who the immediate dominator
- * is for each node. This sweeps the node list and builds the proper
- * dominance tree.
- */
- private void buildDomTree() {
- int szNodes = nodes.size();
-
- for (int i = 0; i < szNodes; i++) {
- DomInfo info = domInfos[i];
-
- if (info.idom == -1) continue;
-
- SsaBasicBlock domParent = nodes.get(info.idom);
- domParent.addDomChild(nodes.get(i));
- }
- }
-
- /**
- * Calculates the dominance-frontier set.
- * from "A Simple, Fast Dominance Algorithm" by Cooper,
- * Harvey, and Kennedy; transliterated to Java.
- */
- private void calcDomFronts() {
- int szNodes = nodes.size();
-
- for (int b = 0; b < szNodes; b++) {
- SsaBasicBlock nb = nodes.get(b);
- DomInfo nbInfo = domInfos[b];
- BitSet pred = nb.getPredecessors();
-
- if (pred.cardinality() > 1) {
- for (int i = pred.nextSetBit(0); i >= 0;
- i = pred.nextSetBit(i + 1)) {
-
- for (int runnerIndex = i;
- runnerIndex != nbInfo.idom; /* empty */) {
- /*
- * We can stop if we hit a block we already
- * added label to, since we must be at a part
- * of the dom tree we have seen before.
- */
- if (runnerIndex == -1) break;
-
- DomInfo runnerInfo = domInfos[runnerIndex];
-
- if (runnerInfo.dominanceFrontiers.has(b)) {
- break;
- }
-
- // Add b to runner's dominance frontier set.
- runnerInfo.dominanceFrontiers.add(b);
- runnerIndex = runnerInfo.idom;
- }
- }
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/Dominators.java b/dx/src/com/android/jack/dx/ssa/Dominators.java
index b3b4c3f..3311efd 100644
--- a/dx/src/com/android/jack/dx/ssa/Dominators.java
+++ b/dx/src/com/android/jack/dx/ssa/Dominators.java
@@ -41,245 +41,229 @@
* rank to keep the union-find tree balanced.
*/
public final class Dominators {
- /* postdom is true if we want post dominators */
- private final boolean postdom;
+ /* postdom is true if we want post dominators */
+ private final boolean postdom;
- /* {@code non-null;} method being processed */
- private final SsaMethod meth;
+ /* {@code non-null;} method being processed */
+ private final SsaMethod meth;
- /* Method's basic blocks. */
- private final ArrayList<SsaBasicBlock> blocks;
+ /* Method's basic blocks. */
+ private final ArrayList<SsaBasicBlock> blocks;
- /** indexed by basic block index */
- private final DFSInfo[] info;
+ /** indexed by basic block index */
+ private final DFSInfo[] info;
- private final ArrayList<SsaBasicBlock> vertex;
+ private final ArrayList<SsaBasicBlock> vertex;
- /** {@code non-null;} the raw dominator info */
- private final DomFront.DomInfo domInfos[];
+ /** {@code non-null;} the raw dominator info */
+ private final DomFront.DomInfo domInfos[];
- /**
- * Constructs an instance.
- *
- * @param meth {@code non-null;} method to process
- * @param domInfos {@code non-null;} the raw dominator info
- * @param postdom true for postdom information, false for normal dom info
+ /**
+ * Constructs an instance.
+ *
+ * @param meth {@code non-null;} method to process
+ * @param domInfos {@code non-null;} the raw dominator info
+ * @param postdom true for postdom information, false for normal dom info
+ */
+ private Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos, boolean postdom) {
+ this.meth = meth;
+ this.domInfos = domInfos;
+ this.postdom = postdom;
+ this.blocks = meth.getBlocks();
+ this.info = new DFSInfo[blocks.size() + 2];
+ this.vertex = new ArrayList<SsaBasicBlock>();
+ }
+
+ /**
+ * Constructs a fully-initialized instance. (This method exists so as
+ * to avoid calling a large amount of code in the constructor.)
+ *
+ * @param meth {@code non-null;} method to process
+ * @param domInfos {@code non-null;} the raw dominator info
+ * @param postdom true for postdom information, false for normal dom info
+ */
+ public static Dominators make(SsaMethod meth, DomFront.DomInfo[] domInfos, boolean postdom) {
+ Dominators result = new Dominators(meth, domInfos, postdom);
+
+ result.run();
+ return result;
+ }
+
+ private BitSet getPreds(SsaBasicBlock block) {
+ if (postdom) {
+ return block.getSuccessors();
+ } else {
+ return block.getPredecessors();
+ }
+ }
+
+ /**
+ * Performs path compress on the DFS info.
+ *
+ * @param in Basic block whose DFS info we are path compressing.
+ */
+ private void compress(SsaBasicBlock in) {
+ DFSInfo bbInfo = info[in.getIndex()];
+ DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()];
+
+ if (ancestorbbInfo.ancestor != null) {
+ ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>();
+ HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>();
+ worklist.add(in);
+
+ while (!worklist.isEmpty()) {
+ int wsize = worklist.size();
+ SsaBasicBlock v = worklist.get(wsize - 1);
+ DFSInfo vbbInfo = info[v.getIndex()];
+ SsaBasicBlock vAncestor = vbbInfo.ancestor;
+ DFSInfo vabbInfo = info[vAncestor.getIndex()];
+
+ // Make sure we process our ancestor before ourselves.
+ if (visited.add(vAncestor) && vabbInfo.ancestor != null) {
+ worklist.add(vAncestor);
+ continue;
+ }
+ worklist.remove(wsize - 1);
+
+ // Update based on ancestor info.
+ if (vabbInfo.ancestor == null) {
+ continue;
+ }
+ SsaBasicBlock vAncestorRep = vabbInfo.rep;
+ SsaBasicBlock vRep = vbbInfo.rep;
+ if (info[vAncestorRep.getIndex()].semidom < info[vRep.getIndex()].semidom) {
+ vbbInfo.rep = vAncestorRep;
+ }
+ vbbInfo.ancestor = vabbInfo.ancestor;
+ }
+ }
+ }
+
+ private SsaBasicBlock eval(SsaBasicBlock v) {
+ DFSInfo bbInfo = info[v.getIndex()];
+
+ if (bbInfo.ancestor == null) {
+ return v;
+ }
+
+ compress(v);
+ return bbInfo.rep;
+ }
+
+ /**
+ * Performs dominator/post-dominator calculation for the control
+ * flow graph.
+ *
+ * @param meth {@code non-null;} method to analyze
+ */
+ private void run() {
+ SsaBasicBlock root = postdom ? meth.getExitBlock() : meth.getEntryBlock();
+
+ if (root != null) {
+ vertex.add(root);
+ domInfos[root.getIndex()].idom = root.getIndex();
+ }
+
+ /*
+ * First we perform a DFS numbering of the blocks, by
+ * numbering the dfs tree roots.
*/
- private Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos,
- boolean postdom) {
- this.meth = meth;
- this.domInfos = domInfos;
- this.postdom = postdom;
- this.blocks = meth.getBlocks();
- this.info = new DFSInfo[blocks.size() + 2];
- this.vertex = new ArrayList<SsaBasicBlock>();
- }
- /**
- * Constructs a fully-initialized instance. (This method exists so as
- * to avoid calling a large amount of code in the constructor.)
- *
- * @param meth {@code non-null;} method to process
- * @param domInfos {@code non-null;} the raw dominator info
- * @param postdom true for postdom information, false for normal dom info
- */
- public static Dominators make(SsaMethod meth, DomFront.DomInfo[] domInfos,
- boolean postdom) {
- Dominators result = new Dominators(meth, domInfos, postdom);
+DfsWalker walker = new DfsWalker();
+ meth.forEachBlockDepthFirst(postdom, walker);
- result.run();
- return result;
- }
+ // the largest semidom number assigned
+ int dfsMax = vertex.size() - 1;
- private BitSet getSuccs(SsaBasicBlock block) {
- if (postdom) {
- return block.getPredecessors();
- } else {
- return block.getSuccessors();
- }
- }
+ // Now calculate semidominators.
+ for (int i = dfsMax; i >= 2; --i) {
+ SsaBasicBlock w = vertex.get(i);
+ DFSInfo wInfo = info[w.getIndex()];
- private BitSet getPreds(SsaBasicBlock block) {
- if (postdom) {
- return block.getSuccessors();
- } else {
- return block.getPredecessors();
- }
- }
-
- /**
- * Performs path compress on the DFS info.
- *
- * @param in Basic block whose DFS info we are path compressing.
- */
- private void compress(SsaBasicBlock in) {
- DFSInfo bbInfo = info[in.getIndex()];
- DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()];
-
- if (ancestorbbInfo.ancestor != null) {
- ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>();
- HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>();
- worklist.add(in);
-
- while (!worklist.isEmpty()) {
- int wsize = worklist.size();
- SsaBasicBlock v = worklist.get(wsize - 1);
- DFSInfo vbbInfo = info[v.getIndex()];
- SsaBasicBlock vAncestor = vbbInfo.ancestor;
- DFSInfo vabbInfo = info[vAncestor.getIndex()];
-
- // Make sure we process our ancestor before ourselves.
- if (visited.add(vAncestor) && vabbInfo.ancestor != null) {
- worklist.add(vAncestor);
- continue;
- }
- worklist.remove(wsize - 1);
-
- // Update based on ancestor info.
- if (vabbInfo.ancestor == null) {
- continue;
- }
- SsaBasicBlock vAncestorRep = vabbInfo.rep;
- SsaBasicBlock vRep = vbbInfo.rep;
- if (info[vAncestorRep.getIndex()].semidom
- < info[vRep.getIndex()].semidom) {
- vbbInfo.rep = vAncestorRep;
- }
- vbbInfo.ancestor = vabbInfo.ancestor;
- }
- }
- }
-
- private SsaBasicBlock eval(SsaBasicBlock v) {
- DFSInfo bbInfo = info[v.getIndex()];
-
- if (bbInfo.ancestor == null) {
- return v;
- }
-
- compress(v);
- return bbInfo.rep;
- }
-
- /**
- * Performs dominator/post-dominator calculation for the control
- * flow graph.
- *
- * @param meth {@code non-null;} method to analyze
- */
- private void run() {
- SsaBasicBlock root = postdom
- ? meth.getExitBlock() : meth.getEntryBlock();
-
- if (root != null) {
- vertex.add(root);
- domInfos[root.getIndex()].idom = root.getIndex();
- }
+ BitSet preds = getPreds(w);
+ for (int j = preds.nextSetBit(0); j >= 0; j = preds.nextSetBit(j + 1)) {
+ SsaBasicBlock predBlock = blocks.get(j);
+ DFSInfo predInfo = info[predBlock.getIndex()];
/*
- * First we perform a DFS numbering of the blocks, by
- * numbering the dfs tree roots.
+ * PredInfo may not exist in case the predecessor is
+ * not reachable.
*/
-
- DfsWalker walker = new DfsWalker();
- meth.forEachBlockDepthFirst(postdom, walker);
-
- // the largest semidom number assigned
- int dfsMax = vertex.size() - 1;
-
- // Now calculate semidominators.
- for (int i = dfsMax; i >= 2; --i) {
- SsaBasicBlock w = vertex.get(i);
- DFSInfo wInfo = info[w.getIndex()];
-
- BitSet preds = getPreds(w);
- for (int j = preds.nextSetBit(0);
- j >= 0;
- j = preds.nextSetBit(j + 1)) {
- SsaBasicBlock predBlock = blocks.get(j);
- DFSInfo predInfo = info[predBlock.getIndex()];
-
- /*
- * PredInfo may not exist in case the predecessor is
- * not reachable.
- */
- if (predInfo != null) {
- int predSemidom = info[eval(predBlock).getIndex()].semidom;
- if (predSemidom < wInfo.semidom) {
- wInfo.semidom = predSemidom;
- }
- }
- }
- info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w);
-
- /*
- * Normally we would call link here, but in our O(m log n)
- * implementation this is equivalent to the following
- * single line.
- */
- wInfo.ancestor = wInfo.parent;
-
- // Implicity define idom for each vertex.
- ArrayList<SsaBasicBlock> wParentBucket;
- wParentBucket = info[wInfo.parent.getIndex()].bucket;
-
- while (!wParentBucket.isEmpty()) {
- int lastItem = wParentBucket.size() - 1;
- SsaBasicBlock last = wParentBucket.remove(lastItem);
- SsaBasicBlock U = eval(last);
- if (info[U.getIndex()].semidom
- < info[last.getIndex()].semidom) {
- domInfos[last.getIndex()].idom = U.getIndex();
- } else {
- domInfos[last.getIndex()].idom = wInfo.parent.getIndex();
- }
- }
+ if (predInfo != null) {
+ int predSemidom = info[eval(predBlock).getIndex()].semidom;
+ if (predSemidom < wInfo.semidom) {
+ wInfo.semidom = predSemidom;
+ }
}
+ }
+ info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w);
- // Now explicitly define the immediate dominator of each vertex
- for (int i = 2; i <= dfsMax; ++i) {
- SsaBasicBlock w = vertex.get(i);
- if (domInfos[w.getIndex()].idom
- != vertex.get(info[w.getIndex()].semidom).getIndex()) {
- domInfos[w.getIndex()].idom
- = domInfos[domInfos[w.getIndex()].idom].idom;
- }
+ /*
+ * Normally we would call link here, but in our O(m log n)
+ * implementation this is equivalent to the following
+ * single line.
+ */
+ wInfo.ancestor = wInfo.parent;
+
+ // Implicity define idom for each vertex.
+ ArrayList<SsaBasicBlock> wParentBucket;
+ wParentBucket = info[wInfo.parent.getIndex()].bucket;
+
+ while (!wParentBucket.isEmpty()) {
+ int lastItem = wParentBucket.size() - 1;
+ SsaBasicBlock last = wParentBucket.remove(lastItem);
+ SsaBasicBlock u = eval(last);
+ if (info[u.getIndex()].semidom < info[last.getIndex()].semidom) {
+ domInfos[last.getIndex()].idom = u.getIndex();
+ } else {
+ domInfos[last.getIndex()].idom = wInfo.parent.getIndex();
}
+ }
}
+ // Now explicitly define the immediate dominator of each vertex
+ for (int i = 2; i <= dfsMax; ++i) {
+ SsaBasicBlock w = vertex.get(i);
+ if (domInfos[w.getIndex()].idom != vertex.get(info[w.getIndex()].semidom).getIndex()) {
+ domInfos[w.getIndex()].idom = domInfos[domInfos[w.getIndex()].idom].idom;
+ }
+ }
+ }
+
+ /**
+ * Callback for depth-first walk through control flow graph (either
+ * from the entry block or the exit block). Records the traversal order
+ * in the {@code info}list.
+ */
+ private class DfsWalker implements SsaBasicBlock.Visitor {
+ private int dfsNum = 0;
+
+ @Override
+ public void visitBlock(SsaBasicBlock v, SsaBasicBlock parent) {
+ DFSInfo bbInfo = new DFSInfo();
+ bbInfo.semidom = ++dfsNum;
+ bbInfo.rep = v;
+ bbInfo.parent = parent;
+ vertex.add(v);
+ info[v.getIndex()] = bbInfo;
+ }
+ }
+
+ private static final class DFSInfo {
+ public int semidom;
+ public SsaBasicBlock parent;
+
/**
- * Callback for depth-first walk through control flow graph (either
- * from the entry block or the exit block). Records the traversal order
- * in the {@code info}list.
+ * rep(resentative) is known as "label" in the paper. It is the node
+ * that our block's DFS info has been unioned to.
*/
- private class DfsWalker implements SsaBasicBlock.Visitor {
- private int dfsNum = 0;
+ public SsaBasicBlock rep;
- public void visitBlock(SsaBasicBlock v, SsaBasicBlock parent) {
- DFSInfo bbInfo = new DFSInfo();
- bbInfo.semidom = ++dfsNum;
- bbInfo.rep = v;
- bbInfo.parent = parent;
- vertex.add(v);
- info[v.getIndex()] = bbInfo;
- }
+ public SsaBasicBlock ancestor;
+ public ArrayList<SsaBasicBlock> bucket;
+
+ public DFSInfo() {
+ bucket = new ArrayList<SsaBasicBlock>();
}
-
- private static final class DFSInfo {
- public int semidom;
- public SsaBasicBlock parent;
-
- /**
- * rep(resentative) is known as "label" in the paper. It is the node
- * that our block's DFS info has been unioned to.
- */
- public SsaBasicBlock rep;
-
- public SsaBasicBlock ancestor;
- public ArrayList<SsaBasicBlock> bucket;
-
- public DFSInfo() {
- bucket = new ArrayList<SsaBasicBlock>();
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java b/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java
index 791a3b5..6021941 100644
--- a/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java
+++ b/dx/src/com/android/jack/dx/ssa/EscapeAnalysis.java
@@ -50,794 +50,768 @@
* the method they are created in and replaces the array values with registers.
*/
public class EscapeAnalysis {
- /**
- * Struct used to generate and maintain escape analysis results.
- */
- static class EscapeSet {
- /** set containing all registers related to an object */
- BitSet regSet;
- /** escape state of the object */
- EscapeState escape;
- /** list of objects that are put into this object */
- ArrayList<EscapeSet> childSets;
- /** list of objects that this object is put into */
- ArrayList<EscapeSet> parentSets;
- /** flag to indicate this object is a scalar replaceable array */
- boolean replaceableArray;
-
- /**
- * Constructs an instance of an EscapeSet
- *
- * @param reg the SSA register that defines the object
- * @param size the number of registers in the method
- * @param escState the lattice value to initially set this to
- */
- EscapeSet(int reg, int size, EscapeState escState) {
- regSet = new BitSet(size);
- regSet.set(reg);
- escape = escState;
- childSets = new ArrayList<EscapeSet>();
- parentSets = new ArrayList<EscapeSet>();
- replaceableArray = false;
- }
- }
+ /**
+ * Struct used to generate and maintain escape analysis results.
+ */
+ static class EscapeSet {
+ /** set containing all registers related to an object */
+ BitSet regSet;
+ /** escape state of the object */
+ EscapeState escape;
+ /** list of objects that are put into this object */
+ ArrayList<EscapeSet> childSets;
+ /** list of objects that this object is put into */
+ ArrayList<EscapeSet> parentSets;
+ /** flag to indicate this object is a scalar replaceable array */
+ boolean replaceableArray;
/**
- * Lattice values used to indicate escape state for an object. Analysis can
- * only raise escape state values, not lower them.
+ * Constructs an instance of an EscapeSet
*
- * TOP - Used for objects that haven't been analyzed yet
- * NONE - Object does not escape, and is eligible for scalar replacement.
- * METHOD - Object remains local to method, but can't be scalar replaced.
- * INTER - Object is passed between methods. (treated as globally escaping
- * since this is an intraprocedural analysis)
- * GLOBAL - Object escapes globally.
+ * @param reg the SSA register that defines the object
+ * @param size the number of registers in the method
+ * @param escState the lattice value to initially set this to
*/
- public enum EscapeState {
- TOP, NONE, METHOD, INTER, GLOBAL
+ EscapeSet(int reg, int size, EscapeState escState) {
+ regSet = new BitSet(size);
+ regSet.set(reg);
+ escape = escState;
+ childSets = new ArrayList<EscapeSet>();
+ parentSets = new ArrayList<EscapeSet>();
+ replaceableArray = false;
}
+ }
- /** method we're processing */
- private SsaMethod ssaMeth;
- /** ssaMeth.getRegCount() */
- private int regCount;
- /** Lattice values for each object register group */
- private ArrayList<EscapeSet> latticeValues;
+ /**
+ * Lattice values used to indicate escape state for an object. Analysis can
+ * only raise escape state values, not lower them.
+ *
+ * TOP - Used for objects that haven't been analyzed yet
+ * NONE - Object does not escape, and is eligible for scalar replacement.
+ * METHOD - Object remains local to method, but can't be scalar replaced.
+ * INTER - Object is passed between methods. (treated as globally escaping
+ * since this is an intraprocedural analysis)
+ * GLOBAL - Object escapes globally.
+ */
+ public enum EscapeState {
+ TOP, NONE, METHOD, INTER, GLOBAL
+ }
- /**
- * Constructs an instance.
- *
- * @param ssaMeth method to process
- */
- private EscapeAnalysis(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
- this.regCount = ssaMeth.getRegCount();
- this.latticeValues = new ArrayList<EscapeSet>();
- }
+ /** method we're processing */
+ private SsaMethod ssaMeth;
+ /** ssaMeth.getRegCount() */
+ private int regCount;
+ /** Lattice values for each object register group */
+ private ArrayList<EscapeSet> latticeValues;
- /**
- * Finds the index in the lattice for a particular register.
- * Returns the size of the lattice if the register wasn't found.
- *
- * @param reg {@code non-null;} register being looked up
- * @return index of the register or size of the lattice if it wasn't found.
- */
- private int findSetIndex(RegisterSpec reg) {
- int i;
- for (i = 0; i < latticeValues.size(); i++) {
- EscapeSet e = latticeValues.get(i);
- if (e.regSet.get(reg.getReg())) {
- return i;
- }
- }
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMeth method to process
+ */
+ private EscapeAnalysis(SsaMethod ssaMeth) {
+ this.ssaMeth = ssaMeth;
+ this.regCount = ssaMeth.getRegCount();
+ this.latticeValues = new ArrayList<EscapeSet>();
+ }
+
+ /**
+ * Finds the index in the lattice for a particular register.
+ * Returns the size of the lattice if the register wasn't found.
+ *
+ * @param reg {@code non-null;} register being looked up
+ * @return index of the register or size of the lattice if it wasn't found.
+ */
+ private int findSetIndex(RegisterSpec reg) {
+ int i;
+ for (i = 0; i < latticeValues.size(); i++) {
+ EscapeSet e = latticeValues.get(i);
+ if (e.regSet.get(reg.getReg())) {
return i;
+ }
}
+ return i;
+ }
- /**
- * Finds the corresponding instruction for a given move result
- *
- * @param moveInsn {@code non-null;} a move result instruction
- * @return {@code non-null;} the instruction that produces the result for
- * the move
- */
- private SsaInsn getInsnForMove(SsaInsn moveInsn) {
- int pred = moveInsn.getBlock().getPredecessors().nextSetBit(0);
- ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
- return predInsns.get(predInsns.size()-1);
+ /**
+ * Finds the corresponding instruction for a given move result
+ *
+ * @param moveInsn {@code non-null;} a move result instruction
+ * @return {@code non-null;} the instruction that produces the result for
+ * the move
+ */
+ private SsaInsn getInsnForMove(SsaInsn moveInsn) {
+ int pred = moveInsn.getBlock().getPredecessors().nextSetBit(0);
+ ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+ return predInsns.get(predInsns.size() - 1);
+ }
+
+ /**
+ * Finds the corresponding move result for a given instruction
+ *
+ * @param insn {@code non-null;} an instruction that must always be
+ * followed by a move result
+ * @return {@code non-null;} the move result for the given instruction
+ */
+ private SsaInsn getMoveForInsn(SsaInsn insn) {
+ int succ = insn.getBlock().getSuccessors().nextSetBit(0);
+ ArrayList<SsaInsn> succInsns = ssaMeth.getBlocks().get(succ).getInsns();
+ return succInsns.get(0);
+ }
+
+ /**
+ * Creates a link in the lattice between two EscapeSets due to a put
+ * instruction. The object being put is the child and the object being put
+ * into is the parent. A child set must always have an escape state at
+ * least as high as its parent.
+ *
+ * @param parentSet {@code non-null;} the EscapeSet for the object being put
+ * into
+ * @param childSet {@code non-null;} the EscapeSet for the object being put
+ */
+ private void addEdge(EscapeSet parentSet, EscapeSet childSet) {
+ if (!childSet.parentSets.contains(parentSet)) {
+ childSet.parentSets.add(parentSet);
}
-
- /**
- * Finds the corresponding move result for a given instruction
- *
- * @param insn {@code non-null;} an instruction that must always be
- * followed by a move result
- * @return {@code non-null;} the move result for the given instruction
- */
- private SsaInsn getMoveForInsn(SsaInsn insn) {
- int succ = insn.getBlock().getSuccessors().nextSetBit(0);
- ArrayList<SsaInsn> succInsns = ssaMeth.getBlocks().get(succ).getInsns();
- return succInsns.get(0);
+ if (!parentSet.childSets.contains(childSet)) {
+ parentSet.childSets.add(childSet);
}
+ }
- /**
- * Creates a link in the lattice between two EscapeSets due to a put
- * instruction. The object being put is the child and the object being put
- * into is the parent. A child set must always have an escape state at
- * least as high as its parent.
- *
- * @param parentSet {@code non-null;} the EscapeSet for the object being put
- * into
- * @param childSet {@code non-null;} the EscapeSet for the object being put
- */
- private void addEdge(EscapeSet parentSet, EscapeSet childSet) {
- if (!childSet.parentSets.contains(parentSet)) {
- childSet.parentSets.add(parentSet);
+ /**
+ * Merges all links in the lattice among two EscapeSets. On return, the
+ * newNode will have its old links as well as all links from the oldNode.
+ * The oldNode has all its links removed.
+ *
+ * @param newNode {@code non-null;} the EscapeSet to merge all links into
+ * @param oldNode {@code non-null;} the EscapeSet to remove all links from
+ */
+ private void replaceNode(EscapeSet newNode, EscapeSet oldNode) {
+ for (EscapeSet e : oldNode.parentSets) {
+ e.childSets.remove(oldNode);
+ e.childSets.add(newNode);
+ newNode.parentSets.add(e);
+ }
+ for (EscapeSet e : oldNode.childSets) {
+ e.parentSets.remove(oldNode);
+ e.parentSets.add(newNode);
+ newNode.childSets.add(e);
+ }
+ }
+
+ /**
+ * Performs escape analysis on a method. Finds scalar replaceable arrays and
+ * replaces them with equivalent registers.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ new EscapeAnalysis(ssaMethod).run();
+ }
+
+ /**
+ * Process a single instruction, looking for new objects resulting from
+ * move result or move param.
+ *
+ * @param insn {@code non-null;} instruction to process
+ */
+ private void processInsn(SsaInsn insn) {
+ int op = insn.getOpcode().getOpcode();
+ RegisterSpec result = insn.getResult();
+ EscapeSet escSet;
+
+ // Identify new objects
+ if (op == RegOps.MOVE_RESULT_PSEUDO
+ && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Handle objects generated through move_result_pseudo
+ escSet = processMoveResultPseudoInsn(insn);
+ processRegister(result, escSet);
+ } else if (op == RegOps.MOVE_PARAM && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Track method arguments that are objects
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ latticeValues.add(escSet);
+ processRegister(result, escSet);
+ } else if (op == RegOps.MOVE_RESULT
+ && result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+ // Track method return values that are objects
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ latticeValues.add(escSet);
+ processRegister(result, escSet);
+ }
+ }
+
+ /**
+ * Determine the origin of a move result pseudo instruction that generates
+ * an object. Creates a new EscapeSet for the new object accordingly.
+ *
+ * @param insn {@code non-null;} move result pseudo instruction to process
+ * @return {@code non-null;} an EscapeSet for the object referred to by the
+ * move result pseudo instruction
+ */
+ private EscapeSet processMoveResultPseudoInsn(SsaInsn insn) {
+ RegisterSpec result = insn.getResult();
+ SsaInsn prevSsaInsn = getInsnForMove(insn);
+ int prevOpcode = prevSsaInsn.getOpcode().getOpcode();
+ EscapeSet escSet;
+ RegisterSpec prevSource;
+
+ switch (prevOpcode) {
+ // New instance / Constant
+ case RegOps.NEW_INSTANCE:
+ case RegOps.CONST:
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ break;
+ // New array
+ case RegOps.NEW_ARRAY:
+ case RegOps.FILLED_NEW_ARRAY:
+ prevSource = prevSsaInsn.getSources().get(0);
+ if (prevSource.getTypeBearer().isConstant()) {
+ // New fixed array
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+ escSet.replaceableArray = true;
+ } else {
+ // New variable array
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
}
- if (!parentSet.childSets.contains(childSet)) {
- parentSet.childSets.add(childSet);
- }
- }
+ break;
+ // Loading a static object
+ case RegOps.GET_STATIC:
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
+ break;
+ // Type cast / load an object from a field or array
+ case RegOps.CHECK_CAST:
+ case RegOps.GET_FIELD:
+ case RegOps.AGET:
+ prevSource = prevSsaInsn.getSources().get(0);
+ int setIndex = findSetIndex(prevSource);
- /**
- * Merges all links in the lattice among two EscapeSets. On return, the
- * newNode will have its old links as well as all links from the oldNode.
- * The oldNode has all its links removed.
- *
- * @param newNode {@code non-null;} the EscapeSet to merge all links into
- * @param oldNode {@code non-null;} the EscapeSet to remove all links from
- */
- private void replaceNode(EscapeSet newNode, EscapeSet oldNode) {
- for (EscapeSet e : oldNode.parentSets) {
- e.childSets.remove(oldNode);
- e.childSets.add(newNode);
- newNode.parentSets.add(e);
- }
- for (EscapeSet e : oldNode.childSets) {
- e.parentSets.remove(oldNode);
- e.parentSets.add(newNode);
- newNode.childSets.add(e);
- }
- }
-
- /**
- * Performs escape analysis on a method. Finds scalar replaceable arrays and
- * replaces them with equivalent registers.
- *
- * @param ssaMethod {@code non-null;} method to process
- */
- public static void process(SsaMethod ssaMethod) {
- new EscapeAnalysis(ssaMethod).run();
- }
-
- /**
- * Process a single instruction, looking for new objects resulting from
- * move result or move param.
- *
- * @param insn {@code non-null;} instruction to process
- */
- private void processInsn(SsaInsn insn) {
- int op = insn.getOpcode().getOpcode();
- RegisterSpec result = insn.getResult();
- EscapeSet escSet;
-
- // Identify new objects
- if (op == RegOps.MOVE_RESULT_PSEUDO &&
- result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Handle objects generated through move_result_pseudo
- escSet = processMoveResultPseudoInsn(insn);
- processRegister(result, escSet);
- } else if (op == RegOps.MOVE_PARAM &&
- result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Track method arguments that are objects
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- latticeValues.add(escSet);
- processRegister(result, escSet);
- } else if (op == RegOps.MOVE_RESULT &&
- result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
- // Track method return values that are objects
- escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
- latticeValues.add(escSet);
- processRegister(result, escSet);
- }
- }
-
- /**
- * Determine the origin of a move result pseudo instruction that generates
- * an object. Creates a new EscapeSet for the new object accordingly.
- *
- * @param insn {@code non-null;} move result pseudo instruction to process
- * @return {@code non-null;} an EscapeSet for the object referred to by the
- * move result pseudo instruction
- */
- private EscapeSet processMoveResultPseudoInsn(SsaInsn insn) {
- RegisterSpec result = insn.getResult();
- SsaInsn prevSsaInsn = getInsnForMove(insn);
- int prevOpcode = prevSsaInsn.getOpcode().getOpcode();
- EscapeSet escSet;
- RegisterSpec prevSource;
-
- switch(prevOpcode) {
- // New instance / Constant
- case RegOps.NEW_INSTANCE:
- case RegOps.CONST:
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.NONE);
- break;
- // New array
- case RegOps.NEW_ARRAY:
- case RegOps.FILLED_NEW_ARRAY:
- prevSource = prevSsaInsn.getSources().get(0);
- if (prevSource.getTypeBearer().isConstant()) {
- // New fixed array
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.NONE);
- escSet.replaceableArray = true;
- } else {
- // New variable array
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.GLOBAL);
- }
- break;
- // Loading a static object
- case RegOps.GET_STATIC:
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.GLOBAL);
- break;
- // Type cast / load an object from a field or array
- case RegOps.CHECK_CAST:
- case RegOps.GET_FIELD:
- case RegOps.AGET:
- prevSource = prevSsaInsn.getSources().get(0);
- int setIndex = findSetIndex(prevSource);
-
- // Set should already exist, try to find it
- if (setIndex != latticeValues.size()) {
- escSet = latticeValues.get(setIndex);
- escSet.regSet.set(result.getReg());
- return escSet;
- }
-
- // Set not found, must be either null or unknown
- if (prevSource.getType() == Type.KNOWN_NULL) {
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.NONE);
- } else {
- escSet = new EscapeSet(result.getReg(), regCount,
- EscapeState.GLOBAL);
- }
- break;
- default:
- return null;
- }
-
- // Add the newly created escSet to the lattice and return it
- latticeValues.add(escSet);
- return escSet;
- }
-
- /**
- * Iterate through all the uses of a new object.
- *
- * @param result {@code non-null;} register where new object is stored
- * @param escSet {@code non-null;} EscapeSet for the new object
- */
- private void processRegister(RegisterSpec result, EscapeSet escSet) {
- ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
- regWorklist.add(result);
-
- // Go through the worklist
- while (!regWorklist.isEmpty()) {
- int listSize = regWorklist.size() - 1;
- RegisterSpec def = regWorklist.remove(listSize);
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
-
- // Handle all the uses of this register
- for (SsaInsn use : useList) {
- Rop useOpcode = use.getOpcode();
-
- if (useOpcode == null) {
- // Handle phis
- processPhiUse(use, escSet, regWorklist);
- } else {
- // Handle other opcodes
- processUse(def, use, escSet, regWorklist);
- }
- }
- }
- }
-
- /**
- * Handles phi uses of new objects. Will merge together the sources of a phi
- * into a single EscapeSet. Adds the result of the phi to the worklist so
- * its uses can be followed.
- *
- * @param use {@code non-null;} phi use being processed
- * @param escSet {@code non-null;} EscapeSet for the object
- * @param regWorklist {@code non-null;} worklist of instructions left to
- * process for this object
- */
- private void processPhiUse(SsaInsn use, EscapeSet escSet,
- ArrayList<RegisterSpec> regWorklist) {
- int setIndex = findSetIndex(use.getResult());
+ // Set should already exist, try to find it
if (setIndex != latticeValues.size()) {
- // Check if result is in a set already
- EscapeSet mergeSet = latticeValues.get(setIndex);
- if (mergeSet != escSet) {
- // If it is, merge the sets and states, then delete the copy
- escSet.replaceableArray = false;
- escSet.regSet.or(mergeSet.regSet);
- if (escSet.escape.compareTo(mergeSet.escape) < 0) {
- escSet.escape = mergeSet.escape;
- }
- replaceNode(escSet, mergeSet);
- latticeValues.remove(setIndex);
- }
+ escSet = latticeValues.get(setIndex);
+ escSet.regSet.set(result.getReg());
+ return escSet;
+ }
+
+ // Set not found, must be either null or unknown
+ if (prevSource.getType() == Type.KNOWN_NULL) {
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
} else {
- // If no set is found, add it to this escSet and the worklist
- escSet.regSet.set(use.getResult().getReg());
- regWorklist.add(use.getResult());
+ escSet = new EscapeSet(result.getReg(), regCount, EscapeState.GLOBAL);
}
+ break;
+ default:
+ return null;
}
- /**
- * Handles non-phi uses of new objects. Checks to see how instruction is
- * used and updates the escape state accordingly.
- *
- * @param def {@code non-null;} register holding definition of new object
- * @param use {@code non-null;} use of object being processed
- * @param escSet {@code non-null;} EscapeSet for the object
- * @param regWorklist {@code non-null;} worklist of instructions left to
- * process for this object
- */
- private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet,
- ArrayList<RegisterSpec> regWorklist) {
- int useOpcode = use.getOpcode().getOpcode();
- switch (useOpcode) {
- case RegOps.MOVE:
- // Follow uses of the move by adding it to the worklist
- escSet.regSet.set(use.getResult().getReg());
- regWorklist.add(use.getResult());
- break;
- case RegOps.IF_EQ:
- case RegOps.IF_NE:
- case RegOps.CHECK_CAST:
- // Compared objects can't be replaced, so promote if necessary
- if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
- escSet.escape = EscapeState.METHOD;
- }
- break;
- case RegOps.APUT:
- // For array puts, check for a constant array index
- RegisterSpec putIndex = use.getSources().get(2);
- if (!putIndex.getTypeBearer().isConstant()) {
- // If not constant, array can't be replaced
- escSet.replaceableArray = false;
- }
- // Intentional fallthrough
- case RegOps.PUT_FIELD:
- // Skip non-object puts
- RegisterSpec putValue = use.getSources().get(0);
- if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
- break;
- }
- escSet.replaceableArray = false;
+ // Add the newly created escSet to the lattice and return it
+ latticeValues.add(escSet);
+ return escSet;
+ }
- // Raise 1st object's escape state to 2nd if 2nd is higher
- RegisterSpecList sources = use.getSources();
- if (sources.get(0).getReg() == def.getReg()) {
- int setIndex = findSetIndex(sources.get(1));
- if (setIndex != latticeValues.size()) {
- EscapeSet parentSet = latticeValues.get(setIndex);
- addEdge(parentSet, escSet);
- if (escSet.escape.compareTo(parentSet.escape) < 0) {
- escSet.escape = parentSet.escape;
- }
- }
- } else {
- int setIndex = findSetIndex(sources.get(0));
- if (setIndex != latticeValues.size()) {
- EscapeSet childSet = latticeValues.get(setIndex);
- addEdge(escSet, childSet);
- if (childSet.escape.compareTo(escSet.escape) < 0) {
- childSet.escape = escSet.escape;
- }
- }
- }
- break;
- case RegOps.AGET:
- // For array gets, check for a constant array index
- RegisterSpec getIndex = use.getSources().get(1);
- if (!getIndex.getTypeBearer().isConstant()) {
- // If not constant, array can't be replaced
- escSet.replaceableArray = false;
- }
- break;
- case RegOps.PUT_STATIC:
- // Static puts cause an object to escape globally
- escSet.escape = EscapeState.GLOBAL;
- break;
- case RegOps.INVOKE_STATIC:
- case RegOps.INVOKE_VIRTUAL:
- case RegOps.INVOKE_SUPER:
- case RegOps.INVOKE_DIRECT:
- case RegOps.INVOKE_INTERFACE:
- case RegOps.RETURN:
- case RegOps.THROW:
- // These operations cause an object to escape interprocedurally
- escSet.escape = EscapeState.INTER;
- break;
- default:
- break;
+ /**
+ * Iterate through all the uses of a new object.
+ *
+ * @param result {@code non-null;} register where new object is stored
+ * @param escSet {@code non-null;} EscapeSet for the new object
+ */
+ private void processRegister(RegisterSpec result, EscapeSet escSet) {
+ ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
+ regWorklist.add(result);
+
+ // Go through the worklist
+ while (!regWorklist.isEmpty()) {
+ int listSize = regWorklist.size() - 1;
+ RegisterSpec def = regWorklist.remove(listSize);
+ List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
+
+ // Handle all the uses of this register
+ for (SsaInsn use : useList) {
+ Rop useOpcode = use.getOpcode();
+
+ if (useOpcode == null) {
+ // Handle phis
+ processPhiUse(use, escSet, regWorklist);
+ } else {
+ // Handle other opcodes
+ processUse(def, use, escSet, regWorklist);
}
+ }
}
+ }
- /**
- * Performs scalar replacement on all eligible arrays.
- */
- private void scalarReplacement() {
- // Iterate through lattice, looking for non-escaping replaceable arrays
- for (EscapeSet escSet : latticeValues) {
- if (!escSet.replaceableArray || escSet.escape != EscapeState.NONE) {
- continue;
+ /**
+ * Handles phi uses of new objects. Will merge together the sources of a phi
+ * into a single EscapeSet. Adds the result of the phi to the worklist so
+ * its uses can be followed.
+ *
+ * @param use {@code non-null;} phi use being processed
+ * @param escSet {@code non-null;} EscapeSet for the object
+ * @param regWorklist {@code non-null;} worklist of instructions left to
+ * process for this object
+ */
+ private void processPhiUse(SsaInsn use, EscapeSet escSet, ArrayList<RegisterSpec> regWorklist) {
+ int setIndex = findSetIndex(use.getResult());
+ if (setIndex != latticeValues.size()) {
+ // Check if result is in a set already
+ EscapeSet mergeSet = latticeValues.get(setIndex);
+ if (mergeSet != escSet) {
+ // If it is, merge the sets and states, then delete the copy
+ escSet.replaceableArray = false;
+ escSet.regSet.or(mergeSet.regSet);
+ if (escSet.escape.compareTo(mergeSet.escape) < 0) {
+ escSet.escape = mergeSet.escape;
+ }
+ replaceNode(escSet, mergeSet);
+ latticeValues.remove(setIndex);
+ }
+ } else {
+ // If no set is found, add it to this escSet and the worklist
+ escSet.regSet.set(use.getResult().getReg());
+ regWorklist.add(use.getResult());
+ }
+ }
+
+ /**
+ * Handles non-phi uses of new objects. Checks to see how instruction is
+ * used and updates the escape state accordingly.
+ *
+ * @param def {@code non-null;} register holding definition of new object
+ * @param use {@code non-null;} use of object being processed
+ * @param escSet {@code non-null;} EscapeSet for the object
+ * @param regWorklist {@code non-null;} worklist of instructions left to
+ * process for this object
+ */
+ private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet,
+ ArrayList<RegisterSpec> regWorklist) {
+ int useOpcode = use.getOpcode().getOpcode();
+ switch (useOpcode) {
+ case RegOps.MOVE:
+ // Follow uses of the move by adding it to the worklist
+ escSet.regSet.set(use.getResult().getReg());
+ regWorklist.add(use.getResult());
+ break;
+ case RegOps.IF_EQ:
+ case RegOps.IF_NE:
+ case RegOps.CHECK_CAST:
+ // Compared objects can't be replaced, so promote if necessary
+ if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
+ escSet.escape = EscapeState.METHOD;
+ }
+ break;
+ case RegOps.APUT:
+ // For array puts, check for a constant array index
+ RegisterSpec putIndex = use.getSources().get(2);
+ if (!putIndex.getTypeBearer().isConstant()) {
+ // If not constant, array can't be replaced
+ escSet.replaceableArray = false;
+ }
+ // Intentional fallthrough
+ case RegOps.PUT_FIELD:
+ // Skip non-object puts
+ RegisterSpec putValue = use.getSources().get(0);
+ if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
+ break;
+ }
+ escSet.replaceableArray = false;
+
+ // Raise 1st object's escape state to 2nd if 2nd is higher
+ RegisterSpecList sources = use.getSources();
+ if (sources.get(0).getReg() == def.getReg()) {
+ int setIndex = findSetIndex(sources.get(1));
+ if (setIndex != latticeValues.size()) {
+ EscapeSet parentSet = latticeValues.get(setIndex);
+ addEdge(parentSet, escSet);
+ if (escSet.escape.compareTo(parentSet.escape) < 0) {
+ escSet.escape = parentSet.escape;
}
-
- // Get the instructions for the definition and move of the array
- int e = escSet.regSet.nextSetBit(0);
- SsaInsn def = ssaMeth.getDefinitionForRegister(e);
- SsaInsn prev = getInsnForMove(def);
-
- // Create a map for the new registers that will be created
- TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
- int length = ((CstLiteralBits) lengthReg).getIntBits();
- ArrayList<RegisterSpec> newRegs =
- new ArrayList<RegisterSpec>(length);
- HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
-
- // Replace the definition of the array with registers
- replaceDef(def, prev, length, newRegs);
-
- // Mark definition instructions for deletion
- deletedInsns.add(prev);
- deletedInsns.add(def);
-
- // Go through all uses of the array
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(e);
- for (SsaInsn use : useList) {
- // Replace the use with scalars and then mark it for deletion
- replaceUse(use, prev, newRegs, deletedInsns);
- deletedInsns.add(use);
+ }
+ } else {
+ int setIndex = findSetIndex(sources.get(0));
+ if (setIndex != latticeValues.size()) {
+ EscapeSet childSet = latticeValues.get(setIndex);
+ addEdge(escSet, childSet);
+ if (childSet.escape.compareTo(escSet.escape) < 0) {
+ childSet.escape = escSet.escape;
}
-
- // Delete all marked instructions
- ssaMeth.deleteInsns(deletedInsns);
- ssaMeth.onInsnsChanged();
-
- // Convert the method back to SSA form
- SsaConverter.updateSsaMethod(ssaMeth, regCount);
-
- // Propagate and remove extra moves added by scalar replacement
- movePropagate();
+ }
}
+ break;
+ case RegOps.AGET:
+ // For array gets, check for a constant array index
+ RegisterSpec getIndex = use.getSources().get(1);
+ if (!getIndex.getTypeBearer().isConstant()) {
+ // If not constant, array can't be replaced
+ escSet.replaceableArray = false;
+ }
+ break;
+ case RegOps.PUT_STATIC:
+ // Static puts cause an object to escape globally
+ escSet.escape = EscapeState.GLOBAL;
+ break;
+ case RegOps.INVOKE_STATIC:
+ case RegOps.INVOKE_VIRTUAL:
+ case RegOps.INVOKE_SUPER:
+ case RegOps.INVOKE_DIRECT:
+ case RegOps.INVOKE_INTERFACE:
+ case RegOps.RETURN:
+ case RegOps.THROW:
+ // These operations cause an object to escape interprocedurally
+ escSet.escape = EscapeState.INTER;
+ break;
+ default:
+ break;
}
+ }
- /**
- * Replaces the instructions that define an array with equivalent registers.
- * For each entry in the array, a register is created, initialized to zero.
- * A mapping between this register and the corresponding array index is
- * added.
- *
- * @param def {@code non-null;} move result instruction for array
- * @param prev {@code non-null;} instruction for instantiating new array
- * @param length size of the new array
- * @param newRegs {@code non-null;} mapping of array indices to new
- * registers to be populated
- */
- private void replaceDef(SsaInsn def, SsaInsn prev, int length,
- ArrayList<RegisterSpec> newRegs) {
- Type resultType = def.getResult().getType();
+ /**
+ * Performs scalar replacement on all eligible arrays.
+ */
+ private void scalarReplacement() {
+ // Iterate through lattice, looking for non-escaping replaceable arrays
+ for (EscapeSet escSet : latticeValues) {
+ if (!escSet.replaceableArray || escSet.escape != EscapeState.NONE) {
+ continue;
+ }
- // Create new zeroed out registers for each element in the array
+ // Get the instructions for the definition and move of the array
+ int e = escSet.regSet.nextSetBit(0);
+ SsaInsn def = ssaMeth.getDefinitionForRegister(e);
+ SsaInsn prev = getInsnForMove(def);
+
+ // Create a map for the new registers that will be created
+ TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+ int length = ((CstLiteralBits) lengthReg).getIntBits();
+ ArrayList<RegisterSpec> newRegs = new ArrayList<RegisterSpec>(length);
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+ // Replace the definition of the array with registers
+ replaceDef(def, prev, length, newRegs);
+
+ // Mark definition instructions for deletion
+ deletedInsns.add(prev);
+ deletedInsns.add(def);
+
+ // Go through all uses of the array
+ List<SsaInsn> useList = ssaMeth.getUseListForRegister(e);
+ for (SsaInsn use : useList) {
+ // Replace the use with scalars and then mark it for deletion
+ replaceUse(use, prev, newRegs, deletedInsns);
+ deletedInsns.add(use);
+ }
+
+ // Delete all marked instructions
+ ssaMeth.deleteInsns(deletedInsns);
+ ssaMeth.onInsnsChanged();
+
+ // Convert the method back to SSA form
+ SsaConverter.updateSsaMethod(ssaMeth, regCount);
+
+ // Propagate and remove extra moves added by scalar replacement
+ movePropagate();
+ }
+ }
+
+ /**
+ * Replaces the instructions that define an array with equivalent registers.
+ * For each entry in the array, a register is created, initialized to zero.
+ * A mapping between this register and the corresponding array index is
+ * added.
+ *
+ * @param def {@code non-null;} move result instruction for array
+ * @param prev {@code non-null;} instruction for instantiating new array
+ * @param length size of the new array
+ * @param newRegs {@code non-null;} mapping of array indices to new
+ * registers to be populated
+ */
+ private void replaceDef(SsaInsn def, SsaInsn prev, int length, ArrayList<RegisterSpec> newRegs) {
+ Type resultType = def.getResult().getType();
+
+ // Create new zeroed out registers for each element in the array
+ for (int i = 0; i < length; i++) {
+ Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
+ TypedConstant typedZero = (TypedConstant) newZero;
+ RegisterSpec newReg = RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
+ newRegs.add(newReg);
+ insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg, RegOps.CONST, newZero);
+ }
+ }
+
+ /**
+ * Replaces the use for a scalar replaceable array. Gets and puts become
+ * move instructions, and array lengths and fills are handled. Can also
+ * identify ArrayIndexOutOfBounds exceptions and throw them if detected.
+ *
+ * @param use {@code non-null;} move result instruction for array
+ * @param prev {@code non-null;} instruction for instantiating new array
+ * @param newRegs {@code non-null;} mapping of array indices to new
+ * registers
+ * @param deletedInsns {@code non-null;} set of instructions marked for
+ * deletion
+ */
+ private void replaceUse(SsaInsn use, SsaInsn prev, ArrayList<RegisterSpec> newRegs,
+ HashSet<SsaInsn> deletedInsns) {
+ int index;
+ int length = newRegs.size();
+ SsaInsn next;
+ RegisterSpecList sources;
+ RegisterSpec source, result;
+ CstLiteralBits indexReg;
+
+ switch (use.getOpcode().getOpcode()) {
+ case RegOps.AGET:
+ // Replace array gets with moves
+ next = getMoveForInsn(use);
+ sources = use.getSources();
+ indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
+ index = indexReg.getIntBits();
+ if (index < length) {
+ source = newRegs.get(index);
+ result = source.withReg(next.getResult().getReg());
+ insertPlainInsnBefore(next, RegisterSpecList.make(source), result, RegOps.MOVE, null);
+ } else {
+ // Throw an exception if the index is out of bounds
+ insertExceptionThrow(next, sources.get(1), deletedInsns);
+ deletedInsns.add(next.getBlock().getInsns().get(2));
+ }
+ deletedInsns.add(next);
+ break;
+ case RegOps.APUT:
+ // Replace array puts with moves
+ sources = use.getSources();
+ indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
+ index = indexReg.getIntBits();
+ if (index < length) {
+ source = sources.get(0);
+ result = source.withReg(newRegs.get(index).getReg());
+ insertPlainInsnBefore(use, RegisterSpecList.make(source), result, RegOps.MOVE, null);
+ // Update the newReg entry to mark value as unknown now
+ newRegs.set(index, result.withSimpleType());
+ } else {
+ // Throw an exception if the index is out of bounds
+ insertExceptionThrow(use, sources.get(2), deletedInsns);
+ }
+ break;
+ case RegOps.ARRAY_LENGTH:
+ // Replace array lengths with const instructions
+ TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+ //CstInteger lengthReg = CstInteger.make(length);
+ next = getMoveForInsn(use);
+ insertPlainInsnBefore(next, RegisterSpecList.EMPTY, next.getResult(), RegOps.CONST,
+ (Constant) lengthReg);
+ deletedInsns.add(next);
+ break;
+ case RegOps.MARK_LOCAL:
+ // Remove mark local instructions
+ break;
+ case RegOps.FILL_ARRAY_DATA:
+ // Create const instructions for each fill value
+ Insn ropUse = use.getOriginalRopInsn();
+ FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
+ ArrayList<Constant> constList = fill.getInitValues();
for (int i = 0; i < length; i++) {
- Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
- TypedConstant typedZero = (TypedConstant) newZero;
- RegisterSpec newReg =
- RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
- newRegs.add(newReg);
- insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg,
- RegOps.CONST, newZero);
+ RegisterSpec newFill =
+ RegisterSpec.make(newRegs.get(i).getReg(), (TypeBearer) constList.get(i));
+ insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill, RegOps.CONST,
+ constList.get(i));
+ // Update the newRegs to hold the new const value
+ newRegs.set(i, newFill);
}
+ break;
+ default:
}
+ }
- /**
- * Replaces the use for a scalar replaceable array. Gets and puts become
- * move instructions, and array lengths and fills are handled. Can also
- * identify ArrayIndexOutOfBounds exceptions and throw them if detected.
- *
- * @param use {@code non-null;} move result instruction for array
- * @param prev {@code non-null;} instruction for instantiating new array
- * @param newRegs {@code non-null;} mapping of array indices to new
- * registers
- * @param deletedInsns {@code non-null;} set of instructions marked for
- * deletion
- */
- private void replaceUse(SsaInsn use, SsaInsn prev,
- ArrayList<RegisterSpec> newRegs,
- HashSet<SsaInsn> deletedInsns) {
- int index;
- int length = newRegs.size();
- SsaInsn next;
- RegisterSpecList sources;
- RegisterSpec source, result;
- CstLiteralBits indexReg;
+ /**
+ * Identifies extra moves added by scalar replacement and propagates the
+ * source of the move to any users of the result.
+ */
+ private void movePropagate() {
+ for (int i = 0; i < ssaMeth.getRegCount(); i++) {
+ SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
- switch (use.getOpcode().getOpcode()) {
- case RegOps.AGET:
- // Replace array gets with moves
- next = getMoveForInsn(use);
- sources = use.getSources();
- indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
- index = indexReg.getIntBits();
- if (index < length) {
- source = newRegs.get(index);
- result = source.withReg(next.getResult().getReg());
- insertPlainInsnBefore(next, RegisterSpecList.make(source),
- result, RegOps.MOVE, null);
- } else {
- // Throw an exception if the index is out of bounds
- insertExceptionThrow(next, sources.get(1), deletedInsns);
- deletedInsns.add(next.getBlock().getInsns().get(2));
- }
- deletedInsns.add(next);
- break;
- case RegOps.APUT:
- // Replace array puts with moves
- sources = use.getSources();
- indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
- index = indexReg.getIntBits();
- if (index < length) {
- source = sources.get(0);
- result = source.withReg(newRegs.get(index).getReg());
- insertPlainInsnBefore(use, RegisterSpecList.make(source),
- result, RegOps.MOVE, null);
- // Update the newReg entry to mark value as unknown now
- newRegs.set(index, result.withSimpleType());
- } else {
- // Throw an exception if the index is out of bounds
- insertExceptionThrow(use, sources.get(2), deletedInsns);
- }
- break;
- case RegOps.ARRAY_LENGTH:
- // Replace array lengths with const instructions
- TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
- //CstInteger lengthReg = CstInteger.make(length);
- next = getMoveForInsn(use);
- insertPlainInsnBefore(next, RegisterSpecList.EMPTY,
- next.getResult(), RegOps.CONST,
- (Constant) lengthReg);
- deletedInsns.add(next);
- break;
- case RegOps.MARK_LOCAL:
- // Remove mark local instructions
- break;
- case RegOps.FILL_ARRAY_DATA:
- // Create const instructions for each fill value
- Insn ropUse = use.getOriginalRopInsn();
- FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
- ArrayList<Constant> constList = fill.getInitValues();
- for (int i = 0; i < length; i++) {
- RegisterSpec newFill =
- RegisterSpec.make(newRegs.get(i).getReg(),
- (TypeBearer) constList.get(i));
- insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill,
- RegOps.CONST, constList.get(i));
- // Update the newRegs to hold the new const value
- newRegs.set(i, newFill);
- }
- break;
- default:
+ // Look for move instructions only
+ if (insn == null || insn.getOpcode() == null || insn.getOpcode().getOpcode() != RegOps.MOVE) {
+ continue;
+ }
+
+ final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
+ final RegisterSpec source = insn.getSources().get(0);
+ final RegisterSpec result = insn.getResult();
+
+ // Ignore moves that weren't added due to scalar replacement
+ if (source.getReg() < regCount && result.getReg() < regCount) {
+ continue;
+ }
+
+ // Create a mapping from source to result
+ RegisterMapper mapper = new RegisterMapper() {
+ @Override
+ public int getNewRegisterCount() {
+ return ssaMeth.getRegCount();
}
- }
- /**
- * Identifies extra moves added by scalar replacement and propagates the
- * source of the move to any users of the result.
- */
- private void movePropagate() {
- for (int i = 0; i < ssaMeth.getRegCount(); i++) {
- SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec.getReg() == result.getReg()) {
+ return source;
+ }
- // Look for move instructions only
- if (insn == null || insn.getOpcode() == null ||
- insn.getOpcode().getOpcode() != RegOps.MOVE) {
- continue;
- }
-
- final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
- final RegisterSpec source = insn.getSources().get(0);
- final RegisterSpec result = insn.getResult();
-
- // Ignore moves that weren't added due to scalar replacement
- if (source.getReg() < regCount && result.getReg() < regCount) {
- continue;
- }
-
- // Create a mapping from source to result
- RegisterMapper mapper = new RegisterMapper() {
- @Override
- public int getNewRegisterCount() {
- return ssaMeth.getRegCount();
- }
-
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec.getReg() == result.getReg()) {
- return source;
- }
-
- return registerSpec;
- }
- };
-
- // Modify all uses of the move to use the source of the move instead
- for (SsaInsn use : useList[result.getReg()]) {
- use.mapSourceRegisters(mapper);
- }
+ return registerSpec;
}
+ };
+
+ // Modify all uses of the move to use the source of the move instead
+ for (SsaInsn use : useList[result.getReg()]) {
+ use.mapSourceRegisters(mapper);
+ }
}
+ }
- /**
- * Runs escape analysis and scalar replacement of arrays.
- */
- private void run() {
- ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
- public void visitBlock (SsaBasicBlock block,
- SsaBasicBlock unused) {
- block.forEachInsn(new SsaInsn.Visitor() {
- public void visitMoveInsn(NormalSsaInsn insn) {
- // do nothing
- }
+ /**
+ * Runs escape analysis and scalar replacement of arrays.
+ */
+ private void run() {
+ ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
+ @Override
+ public void visitBlock(SsaBasicBlock block, SsaBasicBlock unused) {
+ block.forEachInsn(new SsaInsn.Visitor() {
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ // do nothing
+ }
- public void visitPhiInsn(PhiInsn insn) {
- // do nothing
- }
+ @Override
+ public void visitPhiInsn(PhiInsn insn) {
+ // do nothing
+ }
- public void visitNonMoveInsn(NormalSsaInsn insn) {
- processInsn(insn);
- }
- });
- }
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ processInsn(insn);
+ }
});
+ }
+ });
- // Go through lattice and promote fieldSets as necessary
- for (EscapeSet e : latticeValues) {
- if (e.escape != EscapeState.NONE) {
- for (EscapeSet field : e.childSets) {
- if (e.escape.compareTo(field.escape) > 0) {
- field.escape = e.escape;
- }
- }
- }
+ // Go through lattice and promote fieldSets as necessary
+ for (EscapeSet e : latticeValues) {
+ if (e.escape != EscapeState.NONE) {
+ for (EscapeSet field : e.childSets) {
+ if (e.escape.compareTo(field.escape) > 0) {
+ field.escape = e.escape;
+ }
}
-
- // Perform scalar replacement for arrays
- scalarReplacement();
+ }
}
- /**
- * Replaces instructions that trigger an ArrayIndexOutofBounds exception
- * with an actual throw of the exception.
- *
- * @param insn {@code non-null;} instruction causing the exception
- * @param index {@code non-null;} index value that is out of bounds
- * @param deletedInsns {@code non-null;} set of instructions marked for
- * deletion
- */
- private void insertExceptionThrow(SsaInsn insn, RegisterSpec index,
- HashSet<SsaInsn> deletedInsns) {
- // Create a new ArrayIndexOutOfBoundsException
- CstType exception =
- new CstType(Exceptions.TYPE_ArrayIndexOutOfBoundsException);
- insertThrowingInsnBefore(insn, RegisterSpecList.EMPTY, null,
- RegOps.NEW_INSTANCE, exception);
+ // Perform scalar replacement for arrays
+ scalarReplacement();
+ }
- // Add a successor block with a move result pseudo for the exception
- SsaBasicBlock currBlock = insn.getBlock();
- SsaBasicBlock newBlock =
- currBlock.insertNewSuccessor(currBlock.getPrimarySuccessor());
- SsaInsn newInsn = newBlock.getInsns().get(0);
- RegisterSpec newReg =
- RegisterSpec.make(ssaMeth.makeNewSsaReg(), exception);
- insertPlainInsnBefore(newInsn, RegisterSpecList.EMPTY, newReg,
- RegOps.MOVE_RESULT_PSEUDO, null);
+ /**
+ * Replaces instructions that trigger an ArrayIndexOutofBounds exception
+ * with an actual throw of the exception.
+ *
+ * @param insn {@code non-null;} instruction causing the exception
+ * @param index {@code non-null;} index value that is out of bounds
+ * @param deletedInsns {@code non-null;} set of instructions marked for
+ * deletion
+ */
+ private void insertExceptionThrow(SsaInsn insn, RegisterSpec index,
+ HashSet<SsaInsn> deletedInsns) {
+ // Create a new ArrayIndexOutOfBoundsException
+ CstType exception = new CstType(Exceptions.TYPE_ArrayIndexOutOfBoundsException);
+ insertThrowingInsnBefore(insn, RegisterSpecList.EMPTY, null, RegOps.NEW_INSTANCE, exception);
- // Add another successor block to initialize the exception
- SsaBasicBlock newBlock2 =
- newBlock.insertNewSuccessor(newBlock.getPrimarySuccessor());
- SsaInsn newInsn2 = newBlock2.getInsns().get(0);
- CstNat newNat = new CstNat(new CstString("<init>"), new CstString("(I)V"));
- CstMethodRef newRef = new CstMethodRef(exception, newNat);
- insertThrowingInsnBefore(newInsn2, RegisterSpecList.make(newReg, index),
- null, RegOps.INVOKE_DIRECT, newRef);
- deletedInsns.add(newInsn2);
+ // Add a successor block with a move result pseudo for the exception
+ SsaBasicBlock currBlock = insn.getBlock();
+ SsaBasicBlock newBlock = currBlock.insertNewSuccessor(currBlock.getPrimarySuccessor());
+ SsaInsn newInsn = newBlock.getInsns().get(0);
+ RegisterSpec newReg = RegisterSpec.make(ssaMeth.makeNewSsaReg(), exception);
+ insertPlainInsnBefore(newInsn, RegisterSpecList.EMPTY, newReg, RegOps.MOVE_RESULT_PSEUDO, null);
- // Add another successor block to throw the new exception
- SsaBasicBlock newBlock3 =
- newBlock2.insertNewSuccessor(newBlock2.getPrimarySuccessor());
- SsaInsn newInsn3 = newBlock3.getInsns().get(0);
- insertThrowingInsnBefore(newInsn3, RegisterSpecList.make(newReg), null,
- RegOps.THROW, null);
- newBlock3.replaceSuccessor(newBlock3.getPrimarySuccessorIndex(),
- ssaMeth.getExitBlock().getIndex());
- deletedInsns.add(newInsn3);
+ // Add another successor block to initialize the exception
+ SsaBasicBlock newBlock2 = newBlock.insertNewSuccessor(newBlock.getPrimarySuccessor());
+ SsaInsn newInsn2 = newBlock2.getInsns().get(0);
+ CstNat newNat = new CstNat(new CstString("<init>"), new CstString("(I)V"));
+ CstMethodRef newRef = new CstMethodRef(exception, newNat);
+ insertThrowingInsnBefore(newInsn2, RegisterSpecList.make(newReg, index), null,
+ RegOps.INVOKE_DIRECT, newRef);
+ deletedInsns.add(newInsn2);
+
+ // Add another successor block to throw the new exception
+ SsaBasicBlock newBlock3 = newBlock2.insertNewSuccessor(newBlock2.getPrimarySuccessor());
+ SsaInsn newInsn3 = newBlock3.getInsns().get(0);
+ insertThrowingInsnBefore(newInsn3, RegisterSpecList.make(newReg), null, RegOps.THROW, null);
+ newBlock3.replaceSuccessor(newBlock3.getPrimarySuccessorIndex(),
+ ssaMeth.getExitBlock().getIndex());
+ deletedInsns.add(newInsn3);
+ }
+
+ /**
+ * Inserts a new PlainInsn before the given instruction.
+ * TODO(dx team): move this somewhere more appropriate
+ *
+ * @param insn {@code non-null;} instruction to insert before
+ * @param newSources {@code non-null;} sources of new instruction
+ * @param newResult {@code non-null;} result of new instruction
+ * @param newOpcode opcode of new instruction
+ * @param cst {@code null-ok;} constant for new instruction, if any
+ */
+ private void insertPlainInsnBefore(SsaInsn insn, RegisterSpecList newSources,
+ RegisterSpec newResult, int newOpcode, Constant cst) {
+
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ Rop newRop;
+ if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
+ newRop = Rops.opMoveResultPseudo(newResult.getType());
+ } else {
+ newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
}
- /**
- * Inserts a new PlainInsn before the given instruction.
- * TODO: move this somewhere more appropriate
- *
- * @param insn {@code non-null;} instruction to insert before
- * @param newSources {@code non-null;} sources of new instruction
- * @param newResult {@code non-null;} result of new instruction
- * @param newOpcode opcode of new instruction
- * @param cst {@code null-ok;} constant for new instruction, if any
- */
- private void insertPlainInsnBefore(SsaInsn insn,
- RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
- Constant cst) {
-
- Insn originalRopInsn = insn.getOriginalRopInsn();
- Rop newRop;
- if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
- newRop = Rops.opMoveResultPseudo(newResult.getType());
- } else {
- newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
- }
-
- Insn newRopInsn;
- if (cst == null) {
- newRopInsn = new PlainInsn(newRop,
- originalRopInsn.getPosition(), newResult, newSources);
- } else {
- newRopInsn = new PlainCstInsn(newRop,
- originalRopInsn.getPosition(), newResult, newSources, cst);
- }
-
- NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
- List<SsaInsn> insns = insn.getBlock().getInsns();
-
- insns.add(insns.lastIndexOf(insn), newInsn);
- ssaMeth.onInsnAdded(newInsn);
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(), newResult, newSources);
+ } else {
+ newRopInsn =
+ new PlainCstInsn(newRop, originalRopInsn.getPosition(), newResult, newSources, cst);
}
- /**
- * Inserts a new ThrowingInsn before the given instruction.
- * TODO: move this somewhere more appropriate
- *
- * @param insn {@code non-null;} instruction to insert before
- * @param newSources {@code non-null;} sources of new instruction
- * @param newResult {@code non-null;} result of new instruction
- * @param newOpcode opcode of new instruction
- * @param cst {@code null-ok;} constant for new instruction, if any
- */
- private void insertThrowingInsnBefore(SsaInsn insn,
- RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
- Constant cst) {
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+ List<SsaInsn> insns = insn.getBlock().getInsns();
- Insn origRopInsn = insn.getOriginalRopInsn();
- Rop newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
- Insn newRopInsn;
- if (cst == null) {
- newRopInsn = new ThrowingInsn(newRop,
- origRopInsn.getPosition(), newSources, StdTypeList.EMPTY);
- } else {
- newRopInsn = new ThrowingCstInsn(newRop,
- origRopInsn.getPosition(), newSources, StdTypeList.EMPTY, cst);
- }
+ insns.add(insns.lastIndexOf(insn), newInsn);
+ ssaMeth.onInsnAdded(newInsn);
+ }
- NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
- List<SsaInsn> insns = insn.getBlock().getInsns();
+ /**
+ * Inserts a new ThrowingInsn before the given instruction.
+ * TODO(dx team): move this somewhere more appropriate
+ *
+ * @param insn {@code non-null;} instruction to insert before
+ * @param newSources {@code non-null;} sources of new instruction
+ * @param newResult {@code non-null;} result of new instruction
+ * @param newOpcode opcode of new instruction
+ * @param cst {@code null-ok;} constant for new instruction, if any
+ */
+ private void insertThrowingInsnBefore(SsaInsn insn, RegisterSpecList newSources,
+ RegisterSpec newResult, int newOpcode, Constant cst) {
- insns.add(insns.lastIndexOf(insn), newInsn);
- ssaMeth.onInsnAdded(newInsn);
+ Insn origRopInsn = insn.getOriginalRopInsn();
+ Rop newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn =
+ new ThrowingInsn(newRop, origRopInsn.getPosition(), newSources, StdTypeList.EMPTY);
+ } else {
+ newRopInsn = new ThrowingCstInsn(newRop, origRopInsn.getPosition(), newSources,
+ StdTypeList.EMPTY, cst);
}
+
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+ List<SsaInsn> insns = insn.getBlock().getInsns();
+
+ insns.add(insns.lastIndexOf(insn), newInsn);
+ ssaMeth.onInsnAdded(newInsn);
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/InterferenceRegisterMapper.java b/dx/src/com/android/jack/dx/ssa/InterferenceRegisterMapper.java
index 589e2f2..0f3f845 100644
--- a/dx/src/com/android/jack/dx/ssa/InterferenceRegisterMapper.java
+++ b/dx/src/com/android/jack/dx/ssa/InterferenceRegisterMapper.java
@@ -23,7 +23,6 @@
import com.android.jack.dx.util.IntSet;
import java.util.ArrayList;
-import java.util.BitSet;
/**
* A register mapper that keeps track of the accumulated interference
@@ -33,132 +32,127 @@
* have variable register widths/categories, and the new namespace does.
*/
public class InterferenceRegisterMapper extends BasicRegisterMapper {
- /**
- * Array of interference sets. ArrayList is indexed by new namespace
- * and BitIntSet's are indexed by old namespace. The list expands
- * as needed and missing items are assumed to interfere with nothing.
- *
- * Bit sets are always used here, unlike elsewhere, because the max
- * size of this matrix will be (countSsaRegs * countRopRegs), which may
- * grow to hundreds of K but not megabytes.
- */
- private final ArrayList<BitIntSet> newRegInterference;
+ /**
+ * Array of interference sets. ArrayList is indexed by new namespace
+ * and BitIntSet's are indexed by old namespace. The list expands
+ * as needed and missing items are assumed to interfere with nothing.
+ *
+ * Bit sets are always used here, unlike elsewhere, because the max
+ * size of this matrix will be (countSsaRegs * countRopRegs), which may
+ * grow to hundreds of K but not megabytes.
+ */
+ private final ArrayList<BitIntSet> newRegInterference;
- /** the interference graph for the old namespace */
- private final InterferenceGraph oldRegInterference;
+ /** the interference graph for the old namespace */
+ private final InterferenceGraph oldRegInterference;
- /**
- * Constructs an instance
- *
- * @param countOldRegisters number of registers in old namespace
- */
- public InterferenceRegisterMapper(InterferenceGraph oldRegInterference,
- int countOldRegisters) {
- super(countOldRegisters);
+ /**
+ * Constructs an instance
+ *
+ * @param countOldRegisters number of registers in old namespace
+ */
+ public InterferenceRegisterMapper(InterferenceGraph oldRegInterference, int countOldRegisters) {
+ super(countOldRegisters);
- newRegInterference = new ArrayList<BitIntSet>();
- this.oldRegInterference = oldRegInterference;
+ newRegInterference = new ArrayList<BitIntSet>();
+ this.oldRegInterference = oldRegInterference;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addMapping(int oldReg, int newReg, int category) {
+ super.addMapping(oldReg, newReg, category);
+
+ addInterfence(newReg, oldReg);
+
+ if (category == 2) {
+ addInterfence(newReg + 1, oldReg);
}
+ }
- /** {@inheritDoc} */
- @Override
- public void addMapping(int oldReg, int newReg, int category) {
- super.addMapping(oldReg, newReg, category);
+ /**
+ * Checks to see if old namespace reg {@code oldReg} interferes
+ * with what currently maps to {@code newReg}.
+ *
+ * @param oldReg old namespace register
+ * @param newReg new namespace register
+ * @param category category of old namespace register
+ * @return true if oldReg will interfere with newReg
+ */
+ public boolean interferes(int oldReg, int newReg, int category) {
+ if (newReg >= newRegInterference.size()) {
+ return false;
+ } else {
+ IntSet existing = newRegInterference.get(newReg);
- addInterfence(newReg, oldReg);
-
- if (category == 2) {
- addInterfence(newReg + 1, oldReg);
- }
- }
-
- /**
- * Checks to see if old namespace reg {@code oldReg} interferes
- * with what currently maps to {@code newReg}.
- *
- * @param oldReg old namespace register
- * @param newReg new namespace register
- * @param category category of old namespace register
- * @return true if oldReg will interfere with newReg
- */
- public boolean interferes(int oldReg, int newReg, int category) {
- if (newReg >= newRegInterference.size()) {
- return false;
- } else {
- IntSet existing = newRegInterference.get(newReg);
-
- if (existing == null) {
- return false;
- } else if (category == 1) {
- return existing.has(oldReg);
- } else {
- return existing.has(oldReg)
- || (interferes(oldReg, newReg+1, category-1));
- }
- }
- }
-
- /**
- * Checks to see if old namespace reg {@code oldReg} interferes
- * with what currently maps to {@code newReg}.
- *
- * @param oldSpec {@code non-null;} old namespace register
- * @param newReg new namespace register
- * @return true if oldReg will interfere with newReg
- */
- public boolean interferes(RegisterSpec oldSpec, int newReg) {
- return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory());
- }
-
- /**
- * Adds a register's interference set to the interference list,
- * growing it if necessary.
- *
- * @param newReg register in new namespace
- * @param oldReg register in old namespace
- */
- private void addInterfence(int newReg, int oldReg) {
- newRegInterference.ensureCapacity(newReg + 1);
-
- while (newReg >= newRegInterference.size()) {
- newRegInterference.add(new BitIntSet(newReg +1));
- }
-
- oldRegInterference.mergeInterferenceSet(
- oldReg, newRegInterference.get(newReg));
- }
-
- /**
- * Checks to see if any of a set of old-namespace registers are
- * pinned to the specified new-namespace reg + category. Takes into
- * account the category of the old-namespace registers.
- *
- * @param oldSpecs {@code non-null;} set of old-namespace regs
- * @param newReg {@code >= 0;} new-namespace register
- * @param targetCategory {@code 1..2;} the number of adjacent new-namespace
- * registers (starting at ropReg) to consider
- * @return true if any of the old-namespace register have been mapped
- * to the new-namespace register + category
- */
- public boolean areAnyPinned(RegisterSpecList oldSpecs,
- int newReg, int targetCategory) {
- int sz = oldSpecs.size();
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec oldSpec = oldSpecs.get(i);
- int r = oldToNew(oldSpec.getReg());
-
- /*
- * If oldSpec is a category-2 register, then check both newReg
- * and newReg - 1.
- */
- if (r == newReg
- || (oldSpec.getCategory() == 2 && (r + 1) == newReg)
- || (targetCategory == 2 && (r == newReg + 1))) {
- return true;
- }
- }
-
+ if (existing == null) {
return false;
+ } else if (category == 1) {
+ return existing.has(oldReg);
+ } else {
+ return existing.has(oldReg) || (interferes(oldReg, newReg + 1, category - 1));
+ }
}
+ }
+
+ /**
+ * Checks to see if old namespace reg {@code oldReg} interferes
+ * with what currently maps to {@code newReg}.
+ *
+ * @param oldSpec {@code non-null;} old namespace register
+ * @param newReg new namespace register
+ * @return true if oldReg will interfere with newReg
+ */
+ public boolean interferes(RegisterSpec oldSpec, int newReg) {
+ return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory());
+ }
+
+ /**
+ * Adds a register's interference set to the interference list,
+ * growing it if necessary.
+ *
+ * @param newReg register in new namespace
+ * @param oldReg register in old namespace
+ */
+ private void addInterfence(int newReg, int oldReg) {
+ newRegInterference.ensureCapacity(newReg + 1);
+
+ while (newReg >= newRegInterference.size()) {
+ newRegInterference.add(new BitIntSet(newReg + 1));
+ }
+
+ oldRegInterference.mergeInterferenceSet(oldReg, newRegInterference.get(newReg));
+ }
+
+ /**
+ * Checks to see if any of a set of old-namespace registers are
+ * pinned to the specified new-namespace reg + category. Takes into
+ * account the category of the old-namespace registers.
+ *
+ * @param oldSpecs {@code non-null;} set of old-namespace regs
+ * @param newReg {@code >= 0;} new-namespace register
+ * @param targetCategory {@code 1..2;} the number of adjacent new-namespace
+ * registers (starting at ropReg) to consider
+ * @return true if any of the old-namespace register have been mapped
+ * to the new-namespace register + category
+ */
+ public boolean areAnyPinned(RegisterSpecList oldSpecs, int newReg, int targetCategory) {
+ int sz = oldSpecs.size();
+
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec oldSpec = oldSpecs.get(i);
+ int r = oldToNew(oldSpec.getReg());
+
+ /*
+ * If oldSpec is a category-2 register, then check both newReg
+ * and newReg - 1.
+ */
+ if (r == newReg || (oldSpec.getCategory() == 2 && (r + 1) == newReg)
+ || (targetCategory == 2 && (r == newReg + 1))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/LiteralOpUpgrader.java b/dx/src/com/android/jack/dx/ssa/LiteralOpUpgrader.java
index ebf9401..5bbfdcb 100644
--- a/dx/src/com/android/jack/dx/ssa/LiteralOpUpgrader.java
+++ b/dx/src/com/android/jack/dx/ssa/LiteralOpUpgrader.java
@@ -40,168 +40,163 @@
*/
public class LiteralOpUpgrader {
- /** method we're processing */
- private final SsaMethod ssaMeth;
+ /** method we're processing */
+ private final SsaMethod ssaMeth;
- /**
- * Process a method.
- *
- * @param ssaMethod {@code non-null;} method to process
- */
- public static void process(SsaMethod ssaMethod) {
- LiteralOpUpgrader dc;
+ /**
+ * Process a method.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ LiteralOpUpgrader dc;
- dc = new LiteralOpUpgrader(ssaMethod);
+ dc = new LiteralOpUpgrader(ssaMethod);
- dc.run();
+ dc.run();
+ }
+
+ private LiteralOpUpgrader(SsaMethod ssaMethod) {
+ this.ssaMeth = ssaMethod;
+ }
+
+ /**
+ * Returns true if the register contains an integer 0 or a known-null
+ * object reference
+ *
+ * @param spec non-null spec
+ * @return true for 0 or null type bearers
+ */
+ private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
+ TypeBearer tb = spec.getTypeBearer();
+ if (tb instanceof CstLiteralBits) {
+ CstLiteralBits clb = (CstLiteralBits) tb;
+ return (clb.getLongBits() == 0);
}
+ return false;
+ }
- private LiteralOpUpgrader(SsaMethod ssaMethod) {
- this.ssaMeth = ssaMethod;
- }
+ /**
+ * Run the literal op upgrader
+ */
+ private void run() {
+ final TranslationAdvice advice = Optimizer.getAdvice();
- /**
- * Returns true if the register contains an integer 0 or a known-null
- * object reference
- *
- * @param spec non-null spec
- * @return true for 0 or null type bearers
- */
- private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
- TypeBearer tb = spec.getTypeBearer();
- if (tb instanceof CstLiteralBits) {
- CstLiteralBits clb = (CstLiteralBits) tb;
- return (clb.getLongBits() == 0);
- }
- return false;
- }
+ ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ // do nothing
+ }
- /**
- * Run the literal op upgrader
- */
- private void run() {
- final TranslationAdvice advice = Optimizer.getAdvice();
+ @Override
+ public void visitPhiInsn(PhiInsn insn) {
+ // do nothing
+ }
- ssaMeth.forEachInsn(new SsaInsn.Visitor() {
- public void visitMoveInsn(NormalSsaInsn insn) {
- // do nothing
- }
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
- public void visitPhiInsn(PhiInsn insn) {
- // do nothing
- }
-
- public void visitNonMoveInsn(NormalSsaInsn insn) {
-
- Insn originalRopInsn = insn.getOriginalRopInsn();
- Rop opcode = originalRopInsn.getOpcode();
- RegisterSpecList sources = insn.getSources();
-
- // Replace insns with constant results with const insns
- if (tryReplacingWithConstant(insn)) return;
-
- if (sources.size() != 2 ) {
- // We're only dealing with two-source insns here.
- return;
- }
-
- if (opcode.getBranchingness() == Rop.BRANCH_IF) {
- /*
- * An if instruction can become an if-*z instruction.
- */
- if (isConstIntZeroOrKnownNull(sources.get(0))) {
- replacePlainInsn(insn, sources.withoutFirst(),
- RegOps.flippedIfOpcode(opcode.getOpcode()), null);
- } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
- replacePlainInsn(insn, sources.withoutLast(),
- opcode.getOpcode(), null);
- }
- } else if (advice.hasConstantOperation(
- opcode, sources.get(0), sources.get(1))) {
- insn.upgradeToLiteral();
- } else if (opcode.isCommutative()
- && advice.hasConstantOperation(
- opcode, sources.get(1), sources.get(0))) {
- /*
- * An instruction can be commuted to a literal operation
- */
-
- insn.setNewSources(
- RegisterSpecList.make(
- sources.get(1), sources.get(0)));
-
- insn.upgradeToLiteral();
- }
- }
- });
- }
-
- /**
- * Tries to replace an instruction with a const instruction. The given
- * instruction must have a constant result for it to be replaced.
- *
- * @param insn {@code non-null;} instruction to try to replace
- * @return true if the instruction was replaced
- */
- private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
Insn originalRopInsn = insn.getOriginalRopInsn();
Rop opcode = originalRopInsn.getOpcode();
- RegisterSpec result = insn.getResult();
+ RegisterSpecList sources = insn.getSources();
- if (result != null && !ssaMeth.isRegALocal(result) &&
- opcode.getOpcode() != RegOps.CONST) {
- TypeBearer type = insn.getResult().getTypeBearer();
- if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
- // Replace the instruction with a constant
- replacePlainInsn(insn, RegisterSpecList.EMPTY,
- RegOps.CONST, (Constant) type);
-
- // Remove the source as well if this is a move-result-pseudo
- if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
- int pred = insn.getBlock().getPredecessors().nextSetBit(0);
- ArrayList<SsaInsn> predInsns =
- ssaMeth.getBlocks().get(pred).getInsns();
- NormalSsaInsn sourceInsn =
- (NormalSsaInsn) predInsns.get(predInsns.size()-1);
- replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY,
- RegOps.GOTO, null);
- }
- return true;
- }
+ // Replace insns with constant results with const insns
+ if (tryReplacingWithConstant(insn)) {
+ return;
}
- return false;
- }
- /**
- * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
- * new PlainInsn is constructed with a new RegOp and new sources.
- *
- * TODO move this somewhere else.
- *
- * @param insn {@code non-null;} an SsaInsn containing a PlainInsn
- * @param newSources {@code non-null;} new sources list for new insn
- * @param newOpcode A RegOp from {@link RegOps}
- * @param cst {@code null-ok;} constant for new instruction, if any
- */
- private void replacePlainInsn(NormalSsaInsn insn,
- RegisterSpecList newSources, int newOpcode, Constant cst) {
-
- Insn originalRopInsn = insn.getOriginalRopInsn();
- Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst);
- Insn newRopInsn;
- if (cst == null) {
- newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(),
- insn.getResult(), newSources);
- } else {
- newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(),
- insn.getResult(), newSources, cst);
+ if (sources.size() != 2) {
+ // We're only dealing with two-source insns here.
+ return;
}
- NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
- List<SsaInsn> insns = insn.getBlock().getInsns();
+ if (opcode.getBranchingness() == Rop.BRANCH_IF) {
+ /*
+ * An if instruction can become an if-*z instruction.
+ */
+ if (isConstIntZeroOrKnownNull(sources.get(0))) {
+ replacePlainInsn(insn, sources.withoutFirst(),
+ RegOps.flippedIfOpcode(opcode.getOpcode()), null);
+ } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
+ replacePlainInsn(insn, sources.withoutLast(), opcode.getOpcode(), null);
+ }
+ } else if (advice.hasConstantOperation(opcode, sources.get(0), sources.get(1))) {
+ insn.upgradeToLiteral();
+ } else if (opcode.isCommutative()
+ && advice.hasConstantOperation(opcode, sources.get(1), sources.get(0))) {
+ /*
+ * An instruction can be commuted to a literal operation
+ */
- ssaMeth.onInsnRemoved(insn);
- insns.set(insns.lastIndexOf(insn), newInsn);
- ssaMeth.onInsnAdded(newInsn);
+insn.setNewSources(RegisterSpecList.make(sources.get(1), sources.get(0)));
+
+ insn.upgradeToLiteral();
+ }
+ }
+ });
+ }
+
+ /**
+ * Tries to replace an instruction with a const instruction. The given
+ * instruction must have a constant result for it to be replaced.
+ *
+ * @param insn {@code non-null;} instruction to try to replace
+ * @return true if the instruction was replaced
+ */
+ private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ Rop opcode = originalRopInsn.getOpcode();
+ RegisterSpec result = insn.getResult();
+
+ if (result != null && !ssaMeth.isRegALocal(result) && opcode.getOpcode() != RegOps.CONST) {
+ TypeBearer type = insn.getResult().getTypeBearer();
+ if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
+ // Replace the instruction with a constant
+ replacePlainInsn(insn, RegisterSpecList.EMPTY, RegOps.CONST, (Constant) type);
+
+ // Remove the source as well if this is a move-result-pseudo
+ if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+ int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+ ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+ NormalSsaInsn sourceInsn = (NormalSsaInsn) predInsns.get(predInsns.size() - 1);
+ replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY, RegOps.GOTO, null);
+ }
+ return true;
+ }
}
+ return false;
+ }
+
+ /**
+ * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
+ * new PlainInsn is constructed with a new RegOp and new sources.
+ *
+ * TODO(dx team) move this somewhere else.
+ *
+ * @param insn {@code non-null;} an SsaInsn containing a PlainInsn
+ * @param newSources {@code non-null;} new sources list for new insn
+ * @param newOpcode A RegOp from {@link RegOps}
+ * @param cst {@code null-ok;} constant for new instruction, if any
+ */
+ private void replacePlainInsn(NormalSsaInsn insn, RegisterSpecList newSources, int newOpcode,
+ Constant cst) {
+
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst);
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn =
+ new PlainInsn(newRop, originalRopInsn.getPosition(), insn.getResult(), newSources);
+ } else {
+ newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(), insn.getResult(),
+ newSources, cst);
+ }
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+
+ List<SsaInsn> insns = insn.getBlock().getInsns();
+
+ ssaMeth.onInsnRemoved(insn);
+ insns.set(insns.lastIndexOf(insn), newInsn);
+ ssaMeth.onInsnAdded(newInsn);
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/LocalVariableExtractor.java b/dx/src/com/android/jack/dx/ssa/LocalVariableExtractor.java
index a16eeb1..38490ae 100644
--- a/dx/src/com/android/jack/dx/ssa/LocalVariableExtractor.java
+++ b/dx/src/com/android/jack/dx/ssa/LocalVariableExtractor.java
@@ -29,180 +29,172 @@
* a method. Stolen and retrofitted from
* com.android.jack.dx.rop.code.LocalVariableExtractor
*
- * TODO remove this. Allow Rop-form LocalVariableInfo to be passed in,
+ * TODO(dx team) remove this. Allow Rop-form LocalVariableInfo to be passed in,
* converted, and adapted through edge-splitting.
*/
public class LocalVariableExtractor {
- /** {@code non-null;} method being extracted from */
- private final SsaMethod method;
+ /** {@code non-null;} method being extracted from */
+ private final SsaMethod method;
- /** {@code non-null;} block list for the method */
- private final ArrayList<SsaBasicBlock> blocks;
+ /** {@code non-null;} block list for the method */
+ private final ArrayList<SsaBasicBlock> blocks;
- /** {@code non-null;} result in-progress */
- private final LocalVariableInfo resultInfo;
+ /** {@code non-null;} result in-progress */
+ private final LocalVariableInfo resultInfo;
- /** {@code non-null;} work set indicating blocks needing to be processed */
- private final BitSet workSet;
+ /** {@code non-null;} work set indicating blocks needing to be processed */
+ private final BitSet workSet;
- /**
- * Extracts out all the local variable information from the given method.
- *
- * @param method {@code non-null;} the method to extract from
- * @return {@code non-null;} the extracted information
- */
- public static LocalVariableInfo extract(SsaMethod method) {
- LocalVariableExtractor lve = new LocalVariableExtractor(method);
- return lve.doit();
+ /**
+ * Extracts out all the local variable information from the given method.
+ *
+ * @param method {@code non-null;} the method to extract from
+ * @return {@code non-null;} the extracted information
+ */
+ public static LocalVariableInfo extract(SsaMethod method) {
+ LocalVariableExtractor lve = new LocalVariableExtractor(method);
+ return lve.doit();
+ }
+
+ /**
+ * Constructs an instance. This method is private. Use {@link #extract}.
+ *
+ * @param method {@code non-null;} the method to extract from
+ */
+ private LocalVariableExtractor(SsaMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /**
- * Constructs an instance. This method is private. Use {@link #extract}.
- *
- * @param method {@code non-null;} the method to extract from
- */
- private LocalVariableExtractor(SsaMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
+ ArrayList<SsaBasicBlock> blocks = method.getBlocks();
- ArrayList<SsaBasicBlock> blocks = method.getBlocks();
+ this.method = method;
+ this.blocks = blocks;
+ this.resultInfo = new LocalVariableInfo(method);
+ this.workSet = new BitSet(blocks.size());
+ }
- this.method = method;
- this.blocks = blocks;
- this.resultInfo = new LocalVariableInfo(method);
- this.workSet = new BitSet(blocks.size());
+ /**
+ * Does the extraction.
+ *
+ * @return {@code non-null;} the extracted information
+ */
+ private LocalVariableInfo doit() {
+
+ //TODO(dx team) why is this needed here?
+ if (method.getRegCount() > 0) {
+ for (int bi = method.getEntryBlockIndex(); bi >= 0; bi = workSet.nextSetBit(0)) {
+ workSet.clear(bi);
+ processBlock(bi);
+ }
}
- /**
- * Does the extraction.
- *
- * @return {@code non-null;} the extracted information
- */
- private LocalVariableInfo doit() {
+ resultInfo.setImmutable();
+ return resultInfo;
+ }
- //FIXME why is this needed here?
- if (method.getRegCount() > 0 ) {
- for (int bi = method.getEntryBlockIndex();
- bi >= 0;
- bi = workSet.nextSetBit(0)) {
- workSet.clear(bi);
- processBlock(bi);
- }
- }
+ /**
+ * Processes a single block.
+ *
+ * @param blockIndex {@code >= 0;} block index of the block to process
+ */
+ private void processBlock(int blockIndex) {
+ RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex);
+ SsaBasicBlock block = blocks.get(blockIndex);
+ List<SsaInsn> insns = block.getInsns();
+ int insnSz = insns.size();
- resultInfo.setImmutable();
- return resultInfo;
+ // The exit block has no insns and no successors
+ if (blockIndex == method.getExitBlockIndex()) {
+ return;
}
- /**
- * Processes a single block.
- *
- * @param blockIndex {@code >= 0;} block index of the block to process
+ /*
+ * We may have to treat the last instruction specially: If it
+ * can (but doesn't always) throw, and the exception can be
+ * caught within the same method, then we need to use the
+ * state *before* executing it to be what is merged into
+ * exception targets.
*/
- private void processBlock(int blockIndex) {
- RegisterSpecSet primaryState
- = resultInfo.mutableCopyOfStarts(blockIndex);
- SsaBasicBlock block = blocks.get(blockIndex);
- List<SsaInsn> insns = block.getInsns();
- int insnSz = insns.size();
+ SsaInsn lastInsn = insns.get(insnSz - 1);
+ boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0;
+ boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null);
+ int freezeSecondaryStateAt = insnSz - 1;
+ RegisterSpecSet secondaryState = primaryState;
- // The exit block has no insns and no successors
- if (blockIndex == method.getExitBlockIndex()) {
- return;
- }
+ /*
+ * Iterate over the instructions, adding information for each place
+ * that the active variable set changes.
+ */
- /*
- * We may have to treat the last instruction specially: If it
- * can (but doesn't always) throw, and the exception can be
- * caught within the same method, then we need to use the
- * state *before* executing it to be what is merged into
- * exception targets.
- */
- SsaInsn lastInsn = insns.get(insnSz - 1);
- boolean hasExceptionHandlers
- = lastInsn.getOriginalRopInsn().getCatches().size() !=0 ;
- boolean canThrowDuringLastInsn = hasExceptionHandlers
- && (lastInsn.getResult() != null);
- int freezeSecondaryStateAt = insnSz - 1;
- RegisterSpecSet secondaryState = primaryState;
-
- /*
- * Iterate over the instructions, adding information for each place
- * that the active variable set changes.
- */
-
- for (int i = 0; i < insnSz; i++) {
- if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
- // Until this point, primaryState == secondaryState.
- primaryState.setImmutable();
- primaryState = primaryState.mutableCopy();
- }
-
- SsaInsn insn = insns.get(i);
- RegisterSpec result;
-
- result = insn.getLocalAssignment();
-
- if (result == null) {
- // We may be nuking an existing local
-
- result = insn.getResult();
-
- if (result != null && primaryState.get(result.getReg()) != null) {
- primaryState.remove(primaryState.get(result.getReg()));
- }
- continue;
- }
-
- result = result.withSimpleType();
-
- RegisterSpec already = primaryState.get(result);
- /*
- * The equals() check ensures we only add new info if
- * the instruction causes a change to the set of
- * active variables.
- */
- if (!result.equals(already)) {
- /*
- * If this insn represents a local moving from one register
- * to another, remove the association between the old register
- * and the local.
- */
- RegisterSpec previous
- = primaryState.localItemToSpec(result.getLocalItem());
-
- if (previous != null
- && (previous.getReg() != result.getReg())) {
-
- primaryState.remove(previous);
- }
-
- resultInfo.addAssignment(insn, result);
- primaryState.put(result);
- }
- }
-
+for (int i = 0; i < insnSz; i++) {
+ if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
+ // Until this point, primaryState == secondaryState.
primaryState.setImmutable();
+ primaryState = primaryState.mutableCopy();
+ }
- /*
- * Merge this state into the start state for each successor,
- * and update the work set where required (that is, in cases
- * where the start state for a block changes).
- */
+ SsaInsn insn = insns.get(i);
+ RegisterSpec result;
- IntList successors = block.getSuccessorList();
- int succSz = successors.size();
- int primarySuccessor = block.getPrimarySuccessorIndex();
+ result = insn.getLocalAssignment();
- for (int i = 0; i < succSz; i++) {
- int succ = successors.get(i);
- RegisterSpecSet state = (succ == primarySuccessor) ?
- primaryState : secondaryState;
+ if (result == null) {
+ // We may be nuking an existing local
- if (resultInfo.mergeStarts(succ, state)) {
- workSet.set(succ);
- }
+ result = insn.getResult();
+
+ if (result != null && primaryState.get(result.getReg()) != null) {
+ primaryState.remove(primaryState.get(result.getReg()));
}
+ continue;
+ }
+
+ result = result.withSimpleType();
+
+ RegisterSpec already = primaryState.get(result);
+ /*
+ * The equals() check ensures we only add new info if
+ * the instruction causes a change to the set of
+ * active variables.
+ */
+ if (!result.equals(already)) {
+ /*
+ * If this insn represents a local moving from one register
+ * to another, remove the association between the old register
+ * and the local.
+ */
+ RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem());
+
+ if (previous != null && (previous.getReg() != result.getReg())) {
+
+ primaryState.remove(previous);
+ }
+
+ resultInfo.addAssignment(insn, result);
+ primaryState.put(result);
+ }
}
+
+ primaryState.setImmutable();
+
+ /*
+ * Merge this state into the start state for each successor,
+ * and update the work set where required (that is, in cases
+ * where the start state for a block changes).
+ */
+
+IntList successors = block.getSuccessorList();
+ int succSz = successors.size();
+ int primarySuccessor = block.getPrimarySuccessorIndex();
+
+ for (int i = 0; i < succSz; i++) {
+ int succ = successors.get(i);
+ RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState;
+
+ if (resultInfo.mergeStarts(succ, state)) {
+ workSet.set(succ);
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/LocalVariableInfo.java b/dx/src/com/android/jack/dx/ssa/LocalVariableInfo.java
index 0ff957c..8bc7634 100644
--- a/dx/src/com/android/jack/dx/ssa/LocalVariableInfo.java
+++ b/dx/src/com/android/jack/dx/ssa/LocalVariableInfo.java
@@ -28,224 +28,221 @@
* com.android.jack.dx.ssa.SsaMethod}.
* Stolen from {@link com.android.jack.dx.rop.code.LocalVariableInfo}.
*/
-public class LocalVariableInfo extends MutabilityControl {
- /** {@code >= 0;} the register count for the method */
- private final int regCount;
+public class LocalVariableInfo extends MutabilityControl {
+ /** {@code >= 0;} the register count for the method */
+ private final int regCount;
- /**
- * {@code non-null;} {@link com.android.jack.dx.rop.code.RegisterSpecSet} to use when indicating a block
- * that has no locals; it is empty and immutable but has an appropriate
- * max size for the method
- */
- private final RegisterSpecSet emptySet;
+ /**
+ * {@code non-null;} {@link com.android.jack.dx.rop.code.RegisterSpecSet} to use when indicating a
+ * block that has no locals; it is empty and immutable but has an appropriate max size for the
+ * method
+ */
+ private final RegisterSpecSet emptySet;
- /**
- * {@code non-null;} array consisting of register sets representing the
- * sets of variables already assigned upon entry to each block,
- * where array indices correspond to block indices
- */
- private final RegisterSpecSet[] blockStarts;
+ /**
+ * {@code non-null;} array consisting of register sets representing the
+ * sets of variables already assigned upon entry to each block,
+ * where array indices correspond to block indices
+ */
+ private final RegisterSpecSet[] blockStarts;
- /** {@code non-null;} map from instructions to the variable each assigns */
- private final HashMap<SsaInsn, RegisterSpec> insnAssignments;
+ /** {@code non-null;} map from instructions to the variable each assigns */
+ private final HashMap<SsaInsn, RegisterSpec> insnAssignments;
- /**
- * Constructs an instance.
- *
- * @param method {@code non-null;} the method being represented by this instance
- */
- public LocalVariableInfo(SsaMethod method) {
- if (method == null) {
- throw new NullPointerException("method == null");
- }
-
- List<SsaBasicBlock> blocks = method.getBlocks();
-
- this.regCount = method.getRegCount();
- this.emptySet = new RegisterSpecSet(regCount);
- this.blockStarts = new RegisterSpecSet[blocks.size()];
- this.insnAssignments =
- new HashMap<SsaInsn, RegisterSpec>(/*hint here*/);
-
- emptySet.setImmutable();
+ /**
+ * Constructs an instance.
+ *
+ * @param method {@code non-null;} the method being represented by this instance
+ */
+ public LocalVariableInfo(SsaMethod method) {
+ if (method == null) {
+ throw new NullPointerException("method == null");
}
- /**
- * Sets the register set associated with the start of the block with
- * the given index.
- *
- * @param index {@code >= 0;} the block index
- * @param specs {@code non-null;} the register set to associate with the block
- */
- public void setStarts(int index, RegisterSpecSet specs) {
- throwIfImmutable();
+ List<SsaBasicBlock> blocks = method.getBlocks();
- if (specs == null) {
- throw new NullPointerException("specs == null");
- }
+ this.regCount = method.getRegCount();
+ this.emptySet = new RegisterSpecSet(regCount);
+ this.blockStarts = new RegisterSpecSet[blocks.size()];
+ this.insnAssignments = new HashMap<SsaInsn, RegisterSpec>(/*hint here*/);
- try {
- blockStarts[index] = specs;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus index");
- }
+ emptySet.setImmutable();
+ }
+
+ /**
+ * Sets the register set associated with the start of the block with
+ * the given index.
+ *
+ * @param index {@code >= 0;} the block index
+ * @param specs {@code non-null;} the register set to associate with the block
+ */
+ public void setStarts(int index, RegisterSpecSet specs) {
+ throwIfImmutable();
+
+ if (specs == null) {
+ throw new NullPointerException("specs == null");
}
- /**
- * Merges the given register set into the set for the block with the
- * given index. If there was not already an associated set, then this
- * is the same as calling {@link #setStarts}. Otherwise, this will
- * merge the two sets and call {@link #setStarts} on the result of the
- * merge.
- *
- * @param index {@code >= 0;} the block index
- * @param specs {@code non-null;} the register set to merge into the start set
- * for the block
- * @return {@code true} if the merge resulted in an actual change
- * to the associated set (including storing one for the first time) or
- * {@code false} if there was no change
- */
- public boolean mergeStarts(int index, RegisterSpecSet specs) {
- RegisterSpecSet start = getStarts0(index);
- boolean changed = false;
+ try {
+ blockStarts[index] = specs;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus index");
+ }
+ }
- if (start == null) {
- setStarts(index, specs);
- return true;
- }
+ /**
+ * Merges the given register set into the set for the block with the
+ * given index. If there was not already an associated set, then this
+ * is the same as calling {@link #setStarts}. Otherwise, this will
+ * merge the two sets and call {@link #setStarts} on the result of the
+ * merge.
+ *
+ * @param index {@code >= 0;} the block index
+ * @param specs {@code non-null;} the register set to merge into the start set
+ * for the block
+ * @return {@code true} if the merge resulted in an actual change
+ * to the associated set (including storing one for the first time) or
+ * {@code false} if there was no change
+ */
+ public boolean mergeStarts(int index, RegisterSpecSet specs) {
+ RegisterSpecSet start = getStarts0(index);
- RegisterSpecSet newStart = start.mutableCopy();
- newStart.intersect(specs, true);
-
- if (start.equals(newStart)) {
- return false;
- }
-
- newStart.setImmutable();
- setStarts(index, newStart);
-
- return true;
+ if (start == null) {
+ setStarts(index, specs);
+ return true;
}
- /**
- * Gets the register set associated with the start of the block
- * with the given index. This returns an empty set with the appropriate
- * max size if no set was associated with the block in question.
- *
- * @param index {@code >= 0;} the block index
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet getStarts(int index) {
- RegisterSpecSet result = getStarts0(index);
+ RegisterSpecSet newStart = start.mutableCopy();
+ newStart.intersect(specs, true);
- return (result != null) ? result : emptySet;
+ if (start.equals(newStart)) {
+ return false;
}
- /**
- * Gets the register set associated with the start of the given
- * block. This is just convenient shorthand for
- * {@code getStarts(block.getLabel())}.
- *
- * @param block {@code non-null;} the block in question
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet getStarts(SsaBasicBlock block) {
- return getStarts(block.getIndex());
+ newStart.setImmutable();
+ setStarts(index, newStart);
+
+ return true;
+ }
+
+ /**
+ * Gets the register set associated with the start of the block
+ * with the given index. This returns an empty set with the appropriate
+ * max size if no set was associated with the block in question.
+ *
+ * @param index {@code >= 0;} the block index
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet getStarts(int index) {
+ RegisterSpecSet result = getStarts0(index);
+
+ return (result != null) ? result : emptySet;
+ }
+
+ /**
+ * Gets the register set associated with the start of the given
+ * block. This is just convenient shorthand for
+ * {@code getStarts(block.getLabel())}.
+ *
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet getStarts(SsaBasicBlock block) {
+ return getStarts(block.getIndex());
+ }
+
+ /**
+ * Gets a mutable copy of the register set associated with the
+ * start of the block with the given index. This returns a
+ * newly-allocated empty {@link RegisterSpecSet} of appropriate
+ * max size if there is not yet any set associated with the block.
+ *
+ * @param index {@code >= 0;} the block index
+ * @return {@code non-null;} the associated register set
+ */
+ public RegisterSpecSet mutableCopyOfStarts(int index) {
+ RegisterSpecSet result = getStarts0(index);
+
+ return (result != null) ? result.mutableCopy() : new RegisterSpecSet(regCount);
+ }
+
+ /**
+ * Adds an assignment association for the given instruction and
+ * register spec. This throws an exception if the instruction
+ * doesn't actually perform a named variable assignment.
+ *
+ * <b>Note:</b> Although the instruction contains its own spec for
+ * the result, it still needs to be passed in explicitly to this
+ * method, since the spec that is stored here should always have a
+ * simple type and the one in the instruction can be an arbitrary
+ * {@link com.android.jack.dx.rop.type.TypeBearer} (such as a constant value).
+ *
+ * @param insn {@code non-null;} the instruction in question
+ * @param spec {@code non-null;} the associated register spec
+ */
+ public void addAssignment(SsaInsn insn, RegisterSpec spec) {
+ throwIfImmutable();
+
+ if (insn == null) {
+ throw new NullPointerException("insn == null");
}
- /**
- * Gets a mutable copy of the register set associated with the
- * start of the block with the given index. This returns a
- * newly-allocated empty {@link RegisterSpecSet} of appropriate
- * max size if there is not yet any set associated with the block.
- *
- * @param index {@code >= 0;} the block index
- * @return {@code non-null;} the associated register set
- */
- public RegisterSpecSet mutableCopyOfStarts(int index) {
- RegisterSpecSet result = getStarts0(index);
-
- return (result != null) ?
- result.mutableCopy() : new RegisterSpecSet(regCount);
+ if (spec == null) {
+ throw new NullPointerException("spec == null");
}
- /**
- * Adds an assignment association for the given instruction and
- * register spec. This throws an exception if the instruction
- * doesn't actually perform a named variable assignment.
- *
- * <b>Note:</b> Although the instruction contains its own spec for
- * the result, it still needs to be passed in explicitly to this
- * method, since the spec that is stored here should always have a
- * simple type and the one in the instruction can be an arbitrary
- * {@link com.android.jack.dx.rop.type.TypeBearer} (such as a constant value).
- *
- * @param insn {@code non-null;} the instruction in question
- * @param spec {@code non-null;} the associated register spec
- */
- public void addAssignment(SsaInsn insn, RegisterSpec spec) {
- throwIfImmutable();
+ insnAssignments.put(insn, spec);
+ }
- if (insn == null) {
- throw new NullPointerException("insn == null");
- }
+ /**
+ * Gets the named register being assigned by the given instruction, if
+ * previously stored in this instance.
+ *
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code null-ok;} the named register being assigned, if any
+ */
+ public RegisterSpec getAssignment(SsaInsn insn) {
+ return insnAssignments.get(insn);
+ }
- if (spec == null) {
- throw new NullPointerException("spec == null");
- }
+ /**
+ * Gets the number of assignments recorded by this instance.
+ *
+ * @return {@code >= 0;} the number of assignments
+ */
+ public int getAssignmentCount() {
+ return insnAssignments.size();
+ }
- insnAssignments.put(insn, spec);
+ public void debugDump() {
+ for (int index = 0; index < blockStarts.length; index++) {
+ if (blockStarts[index] == null) {
+ continue;
+ }
+
+ if (blockStarts[index] == emptySet) {
+ System.out.printf("%04x: empty set\n", index);
+ } else {
+ System.out.printf("%04x: %s\n", index, blockStarts[index]);
+ }
}
+ }
- /**
- * Gets the named register being assigned by the given instruction, if
- * previously stored in this instance.
- *
- * @param insn {@code non-null;} instruction in question
- * @return {@code null-ok;} the named register being assigned, if any
- */
- public RegisterSpec getAssignment(SsaInsn insn) {
- return insnAssignments.get(insn);
+ /**
+ * Helper method, to get the starts for a index, throwing the
+ * right exception for range problems.
+ *
+ * @param index {@code >= 0;} the block index
+ * @return {@code null-ok;} associated register set or {@code null} if there
+ * is none
+ */
+ private RegisterSpecSet getStarts0(int index) {
+ try {
+ return blockStarts[index];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("bogus index");
}
-
- /**
- * Gets the number of assignments recorded by this instance.
- *
- * @return {@code >= 0;} the number of assignments
- */
- public int getAssignmentCount() {
- return insnAssignments.size();
- }
-
- public void debugDump() {
- for (int index = 0 ; index < blockStarts.length; index++) {
- if (blockStarts[index] == null) {
- continue;
- }
-
- if (blockStarts[index] == emptySet) {
- System.out.printf("%04x: empty set\n", index);
- } else {
- System.out.printf("%04x: %s\n", index, blockStarts[index]);
- }
- }
- }
-
- /**
- * Helper method, to get the starts for a index, throwing the
- * right exception for range problems.
- *
- * @param index {@code >= 0;} the block index
- * @return {@code null-ok;} associated register set or {@code null} if there
- * is none
- */
- private RegisterSpecSet getStarts0(int index) {
- try {
- return blockStarts[index];
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("bogus index");
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/MoveParamCombiner.java b/dx/src/com/android/jack/dx/ssa/MoveParamCombiner.java
index dc05a6e..95fc869 100644
--- a/dx/src/com/android/jack/dx/ssa/MoveParamCombiner.java
+++ b/dx/src/com/android/jack/dx/ssa/MoveParamCombiner.java
@@ -23,7 +23,6 @@
import com.android.jack.dx.rop.cst.CstInteger;
import java.util.HashSet;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -32,125 +31,127 @@
*/
public class MoveParamCombiner {
- /** method to process */
- private final SsaMethod ssaMeth;
+ /** method to process */
+ private final SsaMethod ssaMeth;
- /**
- * Processes a method with this optimization step.
- *
- * @param ssaMethod method to process
- */
- public static void process(SsaMethod ssaMethod) {
- new MoveParamCombiner(ssaMethod).run();
- }
+ /**
+ * Processes a method with this optimization step.
+ *
+ * @param ssaMethod method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ new MoveParamCombiner(ssaMethod).run();
+ }
- private MoveParamCombiner(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
- }
+ private MoveParamCombiner(SsaMethod ssaMeth) {
+ this.ssaMeth = ssaMeth;
+ }
- /**
- * Runs this optimization step.
- */
- private void run() {
- // This will contain the definition specs for each parameter
- final RegisterSpec[] paramSpecs
- = new RegisterSpec[ssaMeth.getParamWidth()];
+ /**
+ * Runs this optimization step.
+ */
+ private void run() {
+ // This will contain the definition specs for each parameter
+ final RegisterSpec[] paramSpecs = new RegisterSpec[ssaMeth.getParamWidth()];
- // Insns to delete when all done
- final HashSet<SsaInsn> deletedInsns = new HashSet();
+ // Insns to delete when all done
+ final HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
- ssaMeth.forEachInsn(new SsaInsn.Visitor() {
- public void visitMoveInsn (NormalSsaInsn insn) {
+ ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {}
+
+ @Override
+ public void visitPhiInsn(PhiInsn phi) {}
+
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) {
+ return;
+ }
+
+ int param = getParamIndex(insn);
+
+ if (paramSpecs[param] == null) {
+ paramSpecs[param] = insn.getResult();
+ } else {
+ final RegisterSpec specA = paramSpecs[param];
+ final RegisterSpec specB = insn.getResult();
+ LocalItem localA = specA.getLocalItem();
+ LocalItem localB = specB.getLocalItem();
+ LocalItem newLocal;
+
+ /*
+ * Is there local information to preserve?
+ */
+
+if (localA == null) {
+ newLocal = localB;
+ } else if (localB == null) {
+ newLocal = localA;
+ } else if (localA.equals(localB)) {
+ newLocal = localA;
+ } else {
+ /*
+ * Oddly, these two identical move-params have distinct
+ * debug info. We'll just keep them distinct.
+ */
+ return;
+ }
+
+ ssaMeth.getDefinitionForRegister(specA.getReg()).setResultLocal(newLocal);
+
+ /*
+ * Map all uses of specB to specA
+ */
+
+RegisterMapper mapper = new RegisterMapper() {
+ /** @inheritDoc */
+ @Override
+ public int getNewRegisterCount() {
+ return ssaMeth.getRegCount();
}
- public void visitPhiInsn (PhiInsn phi) {
+
+ /** @inheritDoc */
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec.getReg() == specB.getReg()) {
+ return specA;
+ }
+
+ return registerSpec;
}
- public void visitNonMoveInsn (NormalSsaInsn insn) {
- if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) {
- return;
- }
+ };
- int param = getParamIndex(insn);
+ List<SsaInsn> uses = ssaMeth.getUseListForRegister(specB.getReg());
- if (paramSpecs[param] == null) {
- paramSpecs[param] = insn.getResult();
- } else {
- final RegisterSpec specA = paramSpecs[param];
- final RegisterSpec specB = insn.getResult();
- LocalItem localA = specA.getLocalItem();
- LocalItem localB = specB.getLocalItem();
- LocalItem newLocal;
+ // Use list is modified by mapSourceRegisters
+ for (int i = uses.size() - 1; i >= 0; i--) {
+ SsaInsn use = uses.get(i);
+ use.mapSourceRegisters(mapper);
+ }
- /*
- * Is there local information to preserve?
- */
+ deletedInsns.add(insn);
+ }
- if (localA == null) {
- newLocal = localB;
- } else if (localB == null) {
- newLocal = localA;
- } else if (localA.equals(localB)) {
- newLocal = localA;
- } else {
- /*
- * Oddly, these two identical move-params have distinct
- * debug info. We'll just keep them distinct.
- */
- return;
- }
+ }
+ });
- ssaMeth.getDefinitionForRegister(specA.getReg())
- .setResultLocal(newLocal);
+ ssaMeth.deleteInsns(deletedInsns);
+ }
- /*
- * Map all uses of specB to specA
- */
+ /**
+ * Returns the parameter index associated with a move-param insn. Does
+ * not verify that the insn is a move-param insn.
+ *
+ * @param insn {@code non-null;} a move-param insn
+ * @return {@code >=0;} parameter index
+ */
+ private int getParamIndex(NormalSsaInsn insn) {
+ CstInsn cstInsn = (CstInsn) (insn.getOriginalRopInsn());
- RegisterMapper mapper = new RegisterMapper() {
- /** @inheritDoc */
- public int getNewRegisterCount() {
- return ssaMeth.getRegCount();
- }
-
- /** @inheritDoc */
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec.getReg() == specB.getReg()) {
- return specA;
- }
-
- return registerSpec;
- }
- };
-
- List<SsaInsn> uses
- = ssaMeth.getUseListForRegister(specB.getReg());
-
- // Use list is modified by mapSourceRegisters
- for (int i = uses.size() - 1; i >= 0; i--) {
- SsaInsn use = uses.get(i);
- use.mapSourceRegisters(mapper);
- }
-
- deletedInsns.add(insn);
- }
-
- }
- });
-
- ssaMeth.deleteInsns(deletedInsns);
- }
-
- /**
- * Returns the parameter index associated with a move-param insn. Does
- * not verify that the insn is a move-param insn.
- *
- * @param insn {@code non-null;} a move-param insn
- * @return {@code >=0;} parameter index
- */
- private int getParamIndex(NormalSsaInsn insn) {
- CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn());
-
- int param = ((CstInteger)cstInsn.getConstant()).getValue();
- return param;
- }
+ int param = ((CstInteger) cstInsn.getConstant()).getValue();
+ return param;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/NormalSsaInsn.java b/dx/src/com/android/jack/dx/ssa/NormalSsaInsn.java
index c669566..b62e554 100644
--- a/dx/src/com/android/jack/dx/ssa/NormalSsaInsn.java
+++ b/dx/src/com/android/jack/dx/ssa/NormalSsaInsn.java
@@ -16,221 +16,226 @@
package com.android.jack.dx.ssa;
-import com.android.jack.dx.rop.code.*;
+import com.android.jack.dx.rop.code.Insn;
+import com.android.jack.dx.rop.code.LocalItem;
+import com.android.jack.dx.rop.code.RegOps;
+import com.android.jack.dx.rop.code.RegisterSpec;
+import com.android.jack.dx.rop.code.RegisterSpecList;
+import com.android.jack.dx.rop.code.Rop;
/**
* A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn.
*/
public final class NormalSsaInsn extends SsaInsn implements Cloneable {
- /** {@code non-null;} rop insn that we're wrapping */
- private Insn insn;
+ /** {@code non-null;} rop insn that we're wrapping */
+ private Insn insn;
- /**
- * Creates an instance.
- *
- * @param insn Rop insn to wrap
- * @param block block that contains this insn
- */
- NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
- super(insn.getResult(), block);
- this.insn = insn;
+ /**
+ * Creates an instance.
+ *
+ * @param insn Rop insn to wrap
+ * @param block block that contains this insn
+ */
+ NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
+ super(insn.getResult(), block);
+ this.insn = insn;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void mapSourceRegisters(RegisterMapper mapper) {
+ RegisterSpecList oldSources = insn.getSources();
+ RegisterSpecList newSources = mapper.map(oldSources);
+
+ if (newSources != oldSources) {
+ insn = insn.withNewRegisters(getResult(), newSources);
+ getBlock().getParent().onSourcesChanged(this, oldSources);
+ }
+ }
+
+ /**
+ * Changes one of the insn's sources. New source should be of same type
+ * and category.
+ *
+ * @param index {@code >=0;} index of source to change
+ * @param newSpec spec for new source
+ */
+ public final void changeOneSource(int index, RegisterSpec newSpec) {
+ RegisterSpecList origSources = insn.getSources();
+ int sz = origSources.size();
+ RegisterSpecList newSources = new RegisterSpecList(sz);
+
+ for (int i = 0; i < sz; i++) {
+ newSources.set(i, i == index ? newSpec : origSources.get(i));
}
- /** {@inheritDoc} */
- @Override
- public final void mapSourceRegisters(RegisterMapper mapper) {
- RegisterSpecList oldSources = insn.getSources();
- RegisterSpecList newSources = mapper.map(oldSources);
+ newSources.setImmutable();
- if (newSources != oldSources) {
- insn = insn.withNewRegisters(getResult(), newSources);
- getBlock().getParent().onSourcesChanged(this, oldSources);
- }
+ RegisterSpec origSpec = origSources.get(index);
+ if (origSpec.getReg() != newSpec.getReg()) {
+ /*
+ * If the register remains unchanged, we're only changing
+ * the type or local var name so don't update use list
+ */
+ getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
}
- /**
- * Changes one of the insn's sources. New source should be of same type
- * and category.
- *
- * @param index {@code >=0;} index of source to change
- * @param newSpec spec for new source
- */
- public final void changeOneSource(int index, RegisterSpec newSpec) {
- RegisterSpecList origSources = insn.getSources();
- int sz = origSources.size();
- RegisterSpecList newSources = new RegisterSpecList(sz);
+ insn = insn.withNewRegisters(getResult(), newSources);
+ }
- for (int i = 0; i < sz; i++) {
- newSources.set(i, i == index ? newSpec : origSources.get(i));
- }
+ /**
+ * Changes the source list of the insn. New source list should be the
+ * same size and consist of sources of identical types.
+ *
+ * @param newSources non-null new sources list.
+ */
+ public final void setNewSources(RegisterSpecList newSources) {
+ RegisterSpecList origSources = insn.getSources();
- newSources.setImmutable();
-
- RegisterSpec origSpec = origSources.get(index);
- if (origSpec.getReg() != newSpec.getReg()) {
- /*
- * If the register remains unchanged, we're only changing
- * the type or local var name so don't update use list
- */
- getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
- }
-
- insn = insn.withNewRegisters(getResult(), newSources);
+ if (origSources.size() != newSources.size()) {
+ throw new RuntimeException("Sources counts don't match");
}
- /**
- * Changes the source list of the insn. New source list should be the
- * same size and consist of sources of identical types.
- *
- * @param newSources non-null new sources list.
- */
- public final void setNewSources (RegisterSpecList newSources) {
- RegisterSpecList origSources = insn.getSources();
+ insn = insn.withNewRegisters(getResult(), newSources);
+ }
- if (origSources.size() != newSources.size()) {
- throw new RuntimeException("Sources counts don't match");
- }
+ /** {@inheritDoc} */
+ @Override
+ public NormalSsaInsn clone() {
+ return (NormalSsaInsn) super.clone();
+ }
- insn = insn.withNewRegisters(getResult(), newSources);
+ /**
+ * Like rop.Insn.getSources().
+ *
+ * @return {@code null-ok;} sources list
+ */
+ @Override
+ public RegisterSpecList getSources() {
+ return insn.getSources();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return toRopInsn().toHuman();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn toRopInsn() {
+ return insn.withNewRegisters(getResult(), insn.getSources());
+ }
+
+ /**
+ * @return the Rop opcode for this insn
+ */
+ @Override
+ public Rop getOpcode() {
+ return insn.getOpcode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Insn getOriginalRopInsn() {
+ return insn;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegisterSpec getLocalAssignment() {
+ RegisterSpec assignment;
+
+ if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
+ assignment = insn.getSources().get(0);
+ } else {
+ assignment = getResult();
}
- /** {@inheritDoc} */
- @Override
- public NormalSsaInsn clone() {
- return (NormalSsaInsn) super.clone();
+ if (assignment == null) {
+ return null;
}
- /**
- * Like rop.Insn.getSources().
- *
- * @return {@code null-ok;} sources list
- */
- @Override
- public RegisterSpecList getSources() {
- return insn.getSources();
+ LocalItem local = assignment.getLocalItem();
+
+ if (local == null) {
+ return null;
}
- /** {@inheritDoc} */
- public String toHuman() {
- return toRopInsn().toHuman();
+ return assignment;
+ }
+
+ /**
+ * Upgrades this insn to a version that represents the constant source
+ * literally. If the upgrade is not possible, this does nothing.
+ *
+ * @see Insn#withSourceLiteral
+ */
+ public void upgradeToLiteral() {
+ RegisterSpecList oldSources = insn.getSources();
+
+ insn = insn.withSourceLiteral();
+ getBlock().getParent().onSourcesChanged(this, oldSources);
+ }
+
+ /**
+ * @return true if this is a move (but not a move-operand) instruction
+ */
+ @Override
+ public boolean isNormalMoveInsn() {
+ return insn.getOpcode().getOpcode() == RegOps.MOVE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isMoveException() {
+ return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean canThrow() {
+ return insn.canThrow();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void accept(Visitor v) {
+ if (isNormalMoveInsn()) {
+ v.visitMoveInsn(this);
+ } else {
+ v.visitNonMoveInsn(this);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isPhiOrMove() {
+ return isNormalMoveInsn();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * TODO(dx team): Increase the scope of this.
+ */
+ @Override
+ public boolean hasSideEffect() {
+ Rop opcode = getOpcode();
+
+ if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+ return true;
}
- /** {@inheritDoc} */
- @Override
- public Insn toRopInsn() {
- return insn.withNewRegisters(getResult(), insn.getSources());
+ boolean hasLocalSideEffect = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+
+ switch (opcode.getOpcode()) {
+ case RegOps.MOVE_RESULT:
+ case RegOps.MOVE:
+ case RegOps.CONST:
+ return hasLocalSideEffect;
+ default:
+ return true;
}
-
- /**
- * @return the Rop opcode for this insn
- */
- @Override
- public Rop getOpcode() {
- return insn.getOpcode();
- }
-
- /** {@inheritDoc} */
- @Override
- public Insn getOriginalRopInsn() {
- return insn;
- }
-
- /** {@inheritDoc} */
- @Override
- public RegisterSpec getLocalAssignment() {
- RegisterSpec assignment;
-
- if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
- assignment = insn.getSources().get(0);
- } else {
- assignment = getResult();
- }
-
- if (assignment == null) {
- return null;
- }
-
- LocalItem local = assignment.getLocalItem();
-
- if (local == null) {
- return null;
- }
-
- return assignment;
- }
-
- /**
- * Upgrades this insn to a version that represents the constant source
- * literally. If the upgrade is not possible, this does nothing.
- *
- * @see Insn#withSourceLiteral
- */
- public void upgradeToLiteral() {
- RegisterSpecList oldSources = insn.getSources();
-
- insn = insn.withSourceLiteral();
- getBlock().getParent().onSourcesChanged(this, oldSources);
- }
-
- /**
- * @return true if this is a move (but not a move-operand) instruction
- */
- @Override
- public boolean isNormalMoveInsn() {
- return insn.getOpcode().getOpcode() == RegOps.MOVE;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isMoveException() {
- return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean canThrow() {
- return insn.canThrow();
- }
-
- /** {@inheritDoc} */
- @Override
- public void accept(Visitor v) {
- if (isNormalMoveInsn()) {
- v.visitMoveInsn(this);
- } else {
- v.visitNonMoveInsn(this);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isPhiOrMove() {
- return isNormalMoveInsn();
- }
-
- /**
- * {@inheritDoc}
- *
- * TODO: Increase the scope of this.
- */
- @Override
- public boolean hasSideEffect() {
- Rop opcode = getOpcode();
-
- if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
- return true;
- }
-
- boolean hasLocalSideEffect
- = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
-
- switch (opcode.getOpcode()) {
- case RegOps.MOVE_RESULT:
- case RegOps.MOVE:
- case RegOps.CONST:
- return hasLocalSideEffect;
- default:
- return true;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/Optimizer.java b/dx/src/com/android/jack/dx/ssa/Optimizer.java
index 799b704..35d6460 100644
--- a/dx/src/com/android/jack/dx/ssa/Optimizer.java
+++ b/dx/src/com/android/jack/dx/ssa/Optimizer.java
@@ -28,230 +28,229 @@
* and returns it to rop form.
*/
public class Optimizer {
- private static boolean preserveLocals = true;
+ private static boolean preserveLocals = true;
- private static TranslationAdvice advice;
+ private static TranslationAdvice advice;
- /** optional optimizer steps */
- public enum OptionalStep {
- MOVE_PARAM_COMBINER, SCCP, LITERAL_UPGRADE, CONST_COLLECTOR,
- ESCAPE_ANALYSIS
+ /** optional optimizer steps */
+ public enum OptionalStep {
+ MOVE_PARAM_COMBINER, SCCP, LITERAL_UPGRADE, CONST_COLLECTOR, ESCAPE_ANALYSIS
+ }
+
+ /**
+ * @return true if local variable information should be preserved, even
+ * at code size/register size cost
+ */
+ public static boolean getPreserveLocals() {
+ return preserveLocals;
+ }
+
+ /**
+ * @return {@code non-null;} translation advice
+ */
+ public static TranslationAdvice getAdvice() {
+ return advice;
+ }
+
+ /**
+ * Runs optimization algorthims over this method, and returns a new
+ * instance of RopMethod with the changes.
+ *
+ * @param rmeth method to process
+ * @param paramWidth the total width, in register-units, of this method's
+ * parameters
+ * @param isStatic true if this method has no 'this' pointer argument.
+ * @param inPreserveLocals true if local variable info should be preserved,
+ * at the cost of some registers and insns
+ * @param inAdvice {@code non-null;} translation advice
+ * @return optimized method
+ */
+ public static RopMethod optimize(RopMethod rmeth, int paramWidth, boolean isStatic,
+ boolean inPreserveLocals, TranslationAdvice inAdvice) {
+
+ return optimize(rmeth,
+ paramWidth,
+ isStatic,
+ inPreserveLocals,
+ inAdvice,
+ EnumSet.allOf(OptionalStep.class));
+ }
+
+ /**
+ * Runs optimization algorthims over this method, and returns a new
+ * instance of RopMethod with the changes.
+ *
+ * @param rmeth method to process
+ * @param paramWidth the total width, in register-units, of this method's
+ * parameters
+ * @param isStatic true if this method has no 'this' pointer argument.
+ * @param inPreserveLocals true if local variable info should be preserved,
+ * at the cost of some registers and insns
+ * @param inAdvice {@code non-null;} translation advice
+ * @param steps set of optional optimization steps to run
+ * @return optimized method
+ */
+ public static RopMethod optimize(RopMethod rmeth,
+ int paramWidth,
+ boolean isStatic,
+ boolean inPreserveLocals,
+ TranslationAdvice inAdvice,
+ EnumSet<OptionalStep> steps) {
+ SsaMethod ssaMeth = null;
+
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
+
+ ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+ runSsaFormSteps(ssaMeth, steps);
+
+ RopMethod resultMeth = SsaToRop.convertToRopMethod(ssaMeth, false);
+
+ if (resultMeth.getBlocks().getRegCount() > advice.getMaxOptimalRegisterCount()) {
+ // Try to see if we can squeeze it under the register count bar
+ resultMeth = optimizeMinimizeRegisters(rmeth, paramWidth, isStatic, steps);
}
+ return resultMeth;
+ }
- /**
- * @return true if local variable information should be preserved, even
- * at code size/register size cost
+ /**
+ * Runs the optimizer with a strategy to minimize the number of rop-form
+ * registers used by the end result. Dex bytecode does not have instruction
+ * forms that take register numbers larger than 15 for all instructions.
+ * If we've produced a method that uses more than 16 registers, try again
+ * with a different strategy to see if we can get under the bar. The end
+ * result will be much more efficient.
+ *
+ * @param rmeth method to process
+ * @param paramWidth the total width, in register-units, of this method's
+ * parameters
+ * @param isStatic true if this method has no 'this' pointer argument.
+ * @param steps set of optional optimization steps to run
+ * @return optimized method
+ */
+ private static RopMethod optimizeMinimizeRegisters(RopMethod rmeth, int paramWidth,
+ boolean isStatic, EnumSet<OptionalStep> steps) {
+ SsaMethod ssaMeth;
+ RopMethod resultMeth;
+
+ ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+
+ EnumSet<OptionalStep> newSteps = steps.clone();
+
+ /*
+ * CONST_COLLECTOR trades insns for registers, which is not an
+ * appropriate strategy here.
*/
- public static boolean getPreserveLocals() {
- return preserveLocals;
+ newSteps.remove(OptionalStep.CONST_COLLECTOR);
+
+ runSsaFormSteps(ssaMeth, newSteps);
+
+ resultMeth = SsaToRop.convertToRopMethod(ssaMeth, true);
+ return resultMeth;
+ }
+
+ private static void runSsaFormSteps(SsaMethod ssaMeth, EnumSet<OptionalStep> steps) {
+ boolean needsDeadCodeRemover = true;
+
+ if (steps.contains(OptionalStep.MOVE_PARAM_COMBINER)) {
+ MoveParamCombiner.process(ssaMeth);
}
- /**
- * @return {@code non-null;} translation advice
+ if (steps.contains(OptionalStep.SCCP)) {
+ SCCP.process(ssaMeth);
+ DeadCodeRemover.process(ssaMeth);
+ needsDeadCodeRemover = false;
+ }
+
+ if (steps.contains(OptionalStep.LITERAL_UPGRADE)) {
+ LiteralOpUpgrader.process(ssaMeth);
+ DeadCodeRemover.process(ssaMeth);
+ needsDeadCodeRemover = false;
+ }
+
+ /*
+ * ESCAPE_ANALYSIS impacts debuggability, so left off by default
*/
- public static TranslationAdvice getAdvice() {
- return advice;
+ steps.remove(OptionalStep.ESCAPE_ANALYSIS);
+ if (steps.contains(OptionalStep.ESCAPE_ANALYSIS)) {
+ EscapeAnalysis.process(ssaMeth);
+ DeadCodeRemover.process(ssaMeth);
+ needsDeadCodeRemover = false;
}
- /**
- * Runs optimization algorthims over this method, and returns a new
- * instance of RopMethod with the changes.
- *
- * @param rmeth method to process
- * @param paramWidth the total width, in register-units, of this method's
- * parameters
- * @param isStatic true if this method has no 'this' pointer argument.
- * @param inPreserveLocals true if local variable info should be preserved,
- * at the cost of some registers and insns
- * @param inAdvice {@code non-null;} translation advice
- * @return optimized method
- */
- public static RopMethod optimize(RopMethod rmeth, int paramWidth,
- boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice) {
-
- return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice,
- EnumSet.allOf(OptionalStep.class));
+ if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
+ ConstCollector.process(ssaMeth);
+ DeadCodeRemover.process(ssaMeth);
+ needsDeadCodeRemover = false;
}
- /**
- * Runs optimization algorthims over this method, and returns a new
- * instance of RopMethod with the changes.
- *
- * @param rmeth method to process
- * @param paramWidth the total width, in register-units, of this method's
- * parameters
- * @param isStatic true if this method has no 'this' pointer argument.
- * @param inPreserveLocals true if local variable info should be preserved,
- * at the cost of some registers and insns
- * @param inAdvice {@code non-null;} translation advice
- * @param steps set of optional optimization steps to run
- * @return optimized method
- */
- public static RopMethod optimize(RopMethod rmeth, int paramWidth,
- boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
- SsaMethod ssaMeth = null;
-
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
-
- ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
- runSsaFormSteps(ssaMeth, steps);
-
- RopMethod resultMeth = SsaToRop.convertToRopMethod(ssaMeth, false);
-
- if (resultMeth.getBlocks().getRegCount()
- > advice.getMaxOptimalRegisterCount()) {
- // Try to see if we can squeeze it under the register count bar
- resultMeth = optimizeMinimizeRegisters(rmeth, paramWidth, isStatic,
- steps);
- }
- return resultMeth;
+ // dead code remover must be run before phi type resolver
+ if (needsDeadCodeRemover) {
+ DeadCodeRemover.process(ssaMeth);
}
- /**
- * Runs the optimizer with a strategy to minimize the number of rop-form
- * registers used by the end result. Dex bytecode does not have instruction
- * forms that take register numbers larger than 15 for all instructions.
- * If we've produced a method that uses more than 16 registers, try again
- * with a different strategy to see if we can get under the bar. The end
- * result will be much more efficient.
- *
- * @param rmeth method to process
- * @param paramWidth the total width, in register-units, of this method's
- * parameters
- * @param isStatic true if this method has no 'this' pointer argument.
- * @param steps set of optional optimization steps to run
- * @return optimized method
- */
- private static RopMethod optimizeMinimizeRegisters(RopMethod rmeth,
- int paramWidth, boolean isStatic,
- EnumSet<OptionalStep> steps) {
- SsaMethod ssaMeth;
- RopMethod resultMeth;
+ PhiTypeResolver.process(ssaMeth);
+ }
- ssaMeth = SsaConverter.convertToSsaMethod(
- rmeth, paramWidth, isStatic);
+ public static SsaMethod debugEdgeSplit(RopMethod rmeth, int paramWidth, boolean isStatic,
+ boolean inPreserveLocals, TranslationAdvice inAdvice) {
- EnumSet<OptionalStep> newSteps = steps.clone();
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
- /*
- * CONST_COLLECTOR trades insns for registers, which is not an
- * appropriate strategy here.
- */
- newSteps.remove(OptionalStep.CONST_COLLECTOR);
+ return SsaConverter.testEdgeSplit(rmeth, paramWidth, isStatic);
+ }
- runSsaFormSteps(ssaMeth, newSteps);
+ public static SsaMethod debugPhiPlacement(RopMethod rmeth, int paramWidth, boolean isStatic,
+ boolean inPreserveLocals, TranslationAdvice inAdvice) {
- resultMeth = SsaToRop.convertToRopMethod(ssaMeth, true);
- return resultMeth;
- }
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
- private static void runSsaFormSteps(SsaMethod ssaMeth,
- EnumSet<OptionalStep> steps) {
- boolean needsDeadCodeRemover = true;
+ return SsaConverter.testPhiPlacement(rmeth, paramWidth, isStatic);
+ }
- if (steps.contains(OptionalStep.MOVE_PARAM_COMBINER)) {
- MoveParamCombiner.process(ssaMeth);
- }
+ public static SsaMethod debugRenaming(RopMethod rmeth, int paramWidth, boolean isStatic,
+ boolean inPreserveLocals, TranslationAdvice inAdvice) {
- if (steps.contains(OptionalStep.SCCP)) {
- SCCP.process(ssaMeth);
- DeadCodeRemover.process(ssaMeth);
- needsDeadCodeRemover = false;
- }
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
- if (steps.contains(OptionalStep.LITERAL_UPGRADE)) {
- LiteralOpUpgrader.process(ssaMeth);
- DeadCodeRemover.process(ssaMeth);
- needsDeadCodeRemover = false;
- }
+ return SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+ }
- /*
- * ESCAPE_ANALYSIS impacts debuggability, so left off by default
- */
- steps.remove(OptionalStep.ESCAPE_ANALYSIS);
- if (steps.contains(OptionalStep.ESCAPE_ANALYSIS)) {
- EscapeAnalysis.process(ssaMeth);
- DeadCodeRemover.process(ssaMeth);
- needsDeadCodeRemover = false;
- }
+ public static SsaMethod debugDeadCodeRemover(RopMethod rmeth, int paramWidth, boolean isStatic,
+ boolean inPreserveLocals, TranslationAdvice inAdvice) {
- if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
- ConstCollector.process(ssaMeth);
- DeadCodeRemover.process(ssaMeth);
- needsDeadCodeRemover = false;
- }
+ SsaMethod ssaMeth;
- // dead code remover must be run before phi type resolver
- if (needsDeadCodeRemover) {
- DeadCodeRemover.process(ssaMeth);
- }
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
- PhiTypeResolver.process(ssaMeth);
- }
+ ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+ DeadCodeRemover.process(ssaMeth);
- public static SsaMethod debugEdgeSplit(RopMethod rmeth, int paramWidth,
- boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice) {
+ return ssaMeth;
+ }
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
+ public static SsaMethod debugNoRegisterAllocation(RopMethod rmeth,
+ int paramWidth,
+ boolean isStatic,
+ boolean inPreserveLocals,
+ TranslationAdvice inAdvice,
+ EnumSet<OptionalStep> steps) {
- return SsaConverter.testEdgeSplit(rmeth, paramWidth, isStatic);
- }
+ SsaMethod ssaMeth;
- public static SsaMethod debugPhiPlacement(RopMethod rmeth, int paramWidth,
- boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice) {
+ preserveLocals = inPreserveLocals;
+ advice = inAdvice;
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
+ ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
- return SsaConverter.testPhiPlacement(rmeth, paramWidth, isStatic);
- }
+ runSsaFormSteps(ssaMeth, steps);
- public static SsaMethod debugRenaming(RopMethod rmeth, int paramWidth,
- boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice) {
+ LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
-
- return SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
- }
-
- public static SsaMethod debugDeadCodeRemover(RopMethod rmeth,
- int paramWidth, boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice) {
-
- SsaMethod ssaMeth;
-
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
-
- ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
- DeadCodeRemover.process(ssaMeth);
-
- return ssaMeth;
- }
-
- public static SsaMethod debugNoRegisterAllocation(RopMethod rmeth,
- int paramWidth, boolean isStatic, boolean inPreserveLocals,
- TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
-
- SsaMethod ssaMeth;
-
- preserveLocals = inPreserveLocals;
- advice = inAdvice;
-
- ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
-
- runSsaFormSteps(ssaMeth, steps);
-
- LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
-
- return ssaMeth;
- }
+ return ssaMeth;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/PhiInsn.java b/dx/src/com/android/jack/dx/ssa/PhiInsn.java
index 9372305..d7419d6 100644
--- a/dx/src/com/android/jack/dx/ssa/PhiInsn.java
+++ b/dx/src/com/android/jack/dx/ssa/PhiInsn.java
@@ -16,7 +16,12 @@
package com.android.jack.dx.ssa;
-import com.android.jack.dx.rop.code.*;
+import com.android.jack.dx.rop.code.Insn;
+import com.android.jack.dx.rop.code.LocalItem;
+import com.android.jack.dx.rop.code.RegisterSpec;
+import com.android.jack.dx.rop.code.RegisterSpecList;
+import com.android.jack.dx.rop.code.Rop;
+import com.android.jack.dx.rop.code.SourcePosition;
import com.android.jack.dx.rop.type.Type;
import com.android.jack.dx.rop.type.TypeBearer;
import com.android.jack.dx.util.Hex;
@@ -30,369 +35,362 @@
* conversion back to ROP form.
*/
public final class PhiInsn extends SsaInsn {
- /**
- * result register. The original result register of the phi insn
- * is needed during the renaming process after the new result
- * register has already been chosen.
- */
- private final int ropResultReg;
+ /**
+ * result register. The original result register of the phi insn
+ * is needed during the renaming process after the new result
+ * register has already been chosen.
+ */
+ private final int ropResultReg;
- /**
- * {@code non-null;} operands of the instruction; built up by
- * {@link #addPhiOperand}
- */
- private final ArrayList<Operand> operands = new ArrayList<Operand>();
+ /**
+ * {@code non-null;} operands of the instruction; built up by
+ * {@link #addPhiOperand}
+ */
+ private final ArrayList<Operand> operands = new ArrayList<Operand>();
- /** {@code null-ok;} source registers; constructed lazily */
- private RegisterSpecList sources;
+ /** {@code null-ok;} source registers; constructed lazily */
+ private RegisterSpecList sources;
- /**
- * Constructs a new phi insn with no operands.
- *
- * @param resultReg the result reg for this phi insn
- * @param block block containing this insn.
+ /**
+ * Constructs a new phi insn with no operands.
+ *
+ * @param resultReg the result reg for this phi insn
+ * @param block block containing this insn.
+ */
+ public PhiInsn(RegisterSpec resultReg, SsaBasicBlock block) {
+ super(resultReg, block);
+ ropResultReg = resultReg.getReg();
+ }
+
+ /**
+ * Makes a phi insn with a void result type.
+ *
+ * @param resultReg the result register for this phi insn.
+ * @param block block containing this insn.
+ */
+ public PhiInsn(final int resultReg, final SsaBasicBlock block) {
+ /*
+ * The result type here is bogus: The type depends on the
+ * operand and will be derived later.
*/
- public PhiInsn(RegisterSpec resultReg, SsaBasicBlock block) {
- super(resultReg, block);
- ropResultReg = resultReg.getReg();
+ super(RegisterSpec.make(resultReg, Type.VOID), block);
+ ropResultReg = resultReg;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public PhiInsn clone() {
+ throw new UnsupportedOperationException("can't clone phi");
+ }
+
+ /**
+ * Updates the TypeBearers of all the sources (phi operands) to be
+ * the current TypeBearer of the register-defining instruction's result.
+ * This is used during phi-type resolution.<p>
+ *
+ * Note that local association of operands are preserved in this step.
+ *
+ * @param ssaMeth method that contains this insn
+ */
+ public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
+ for (Operand o : operands) {
+ RegisterSpec def = ssaMeth.getDefinitionForRegister(o.regSpec.getReg()).getResult();
+
+ o.regSpec = o.regSpec.withType(def.getType());
}
- /**
- * Makes a phi insn with a void result type.
- *
- * @param resultReg the result register for this phi insn.
- * @param block block containing this insn.
+ sources = null;
+ }
+
+ /**
+ * Changes the result type. Used during phi type resolution
+ *
+ * @param type {@code non-null;} new TypeBearer
+ * @param local {@code null-ok;} new local info, if available
+ */
+ public void changeResultType(TypeBearer type, LocalItem local) {
+ setResult(RegisterSpec.makeLocalOptional(getResult().getReg(), type, local));
+ }
+
+ /**
+ * Gets the original rop-form result reg. This is useful during renaming.
+ *
+ * @return the original rop-form result reg
+ */
+ public int getRopResultReg() {
+ return ropResultReg;
+ }
+
+ /**
+ * Adds an operand to this phi instruction.
+ *
+ * @param registerSpec register spec, including type and reg of operand
+ * @param predBlock predecessor block to be associated with this operand
+ */
+ public void addPhiOperand(RegisterSpec registerSpec, SsaBasicBlock predBlock) {
+ operands.add(new Operand(registerSpec, predBlock.getIndex(), predBlock.getRopLabel()));
+
+ // Un-cache sources, in case someone has already called getSources().
+ sources = null;
+ }
+
+ /**
+ * Removes all operand uses of a register from this phi instruction.
+ *
+ * @param registerSpec register spec, including type and reg of operand
+ */
+ public void removePhiRegister(RegisterSpec registerSpec) {
+ ArrayList<Operand> operandsToRemove = new ArrayList<Operand>();
+ for (Operand o : operands) {
+ if (o.regSpec.getReg() == registerSpec.getReg()) {
+ operandsToRemove.add(o);
+ }
+ }
+
+ operands.removeAll(operandsToRemove);
+
+ // Un-cache sources, in case someone has already called getSources().
+ sources = null;
+ }
+
+ /**
+ * Gets the index of the pred block associated with the RegisterSpec
+ * at the particular getSources() index.
+ *
+ * @param sourcesIndex index of source in getSources()
+ * @return block index
+ */
+ public int predBlockIndexForSourcesIndex(int sourcesIndex) {
+ return operands.get(sourcesIndex).blockIndex;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Always returns null for {@code PhiInsn}s.
+ */
+ @Override
+ public Rop getOpcode() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Always returns null for {@code PhiInsn}s.
+ */
+ @Override
+ public Insn getOriginalRopInsn() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Always returns false for {@code PhiInsn}s.
+ */
+ @Override
+ public boolean canThrow() {
+ return false;
+ }
+
+ /**
+ * Gets sources. Constructed lazily from phi operand data structures and
+ * then cached.
+ *
+ * @return {@code non-null;} sources list
+ */
+ @Override
+ public RegisterSpecList getSources() {
+ if (sources != null) {
+ return sources;
+ }
+
+ if (operands.size() == 0) {
+ // How'd this happen? A phi insn with no operand?
+ return RegisterSpecList.EMPTY;
+ }
+
+ int szSources = operands.size();
+ sources = new RegisterSpecList(szSources);
+
+ for (int i = 0; i < szSources; i++) {
+ Operand o = operands.get(i);
+
+ sources.set(i, o.regSpec);
+ }
+
+ sources.setImmutable();
+ return sources;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isRegASource(int reg) {
+ /*
+ * Avoid creating a sources list in case it has not already been
+ * created.
*/
- public PhiInsn(final int resultReg, final SsaBasicBlock block) {
- /*
- * The result type here is bogus: The type depends on the
- * operand and will be derived later.
- */
- super(RegisterSpec.make(resultReg, Type.VOID), block);
- ropResultReg = resultReg;
- }
- /** {@inheritDoc} */
- @Override
- public PhiInsn clone() {
- throw new UnsupportedOperationException("can't clone phi");
- }
-
- /**
- * Updates the TypeBearers of all the sources (phi operands) to be
- * the current TypeBearer of the register-defining instruction's result.
- * This is used during phi-type resolution.<p>
- *
- * Note that local association of operands are preserved in this step.
- *
- * @param ssaMeth method that contains this insn
- */
- public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
- for (Operand o : operands) {
- RegisterSpec def
- = ssaMeth.getDefinitionForRegister(
- o.regSpec.getReg()).getResult();
-
- o.regSpec = o.regSpec.withType(def.getType());
- }
-
- sources = null;
- }
-
- /**
- * Changes the result type. Used during phi type resolution
- *
- * @param type {@code non-null;} new TypeBearer
- * @param local {@code null-ok;} new local info, if available
- */
- public void changeResultType(TypeBearer type, LocalItem local) {
- setResult(RegisterSpec.makeLocalOptional(
- getResult().getReg(), type, local));
- }
-
- /**
- * Gets the original rop-form result reg. This is useful during renaming.
- *
- * @return the original rop-form result reg
- */
- public int getRopResultReg() {
- return ropResultReg;
- }
-
- /**
- * Adds an operand to this phi instruction.
- *
- * @param registerSpec register spec, including type and reg of operand
- * @param predBlock predecessor block to be associated with this operand
- */
- public void addPhiOperand(RegisterSpec registerSpec,
- SsaBasicBlock predBlock) {
- operands.add(new Operand(registerSpec, predBlock.getIndex(),
- predBlock.getRopLabel()));
-
- // Un-cache sources, in case someone has already called getSources().
- sources = null;
- }
-
- /**
- * Removes all operand uses of a register from this phi instruction.
- *
- * @param registerSpec register spec, including type and reg of operand
- */
- public void removePhiRegister(RegisterSpec registerSpec) {
- ArrayList<Operand> operandsToRemove = new ArrayList<Operand>();
- for (Operand o : operands) {
- if (o.regSpec.getReg() == registerSpec.getReg()) {
- operandsToRemove.add(o);
- }
- }
-
- operands.removeAll(operandsToRemove);
-
- // Un-cache sources, in case someone has already called getSources().
- sources = null;
- }
-
- /**
- * Gets the index of the pred block associated with the RegisterSpec
- * at the particular getSources() index.
- *
- * @param sourcesIndex index of source in getSources()
- * @return block index
- */
- public int predBlockIndexForSourcesIndex(int sourcesIndex) {
- return operands.get(sourcesIndex).blockIndex;
- }
-
- /**
- * {@inheritDoc}
- *
- * Always returns null for {@code PhiInsn}s.
- */
- @Override
- public Rop getOpcode() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * Always returns null for {@code PhiInsn}s.
- */
- @Override
- public Insn getOriginalRopInsn() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * Always returns false for {@code PhiInsn}s.
- */
- @Override
- public boolean canThrow() {
- return false;
- }
-
- /**
- * Gets sources. Constructed lazily from phi operand data structures and
- * then cached.
- *
- * @return {@code non-null;} sources list
- */
- @Override
- public RegisterSpecList getSources() {
- if (sources != null) {
- return sources;
- }
-
- if (operands.size() == 0) {
- // How'd this happen? A phi insn with no operand?
- return RegisterSpecList.EMPTY;
- }
-
- int szSources = operands.size();
- sources = new RegisterSpecList(szSources);
-
- for (int i = 0; i < szSources; i++) {
- Operand o = operands.get(i);
-
- sources.set(i, o.regSpec);
- }
-
- sources.setImmutable();
- return sources;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isRegASource(int reg) {
- /*
- * Avoid creating a sources list in case it has not already been
- * created.
- */
-
- for (Operand o : operands) {
- if (o.regSpec.getReg() == reg) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @return true if all operands use the same register
- */
- public boolean areAllOperandsEqual() {
- if (operands.size() == 0 ) {
- // This should never happen.
- return true;
- }
-
- int firstReg = operands.get(0).regSpec.getReg();
- for (Operand o : operands) {
- if (firstReg != o.regSpec.getReg()) {
- return false;
- }
- }
-
+for (Operand o : operands) {
+ if (o.regSpec.getReg() == reg) {
return true;
+ }
}
- /** {@inheritDoc} */
- @Override
- public final void mapSourceRegisters(RegisterMapper mapper) {
- for (Operand o : operands) {
- RegisterSpec old = o.regSpec;
- o.regSpec = mapper.map(old);
- if (old != o.regSpec) {
- getBlock().getParent().onSourceChanged(this, old, o.regSpec);
- }
- }
- sources = null;
+ return false;
+ }
+
+ /**
+ * @return true if all operands use the same register
+ */
+ public boolean areAllOperandsEqual() {
+ if (operands.size() == 0) {
+ // This should never happen.
+ return true;
}
- /**
- * Always throws an exeption, since a phi insn may not be
- * converted back to rop form.
- *
- * @return always throws exception
- */
- @Override
- public Insn toRopInsn() {
- throw new IllegalArgumentException(
- "Cannot convert phi insns to rop form");
+ int firstReg = operands.get(0).regSpec.getReg();
+ for (Operand o : operands) {
+ if (firstReg != o.regSpec.getReg()) {
+ return false;
+ }
}
- /**
- * Returns the list of predecessor blocks associated with all operands
- * that have {@code reg} as an operand register.
- *
- * @param reg register to look up
- * @param ssaMeth method we're operating on
- * @return list of predecessor blocks, empty if none
- */
- public List<SsaBasicBlock> predBlocksForReg(int reg, SsaMethod ssaMeth) {
- ArrayList<SsaBasicBlock> ret = new ArrayList<SsaBasicBlock>();
+ return true;
+ }
- for (Operand o : operands) {
- if (o.regSpec.getReg() == reg) {
- ret.add(ssaMeth.getBlocks().get(o.blockIndex));
- }
- }
+ /** {@inheritDoc} */
+ @Override
+ public final void mapSourceRegisters(RegisterMapper mapper) {
+ for (Operand o : operands) {
+ RegisterSpec old = o.regSpec;
+ o.regSpec = mapper.map(old);
+ if (old != o.regSpec) {
+ getBlock().getParent().onSourceChanged(this, old, o.regSpec);
+ }
+ }
+ sources = null;
+ }
- return ret;
+ /**
+ * Always throws an exeption, since a phi insn may not be
+ * converted back to rop form.
+ *
+ * @return always throws exception
+ */
+ @Override
+ public Insn toRopInsn() {
+ throw new IllegalArgumentException("Cannot convert phi insns to rop form");
+ }
+
+ /**
+ * Returns the list of predecessor blocks associated with all operands
+ * that have {@code reg} as an operand register.
+ *
+ * @param reg register to look up
+ * @param ssaMeth method we're operating on
+ * @return list of predecessor blocks, empty if none
+ */
+ public List<SsaBasicBlock> predBlocksForReg(int reg, SsaMethod ssaMeth) {
+ ArrayList<SsaBasicBlock> ret = new ArrayList<SsaBasicBlock>();
+
+ for (Operand o : operands) {
+ if (o.regSpec.getReg() == reg) {
+ ret.add(ssaMeth.getBlocks().get(o.blockIndex));
+ }
}
- /** {@inheritDoc} */
- @Override
- public boolean isPhiOrMove() {
- return true;
+ return ret;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isPhiOrMove() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasSideEffect() {
+ return Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void accept(SsaInsn.Visitor v) {
+ v.visitPhiInsn(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toHuman() {
+ return toHumanWithInline(null);
+ }
+
+ /**
+ * Returns human-readable string for listing dumps. This method
+ * allows sub-classes to specify extra text.
+ *
+ * @param extra {@code null-ok;} the argument to print after the opcode
+ * @return human-readable string for listing dumps
+ */
+ protected final String toHumanWithInline(String extra) {
+ StringBuffer sb = new StringBuffer(80);
+
+ sb.append(SourcePosition.NO_INFO);
+ sb.append(": phi");
+
+ if (extra != null) {
+ sb.append("(");
+ sb.append(extra);
+ sb.append(")");
}
- /** {@inheritDoc} */
- @Override
- public boolean hasSideEffect() {
- return Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+ RegisterSpec result = getResult();
+
+ if (result == null) {
+ sb.append(" .");
+ } else {
+ sb.append(" ");
+ sb.append(result.toHuman());
}
- /** {@inheritDoc} */
- @Override
- public void accept(SsaInsn.Visitor v) {
- v.visitPhiInsn(this);
+ sb.append(" <-");
+
+ int sz = getSources().size();
+ if (sz == 0) {
+ sb.append(" .");
+ } else {
+ for (int i = 0; i < sz; i++) {
+ sb.append(" ");
+ sb.append(sources.get(i).toHuman() + "[b=" + Hex.u2(operands.get(i).ropLabel) + "]");
+ }
}
- /** {@inheritDoc} */
- public String toHuman() {
- return toHumanWithInline(null);
+ return sb.toString();
+ }
+
+ /**
+ * A single phi operand, consiting of source register and block index
+ * for move.
+ */
+ private static class Operand {
+ public RegisterSpec regSpec;
+ public final int blockIndex;
+ public final int ropLabel; // only used for debugging
+
+ public Operand(RegisterSpec regSpec, int blockIndex, int ropLabel) {
+ this.regSpec = regSpec;
+ this.blockIndex = blockIndex;
+ this.ropLabel = ropLabel;
}
+ }
- /**
- * Returns human-readable string for listing dumps. This method
- * allows sub-classes to specify extra text.
- *
- * @param extra {@code null-ok;} the argument to print after the opcode
- * @return human-readable string for listing dumps
- */
- protected final String toHumanWithInline(String extra) {
- StringBuffer sb = new StringBuffer(80);
-
- sb.append(SourcePosition.NO_INFO);
- sb.append(": phi");
-
- if (extra != null) {
- sb.append("(");
- sb.append(extra);
- sb.append(")");
- }
-
- RegisterSpec result = getResult();
-
- if (result == null) {
- sb.append(" .");
- } else {
- sb.append(" ");
- sb.append(result.toHuman());
- }
-
- sb.append(" <-");
-
- int sz = getSources().size();
- if (sz == 0) {
- sb.append(" .");
- } else {
- for (int i = 0; i < sz; i++) {
- sb.append(" ");
- sb.append(sources.get(i).toHuman()
- + "[b="
- + Hex.u2(operands.get(i).ropLabel) + "]");
- }
- }
-
- return sb.toString();
- }
-
- /**
- * A single phi operand, consiting of source register and block index
- * for move.
- */
- private static class Operand {
- public RegisterSpec regSpec;
- public final int blockIndex;
- public final int ropLabel; // only used for debugging
-
- public Operand(RegisterSpec regSpec, int blockIndex, int ropLabel) {
- this.regSpec = regSpec;
- this.blockIndex = blockIndex;
- this.ropLabel = ropLabel;
- }
- }
-
- /**
- * Visitor interface for instances of this (outer) class.
- */
- public static interface Visitor {
- public void visitPhiInsn(PhiInsn insn);
- }
+ /**
+ * Visitor interface for instances of this (outer) class.
+ */
+ public static interface Visitor {
+ public void visitPhiInsn(PhiInsn insn);
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/PhiTypeResolver.java b/dx/src/com/android/jack/dx/ssa/PhiTypeResolver.java
index abc1253..896f816 100644
--- a/dx/src/com/android/jack/dx/ssa/PhiTypeResolver.java
+++ b/dx/src/com/android/jack/dx/ssa/PhiTypeResolver.java
@@ -42,222 +42,218 @@
*/
public class PhiTypeResolver {
- SsaMethod ssaMeth;
- /** indexed by register; all registers still defined by unresolved phis */
- private final BitSet worklist;
+ SsaMethod ssaMeth;
+ /** indexed by register; all registers still defined by unresolved phis */
+ private final BitSet worklist;
- /**
- * Resolves all phi types in the method
- * @param ssaMeth method to process
- */
- public static void process (SsaMethod ssaMeth) {
- new PhiTypeResolver(ssaMeth).run();
+ /**
+ * Resolves all phi types in the method
+ * @param ssaMeth method to process
+ */
+ public static void process(SsaMethod ssaMeth) {
+ new PhiTypeResolver(ssaMeth).run();
+ }
+
+ private PhiTypeResolver(SsaMethod ssaMeth) {
+ this.ssaMeth = ssaMeth;
+ worklist = new BitSet(ssaMeth.getRegCount());
+ }
+
+ /**
+ * Runs the phi-type resolver.
+ */
+ private void run() {
+
+ int regCount = ssaMeth.getRegCount();
+
+ for (int reg = 0; reg < regCount; reg++) {
+ SsaInsn definsn = ssaMeth.getDefinitionForRegister(reg);
+
+ if (definsn != null && (definsn.getResult().getBasicType() == Type.BT_VOID)) {
+ worklist.set(reg);
+ }
}
- private PhiTypeResolver(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
- worklist = new BitSet(ssaMeth.getRegCount());
- }
+ int reg;
+ while (0 <= (reg = worklist.nextSetBit(0))) {
+ worklist.clear(reg);
- /**
- * Runs the phi-type resolver.
- */
- private void run() {
+ /*
+ * definitions on the worklist have a type of BT_VOID, which
+ * must have originated from a PhiInsn.
+ */
+ PhiInsn definsn = (PhiInsn) ssaMeth.getDefinitionForRegister(reg);
- int regCount = ssaMeth.getRegCount();
+ if (resolveResultType(definsn)) {
+ /*
+ * If the result type has changed, re-resolve all phis
+ * that use this.
+ */
- for (int reg = 0; reg < regCount; reg++) {
- SsaInsn definsn = ssaMeth.getDefinitionForRegister(reg);
+List<SsaInsn> useList = ssaMeth.getUseListForRegister(reg);
- if (definsn != null
- && (definsn.getResult().getBasicType() == Type.BT_VOID)) {
- worklist.set(reg);
- }
+ int sz = useList.size();
+ for (int i = 0; i < sz; i++) {
+ SsaInsn useInsn = useList.get(i);
+ RegisterSpec resultReg = useInsn.getResult();
+ if (resultReg != null && useInsn instanceof PhiInsn) {
+ worklist.set(resultReg.getReg());
+ }
}
+ }
+ }
+ }
- int reg;
- while ( 0 <= (reg = worklist.nextSetBit(0))) {
- worklist.clear(reg);
+ /**
+ * Returns true if a and b are equal, whether
+ * or not either of them are null.
+ * @param a
+ * @param b
+ * @return true if equal
+ */
+ private static boolean equalsHandlesNulls(LocalItem a, LocalItem b) {
+ return (a == b) || ((a != null) && a.equals(b));
+ }
+ /**
+ * Resolves the result of a phi insn based on its operands. The "void"
+ * type, which is a nonsensical type for a register, is used for
+ * registers defined by as-of-yet-unresolved phi operations.
+ *
+ * @return true if the result type changed, false if no change
+ */
+ boolean resolveResultType(PhiInsn insn) {
+ insn.updateSourcesToDefinitions(ssaMeth);
+
+ RegisterSpecList sources = insn.getSources();
+
+ // Start by finding the first non-void operand
+ RegisterSpec first = null;
+ int firstIndex = -1;
+
+ int szSources = sources.size();
+ for (int i = 0; i < szSources; i++) {
+ RegisterSpec rs = sources.get(i);
+
+ if (rs.getBasicType() != Type.BT_VOID) {
+ first = rs;
+ firstIndex = i;
+ }
+ }
+
+ if (first == null) {
+ // All operands are void -- we're not ready to resolve yet
+ return false;
+ }
+
+ LocalItem firstLocal = first.getLocalItem();
+ TypeBearer mergedType = first.getType();
+ boolean sameLocals = true;
+ for (int i = 0; i < szSources; i++) {
+ if (i == firstIndex) {
+ continue;
+ }
+
+ RegisterSpec rs = sources.get(i);
+
+ // Just skip void (unresolved phi results) for now
+ if (rs.getBasicType() == Type.BT_VOID) {
+ continue;
+ }
+
+ sameLocals = sameLocals && equalsHandlesNulls(firstLocal, rs.getLocalItem());
+
+ mergedType = mergeType(mergedType, rs.getType());
+ }
+
+ TypeBearer newResultType;
+
+ if (mergedType != null) {
+ newResultType = mergedType;
+ } else {
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < szSources; i++) {
+ sb.append(sources.get(i).toString());
+ sb.append(' ');
+ }
+
+ throw new RuntimeException("Couldn't map types in phi insn:" + sb);
+ }
+
+ LocalItem newLocal = sameLocals ? firstLocal : null;
+
+ RegisterSpec result = insn.getResult();
+
+ if ((result.getTypeBearer() == newResultType)
+ && equalsHandlesNulls(newLocal, result.getLocalItem())) {
+ return false;
+ }
+
+ insn.changeResultType(newResultType, newLocal);
+
+ return true;
+ }
+
+ /**
+ * Merges two frame types.
+ *
+ * @param ft1 {@code non-null;} a frame type
+ * @param ft2 {@code non-null;} another frame type
+ * @return {@code non-null;} the result of merging the two types
+ */
+ private static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) {
+ if ((ft1 == null) || ft1.equals(ft2)) {
+ return ft1;
+ } else if (ft2 == null) {
+ return null;
+ } else {
+ Type type1 = ft1.getType();
+ Type type2 = ft2.getType();
+
+ if (type1 == type2) {
+ return type1;
+ } else if (type1.isReference() && type2.isReference()) {
+ if (type1 == Type.KNOWN_NULL) {
+ /*
+ * A known-null merges with any other reference type to
+ * be that reference type.
+ */
+ return type2;
+ } else if (type2 == Type.KNOWN_NULL) {
+ /*
+ * The same as above, but this time it's type2 that's
+ * the known-null.
+ */
+ return type1;
+ } else if (type1.isArray() && type2.isArray()) {
+ TypeBearer componentUnion = mergeType(type1.getComponentType(), type2.getComponentType());
+ if (componentUnion == null) {
/*
- * definitions on the worklist have a type of BT_VOID, which
- * must have originated from a PhiInsn.
+ * At least one of the types is a primitive type,
+ * so the merged result is just Object.
*/
- PhiInsn definsn = (PhiInsn)ssaMeth.getDefinitionForRegister(reg);
-
- if (resolveResultType(definsn)) {
- /*
- * If the result type has changed, re-resolve all phis
- * that use this.
- */
-
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(reg);
-
- int sz = useList.size();
- for (int i = 0; i < sz; i++ ) {
- SsaInsn useInsn = useList.get(i);
- RegisterSpec resultReg = useInsn.getResult();
- if (resultReg != null && useInsn instanceof PhiInsn) {
- worklist.set(resultReg.getReg());
- }
- }
- }
- }
- }
-
- /**
- * Returns true if a and b are equal, whether
- * or not either of them are null.
- * @param a
- * @param b
- * @return true if equal
- */
- private static boolean equalsHandlesNulls(LocalItem a, LocalItem b) {
- return (a == b) || ((a != null) && a.equals(b));
- }
-
- /**
- * Resolves the result of a phi insn based on its operands. The "void"
- * type, which is a nonsensical type for a register, is used for
- * registers defined by as-of-yet-unresolved phi operations.
- *
- * @return true if the result type changed, false if no change
- */
- boolean resolveResultType(PhiInsn insn) {
- insn.updateSourcesToDefinitions(ssaMeth);
-
- RegisterSpecList sources = insn.getSources();
-
- // Start by finding the first non-void operand
- RegisterSpec first = null;
- int firstIndex = -1;
-
- int szSources = sources.size();
- for (int i = 0 ; i <szSources ; i++) {
- RegisterSpec rs = sources.get(i);
-
- if (rs.getBasicType() != Type.BT_VOID) {
- first = rs;
- firstIndex = i;
- }
- }
-
- if (first == null) {
- // All operands are void -- we're not ready to resolve yet
- return false;
- }
-
- LocalItem firstLocal = first.getLocalItem();
- TypeBearer mergedType = first.getType();
- boolean sameLocals = true;
- for (int i = 0 ; i < szSources ; i++) {
- if (i == firstIndex) {
- continue;
- }
-
- RegisterSpec rs = sources.get(i);
-
- // Just skip void (unresolved phi results) for now
- if (rs.getBasicType() == Type.BT_VOID){
- continue;
- }
-
- sameLocals = sameLocals
- && equalsHandlesNulls(firstLocal, rs.getLocalItem());
-
- mergedType = mergeType(mergedType, rs.getType());
- }
-
- TypeBearer newResultType;
-
- if (mergedType != null) {
- newResultType = mergedType;
+ return Type.OBJECT;
+ }
+ return ((Type) componentUnion).getArrayType();
} else {
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0; i < szSources; i++) {
- sb.append(sources.get(i).toString());
- sb.append(' ');
- }
-
- throw new RuntimeException ("Couldn't map types in phi insn:" + sb);
+ /*
+ * All other unequal reference types get merged to be
+ * Object in this phase. This is fine here, but it
+ * won't be the right thing to do in the verifier.
+ */
+ return Type.OBJECT;
}
-
- LocalItem newLocal = sameLocals ? firstLocal : null;
-
- RegisterSpec result = insn.getResult();
-
- if ((result.getTypeBearer() == newResultType)
- && equalsHandlesNulls(newLocal, result.getLocalItem())) {
- return false;
- }
-
- insn.changeResultType(newResultType, newLocal);
-
- return true;
+ } else if (type1.isIntlike() && type2.isIntlike()) {
+ /*
+ * Merging two non-identical int-like types results in
+ * the type int.
+ */
+ return Type.INT;
+ } else {
+ return null;
+ }
}
-
- /**
- * Merges two frame types.
- *
- * @param ft1 {@code non-null;} a frame type
- * @param ft2 {@code non-null;} another frame type
- * @return {@code non-null;} the result of merging the two types
- */
- private static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) {
- if ((ft1 == null) || ft1.equals(ft2)) {
- return ft1;
- } else if (ft2 == null) {
- return null;
- } else {
- Type type1 = ft1.getType();
- Type type2 = ft2.getType();
-
- if (type1 == type2) {
- return type1;
- } else if (type1.isReference() && type2.isReference()) {
- if (type1 == Type.KNOWN_NULL) {
- /*
- * A known-null merges with any other reference type to
- * be that reference type.
- */
- return type2;
- } else if (type2 == Type.KNOWN_NULL) {
- /*
- * The same as above, but this time it's type2 that's
- * the known-null.
- */
- return type1;
- } else if (type1.isArray() && type2.isArray()) {
- TypeBearer componentUnion =
- mergeType(type1.getComponentType(),
- type2.getComponentType());
- if (componentUnion == null) {
- /*
- * At least one of the types is a primitive type,
- * so the merged result is just Object.
- */
- return Type.OBJECT;
- }
- return ((Type) componentUnion).getArrayType();
- } else {
- /*
- * All other unequal reference types get merged to be
- * Object in this phase. This is fine here, but it
- * won't be the right thing to do in the verifier.
- */
- return Type.OBJECT;
- }
- } else if (type1.isIntlike() && type2.isIntlike()) {
- /*
- * Merging two non-identical int-like types results in
- * the type int.
- */
- return Type.INT;
- } else {
- return null;
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/RegisterMapper.java b/dx/src/com/android/jack/dx/ssa/RegisterMapper.java
index 300d956..2807fdb 100644
--- a/dx/src/com/android/jack/dx/ssa/RegisterMapper.java
+++ b/dx/src/com/android/jack/dx/ssa/RegisterMapper.java
@@ -18,7 +18,6 @@
import com.android.jack.dx.rop.code.RegisterSpec;
import com.android.jack.dx.rop.code.RegisterSpecList;
-import com.android.jack.dx.util.ToHuman;
/**
* Represents a mapping between two register numbering schemes.
@@ -27,35 +26,35 @@
* instances of this class are passed.
*/
public abstract class RegisterMapper {
- /**
- * Gets the count of registers (really, the total register width, since
- * category width is counted) in the new namespace.
- * @return >= 0 width of new namespace.
- */
- public abstract int getNewRegisterCount();
+ /**
+ * Gets the count of registers (really, the total register width, since
+ * category width is counted) in the new namespace.
+ * @return >= 0 width of new namespace.
+ */
+ public abstract int getNewRegisterCount();
- /**
- * @param registerSpec old register
- * @return register in new space
- */
- public abstract RegisterSpec map(RegisterSpec registerSpec);
+ /**
+ * @param registerSpec old register
+ * @return register in new space
+ */
+ public abstract RegisterSpec map(RegisterSpec registerSpec);
- /**
- *
- * @param sources old register list
- * @return new mapped register list, or old if nothing has changed.
- */
- public final RegisterSpecList map(RegisterSpecList sources) {
- int sz = sources.size();
- RegisterSpecList newSources = new RegisterSpecList(sz);
+ /**
+ *
+ * @param sources old register list
+ * @return new mapped register list, or old if nothing has changed.
+ */
+ public final RegisterSpecList map(RegisterSpecList sources) {
+ int sz = sources.size();
+ RegisterSpecList newSources = new RegisterSpecList(sz);
- for (int i = 0; i < sz; i++) {
- newSources.set(i, map(sources.get(i)));
- }
-
- newSources.setImmutable();
-
- // Return the old sources if nothing has changed.
- return newSources.equals(sources) ? sources : newSources;
+ for (int i = 0; i < sz; i++) {
+ newSources.set(i, map(sources.get(i)));
}
+
+ newSources.setImmutable();
+
+ // Return the old sources if nothing has changed.
+ return newSources.equals(sources) ? sources : newSources;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SCCP.java b/dx/src/com/android/jack/dx/ssa/SCCP.java
index 9575353..4fc3a21 100644
--- a/dx/src/com/android/jack/dx/ssa/SCCP.java
+++ b/dx/src/com/android/jack/dx/ssa/SCCP.java
@@ -39,659 +39,646 @@
* Propagation algorithm.
*/
public class SCCP {
- /** Lattice values */
- private static final int TOP = 0;
- private static final int CONSTANT = 1;
- private static final int VARYING = 2;
- /** method we're processing */
- private SsaMethod ssaMeth;
- /** ssaMeth.getRegCount() */
- private int regCount;
- /** Lattice values for each SSA register */
- private int[] latticeValues;
- /** For those registers that are constant, this is the constant value */
- private Constant[] latticeConstants;
- /** Worklist of basic blocks to be processed */
- private ArrayList<SsaBasicBlock> cfgWorklist;
- /** Worklist of executed basic blocks with phis to be processed */
- private ArrayList<SsaBasicBlock> cfgPhiWorklist;
- /** Bitset containing bits for each block that has been found executable */
- private BitSet executableBlocks;
- /** Worklist for SSA edges. This is a list of registers to process */
- private ArrayList<SsaInsn> ssaWorklist;
- /**
- * Worklist for SSA edges that represent varying values. It makes the
- * algorithm much faster if you move all values to VARYING as fast as
- * possible.
- */
- private ArrayList<SsaInsn> varyingWorklist;
- /** Worklist of potential branches to convert to gotos */
- private ArrayList<SsaInsn> branchWorklist;
+ /** Lattice values */
+ private static final int TOP = 0;
+ private static final int CONSTANT = 1;
+ private static final int VARYING = 2;
+ /** method we're processing */
+ private SsaMethod ssaMeth;
+ /** ssaMeth.getRegCount() */
+ private int regCount;
+ /** Lattice values for each SSA register */
+ private int[] latticeValues;
+ /** For those registers that are constant, this is the constant value */
+ private Constant[] latticeConstants;
+ /** Worklist of basic blocks to be processed */
+ private ArrayList<SsaBasicBlock> cfgWorklist;
+ /** Worklist of executed basic blocks with phis to be processed */
+ private ArrayList<SsaBasicBlock> cfgPhiWorklist;
+ /** Bitset containing bits for each block that has been found executable */
+ private BitSet executableBlocks;
+ /** Worklist for SSA edges. This is a list of registers to process */
+ private ArrayList<SsaInsn> ssaWorklist;
+ /**
+ * Worklist for SSA edges that represent varying values. It makes the
+ * algorithm much faster if you move all values to VARYING as fast as
+ * possible.
+ */
+ private ArrayList<SsaInsn> varyingWorklist;
+ /** Worklist of potential branches to convert to gotos */
+ private ArrayList<SsaInsn> branchWorklist;
- private SCCP(SsaMethod ssaMeth) {
- this.ssaMeth = ssaMeth;
- this.regCount = ssaMeth.getRegCount();
- this.latticeValues = new int[this.regCount];
- this.latticeConstants = new Constant[this.regCount];
- this.cfgWorklist = new ArrayList<SsaBasicBlock>();
- this.cfgPhiWorklist = new ArrayList<SsaBasicBlock>();
- this.executableBlocks = new BitSet(ssaMeth.getBlocks().size());
- this.ssaWorklist = new ArrayList<SsaInsn>();
- this.varyingWorklist = new ArrayList<SsaInsn>();
- this.branchWorklist = new ArrayList<SsaInsn>();
- for (int i = 0; i < this.regCount; i++) {
- latticeValues[i] = TOP;
- latticeConstants[i] = null;
- }
+ private SCCP(SsaMethod ssaMeth) {
+ this.ssaMeth = ssaMeth;
+ this.regCount = ssaMeth.getRegCount();
+ this.latticeValues = new int[this.regCount];
+ this.latticeConstants = new Constant[this.regCount];
+ this.cfgWorklist = new ArrayList<SsaBasicBlock>();
+ this.cfgPhiWorklist = new ArrayList<SsaBasicBlock>();
+ this.executableBlocks = new BitSet(ssaMeth.getBlocks().size());
+ this.ssaWorklist = new ArrayList<SsaInsn>();
+ this.varyingWorklist = new ArrayList<SsaInsn>();
+ this.branchWorklist = new ArrayList<SsaInsn>();
+ for (int i = 0; i < this.regCount; i++) {
+ latticeValues[i] = TOP;
+ latticeConstants[i] = null;
+ }
+ }
+
+ /**
+ * Performs sparse conditional constant propagation on a method.
+ * @param ssaMethod Method to process
+ */
+ public static void process(SsaMethod ssaMethod) {
+ new SCCP(ssaMethod).run();
+ }
+
+ /**
+ * Adds a SSA basic block to the CFG worklist if it's unexecuted, or
+ * to the CFG phi worklist if it's already executed.
+ * @param ssaBlock Block to add
+ */
+ private void addBlockToWorklist(SsaBasicBlock ssaBlock) {
+ if (!executableBlocks.get(ssaBlock.getIndex())) {
+ cfgWorklist.add(ssaBlock);
+ executableBlocks.set(ssaBlock.getIndex());
+ } else {
+ cfgPhiWorklist.add(ssaBlock);
+ }
+ }
+
+ /**
+ * Adds an SSA register's uses to the SSA worklist.
+ * @param reg SSA register
+ * @param latticeValue new lattice value for @param reg.
+ */
+ private void addUsersToWorklist(int reg, int latticeValue) {
+ if (latticeValue == VARYING) {
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+ varyingWorklist.add(insn);
+ }
+ } else {
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+ ssaWorklist.add(insn);
+ }
+ }
+ }
+
+ /**
+ * Sets a lattice value for a register to value.
+ * @param reg SSA register
+ * @param value Lattice value
+ * @param cst Constant value (may be null)
+ * @return true if the lattice value changed.
+ */
+ private boolean setLatticeValueTo(int reg, int value, Constant cst) {
+ if (value != CONSTANT) {
+ if (latticeValues[reg] != value) {
+ latticeValues[reg] = value;
+ return true;
+ }
+ return false;
+ } else {
+ if (latticeValues[reg] != value || !latticeConstants[reg].equals(cst)) {
+ latticeValues[reg] = value;
+ latticeConstants[reg] = cst;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Simulates a PHI node and set the lattice for the result
+ * to the appropriate value.
+ * Meet values:
+ * TOP x anything = TOP
+ * VARYING x anything = VARYING
+ * CONSTANT x CONSTANT = CONSTANT if equal constants, VARYING otherwise
+ * @param insn PHI to simulate.
+ */
+ private void simulatePhi(PhiInsn insn) {
+ int phiResultReg = insn.getResult().getReg();
+
+ if (latticeValues[phiResultReg] == VARYING) {
+ return;
}
- /**
- * Performs sparse conditional constant propagation on a method.
- * @param ssaMethod Method to process
- */
- public static void process (SsaMethod ssaMethod) {
- new SCCP(ssaMethod).run();
- }
+ RegisterSpecList sources = insn.getSources();
+ int phiResultValue = TOP;
+ Constant phiConstant = null;
+ int sourceSize = sources.size();
- /**
- * Adds a SSA basic block to the CFG worklist if it's unexecuted, or
- * to the CFG phi worklist if it's already executed.
- * @param ssaBlock Block to add
- */
- private void addBlockToWorklist(SsaBasicBlock ssaBlock) {
- if (!executableBlocks.get(ssaBlock.getIndex())) {
- cfgWorklist.add(ssaBlock);
- executableBlocks.set(ssaBlock.getIndex());
- } else {
- cfgPhiWorklist.add(ssaBlock);
+ for (int i = 0; i < sourceSize; i++) {
+ int predBlockIndex = insn.predBlockIndexForSourcesIndex(i);
+ int sourceReg = sources.get(i).getReg();
+ int sourceRegValue = latticeValues[sourceReg];
+
+ if (!executableBlocks.get(predBlockIndex)) {
+ continue;
+ }
+
+ if (sourceRegValue == CONSTANT) {
+ if (phiConstant == null) {
+ phiConstant = latticeConstants[sourceReg];
+ phiResultValue = CONSTANT;
+ } else if (!latticeConstants[sourceReg].equals(phiConstant)) {
+ phiResultValue = VARYING;
+ break;
}
+ } else {
+ phiResultValue = sourceRegValue;
+ break;
+ }
}
-
- /**
- * Adds an SSA register's uses to the SSA worklist.
- * @param reg SSA register
- * @param latticeValue new lattice value for @param reg.
- */
- private void addUsersToWorklist(int reg, int latticeValue) {
- if (latticeValue == VARYING) {
- for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
- varyingWorklist.add(insn);
- }
- } else {
- for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
- ssaWorklist.add(insn);
- }
- }
+ if (setLatticeValueTo(phiResultReg, phiResultValue, phiConstant)) {
+ addUsersToWorklist(phiResultReg, phiResultValue);
}
+ }
- /**
- * Sets a lattice value for a register to value.
- * @param reg SSA register
- * @param value Lattice value
- * @param cst Constant value (may be null)
- * @return true if the lattice value changed.
- */
- private boolean setLatticeValueTo(int reg, int value, Constant cst) {
- if (value != CONSTANT) {
- if (latticeValues[reg] != value) {
- latticeValues[reg] = value;
- return true;
- }
- return false;
- } else {
- if (latticeValues[reg] != value
- || !latticeConstants[reg].equals(cst)) {
- latticeValues[reg] = value;
- latticeConstants[reg] = cst;
- return true;
- }
- return false;
- }
+ /**
+ * Simulate a block and note the results in the lattice.
+ * @param block Block to visit
+ */
+ private void simulateBlock(SsaBasicBlock block) {
+ for (SsaInsn insn : block.getInsns()) {
+ if (insn instanceof PhiInsn) {
+ simulatePhi((PhiInsn) insn);
+ } else {
+ simulateStmt(insn);
+ }
}
+ }
- /**
- * Simulates a PHI node and set the lattice for the result
- * to the appropriate value.
- * Meet values:
- * TOP x anything = TOP
- * VARYING x anything = VARYING
- * CONSTANT x CONSTANT = CONSTANT if equal constants, VARYING otherwise
- * @param insn PHI to simulate.
- */
- private void simulatePhi(PhiInsn insn) {
- int phiResultReg = insn.getResult().getReg();
+ /**
+ * Simulate the phis in a block and note the results in the lattice.
+ * @param block Block to visit
+ */
+ private void simulatePhiBlock(SsaBasicBlock block) {
+ for (SsaInsn insn : block.getInsns()) {
+ if (insn instanceof PhiInsn) {
+ simulatePhi((PhiInsn) insn);
+ } else {
+ return;
+ }
+ }
+ }
- if (latticeValues[phiResultReg] == VARYING) {
- return;
+ /**
+ * Simulates branch insns, if possible. Adds reachable successor blocks
+ * to the CFG worklists.
+ * @param insn branch to simulate
+ */
+ private void simulateBranch(SsaInsn insn) {
+ Rop opcode = insn.getOpcode();
+ RegisterSpecList sources = insn.getSources();
+
+ boolean constantBranch = false;
+ boolean constantSuccessor = false;
+
+ // Check if the insn is a branch with a constant condition
+ if (opcode.getBranchingness() == Rop.BRANCH_IF) {
+ Constant cA = null;
+ Constant cB = null;
+
+ RegisterSpec specA = sources.get(0);
+ int regA = specA.getReg();
+ if (!ssaMeth.isRegALocal(specA) && latticeValues[regA] == CONSTANT) {
+ cA = latticeConstants[regA];
+ }
+
+ if (sources.size() == 2) {
+ RegisterSpec specB = sources.get(1);
+ int regB = specB.getReg();
+ if (!ssaMeth.isRegALocal(specB) && latticeValues[regB] == CONSTANT) {
+ cB = latticeConstants[regB];
}
+ }
- RegisterSpecList sources = insn.getSources();
- int phiResultValue = TOP;
- Constant phiConstant = null;
- int sourceSize = sources.size();
-
- for (int i = 0; i < sourceSize; i++) {
- int predBlockIndex = insn.predBlockIndexForSourcesIndex(i);
- int sourceReg = sources.get(i).getReg();
- int sourceRegValue = latticeValues[sourceReg];
-
- if (!executableBlocks.get(predBlockIndex)) {
- continue;
- }
-
- if (sourceRegValue == CONSTANT) {
- if (phiConstant == null) {
- phiConstant = latticeConstants[sourceReg];
- phiResultValue = CONSTANT;
- } else if (!latticeConstants[sourceReg].equals(phiConstant)){
- phiResultValue = VARYING;
- break;
- }
- } else {
- phiResultValue = sourceRegValue;
+ // Calculate the result of the condition
+ if (cA != null && sources.size() == 1) {
+ switch (((TypedConstant) cA).getBasicType()) {
+ case Type.BT_BOOLEAN: {
+ constantBranch = true;
+ boolean vA = ((CstBoolean) cA).getValue();
+ switch (opcode.getOpcode()) {
+ case RegOps.IF_EQ:
+ constantSuccessor = !vA;
break;
+ case RegOps.IF_NE:
+ constantSuccessor = vA;
+ break;
+ default:
+ throw new RuntimeException("Unexpected op");
}
+ break;
+ }
+ case Type.BT_INT:
+ constantBranch = true;
+ int vA = ((CstInteger) cA).getValue();
+ switch (opcode.getOpcode()) {
+ case RegOps.IF_EQ:
+ constantSuccessor = (vA == 0);
+ break;
+ case RegOps.IF_NE:
+ constantSuccessor = (vA != 0);
+ break;
+ case RegOps.IF_LT:
+ constantSuccessor = (vA < 0);
+ break;
+ case RegOps.IF_GE:
+ constantSuccessor = (vA >= 0);
+ break;
+ case RegOps.IF_LE:
+ constantSuccessor = (vA <= 0);
+ break;
+ case RegOps.IF_GT:
+ constantSuccessor = (vA > 0);
+ break;
+ default:
+ throw new RuntimeException("Unexpected op");
+ }
+ break;
+ default:
+ // not yet supported
}
- if (setLatticeValueTo(phiResultReg, phiResultValue, phiConstant)) {
- addUsersToWorklist(phiResultReg, phiResultValue);
+ } else if (cA != null && cB != null) {
+ switch (((TypedConstant) cA).getBasicType()) {
+ case Type.BT_INT:
+ constantBranch = true;
+ int vA = ((CstInteger) cA).getValue();
+ int vB = ((CstInteger) cB).getValue();
+ switch (opcode.getOpcode()) {
+ case RegOps.IF_EQ:
+ constantSuccessor = (vA == vB);
+ break;
+ case RegOps.IF_NE:
+ constantSuccessor = (vA != vB);
+ break;
+ case RegOps.IF_LT:
+ constantSuccessor = (vA < vB);
+ break;
+ case RegOps.IF_GE:
+ constantSuccessor = (vA >= vB);
+ break;
+ case RegOps.IF_LE:
+ constantSuccessor = (vA <= vB);
+ break;
+ case RegOps.IF_GT:
+ constantSuccessor = (vA > vB);
+ break;
+ default:
+ throw new RuntimeException("Unexpected op");
+ }
+ break;
+ default:
+ // not yet supported
}
+ }
}
- /**
- * Simulate a block and note the results in the lattice.
- * @param block Block to visit
+ /*
+ * If condition is constant, add only the target block to the
+ * worklist. Otherwise, add all successors to the worklist.
*/
- private void simulateBlock(SsaBasicBlock block) {
- for (SsaInsn insn : block.getInsns()) {
- if (insn instanceof PhiInsn) {
- simulatePhi((PhiInsn) insn);
- } else {
- simulateStmt(insn);
- }
- }
+ SsaBasicBlock block = insn.getBlock();
+
+ if (constantBranch) {
+ int successorBlock;
+ if (constantSuccessor) {
+ successorBlock = block.getSuccessorList().get(1);
+ } else {
+ successorBlock = block.getSuccessorList().get(0);
+ }
+ addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
+ branchWorklist.add(insn);
+ } else {
+ for (int i = 0; i < block.getSuccessorList().size(); i++) {
+ int successorBlock = block.getSuccessorList().get(i);
+ addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
+ }
+ }
+ }
+
+ /**
+ * Simulates math insns, if possible.
+ *
+ * @param insn non-null insn to simulate
+ * @param resultType basic type of the result
+ * @return constant result or null if not simulatable.
+ */
+ private Constant simulateMath(SsaInsn insn, int resultType) {
+ Insn ropInsn = insn.getOriginalRopInsn();
+ int opcode = insn.getOpcode().getOpcode();
+ RegisterSpecList sources = insn.getSources();
+ int regA = sources.get(0).getReg();
+ Constant cA;
+ Constant cB;
+
+ if (latticeValues[regA] != CONSTANT) {
+ cA = null;
+ } else {
+ cA = latticeConstants[regA];
}
- /**
- * Simulate the phis in a block and note the results in the lattice.
- * @param block Block to visit
- */
- private void simulatePhiBlock(SsaBasicBlock block) {
- for (SsaInsn insn : block.getInsns()) {
- if (insn instanceof PhiInsn) {
- simulatePhi((PhiInsn) insn);
- } else {
- return;
- }
- }
+ if (sources.size() == 1) {
+ CstInsn cstInsn = (CstInsn) ropInsn;
+ cB = cstInsn.getConstant();
+ } else { /* sources.size() == 2 */
+ int regB = sources.get(1).getReg();
+ if (latticeValues[regB] != CONSTANT) {
+ cB = null;
+ } else {
+ cB = latticeConstants[regB];
+ }
}
- private static String latticeValName(int latticeVal) {
- switch (latticeVal) {
- case TOP: return "TOP";
- case CONSTANT: return "CONSTANT";
- case VARYING: return "VARYING";
- default: return "UNKNOWN";
- }
+ if (cA == null || cB == null) {
+ //TODO(dx team) handle a constant of 0 with MUL or AND
+ return null;
}
- /**
- * Simulates branch insns, if possible. Adds reachable successor blocks
- * to the CFG worklists.
- * @param insn branch to simulate
- */
- private void simulateBranch(SsaInsn insn) {
- Rop opcode = insn.getOpcode();
- RegisterSpecList sources = insn.getSources();
+ switch (resultType) {
+ case Type.BT_INT:
+ int vR;
+ boolean skip = false;
- boolean constantBranch = false;
- boolean constantSuccessor = false;
-
- // Check if the insn is a branch with a constant condition
- if (opcode.getBranchingness() == Rop.BRANCH_IF) {
- Constant cA = null;
- Constant cB = null;
-
- RegisterSpec specA = sources.get(0);
- int regA = specA.getReg();
- if (!ssaMeth.isRegALocal(specA) &&
- latticeValues[regA] == CONSTANT) {
- cA = latticeConstants[regA];
- }
-
- if (sources.size() == 2) {
- RegisterSpec specB = sources.get(1);
- int regB = specB.getReg();
- if (!ssaMeth.isRegALocal(specB) &&
- latticeValues[regB] == CONSTANT) {
- cB = latticeConstants[regB];
- }
- }
-
- // Calculate the result of the condition
- if (cA != null && sources.size() == 1) {
- switch (((TypedConstant) cA).getBasicType()) {
- case Type.BT_BOOLEAN: {
- constantBranch = true;
- boolean vA = ((CstBoolean) cA).getValue();
- switch (opcode.getOpcode()) {
- case RegOps.IF_EQ:
- constantSuccessor = !vA;
- break;
- case RegOps.IF_NE:
- constantSuccessor = vA;
- break;
- default:
- throw new RuntimeException("Unexpected op");
- }
- break;
- }
- case Type.BT_INT:
- constantBranch = true;
- int vA = ((CstInteger) cA).getValue();
- switch (opcode.getOpcode()) {
- case RegOps.IF_EQ:
- constantSuccessor = (vA == 0);
- break;
- case RegOps.IF_NE:
- constantSuccessor = (vA != 0);
- break;
- case RegOps.IF_LT:
- constantSuccessor = (vA < 0);
- break;
- case RegOps.IF_GE:
- constantSuccessor = (vA >= 0);
- break;
- case RegOps.IF_LE:
- constantSuccessor = (vA <= 0);
- break;
- case RegOps.IF_GT:
- constantSuccessor = (vA > 0);
- break;
- default:
- throw new RuntimeException("Unexpected op");
- }
- break;
- default:
- // not yet supported
- }
- } else if (cA != null && cB != null) {
- switch (((TypedConstant) cA).getBasicType()) {
- case Type.BT_INT:
- constantBranch = true;
- int vA = ((CstInteger) cA).getValue();
- int vB = ((CstInteger) cB).getValue();
- switch (opcode.getOpcode()) {
- case RegOps.IF_EQ:
- constantSuccessor = (vA == vB);
- break;
- case RegOps.IF_NE:
- constantSuccessor = (vA != vB);
- break;
- case RegOps.IF_LT:
- constantSuccessor = (vA < vB);
- break;
- case RegOps.IF_GE:
- constantSuccessor = (vA >= vB);
- break;
- case RegOps.IF_LE:
- constantSuccessor = (vA <= vB);
- break;
- case RegOps.IF_GT:
- constantSuccessor = (vA > vB);
- break;
- default:
- throw new RuntimeException("Unexpected op");
- }
- break;
- default:
- // not yet supported
- }
- }
- }
-
- /*
- * If condition is constant, add only the target block to the
- * worklist. Otherwise, add all successors to the worklist.
- */
- SsaBasicBlock block = insn.getBlock();
-
- if (constantBranch) {
- int successorBlock;
- if (constantSuccessor) {
- successorBlock = block.getSuccessorList().get(1);
- } else {
- successorBlock = block.getSuccessorList().get(0);
- }
- addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
- branchWorklist.add(insn);
- } else {
- for (int i = 0; i < block.getSuccessorList().size(); i++) {
- int successorBlock = block.getSuccessorList().get(i);
- addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
- }
- }
- }
-
- /**
- * Simulates math insns, if possible.
- *
- * @param insn non-null insn to simulate
- * @param resultType basic type of the result
- * @return constant result or null if not simulatable.
- */
- private Constant simulateMath(SsaInsn insn, int resultType) {
- Insn ropInsn = insn.getOriginalRopInsn();
- int opcode = insn.getOpcode().getOpcode();
- RegisterSpecList sources = insn.getSources();
- int regA = sources.get(0).getReg();
- Constant cA;
- Constant cB;
-
- if (latticeValues[regA] != CONSTANT) {
- cA = null;
- } else {
- cA = latticeConstants[regA];
- }
-
- if (sources.size() == 1) {
- CstInsn cstInsn = (CstInsn) ropInsn;
- cB = cstInsn.getConstant();
- } else { /* sources.size() == 2 */
- int regB = sources.get(1).getReg();
- if (latticeValues[regB] != CONSTANT) {
- cB = null;
- } else {
- cB = latticeConstants[regB];
- }
- }
-
- if (cA == null || cB == null) {
- //TODO handle a constant of 0 with MUL or AND
- return null;
- }
-
- switch (resultType) {
- case Type.BT_INT:
- int vR;
- boolean skip=false;
-
- int vA = ((CstInteger) cA).getValue();
- int vB = ((CstInteger) cB).getValue();
-
- switch (opcode) {
- case RegOps.ADD:
- vR = vA + vB;
- break;
- case RegOps.SUB:
- // 1 source for reverse sub, 2 sources for regular sub
- if (sources.size() == 1) {
- vR = vB - vA;
- } else {
- vR = vA - vB;
- }
- break;
- case RegOps.MUL:
- vR = vA * vB;
- break;
- case RegOps.DIV:
- if (vB == 0) {
- skip = true;
- vR = 0; // just to hide a warning
- } else {
- vR = vA / vB;
- }
- break;
- case RegOps.AND:
- vR = vA & vB;
- break;
- case RegOps.OR:
- vR = vA | vB;
- break;
- case RegOps.XOR:
- vR = vA ^ vB;
- break;
- case RegOps.SHL:
- vR = vA << vB;
- break;
- case RegOps.SHR:
- vR = vA >> vB;
- break;
- case RegOps.USHR:
- vR = vA >>> vB;
- break;
- case RegOps.REM:
- if (vB == 0) {
- skip = true;
- vR = 0; // just to hide a warning
- } else {
- vR = vA % vB;
- }
- break;
- default:
- throw new RuntimeException("Unexpected op");
- }
-
- return skip ? null : CstInteger.make(vR);
-
- default:
- // not yet supported
- return null;
- }
- }
-
- /**
- * Simulates a statement and set the result lattice value.
- * @param insn instruction to simulate
- */
- private void simulateStmt(SsaInsn insn) {
- Insn ropInsn = insn.getOriginalRopInsn();
- if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE
- || ropInsn.getOpcode().isCallLike()) {
- simulateBranch(insn);
- }
-
- int opcode = insn.getOpcode().getOpcode();
- RegisterSpec result = insn.getResult();
-
- if (result == null) {
- // Find move-result-pseudo result for int div and int rem
- if (opcode == RegOps.DIV || opcode == RegOps.REM) {
- SsaBasicBlock succ = insn.getBlock().getPrimarySuccessor();
- result = succ.getInsns().get(0).getResult();
- } else {
- return;
- }
- }
-
- int resultReg = result.getReg();
- int resultValue = VARYING;
- Constant resultConstant = null;
+ int vA = ((CstInteger) cA).getValue();
+ int vB = ((CstInteger) cB).getValue();
switch (opcode) {
- case RegOps.CONST: {
- CstInsn cstInsn = (CstInsn)ropInsn;
- resultValue = CONSTANT;
- resultConstant = cstInsn.getConstant();
- break;
+ case RegOps.ADD:
+ vR = vA + vB;
+ break;
+ case RegOps.SUB:
+ // 1 source for reverse sub, 2 sources for regular sub
+ if (sources.size() == 1) {
+ vR = vB - vA;
+ } else {
+ vR = vA - vB;
}
- case RegOps.MOVE: {
- if (insn.getSources().size() == 1) {
- int sourceReg = insn.getSources().get(0).getReg();
- resultValue = latticeValues[sourceReg];
- resultConstant = latticeConstants[sourceReg];
- }
- break;
+ break;
+ case RegOps.MUL:
+ vR = vA * vB;
+ break;
+ case RegOps.DIV:
+ if (vB == 0) {
+ skip = true;
+ vR = 0; // just to hide a warning
+ } else {
+ vR = vA / vB;
}
- case RegOps.ADD:
- case RegOps.SUB:
- case RegOps.MUL:
- case RegOps.DIV:
- case RegOps.AND:
- case RegOps.OR:
- case RegOps.XOR:
- case RegOps.SHL:
- case RegOps.SHR:
- case RegOps.USHR:
- case RegOps.REM: {
- resultConstant = simulateMath(insn, result.getBasicType());
- if (resultConstant != null) {
- resultValue = CONSTANT;
- }
- break;
+ break;
+ case RegOps.AND:
+ vR = vA & vB;
+ break;
+ case RegOps.OR:
+ vR = vA | vB;
+ break;
+ case RegOps.XOR:
+ vR = vA ^ vB;
+ break;
+ case RegOps.SHL:
+ vR = vA << vB;
+ break;
+ case RegOps.SHR:
+ vR = vA >> vB;
+ break;
+ case RegOps.USHR:
+ vR = vA >>> vB;
+ break;
+ case RegOps.REM:
+ if (vB == 0) {
+ skip = true;
+ vR = 0; // just to hide a warning
+ } else {
+ vR = vA % vB;
}
- case RegOps.MOVE_RESULT_PSEUDO: {
- if (latticeValues[resultReg] == CONSTANT) {
- resultValue = latticeValues[resultReg];
- resultConstant = latticeConstants[resultReg];
- }
- break;
- }
- // TODO: Handle non-int arithmetic.
- // TODO: Eliminate check casts that we can prove the type of.
- default: {}
+ break;
+ default:
+ throw new RuntimeException("Unexpected op");
}
- if (setLatticeValueTo(resultReg, resultValue, resultConstant)) {
- addUsersToWorklist(resultReg, resultValue);
- }
+
+ return skip ? null : CstInteger.make(vR);
+
+ default:
+ // not yet supported
+ return null;
+ }
+ }
+
+ /**
+ * Simulates a statement and set the result lattice value.
+ * @param insn instruction to simulate
+ */
+ private void simulateStmt(SsaInsn insn) {
+ Insn ropInsn = insn.getOriginalRopInsn();
+ if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE
+ || ropInsn.getOpcode().isCallLike()) {
+ simulateBranch(insn);
}
- private void run() {
- SsaBasicBlock firstBlock = ssaMeth.getEntryBlock();
- addBlockToWorklist(firstBlock);
+ int opcode = insn.getOpcode().getOpcode();
+ RegisterSpec result = insn.getResult();
- /* Empty all the worklists by propagating our values */
- while (!cfgWorklist.isEmpty()
- || !cfgPhiWorklist.isEmpty()
- || !ssaWorklist.isEmpty()
- || !varyingWorklist.isEmpty()) {
- while (!cfgWorklist.isEmpty()) {
- int listSize = cfgWorklist.size() - 1;
- SsaBasicBlock block = cfgWorklist.remove(listSize);
- simulateBlock(block);
- }
-
- while (!cfgPhiWorklist.isEmpty()) {
- int listSize = cfgPhiWorklist.size() - 1;
- SsaBasicBlock block = cfgPhiWorklist.remove(listSize);
- simulatePhiBlock(block);
- }
-
- while (!varyingWorklist.isEmpty()) {
- int listSize = varyingWorklist.size() - 1;
- SsaInsn insn = varyingWorklist.remove(listSize);
-
- if (!executableBlocks.get(insn.getBlock().getIndex())) {
- continue;
- }
-
- if (insn instanceof PhiInsn) {
- simulatePhi((PhiInsn)insn);
- } else {
- simulateStmt(insn);
- }
- }
- while (!ssaWorklist.isEmpty()) {
- int listSize = ssaWorklist.size() - 1;
- SsaInsn insn = ssaWorklist.remove(listSize);
-
- if (!executableBlocks.get(insn.getBlock().getIndex())) {
- continue;
- }
-
- if (insn instanceof PhiInsn) {
- simulatePhi((PhiInsn)insn);
- } else {
- simulateStmt(insn);
- }
- }
- }
-
- replaceConstants();
- replaceBranches();
+ if (result == null) {
+ // Find move-result-pseudo result for int div and int rem
+ if (opcode == RegOps.DIV || opcode == RegOps.REM) {
+ SsaBasicBlock succ = insn.getBlock().getPrimarySuccessor();
+ result = succ.getInsns().get(0).getResult();
+ } else {
+ return;
+ }
}
- /**
- * Replaces TypeBearers in source register specs with constant type
- * bearers if possible. These are then referenced in later optimization
- * steps.
- */
- private void replaceConstants() {
- for (int reg = 0; reg < regCount; reg++) {
- if (latticeValues[reg] != CONSTANT) {
- continue;
- }
- if (!(latticeConstants[reg] instanceof TypedConstant)) {
- // We can't do much with these
- continue;
- }
+ int resultReg = result.getReg();
+ int resultValue = VARYING;
+ Constant resultConstant = null;
- SsaInsn defn = ssaMeth.getDefinitionForRegister(reg);
- TypeBearer typeBearer = defn.getResult().getTypeBearer();
-
- if (typeBearer.isConstant()) {
- /*
- * The definition was a constant already.
- * The uses should be as well.
- */
- continue;
- }
-
- // Update the destination RegisterSpec with the constant value
- RegisterSpec dest = defn.getResult();
- RegisterSpec newDest
- = dest.withType((TypedConstant)latticeConstants[reg]);
- defn.setResult(newDest);
-
- /*
- * Update the sources RegisterSpec's of all non-move uses.
- * These will be used in later steps.
- */
- for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
- if (insn.isPhiOrMove()) {
- continue;
- }
-
- NormalSsaInsn nInsn = (NormalSsaInsn) insn;
- RegisterSpecList sources = insn.getSources();
-
- int index = sources.indexOfRegister(reg);
-
- RegisterSpec spec = sources.get(index);
- RegisterSpec newSpec
- = spec.withType((TypedConstant)latticeConstants[reg]);
-
- nInsn.changeOneSource(index, newSpec);
- }
+ switch (opcode) {
+ case RegOps.CONST: {
+ CstInsn cstInsn = (CstInsn) ropInsn;
+ resultValue = CONSTANT;
+ resultConstant = cstInsn.getConstant();
+ break;
+ }
+ case RegOps.MOVE: {
+ if (insn.getSources().size() == 1) {
+ int sourceReg = insn.getSources().get(0).getReg();
+ resultValue = latticeValues[sourceReg];
+ resultConstant = latticeConstants[sourceReg];
}
+ break;
+ }
+ case RegOps.ADD:
+ case RegOps.SUB:
+ case RegOps.MUL:
+ case RegOps.DIV:
+ case RegOps.AND:
+ case RegOps.OR:
+ case RegOps.XOR:
+ case RegOps.SHL:
+ case RegOps.SHR:
+ case RegOps.USHR:
+ case RegOps.REM: {
+ resultConstant = simulateMath(insn, result.getBasicType());
+ if (resultConstant != null) {
+ resultValue = CONSTANT;
+ }
+ break;
+ }
+ case RegOps.MOVE_RESULT_PSEUDO: {
+ if (latticeValues[resultReg] == CONSTANT) {
+ resultValue = latticeValues[resultReg];
+ resultConstant = latticeConstants[resultReg];
+ }
+ break;
+ }
+ // TODO(dx team): Handle non-int arithmetic.
+ // TODO(dx team): Eliminate check casts that we can prove the type of.
+ default: {
+ }
+ }
+ if (setLatticeValueTo(resultReg, resultValue, resultConstant)) {
+ addUsersToWorklist(resultReg, resultValue);
+ }
+ }
+
+ private void run() {
+ SsaBasicBlock firstBlock = ssaMeth.getEntryBlock();
+ addBlockToWorklist(firstBlock);
+
+ /* Empty all the worklists by propagating our values */
+ while (!cfgWorklist.isEmpty() || !cfgPhiWorklist.isEmpty() || !ssaWorklist.isEmpty()
+ || !varyingWorklist.isEmpty()) {
+ while (!cfgWorklist.isEmpty()) {
+ int listSize = cfgWorklist.size() - 1;
+ SsaBasicBlock block = cfgWorklist.remove(listSize);
+ simulateBlock(block);
+ }
+
+ while (!cfgPhiWorklist.isEmpty()) {
+ int listSize = cfgPhiWorklist.size() - 1;
+ SsaBasicBlock block = cfgPhiWorklist.remove(listSize);
+ simulatePhiBlock(block);
+ }
+
+ while (!varyingWorklist.isEmpty()) {
+ int listSize = varyingWorklist.size() - 1;
+ SsaInsn insn = varyingWorklist.remove(listSize);
+
+ if (!executableBlocks.get(insn.getBlock().getIndex())) {
+ continue;
+ }
+
+ if (insn instanceof PhiInsn) {
+ simulatePhi((PhiInsn) insn);
+ } else {
+ simulateStmt(insn);
+ }
+ }
+ while (!ssaWorklist.isEmpty()) {
+ int listSize = ssaWorklist.size() - 1;
+ SsaInsn insn = ssaWorklist.remove(listSize);
+
+ if (!executableBlocks.get(insn.getBlock().getIndex())) {
+ continue;
+ }
+
+ if (insn instanceof PhiInsn) {
+ simulatePhi((PhiInsn) insn);
+ } else {
+ simulateStmt(insn);
+ }
+ }
}
- /**
- * Replaces branches that have constant conditions with gotos
- */
- private void replaceBranches() {
- for (SsaInsn insn : branchWorklist) {
- // Find if a successor block is never executed
- int oldSuccessor = -1;
- SsaBasicBlock block = insn.getBlock();
- int successorSize = block.getSuccessorList().size();
- for (int i = 0; i < successorSize; i++) {
- int successorBlock = block.getSuccessorList().get(i);
- if (!executableBlocks.get(successorBlock)) {
- oldSuccessor = successorBlock;
- }
- }
+ replaceConstants();
+ replaceBranches();
+ }
- /*
- * Prune branches that have already been handled and ones that no
- * longer have constant conditions (no nonexecutable successors)
- */
- if (successorSize != 2 || oldSuccessor == -1) continue;
+ /**
+ * Replaces TypeBearers in source register specs with constant type
+ * bearers if possible. These are then referenced in later optimization
+ * steps.
+ */
+ private void replaceConstants() {
+ for (int reg = 0; reg < regCount; reg++) {
+ if (latticeValues[reg] != CONSTANT) {
+ continue;
+ }
+ if (!(latticeConstants[reg] instanceof TypedConstant)) {
+ // We can't do much with these
+ continue;
+ }
- // Replace branch with goto
- Insn originalRopInsn = insn.getOriginalRopInsn();
- block.replaceLastInsn(new PlainInsn(Rops.GOTO,
- originalRopInsn.getPosition(), null, RegisterSpecList.EMPTY));
- block.removeSuccessor(oldSuccessor);
+ SsaInsn defn = ssaMeth.getDefinitionForRegister(reg);
+ TypeBearer typeBearer = defn.getResult().getTypeBearer();
+
+ if (typeBearer.isConstant()) {
+ /*
+ * The definition was a constant already.
+ * The uses should be as well.
+ */
+ continue;
+ }
+
+ // Update the destination RegisterSpec with the constant value
+ RegisterSpec dest = defn.getResult();
+ RegisterSpec newDest = dest.withType((TypedConstant) latticeConstants[reg]);
+ defn.setResult(newDest);
+
+ /*
+ * Update the sources RegisterSpec's of all non-move uses.
+ * These will be used in later steps.
+ */
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+ if (insn.isPhiOrMove()) {
+ continue;
}
+
+ NormalSsaInsn nInsn = (NormalSsaInsn) insn;
+ RegisterSpecList sources = insn.getSources();
+
+ int index = sources.indexOfRegister(reg);
+
+ RegisterSpec spec = sources.get(index);
+ RegisterSpec newSpec = spec.withType((TypedConstant) latticeConstants[reg]);
+
+ nInsn.changeOneSource(index, newSpec);
+ }
}
+ }
+
+ /**
+ * Replaces branches that have constant conditions with gotos
+ */
+ private void replaceBranches() {
+ for (SsaInsn insn : branchWorklist) {
+ // Find if a successor block is never executed
+ int oldSuccessor = -1;
+ SsaBasicBlock block = insn.getBlock();
+ int successorSize = block.getSuccessorList().size();
+ for (int i = 0; i < successorSize; i++) {
+ int successorBlock = block.getSuccessorList().get(i);
+ if (!executableBlocks.get(successorBlock)) {
+ oldSuccessor = successorBlock;
+ }
+ }
+
+ /*
+ * Prune branches that have already been handled and ones that no
+ * longer have constant conditions (no nonexecutable successors)
+ */
+ if (successorSize != 2 || oldSuccessor == -1) {
+ continue;
+ }
+
+ // Replace branch with goto
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ block.replaceLastInsn(
+ new PlainInsn(Rops.GOTO, originalRopInsn.getPosition(), null, RegisterSpecList.EMPTY));
+ block.removeSuccessor(oldSuccessor);
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SetFactory.java b/dx/src/com/android/jack/dx/ssa/SetFactory.java
index 9c24b8b..0d92d20 100644
--- a/dx/src/com/android/jack/dx/ssa/SetFactory.java
+++ b/dx/src/com/android/jack/dx/ssa/SetFactory.java
@@ -26,70 +26,65 @@
*/
public final class SetFactory {
- /**
- * BitIntSet/ListIntSet threshold for dominance frontier sets. These
- * sets are kept per basic block until phi placement and tend to be,
- * like the CFG itself, very sparse at large sizes.
- *
- * A value of 3072 here is somewhere around 1.125mb of total bitset size.
- */
- private static final int DOMFRONT_SET_THRESHOLD_SIZE = 3072;
+ /**
+ * BitIntSet/ListIntSet threshold for dominance frontier sets. These
+ * sets are kept per basic block until phi placement and tend to be,
+ * like the CFG itself, very sparse at large sizes.
+ *
+ * A value of 3072 here is somewhere around 1.125mb of total bitset size.
+ */
+ private static final int DOMFRONT_SET_THRESHOLD_SIZE = 3072;
- /**
- * BitIntSet/ListIntSet threshold for interference graph sets. These
- * sets are kept per register until register allocation is done.
- *
- * A value of 3072 here is somewhere around 1.125mb of total bitset size.
- */
- private static final int INTERFERENCE_SET_THRESHOLD_SIZE = 3072;
+ /**
+ * BitIntSet/ListIntSet threshold for interference graph sets. These
+ * sets are kept per register until register allocation is done.
+ *
+ * A value of 3072 here is somewhere around 1.125mb of total bitset size.
+ */
+ private static final int INTERFERENCE_SET_THRESHOLD_SIZE = 3072;
- /**
- * BitIntSet/ListIntSet threshold for the live in/out sets kept by
- * {@link SsaBasicBlock}. These are sets of SSA registers kept per basic
- * block during register allocation.
- *
- * The total size of a bitset for this would be the count of blocks
- * times the size of registers. The threshold value here is merely
- * the register count, which is typically on the order of the block
- * count as well.
- */
- private static final int LIVENESS_SET_THRESHOLD_SIZE = 3072;
+ /**
+ * BitIntSet/ListIntSet threshold for the live in/out sets kept by
+ * {@link SsaBasicBlock}. These are sets of SSA registers kept per basic
+ * block during register allocation.
+ *
+ * The total size of a bitset for this would be the count of blocks
+ * times the size of registers. The threshold value here is merely
+ * the register count, which is typically on the order of the block
+ * count as well.
+ */
+ private static final int LIVENESS_SET_THRESHOLD_SIZE = 3072;
- /**
- * Make IntSet for the dominance-frontier sets.
- *
- * @param szBlocks {@code >=0;} count of basic blocks in method
- * @return {@code non-null;} appropriate set
- */
- /*package*/ static IntSet makeDomFrontSet(int szBlocks) {
- return szBlocks <= DOMFRONT_SET_THRESHOLD_SIZE
- ? new BitIntSet(szBlocks)
- : new ListIntSet();
- }
+ /**
+ * Make IntSet for the dominance-frontier sets.
+ *
+ * @param szBlocks {@code >=0;} count of basic blocks in method
+ * @return {@code non-null;} appropriate set
+ */
+ /*package*/static IntSet makeDomFrontSet(int szBlocks) {
+ return szBlocks <= DOMFRONT_SET_THRESHOLD_SIZE ? new BitIntSet(szBlocks) : new ListIntSet();
+ }
- /**
- * Make IntSet for the interference graph sets. Public because
- * InterferenceGraph is in another package.
- *
- * @param countRegs {@code >=0;} count of SSA registers used in method
- * @return {@code non-null;} appropriate set
- */
- public static IntSet makeInterferenceSet(int countRegs) {
- return countRegs <= INTERFERENCE_SET_THRESHOLD_SIZE
- ? new BitIntSet(countRegs)
- : new ListIntSet();
- }
+ /**
+ * Make IntSet for the interference graph sets. Public because
+ * InterferenceGraph is in another package.
+ *
+ * @param countRegs {@code >=0;} count of SSA registers used in method
+ * @return {@code non-null;} appropriate set
+ */
+ public static IntSet makeInterferenceSet(int countRegs) {
+ return countRegs <= INTERFERENCE_SET_THRESHOLD_SIZE ? new BitIntSet(countRegs)
+ : new ListIntSet();
+ }
- /**
- * Make IntSet for register live in/out sets.
- *
- * @param countRegs {@code >=0;} count of SSA registers used in method
- * @return {@code non-null;} appropriate set
- */
- /*package*/ static IntSet makeLivenessSet(int countRegs) {
- return countRegs <= LIVENESS_SET_THRESHOLD_SIZE
- ? new BitIntSet(countRegs)
- : new ListIntSet();
- }
+ /**
+ * Make IntSet for register live in/out sets.
+ *
+ * @param countRegs {@code >=0;} count of SSA registers used in method
+ * @return {@code non-null;} appropriate set
+ */
+ /*package*/static IntSet makeLivenessSet(int countRegs) {
+ return countRegs <= LIVENESS_SET_THRESHOLD_SIZE ? new BitIntSet(countRegs) : new ListIntSet();
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SsaBasicBlock.java b/dx/src/com/android/jack/dx/ssa/SsaBasicBlock.java
index 4217184..2d16474 100644
--- a/dx/src/com/android/jack/dx/ssa/SsaBasicBlock.java
+++ b/dx/src/com/android/jack/dx/ssa/SsaBasicBlock.java
@@ -41,992 +41,962 @@
* An SSA representation of a basic block.
*/
public final class SsaBasicBlock {
- /**
- * {@code non-null;} comparator for instances of this class that
- * just compares block labels
- */
- public static final Comparator<SsaBasicBlock> LABEL_COMPARATOR =
- new LabelComparator();
- /** {@code non-null;} insn list associated with this instance */
- private ArrayList<SsaInsn> insns;
+ public static boolean enablePhisBeforeMoveException = false;
- /** {@code non-null;} predecessor set (by block list index) */
- private BitSet predecessors;
+ /**
+ * {@code non-null;} comparator for instances of this class that
+ * just compares block labels
+ */
+ public static final Comparator<SsaBasicBlock> LABEL_COMPARATOR = new LabelComparator();
- /** {@code non-null;} successor set (by block list index) */
- private BitSet successors;
+ /** {@code non-null;} insn list associated with this instance */
+ private ArrayList<SsaInsn> insns;
- /**
- * {@code non-null;} ordered successor list
- * (same block may be listed more than once)
- */
- private IntList successorList;
+ /** {@code non-null;} predecessor set (by block list index) */
+ private BitSet predecessors;
- /**
- * block list index of primary successor, or {@code -1} for no primary
- * successor
- */
- private int primarySuccessor = -1;
+ /** {@code non-null;} successor set (by block list index) */
+ private BitSet successors;
- /** label of block in rop form */
- private int ropLabel;
+ /**
+ * {@code non-null;} ordered successor list
+ * (same block may be listed more than once)
+ */
+ private IntList successorList;
- /** {@code non-null;} method we belong to */
- private SsaMethod parent;
+ /**
+ * block list index of primary successor, or {@code -1} for no primary
+ * successor
+ */
+ private int primarySuccessor = -1;
- /** our index into parent.getBlock() */
- private int index;
+ /** label of block in rop form */
+ private int ropLabel;
- /** list of dom children */
- private final ArrayList<SsaBasicBlock> domChildren;
+ /** {@code non-null;} method we belong to */
+ private SsaMethod parent;
- /**
- * the number of moves added to the end of the block during the
- * phi-removal process. Retained for subsequent move scheduling.
- */
- private int movesFromPhisAtEnd = 0;
+ /** our index into parent.getBlock() */
+ private int index;
- /**
- * the number of moves added to the beginning of the block during the
- * phi-removal process. Retained for subsequent move scheduling.
- */
- private int movesFromPhisAtBeginning = 0;
+ /** list of dom children */
+ private final ArrayList<SsaBasicBlock> domChildren;
- /**
- * contains last computed value of reachability of this block, or -1
- * if reachability hasn't been calculated yet
- */
- private int reachable = -1;
+ /**
+ * the number of moves added to the end of the block during the
+ * phi-removal process. Retained for subsequent move scheduling.
+ */
+ private int movesFromPhisAtEnd = 0;
- /**
- * {@code null-ok;} indexed by reg: the regs that are live-in at
- * this block
- */
- private IntSet liveIn;
+ /**
+ * the number of moves added to the beginning of the block during the
+ * phi-removal process. Retained for subsequent move scheduling.
+ */
+ private int movesFromPhisAtBeginning = 0;
- /**
- * {@code null-ok;} indexed by reg: the regs that are live-out at
- * this block
- */
- private IntSet liveOut;
+ /**
+ * contains last computed value of reachability of this block, or -1
+ * if reachability hasn't been calculated yet
+ */
+ private int reachable = -1;
- /**
- * Creates a new empty basic block.
- *
- * @param basicBlockIndex index this block will have
- * @param ropLabel original rop-form label
- * @param parent method of this block
- */
- public SsaBasicBlock(final int basicBlockIndex, final int ropLabel,
- final SsaMethod parent) {
- this.parent = parent;
- this.index = basicBlockIndex;
- this.insns = new ArrayList<SsaInsn>();
- this.ropLabel = ropLabel;
+ /**
+ * {@code null-ok;} indexed by reg: the regs that are live-in at
+ * this block
+ */
+ private IntSet liveIn;
- this.predecessors = new BitSet(parent.getBlocks().size());
- this.successors = new BitSet(parent.getBlocks().size());
- this.successorList = new IntList();
+ /**
+ * {@code null-ok;} indexed by reg: the regs that are live-out at
+ * this block
+ */
+ private IntSet liveOut;
- domChildren = new ArrayList<SsaBasicBlock>();
+ /**
+ * Creates a new empty basic block.
+ *
+ * @param basicBlockIndex index this block will have
+ * @param ropLabel original rop-form label
+ * @param parent method of this block
+ */
+ public SsaBasicBlock(final int basicBlockIndex, final int ropLabel, final SsaMethod parent) {
+ this.parent = parent;
+ this.index = basicBlockIndex;
+ this.insns = new ArrayList<SsaInsn>();
+ this.ropLabel = ropLabel;
+
+ this.predecessors = new BitSet(parent.getBlocks().size());
+ this.successors = new BitSet(parent.getBlocks().size());
+ this.successorList = new IntList();
+
+ domChildren = new ArrayList<SsaBasicBlock>();
+ }
+
+ /**
+ * Creates a new SSA basic block from a ROP form basic block.
+ *
+ * @param rmeth original method
+ * @param basicBlockIndex index this block will have
+ * @param parent method of this block predecessor set will be
+ * updated
+ * @return new instance
+ */
+ public static SsaBasicBlock newFromRop(RopMethod rmeth, int basicBlockIndex,
+ final SsaMethod parent) {
+ BasicBlockList ropBlocks = rmeth.getBlocks();
+ BasicBlock bb = ropBlocks.get(basicBlockIndex);
+ SsaBasicBlock result = new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
+ InsnList ropInsns = bb.getInsns();
+
+ result.insns.ensureCapacity(ropInsns.size());
+
+ for (int i = 0, sz = ropInsns.size(); i < sz; i++) {
+ result.insns.add(new NormalSsaInsn(ropInsns.get(i), result));
}
- /**
- * Creates a new SSA basic block from a ROP form basic block.
- *
- * @param rmeth original method
- * @param basicBlockIndex index this block will have
- * @param parent method of this block predecessor set will be
- * updated
- * @return new instance
- */
- public static SsaBasicBlock newFromRop(RopMethod rmeth,
- int basicBlockIndex, final SsaMethod parent) {
- BasicBlockList ropBlocks = rmeth.getBlocks();
- BasicBlock bb = ropBlocks.get(basicBlockIndex);
- SsaBasicBlock result =
- new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
- InsnList ropInsns = bb.getInsns();
+ result.predecessors =
+ SsaMethod.bitSetFromLabelList(ropBlocks, rmeth.labelToPredecessors(bb.getLabel()));
- result.insns.ensureCapacity(ropInsns.size());
+ result.successors = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors());
- for (int i = 0, sz = ropInsns.size() ; i < sz ; i++) {
- result.insns.add(new NormalSsaInsn (ropInsns.get(i), result));
- }
+ result.successorList = SsaMethod.indexListFromLabelList(ropBlocks, bb.getSuccessors());
- result.predecessors = SsaMethod.bitSetFromLabelList(
- ropBlocks,
- rmeth.labelToPredecessors(bb.getLabel()));
+ if (result.successorList.size() != 0) {
+ int primarySuccessor = bb.getPrimarySuccessor();
- result.successors
- = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors());
-
- result.successorList
- = SsaMethod.indexListFromLabelList(ropBlocks,
- bb.getSuccessors());
-
- if (result.successorList.size() != 0) {
- int primarySuccessor = bb.getPrimarySuccessor();
-
- result.primarySuccessor = (primarySuccessor < 0)
- ? -1 : ropBlocks.indexOfLabel(primarySuccessor);
- }
-
- return result;
+ result.primarySuccessor =
+ (primarySuccessor < 0) ? -1 : ropBlocks.indexOfLabel(primarySuccessor);
}
- /**
- * Adds a basic block as a dom child for this block. Used when constructing
- * the dom tree.
- *
- * @param child {@code non-null;} new dom child
- */
- public void addDomChild(SsaBasicBlock child) {
- domChildren.add(child);
+ return result;
+ }
+
+ /**
+ * Adds a basic block as a dom child for this block. Used when constructing
+ * the dom tree.
+ *
+ * @param child {@code non-null;} new dom child
+ */
+ public void addDomChild(SsaBasicBlock child) {
+ domChildren.add(child);
+ }
+
+ /**
+ * Gets the dom children for this node. Don't modify this list.
+ *
+ * @return {@code non-null;} list of dom children
+ */
+ public ArrayList<SsaBasicBlock> getDomChildren() {
+ return domChildren;
+ }
+
+ /**
+ * Adds a phi insn to the beginning of this block. The result type of
+ * the phi will be set to void, to indicate that it's currently unknown.
+ *
+ * @param reg {@code >=0;} result reg
+ */
+ public void addPhiInsnForReg(int reg) {
+ insns.add(0, new PhiInsn(reg, this));
+ }
+
+ /**
+ * Adds a phi insn to the beginning of this block. This is to be used
+ * when the result type or local-association can be determined at phi
+ * insert time.
+ *
+ * @param resultSpec {@code non-null;} reg
+ */
+ public void addPhiInsnForReg(RegisterSpec resultSpec) {
+ insns.add(0, new PhiInsn(resultSpec, this));
+ }
+
+ /**
+ * Adds an insn to the head of this basic block, just after any phi
+ * insns.
+ *
+ * @param insn {@code non-null;} rop-form insn to add
+ */
+ public void addInsnToHead(Insn insn) {
+ SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
+ insns.add(getCountPhiInsns(), newInsn);
+ parent.onInsnAdded(newInsn);
+ }
+
+ /**
+ * Replaces the last insn in this block. The provided insn must have
+ * some branchingness.
+ *
+ * @param insn {@code non-null;} rop-form insn to add, which must branch.
+ */
+ public void replaceLastInsn(Insn insn) {
+ if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
+ throw new IllegalArgumentException("last insn must branch");
}
- /**
- * Gets the dom children for this node. Don't modify this list.
- *
- * @return {@code non-null;} list of dom children
- */
- public ArrayList<SsaBasicBlock> getDomChildren() {
- return domChildren;
- }
+ SsaInsn oldInsn = insns.get(insns.size() - 1);
+ SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
- /**
- * Adds a phi insn to the beginning of this block. The result type of
- * the phi will be set to void, to indicate that it's currently unknown.
- *
- * @param reg {@code >=0;} result reg
- */
- public void addPhiInsnForReg(int reg) {
- insns.add(0, new PhiInsn(reg, this));
- }
+ insns.set(insns.size() - 1, newInsn);
- /**
- * Adds a phi insn to the beginning of this block. This is to be used
- * when the result type or local-association can be determined at phi
- * insert time.
- *
- * @param resultSpec {@code non-null;} reg
- */
- public void addPhiInsnForReg(RegisterSpec resultSpec) {
- insns.add(0, new PhiInsn(resultSpec, this));
- }
+ parent.onInsnRemoved(oldInsn);
+ parent.onInsnAdded(newInsn);
+ }
- /**
- * Adds an insn to the head of this basic block, just after any phi
- * insns.
- *
- * @param insn {@code non-null;} rop-form insn to add
- */
- public void addInsnToHead(Insn insn) {
- SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
- insns.add(getCountPhiInsns(), newInsn);
- parent.onInsnAdded(newInsn);
- }
+ /**
+ * Visits each phi insn.
+ *
+ * @param v {@code non-null;} the callback
+ */
+ public void forEachPhiInsn(PhiInsn.Visitor v) {
+ int sz = insns.size();
- /**
- * Replaces the last insn in this block. The provided insn must have
- * some branchingness.
- *
- * @param insn {@code non-null;} rop-form insn to add, which must branch.
- */
- public void replaceLastInsn(Insn insn) {
- if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
- throw new IllegalArgumentException("last insn must branch");
- }
-
- SsaInsn oldInsn = insns.get(insns.size() - 1);
- SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
-
- insns.set(insns.size() - 1, newInsn);
-
- parent.onInsnRemoved(oldInsn);
- parent.onInsnAdded(newInsn);
- }
-
- /**
- * Visits each phi insn.
- *
- * @param v {@code non-null;} the callback
- */
- public void forEachPhiInsn(PhiInsn.Visitor v) {
- int sz = insns.size();
-
- for (int i = 0; i < sz; i++) {
- SsaInsn insn = insns.get(i);
- if (insn instanceof PhiInsn) {
- v.visitPhiInsn((PhiInsn) insn);
- } else {
- /*
- * Presently we assume PhiInsn's are in a continuous
- * block at the top of the list
- */
- break;
- }
- }
- }
-
- /**
- * Deletes all phi insns. Do this after adding appropriate move insns.
- */
- public void removeAllPhiInsns() {
+ for (int i = 0; i < sz; i++) {
+ SsaInsn insn = insns.get(i);
+ if (insn instanceof PhiInsn) {
+ v.visitPhiInsn((PhiInsn) insn);
+ } else {
/*
* Presently we assume PhiInsn's are in a continuous
- * block at the top of the list.
+ * block at the top of the list
*/
+ break;
+ }
+ }
+ }
- insns.subList(0, getCountPhiInsns()).clear();
+ /**
+ * Deletes all phi insns. Do this after adding appropriate move insns.
+ */
+ public void removeAllPhiInsns() {
+ /*
+ * Presently we assume PhiInsn's are in a continuous
+ * block at the top of the list.
+ */
+
+insns.subList(0, getCountPhiInsns()).clear();
+ }
+
+ /**
+ * Gets the number of phi insns at the top of this basic block.
+ *
+ * @return count of phi insns
+ */
+ private int getCountPhiInsns() {
+ int countPhiInsns;
+
+ int sz = insns.size();
+ for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) {
+ SsaInsn insn = insns.get(countPhiInsns);
+ if (!(insn instanceof PhiInsn)) {
+ break;
+ }
}
- /**
- * Gets the number of phi insns at the top of this basic block.
- *
- * @return count of phi insns
- */
- private int getCountPhiInsns() {
- int countPhiInsns;
+ return countPhiInsns;
+ }
- int sz = insns.size();
- for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) {
- SsaInsn insn = insns.get(countPhiInsns);
- if (!(insn instanceof PhiInsn)) {
- break;
- }
- }
+ /**
+ * @return {@code non-null;} the (mutable) instruction list for this block,
+ * with phi insns at the beginning
+ */
+ public ArrayList<SsaInsn> getInsns() {
+ return insns;
+ }
- return countPhiInsns;
+ /**
+ * @return {@code non-null;} the (mutable) list of phi insns for this block
+ */
+ public List<SsaInsn> getPhiInsns() {
+ return insns.subList(0, getCountPhiInsns());
+ }
+
+ /**
+ * @return the block index of this block
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * @return the label of this block in rop form
+ */
+ public int getRopLabel() {
+ return ropLabel;
+ }
+
+ /**
+ * @return the label of this block in rop form as a hex string
+ */
+ public String getRopLabelString() {
+ return Hex.u2(ropLabel);
+ }
+
+ /**
+ * @return {@code non-null;} predecessors set, indexed by block index
+ */
+ public BitSet getPredecessors() {
+ return predecessors;
+ }
+
+ /**
+ * @return {@code non-null;} successors set, indexed by block index
+ */
+ public BitSet getSuccessors() {
+ return successors;
+ }
+
+ /**
+ * @return {@code non-null;} ordered successor list, containing block
+ * indicies
+ */
+ public IntList getSuccessorList() {
+ return successorList;
+ }
+
+ /**
+ * @return {@code >= -1;} block index of primary successor or
+ * {@code -1} if no primary successor
+ */
+ public int getPrimarySuccessorIndex() {
+ return primarySuccessor;
+ }
+
+ /**
+ * @return rop label of primary successor
+ */
+ public int getPrimarySuccessorRopLabel() {
+ return parent.blockIndexToRopLabel(primarySuccessor);
+ }
+
+ /**
+ * @return {@code null-ok;} the primary successor block or {@code null}
+ * if there is none
+ */
+ public SsaBasicBlock getPrimarySuccessor() {
+ if (primarySuccessor < 0) {
+ return null;
+ } else {
+ return parent.getBlocks().get(primarySuccessor);
+ }
+ }
+
+ /**
+ * @return successor list of rop labels
+ */
+ public IntList getRopLabelSuccessorList() {
+ IntList result = new IntList(successorList.size());
+
+ int sz = successorList.size();
+
+ for (int i = 0; i < sz; i++) {
+ result.add(parent.blockIndexToRopLabel(successorList.get(i)));
+ }
+ return result;
+ }
+
+ /**
+ * @return {@code non-null;} method that contains this block
+ */
+ public SsaMethod getParent() {
+ return parent;
+ }
+
+ /**
+ * Inserts a new empty GOTO block as a predecessor to this block.
+ * All previous predecessors will be predecessors to the new block.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public SsaBasicBlock insertNewPredecessor() {
+ SsaBasicBlock newPred = parent.makeNewGotoBlock();
+
+ // Update the new block.
+ newPred.predecessors = predecessors;
+ newPred.successors.set(index);
+ newPred.successorList.add(index);
+ newPred.primarySuccessor = index;
+
+
+ // Update us.
+ predecessors = new BitSet(parent.getBlocks().size());
+ predecessors.set(newPred.index);
+
+ // Update our (soon-to-be) old predecessors.
+ for (int i = newPred.predecessors.nextSetBit(0); i >= 0;
+ i = newPred.predecessors.nextSetBit(i + 1)) {
+
+ SsaBasicBlock predBlock = parent.getBlocks().get(i);
+
+ predBlock.replaceSuccessor(index, newPred.index);
}
- /**
- * @return {@code non-null;} the (mutable) instruction list for this block,
- * with phi insns at the beginning
- */
- public ArrayList<SsaInsn> getInsns() {
- return insns;
+ return newPred;
+ }
+
+ /**
+ * Constructs and inserts a new empty GOTO block {@code Z} between
+ * this block ({@code A}) and a current successor block
+ * ({@code B}). The new block will replace B as A's successor and
+ * A as B's predecessor. A and B will no longer be directly connected.
+ * If B is listed as a successor multiple times, all references
+ * are replaced.
+ *
+ * @param other current successor (B)
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
+ SsaBasicBlock newSucc = parent.makeNewGotoBlock();
+
+ if (!successors.get(other.index)) {
+ throw new RuntimeException(
+ "Block " + other.getRopLabelString() + " not successor of " + getRopLabelString());
}
- /**
- * @return {@code non-null;} the (mutable) list of phi insns for this block
- */
- public List<SsaInsn> getPhiInsns() {
- return insns.subList(0, getCountPhiInsns());
+ // Update the new block.
+ newSucc.predecessors.set(this.index);
+ newSucc.successors.set(other.index);
+ newSucc.successorList.add(other.index);
+ newSucc.primarySuccessor = other.index;
+
+ // Update us.
+ for (int i = successorList.size() - 1; i >= 0; i--) {
+ if (successorList.get(i) == other.index) {
+ successorList.set(i, newSucc.index);
+ }
}
- /**
- * @return the block index of this block
- */
- public int getIndex() {
- return index;
+ if (primarySuccessor == other.index) {
+ primarySuccessor = newSucc.index;
+ }
+ successors.clear(other.index);
+ successors.set(newSucc.index);
+
+ // Update "other".
+ other.predecessors.set(newSucc.index);
+ other.predecessors.set(index, successors.get(other.index));
+
+ return newSucc;
+ }
+
+ /**
+ * Replaces an old successor with a new successor. This will throw
+ * RuntimeException if {@code oldIndex} was not a successor.
+ *
+ * @param oldIndex index of old successor block
+ * @param newIndex index of new successor block
+ */
+ public void replaceSuccessor(int oldIndex, int newIndex) {
+ if (oldIndex == newIndex) {
+ return;
}
- /**
- * @return the label of this block in rop form
- */
- public int getRopLabel() {
- return ropLabel;
+ // Update us.
+ successors.set(newIndex);
+
+ if (primarySuccessor == oldIndex) {
+ primarySuccessor = newIndex;
}
- /**
- * @return the label of this block in rop form as a hex string
- */
- public String getRopLabelString() {
- return Hex.u2(ropLabel);
+ for (int i = successorList.size() - 1; i >= 0; i--) {
+ if (successorList.get(i) == oldIndex) {
+ successorList.set(i, newIndex);
+ }
}
- /**
- * @return {@code non-null;} predecessors set, indexed by block index
- */
- public BitSet getPredecessors() {
- return predecessors;
+ successors.clear(oldIndex);
+
+ // Update new successor.
+ parent.getBlocks().get(newIndex).predecessors.set(index);
+
+ // Update old successor.
+ parent.getBlocks().get(oldIndex).predecessors.clear(index);
+ }
+
+ /**
+ * Removes a successor from this block's successor list.
+ *
+ * @param oldIndex index of successor block to remove
+ */
+ public void removeSuccessor(int oldIndex) {
+ int removeIndex = 0;
+
+ for (int i = successorList.size() - 1; i >= 0; i--) {
+ if (successorList.get(i) == oldIndex) {
+ removeIndex = i;
+ } else {
+ primarySuccessor = successorList.get(i);
+ }
}
- /**
- * @return {@code non-null;} successors set, indexed by block index
- */
- public BitSet getSuccessors() {
- return successors;
+ successorList.removeIndex(removeIndex);
+ successors.clear(oldIndex);
+ parent.getBlocks().get(oldIndex).predecessors.clear(index);
+ }
+
+ /**
+ * Attaches block to an exit block if necessary. If this block
+ * is not an exit predecessor or is the exit block, this block does
+ * nothing. For use by {@link com.android.jack.dx.ssa.SsaMethod#makeExitBlock}
+ *
+ * @param exitBlock {@code non-null;} exit block
+ */
+ public void exitBlockFixup(SsaBasicBlock exitBlock) {
+ if (this == exitBlock) {
+ return;
}
- /**
- * @return {@code non-null;} ordered successor list, containing block
- * indicies
- */
- public IntList getSuccessorList() {
- return successorList;
+ if (successorList.size() == 0) {
+ /*
+ * This is an exit predecessor.
+ * Set the successor to the exit block
+ */
+ successors.set(exitBlock.index);
+ successorList.add(exitBlock.index);
+ primarySuccessor = exitBlock.index;
+ exitBlock.predecessors.set(this.index);
+ }
+ }
+
+ /**
+ * Adds a move instruction to the end of this basic block, just
+ * before the last instruction. If the result of the final instruction
+ * is the source in question, then the move is placed at the beginning of
+ * the primary successor block. This is for unversioned registers.
+ *
+ * @param result move destination
+ * @param source move source
+ */
+ public void addMoveToEnd(RegisterSpec result, RegisterSpec source) {
+
+ if (result.getReg() == source.getReg()) {
+ // Sometimes we end up with no-op moves. Ignore them here.
+ return;
}
- /**
- * @return {@code >= -1;} block index of primary successor or
- * {@code -1} if no primary successor
+ /*
+ * The last Insn has to be a normal SSA insn: a phi can't branch
+ * or return or cause an exception, etc.
*/
- public int getPrimarySuccessorIndex() {
- return primarySuccessor;
+ NormalSsaInsn lastInsn;
+ lastInsn = (NormalSsaInsn) insns.get(insns.size() - 1);
+
+ if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) {
+ /*
+ * The final insn in this block has a source or result
+ * register, and the moves we may need to place and
+ * schedule may interfere. We need to insert this
+ * instruction at the beginning of the primary successor
+ * block instead. We know this is safe, because when we
+ * edge-split earlier, we ensured that each successor has
+ * only us as a predecessor.
+ */
+
+for (int i = successors.nextSetBit(0); i >= 0; i = successors.nextSetBit(i + 1)) {
+
+ SsaBasicBlock succ;
+
+ succ = parent.getBlocks().get(i);
+ succ.addMoveToBeginning(result, source);
+ }
+ } else {
+ /*
+ * We can safely add a move to the end of the block just
+ * before the last instruction, because the final insn does
+ * not assign to anything.
+ */
+ RegisterSpecList sources = RegisterSpecList.make(source);
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, sources),
+ this);
+
+ insns.add(insns.size() - 1, toAdd);
+
+ movesFromPhisAtEnd++;
+ }
+ }
+
+ /**
+ * Adds a move instruction after the phi insn block.
+ *
+ * @param result move destination
+ * @param source move source
+ */
+ public void addMoveToBeginning(RegisterSpec result, RegisterSpec source) {
+ if (result.getReg() == source.getReg()) {
+ // Sometimes we end up with no-op moves. Ignore them here.
+ return;
}
- /**
- * @return rop label of primary successor
- */
- public int getPrimarySuccessorRopLabel() {
- return parent.blockIndexToRopLabel(primarySuccessor);
+ RegisterSpecList sources = RegisterSpecList.make(source);
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, sources),
+ this);
+
+ insns.add(getCountPhiInsns(), toAdd);
+ movesFromPhisAtBeginning++;
+ }
+
+ /**
+ * Sets the register as used in a bitset, taking into account its
+ * category/width.
+ *
+ * @param regsUsed set, indexed by register number
+ * @param rs register to mark as used
+ */
+ private static void setRegsUsed(BitSet regsUsed, RegisterSpec rs) {
+ regsUsed.set(rs.getReg());
+ if (rs.getCategory() > 1) {
+ regsUsed.set(rs.getReg() + 1);
}
+ }
- /**
- * @return {@code null-ok;} the primary successor block or {@code null}
- * if there is none
- */
- public SsaBasicBlock getPrimarySuccessor() {
- if (primarySuccessor < 0) {
- return null;
- } else {
- return parent.getBlocks().get(primarySuccessor);
- }
- }
+ /**
+ * Checks to see if the register is used in a bitset, taking
+ * into account its category/width.
+ *
+ * @param regsUsed set, indexed by register number
+ * @param rs register to mark as used
+ * @return true if register is fully or partially (for the case of wide
+ * registers) used.
+ */
+ private static boolean checkRegUsed(BitSet regsUsed, RegisterSpec rs) {
+ int reg = rs.getReg();
+ int category = rs.getCategory();
- /**
- * @return successor list of rop labels
- */
- public IntList getRopLabelSuccessorList() {
- IntList result = new IntList(successorList.size());
+ return regsUsed.get(reg) || (category == 2 ? regsUsed.get(reg + 1) : false);
+ }
- int sz = successorList.size();
+ /**
+ * Ensures that all move operations in this block occur such that
+ * reads of any register happen before writes to that register.
+ * NOTE: caller is expected to returnSpareRegisters()!
+ *
+ * TODO(dx team): See Briggs, et al "Practical Improvements to the Construction and
+ * Destruction of Static Single Assignment Form" section 5. a) This can
+ * be done in three passes.
+ *
+ * @param toSchedule List of instructions. Must consist only of moves.
+ */
+ private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) {
+ BitSet regsUsedAsSources = new BitSet(parent.getRegCount());
- for (int i = 0; i < sz; i++) {
- result.add(parent.blockIndexToRopLabel(successorList.get(i)));
- }
- return result;
- }
+ // TODO(dx team): Get rid of this.
+ BitSet regsUsedAsResults = new BitSet(parent.getRegCount());
- /**
- * @return {@code non-null;} method that contains this block
- */
- public SsaMethod getParent() {
- return parent;
- }
+ int sz = toSchedule.size();
- /**
- * Inserts a new empty GOTO block as a predecessor to this block.
- * All previous predecessors will be predecessors to the new block.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public SsaBasicBlock insertNewPredecessor() {
- SsaBasicBlock newPred = parent.makeNewGotoBlock();
+ int insertPlace = 0;
- // Update the new block.
- newPred.predecessors = predecessors;
- newPred.successors.set(index) ;
- newPred.successorList.add(index);
- newPred.primarySuccessor = index;
+ while (insertPlace < sz) {
+ int oldInsertPlace = insertPlace;
+ // Record all registers used as sources in this block.
+ for (int i = insertPlace; i < sz; i++) {
+ setRegsUsed(regsUsedAsSources, toSchedule.get(i).getSources().get(0));
- // Update us.
- predecessors = new BitSet(parent.getBlocks().size());
- predecessors.set(newPred.index);
+ setRegsUsed(regsUsedAsResults, toSchedule.get(i).getResult());
+ }
- // Update our (soon-to-be) old predecessors.
- for (int i = newPred.predecessors.nextSetBit(0); i >= 0;
- i = newPred.predecessors.nextSetBit(i + 1)) {
-
- SsaBasicBlock predBlock = parent.getBlocks().get(i);
-
- predBlock.replaceSuccessor(index, newPred.index);
- }
-
- return newPred;
- }
-
- /**
- * Constructs and inserts a new empty GOTO block {@code Z} between
- * this block ({@code A}) and a current successor block
- * ({@code B}). The new block will replace B as A's successor and
- * A as B's predecessor. A and B will no longer be directly connected.
- * If B is listed as a successor multiple times, all references
- * are replaced.
- *
- * @param other current successor (B)
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
- SsaBasicBlock newSucc = parent.makeNewGotoBlock();
-
- if (!successors.get(other.index)) {
- throw new RuntimeException("Block " + other.getRopLabelString()
- + " not successor of " + getRopLabelString());
- }
-
- // Update the new block.
- newSucc.predecessors.set(this.index);
- newSucc.successors.set(other.index) ;
- newSucc.successorList.add(other.index);
- newSucc.primarySuccessor = other.index;
-
- // Update us.
- for (int i = successorList.size() - 1 ; i >= 0; i--) {
- if (successorList.get(i) == other.index) {
- successorList.set(i, newSucc.index);
- }
- }
-
- if (primarySuccessor == other.index) {
- primarySuccessor = newSucc.index;
- }
- successors.clear(other.index);
- successors.set(newSucc.index);
-
- // Update "other".
- other.predecessors.set(newSucc.index);
- other.predecessors.set(index, successors.get(other.index));
-
- return newSucc;
- }
-
- /**
- * Replaces an old successor with a new successor. This will throw
- * RuntimeException if {@code oldIndex} was not a successor.
- *
- * @param oldIndex index of old successor block
- * @param newIndex index of new successor block
- */
- public void replaceSuccessor(int oldIndex, int newIndex) {
- if (oldIndex == newIndex) {
- return;
- }
-
- // Update us.
- successors.set(newIndex);
-
- if (primarySuccessor == oldIndex) {
- primarySuccessor = newIndex;
- }
-
- for (int i = successorList.size() - 1 ; i >= 0; i--) {
- if (successorList.get(i) == oldIndex) {
- successorList.set(i, newIndex);
- }
- }
-
- successors.clear(oldIndex);
-
- // Update new successor.
- parent.getBlocks().get(newIndex).predecessors.set(index);
-
- // Update old successor.
- parent.getBlocks().get(oldIndex).predecessors.clear(index);
- }
-
- /**
- * Removes a successor from this block's successor list.
- *
- * @param oldIndex index of successor block to remove
- */
- public void removeSuccessor(int oldIndex) {
- int removeIndex = 0;
-
- for (int i = successorList.size() - 1; i >= 0; i--) {
- if (successorList.get(i) == oldIndex) {
- removeIndex = i;
- } else {
- primarySuccessor = successorList.get(i);
- }
- }
-
- successorList.removeIndex(removeIndex);
- successors.clear(oldIndex);
- parent.getBlocks().get(oldIndex).predecessors.clear(index);
- }
-
- /**
- * Attaches block to an exit block if necessary. If this block
- * is not an exit predecessor or is the exit block, this block does
- * nothing. For use by {@link com.android.jack.dx.ssa.SsaMethod#makeExitBlock}
- *
- * @param exitBlock {@code non-null;} exit block
- */
- public void exitBlockFixup(SsaBasicBlock exitBlock) {
- if (this == exitBlock) {
- return;
- }
-
- if (successorList.size() == 0) {
- /*
- * This is an exit predecessor.
- * Set the successor to the exit block
- */
- successors.set(exitBlock.index);
- successorList.add(exitBlock.index);
- primarySuccessor = exitBlock.index;
- exitBlock.predecessors.set(this.index);
- }
- }
-
- /**
- * Adds a move instruction to the end of this basic block, just
- * before the last instruction. If the result of the final instruction
- * is the source in question, then the move is placed at the beginning of
- * the primary successor block. This is for unversioned registers.
- *
- * @param result move destination
- * @param source move source
- */
- public void addMoveToEnd(RegisterSpec result, RegisterSpec source) {
-
- if (result.getReg() == source.getReg()) {
- // Sometimes we end up with no-op moves. Ignore them here.
- return;
- }
+ /*
+ * If there are no circular dependencies, then there exists
+ * n instructions where n > 1 whose result is not used as a source.
+ */
+ for (int i = insertPlace; i < sz; i++) {
+ SsaInsn insn = toSchedule.get(i);
/*
- * The last Insn has to be a normal SSA insn: a phi can't branch
- * or return or cause an exception, etc.
+ * Move these n registers to the front, since they overwrite
+ * nothing.
*/
- NormalSsaInsn lastInsn;
- lastInsn = (NormalSsaInsn)insns.get(insns.size()-1);
+ if (!checkRegUsed(regsUsedAsSources, insn.getResult())) {
+ Collections.swap(toSchedule, i, insertPlace++);
+ }
+ }
- if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) {
+ /*
+ * If we've made no progress in this iteration, there's a
+ * circular dependency. Split it using the temp reg.
+ */
+ if (oldInsertPlace == insertPlace) {
+
+ SsaInsn insnToSplit = null;
+
+ // Find an insn whose result is used as a source.
+ for (int i = insertPlace; i < sz; i++) {
+ SsaInsn insn = toSchedule.get(i);
+ if (checkRegUsed(regsUsedAsSources, insn.getResult())
+ && checkRegUsed(regsUsedAsResults, insn.getSources().get(0))) {
+
+ insnToSplit = insn;
/*
- * The final insn in this block has a source or result
- * register, and the moves we may need to place and
- * schedule may interfere. We need to insert this
- * instruction at the beginning of the primary successor
- * block instead. We know this is safe, because when we
- * edge-split earlier, we ensured that each successor has
- * only us as a predecessor.
+ * We're going to split this insn; move it to the
+ * front.
*/
+ Collections.swap(toSchedule, insertPlace, i);
+ break;
+ }
+ }
- for (int i = successors.nextSetBit(0)
- ; i >= 0
- ; i = successors.nextSetBit(i + 1)) {
+ // At least one insn will be set above.
- SsaBasicBlock succ;
+ RegisterSpec result = insnToSplit.getResult();
+ RegisterSpec tempSpec = result.withReg(parent.borrowSpareRegister(result.getCategory()));
- succ = parent.getBlocks().get(i);
- succ.addMoveToBeginning(result, source);
- }
+ NormalSsaInsn toAdd = new NormalSsaInsn(new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO, tempSpec, insnToSplit.getSources()), this);
+
+ toSchedule.add(insertPlace++, toAdd);
+
+ RegisterSpecList newSources = RegisterSpecList.make(tempSpec);
+
+ NormalSsaInsn toReplace = new NormalSsaInsn(new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO, result, newSources), this);
+
+ toSchedule.set(insertPlace, toReplace);
+
+ // The size changed.
+ sz = toSchedule.size();
+ }
+
+ regsUsedAsSources.clear();
+ regsUsedAsResults.clear();
+ }
+ }
+
+ /**
+ * Adds {@code regV} to the live-out list for this block. This is called
+ * by the liveness analyzer.
+ *
+ * @param regV register that is live-out for this block.
+ */
+ public void addLiveOut(int regV) {
+ if (liveOut == null) {
+ liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
+ }
+
+ liveOut.add(regV);
+ }
+
+ /**
+ * Adds {@code regV} to the live-in list for this block. This is
+ * called by the liveness analyzer.
+ *
+ * @param regV register that is live-in for this block.
+ */
+ public void addLiveIn(int regV) {
+ if (liveIn == null) {
+ liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
+ }
+
+ liveIn.add(regV);
+ }
+
+ /**
+ * Returns the set of live-in registers. Valid after register
+ * interference graph has been generated, otherwise empty.
+ *
+ * @return {@code non-null;} live-in register set.
+ */
+ public IntSet getLiveInRegs() {
+ if (liveIn == null) {
+ liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
+ }
+ return liveIn;
+ }
+
+ /**
+ * Returns the set of live-out registers. Valid after register
+ * interference graph has been generated, otherwise empty.
+ *
+ * @return {@code non-null;} live-out register set
+ */
+ public IntSet getLiveOutRegs() {
+ if (liveOut == null) {
+ liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
+ }
+ return liveOut;
+ }
+
+ /**
+ * @return true if this is the one-and-only exit block for this method
+ */
+ public boolean isExitBlock() {
+ return index == parent.getExitBlockIndex();
+ }
+
+ /**
+ * Returns true if this block was last calculated to be reachable.
+ * Recalculates reachability if value has never been computed.
+ *
+ * @return {@code true} if reachable
+ */
+ public boolean isReachable() {
+ if (reachable == -1) {
+ parent.computeReachability();
+ }
+ return (reachable == 1);
+ }
+
+ /**
+ * Sets reachability of block to specified value
+ *
+ * @param reach new value of reachability for block
+ */
+ public void setReachable(int reach) {
+ reachable = reach;
+ }
+
+ /**
+ * Sorts move instructions added via {@code addMoveToEnd} during
+ * phi removal so that results don't overwrite sources that are used.
+ * For use after all phis have been removed and all calls to
+ * addMoveToEnd() have been made.<p>
+ *
+ * This is necessary because copy-propogation may have left us in a state
+ * where the same basic block has the same register as a phi operand
+ * and a result. In this case, the register in the phi operand always
+ * refers value before any other phis have executed.
+ */
+ public void scheduleMovesFromPhis() {
+ if (movesFromPhisAtBeginning > 1) {
+ List<SsaInsn> toSchedule;
+
+ toSchedule = insns.subList(0, movesFromPhisAtBeginning);
+
+ scheduleUseBeforeAssigned(toSchedule);
+
+ SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning);
+
+ /*
+ * TODO(dx team): It's actually possible that this case never happens,
+ * because a move-exception block, having only one predecessor
+ * in SSA form, perhaps is never on a dominance frontier.
+ */
+ if (firstNonPhiMoveInsn.isMoveException()) {
+ if (!enablePhisBeforeMoveException) {
+ /*
+ * We've yet to observe this case, and if it can
+ * occur the code written to handle it probably
+ * does not work.
+ */
+ throw new RuntimeException("Unexpected: moves from " + "phis before move-exception");
} else {
- /*
- * We can safely add a move to the end of the block just
- * before the last instruction, because the final insn does
- * not assign to anything.
- */
- RegisterSpecList sources = RegisterSpecList.make(source);
- NormalSsaInsn toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO, result, sources), this);
+ /*
+ * A move-exception insn must be placed first in this block
+ * We need to move it there, and deal with possible
+ * interference.
+ */
+ boolean moveExceptionInterferes = false;
- insns.add(insns.size() - 1, toAdd);
+ int moveExceptionResult = firstNonPhiMoveInsn.getResult().getReg();
- movesFromPhisAtEnd++;
- }
- }
-
- /**
- * Adds a move instruction after the phi insn block.
- *
- * @param result move destination
- * @param source move source
- */
- public void addMoveToBeginning (RegisterSpec result, RegisterSpec source) {
- if (result.getReg() == source.getReg()) {
- // Sometimes we end up with no-op moves. Ignore them here.
- return;
- }
-
- RegisterSpecList sources = RegisterSpecList.make(source);
- NormalSsaInsn toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO, result, sources), this);
-
- insns.add(getCountPhiInsns(), toAdd);
- movesFromPhisAtBeginning++;
- }
-
- /**
- * Sets the register as used in a bitset, taking into account its
- * category/width.
- *
- * @param regsUsed set, indexed by register number
- * @param rs register to mark as used
- */
- private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) {
- regsUsed.set(rs.getReg());
- if (rs.getCategory() > 1) {
- regsUsed.set(rs.getReg() + 1);
- }
- }
-
- /**
- * Checks to see if the register is used in a bitset, taking
- * into account its category/width.
- *
- * @param regsUsed set, indexed by register number
- * @param rs register to mark as used
- * @return true if register is fully or partially (for the case of wide
- * registers) used.
- */
- private static boolean checkRegUsed (BitSet regsUsed, RegisterSpec rs) {
- int reg = rs.getReg();
- int category = rs.getCategory();
-
- return regsUsed.get(reg)
- || (category == 2 ? regsUsed.get(reg + 1) : false);
- }
-
- /**
- * Ensures that all move operations in this block occur such that
- * reads of any register happen before writes to that register.
- * NOTE: caller is expected to returnSpareRegisters()!
- *
- * TODO: See Briggs, et al "Practical Improvements to the Construction and
- * Destruction of Static Single Assignment Form" section 5. a) This can
- * be done in three passes.
- *
- * @param toSchedule List of instructions. Must consist only of moves.
- */
- private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) {
- BitSet regsUsedAsSources = new BitSet(parent.getRegCount());
-
- // TODO: Get rid of this.
- BitSet regsUsedAsResults = new BitSet(parent.getRegCount());
-
- int sz = toSchedule.size();
-
- int insertPlace = 0;
-
- while (insertPlace < sz) {
- int oldInsertPlace = insertPlace;
-
- // Record all registers used as sources in this block.
- for (int i = insertPlace; i < sz; i++) {
- setRegsUsed(regsUsedAsSources,
- toSchedule.get(i).getSources().get(0));
-
- setRegsUsed(regsUsedAsResults,
- toSchedule.get(i).getResult());
+ /*
+ * Does the move-exception result reg interfere with the
+ * phi moves?
+ */
+ for (SsaInsn insn : toSchedule) {
+ if (insn.isResultReg(moveExceptionResult) || insn.isRegASource(moveExceptionResult)) {
+ moveExceptionInterferes = true;
+ break;
}
+ }
+
+ if (!moveExceptionInterferes) {
+ // This is the easy case.
+ insns.remove(movesFromPhisAtBeginning);
+ insns.add(0, firstNonPhiMoveInsn);
+ } else {
+ /*
+ * We need to move the result to a spare reg
+ * and move it back.
+ */
+ RegisterSpec originalResultSpec = firstNonPhiMoveInsn.getResult();
+ int spareRegister = parent.borrowSpareRegister(originalResultSpec.getCategory());
+
+ // We now move it to a spare register.
+ firstNonPhiMoveInsn.changeResultReg(spareRegister);
+ RegisterSpec tempSpec = firstNonPhiMoveInsn.getResult();
+
+ insns.add(0, firstNonPhiMoveInsn);
+
+ // And here we move it back.
+
+ NormalSsaInsn toAdd = new NormalSsaInsn(new PlainInsn(Rops.opMove(tempSpec.getType()),
+ SourcePosition.NO_INFO, originalResultSpec, RegisterSpecList.make(tempSpec)), this);
+
/*
- * If there are no circular dependencies, then there exists
- * n instructions where n > 1 whose result is not used as a source.
+ * Place it immediately after the phi-moves,
+ * overwriting the move-exception that was there.
*/
- for (int i = insertPlace; i <sz; i++) {
- SsaInsn insn = toSchedule.get(i);
-
- /*
- * Move these n registers to the front, since they overwrite
- * nothing.
- */
- if (!checkRegUsed(regsUsedAsSources, insn.getResult())) {
- Collections.swap(toSchedule, i, insertPlace++);
- }
- }
-
- /*
- * If we've made no progress in this iteration, there's a
- * circular dependency. Split it using the temp reg.
- */
- if (oldInsertPlace == insertPlace) {
-
- SsaInsn insnToSplit = null;
-
- // Find an insn whose result is used as a source.
- for (int i = insertPlace; i < sz; i++) {
- SsaInsn insn = toSchedule.get(i);
- if (checkRegUsed(regsUsedAsSources, insn.getResult())
- && checkRegUsed(regsUsedAsResults,
- insn.getSources().get(0))) {
-
- insnToSplit = insn;
- /*
- * We're going to split this insn; move it to the
- * front.
- */
- Collections.swap(toSchedule, insertPlace, i);
- break;
- }
- }
-
- // At least one insn will be set above.
-
- RegisterSpec result = insnToSplit.getResult();
- RegisterSpec tempSpec = result.withReg(
- parent.borrowSpareRegister(result.getCategory()));
-
- NormalSsaInsn toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO,
- tempSpec,
- insnToSplit.getSources()), this);
-
- toSchedule.add(insertPlace++, toAdd);
-
- RegisterSpecList newSources = RegisterSpecList.make(tempSpec);
-
- NormalSsaInsn toReplace = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO,
- result,
- newSources), this);
-
- toSchedule.set(insertPlace, toReplace);
-
- // The size changed.
- sz = toSchedule.size();
- }
-
- regsUsedAsSources.clear();
- regsUsedAsResults.clear();
+ insns.set(movesFromPhisAtBeginning + 1, toAdd);
+ }
}
+ }
}
+ if (movesFromPhisAtEnd > 1) {
+ scheduleUseBeforeAssigned(
+ insns.subList(insns.size() - movesFromPhisAtEnd - 1, insns.size() - 1));
+ }
+
+ // Return registers borrowed here and in scheduleUseBeforeAssigned().
+ parent.returnSpareRegisters();
+
+ }
+
+ /**
+ * Visits all insns in this block.
+ *
+ * @param visitor {@code non-null;} callback interface
+ */
+ public void forEachInsn(SsaInsn.Visitor visitor) {
+ // This gets called a LOT, and not using an iterator
+ // saves a lot of allocations and reduces memory usage
+ int len = insns.size();
+ for (int i = 0; i < len; i++) {
+ insns.get(i).accept(visitor);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "{" + index + ":" + Hex.u2(ropLabel) + '}';
+ }
+
+ /**
+ * Visitor interface for basic blocks.
+ */
+ public interface Visitor {
/**
- * Adds {@code regV} to the live-out list for this block. This is called
- * by the liveness analyzer.
+ * Indicates a block has been visited by an iterator method.
*
- * @param regV register that is live-out for this block.
+ * @param v {@code non-null;} block visited
+ * @param parent {@code null-ok;} parent node if applicable
*/
- public void addLiveOut (int regV) {
- if (liveOut == null) {
- liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
- }
+ void visitBlock(SsaBasicBlock v, SsaBasicBlock parent);
+ }
- liveOut.add(regV);
- }
-
- /**
- * Adds {@code regV} to the live-in list for this block. This is
- * called by the liveness analyzer.
- *
- * @param regV register that is live-in for this block.
- */
- public void addLiveIn (int regV) {
- if (liveIn == null) {
- liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
- }
-
- liveIn.add(regV);
- }
-
- /**
- * Returns the set of live-in registers. Valid after register
- * interference graph has been generated, otherwise empty.
- *
- * @return {@code non-null;} live-in register set.
- */
- public IntSet getLiveInRegs() {
- if (liveIn == null) {
- liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
- }
- return liveIn;
- }
-
- /**
- * Returns the set of live-out registers. Valid after register
- * interference graph has been generated, otherwise empty.
- *
- * @return {@code non-null;} live-out register set
- */
- public IntSet getLiveOutRegs() {
- if (liveOut == null) {
- liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
- }
- return liveOut;
- }
-
- /**
- * @return true if this is the one-and-only exit block for this method
- */
- public boolean isExitBlock() {
- return index == parent.getExitBlockIndex();
- }
-
- /**
- * Returns true if this block was last calculated to be reachable.
- * Recalculates reachability if value has never been computed.
- *
- * @return {@code true} if reachable
- */
- public boolean isReachable() {
- if (reachable == -1) {
- parent.computeReachability();
- }
- return (reachable == 1);
- }
-
- /**
- * Sets reachability of block to specified value
- *
- * @param reach new value of reachability for block
- */
- public void setReachable(int reach) {
- reachable = reach;
- }
-
- /**
- * Sorts move instructions added via {@code addMoveToEnd} during
- * phi removal so that results don't overwrite sources that are used.
- * For use after all phis have been removed and all calls to
- * addMoveToEnd() have been made.<p>
- *
- * This is necessary because copy-propogation may have left us in a state
- * where the same basic block has the same register as a phi operand
- * and a result. In this case, the register in the phi operand always
- * refers value before any other phis have executed.
- */
- public void scheduleMovesFromPhis() {
- if (movesFromPhisAtBeginning > 1) {
- List<SsaInsn> toSchedule;
-
- toSchedule = insns.subList(0, movesFromPhisAtBeginning);
-
- scheduleUseBeforeAssigned(toSchedule);
-
- SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning);
-
- /*
- * TODO: It's actually possible that this case never happens,
- * because a move-exception block, having only one predecessor
- * in SSA form, perhaps is never on a dominance frontier.
- */
- if (firstNonPhiMoveInsn.isMoveException()) {
- if (true) {
- /*
- * We've yet to observe this case, and if it can
- * occur the code written to handle it probably
- * does not work.
- */
- throw new RuntimeException(
- "Unexpected: moves from "
- +"phis before move-exception");
- } else {
- /*
- * A move-exception insn must be placed first in this block
- * We need to move it there, and deal with possible
- * interference.
- */
- boolean moveExceptionInterferes = false;
-
- int moveExceptionResult
- = firstNonPhiMoveInsn.getResult().getReg();
-
- /*
- * Does the move-exception result reg interfere with the
- * phi moves?
- */
- for (SsaInsn insn : toSchedule) {
- if (insn.isResultReg(moveExceptionResult)
- || insn.isRegASource(moveExceptionResult)) {
- moveExceptionInterferes = true;
- break;
- }
- }
-
- if (!moveExceptionInterferes) {
- // This is the easy case.
- insns.remove(movesFromPhisAtBeginning);
- insns.add(0, firstNonPhiMoveInsn);
- } else {
- /*
- * We need to move the result to a spare reg
- * and move it back.
- */
- RegisterSpec originalResultSpec
- = firstNonPhiMoveInsn.getResult();
- int spareRegister = parent.borrowSpareRegister(
- originalResultSpec.getCategory());
-
- // We now move it to a spare register.
- firstNonPhiMoveInsn.changeResultReg(spareRegister);
- RegisterSpec tempSpec =
- firstNonPhiMoveInsn.getResult();
-
- insns.add(0, firstNonPhiMoveInsn);
-
- // And here we move it back.
-
- NormalSsaInsn toAdd = new NormalSsaInsn(
- new PlainInsn(
- Rops.opMove(tempSpec.getType()),
- SourcePosition.NO_INFO,
- originalResultSpec,
- RegisterSpecList.make(tempSpec)),
- this);
-
-
- /*
- * Place it immediately after the phi-moves,
- * overwriting the move-exception that was there.
- */
- insns.set(movesFromPhisAtBeginning + 1, toAdd);
- }
- }
- }
- }
-
- if (movesFromPhisAtEnd > 1) {
- scheduleUseBeforeAssigned(
- insns.subList(insns.size() - movesFromPhisAtEnd - 1,
- insns.size() - 1));
- }
-
- // Return registers borrowed here and in scheduleUseBeforeAssigned().
- parent.returnSpareRegisters();
-
- }
-
- /**
- * Visits all insns in this block.
- *
- * @param visitor {@code non-null;} callback interface
- */
- public void forEachInsn(SsaInsn.Visitor visitor) {
- // This gets called a LOT, and not using an iterator
- // saves a lot of allocations and reduces memory usage
- int len = insns.size();
- for (int i = 0; i < len; i++) {
- insns.get(i).accept(visitor);
- }
- }
-
+ /**
+ * Label comparator.
+ */
+ public static final class LabelComparator implements Comparator<SsaBasicBlock> {
/** {@inheritDoc} */
@Override
- public String toString() {
- return "{" + index + ":" + Hex.u2(ropLabel) + '}';
- }
+ public int compare(SsaBasicBlock b1, SsaBasicBlock b2) {
+ int label1 = b1.ropLabel;
+ int label2 = b2.ropLabel;
- /**
- * Visitor interface for basic blocks.
- */
- public interface Visitor {
- /**
- * Indicates a block has been visited by an iterator method.
- *
- * @param v {@code non-null;} block visited
- * @param parent {@code null-ok;} parent node if applicable
- */
- void visitBlock (SsaBasicBlock v, SsaBasicBlock parent);
+ if (label1 < label2) {
+ return -1;
+ } else if (label1 > label2) {
+ return 1;
+ } else {
+ return 0;
+ }
}
-
- /**
- * Label comparator.
- */
- public static final class LabelComparator
- implements Comparator<SsaBasicBlock> {
- /** {@inheritDoc} */
- public int compare(SsaBasicBlock b1, SsaBasicBlock b2) {
- int label1 = b1.ropLabel;
- int label2 = b2.ropLabel;
-
- if (label1 < label2) {
- return -1;
- } else if (label1 > label2) {
- return 1;
- } else {
- return 0;
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SsaConverter.java b/dx/src/com/android/jack/dx/ssa/SsaConverter.java
index 89dd19d..0c6862d 100644
--- a/dx/src/com/android/jack/dx/ssa/SsaConverter.java
+++ b/dx/src/com/android/jack/dx/ssa/SsaConverter.java
@@ -27,365 +27,354 @@
* Converts ROP methods to SSA Methods
*/
public class SsaConverter {
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = false;
- /**
- * Returns an SSA representation, edge-split and with phi
- * functions placed.
- *
- * @param rmeth input
- * @param paramWidth the total width, in register-units, of the method's
- * parameters
- * @param isStatic {@code true} if this method has no {@code this}
- * pointer argument
- * @return output in SSA form
+ /**
+ * Returns an SSA representation, edge-split and with phi
+ * functions placed.
+ *
+ * @param rmeth input
+ * @param paramWidth the total width, in register-units, of the method's
+ * parameters
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return output in SSA form
+ */
+ public static SsaMethod convertToSsaMethod(RopMethod rmeth, int paramWidth, boolean isStatic) {
+ SsaMethod result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+ edgeSplit(result);
+
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+ placePhiFunctions(result, localInfo, 0);
+ new SsaRenamer(result).run();
+
+ /*
+ * The exit block, added here, is not considered for edge splitting
+ * or phi placement since no actual control flows to it.
*/
- public static SsaMethod convertToSsaMethod(RopMethod rmeth,
- int paramWidth, boolean isStatic) {
- SsaMethod result
- = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+ result.makeExitBlock();
- edgeSplit(result);
+ return result;
+ }
- LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+ /**
+ * Updates an SSA representation, placing phi functions and renaming all
+ * registers above a certain threshold number.
+ *
+ * @param ssaMeth input
+ * @param threshold registers below this number are unchanged
+ */
+ public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
+ placePhiFunctions(ssaMeth, localInfo, threshold);
+ new SsaRenamer(ssaMeth, threshold).run();
+ }
- placePhiFunctions(result, localInfo, 0);
- new SsaRenamer(result).run();
+ /**
+ * Returns an SSA represention with only the edge-splitter run.
+ *
+ * @param rmeth method to process
+ * @param paramWidth width of all arguments in the method
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
+ */
+ public static SsaMethod testEdgeSplit(RopMethod rmeth, int paramWidth, boolean isStatic) {
+ SsaMethod result;
- /*
- * The exit block, added here, is not considered for edge splitting
- * or phi placement since no actual control flows to it.
- */
- result.makeExitBlock();
+ result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
- return result;
+ edgeSplit(result);
+ return result;
+ }
+
+ /**
+ * Returns an SSA represention with only the steps through the
+ * phi placement run.
+ *
+ * @param rmeth method to process
+ * @param paramWidth width of all arguments in the method
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
+ */
+ public static SsaMethod testPhiPlacement(RopMethod rmeth, int paramWidth, boolean isStatic) {
+ SsaMethod result;
+
+ result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+ edgeSplit(result);
+
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+ placePhiFunctions(result, localInfo, 0);
+ return result;
+ }
+
+ /**
+ * See Appel section 19.1:
+ *
+ * Converts CFG into "edge-split" form, such that each node either a
+ * unique successor or unique predecessor.<p>
+ *
+ * In addition, the SSA form we use enforces a further constraint,
+ * requiring each block with a final instruction that returns a
+ * value to have a primary successor that has no other
+ * predecessor. This ensures move statements can always be
+ * inserted correctly when phi statements are removed.
+ *
+ * @param result method to process
+ */
+ private static void edgeSplit(SsaMethod result) {
+ edgeSplitPredecessors(result);
+ edgeSplitMoveExceptionsAndResults(result);
+ edgeSplitSuccessors(result);
+ }
+
+ /**
+ * Inserts Z nodes as new predecessors for every node that has multiple
+ * successors and multiple predecessors.
+ *
+ * @param result {@code non-null;} method to process
+ */
+ private static void edgeSplitPredecessors(SsaMethod result) {
+ ArrayList<SsaBasicBlock> blocks = result.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i--) {
+ SsaBasicBlock block = blocks.get(i);
+ if (nodeNeedsUniquePredecessor(block)) {
+ block.insertNewPredecessor();
+ }
+ }
+ }
+
+ /**
+ * @param block {@code non-null;} block in question
+ * @return {@code true} if this node needs to have a unique
+ * predecessor created for it
+ */
+ private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
+ /*
+ * Any block with that has both multiple successors and multiple
+ * predecessors needs a new predecessor node.
+ */
+
+int countPredecessors = block.getPredecessors().cardinality();
+ int countSuccessors = block.getSuccessors().cardinality();
+
+ return (countPredecessors > 1 && countSuccessors > 1);
+ }
+
+ /**
+ * In ROP form, move-exception must occur as the first insn in a block
+ * immediately succeeding the insn that could thrown an exception.
+ * We may need room to insert move insns later, so make sure to split
+ * any block that starts with a move-exception such that there is a
+ * unique move-exception block for each predecessor.
+ *
+ * @param ssaMeth method to process
+ */
+ private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
+ ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i--) {
+ SsaBasicBlock block = blocks.get(i);
+
+ /*
+ * Any block that starts with a move-exception and has more than
+ * one predecessor...
+ */
+ if (!block.isExitBlock() && block.getPredecessors().cardinality() > 1
+ && block.getInsns().get(0).isMoveException()) {
+
+ // block.getPredecessors() is changed in the loop below.
+ BitSet preds = (BitSet) block.getPredecessors().clone();
+ for (int j = preds.nextSetBit(0); j >= 0; j = preds.nextSetBit(j + 1)) {
+ SsaBasicBlock predecessor = blocks.get(j);
+ SsaBasicBlock zNode = predecessor.insertNewSuccessor(block);
+
+ /*
+ * Make sure to place the move-exception as the
+ * first insn.
+ */
+ zNode.getInsns().add(0, block.getInsns().get(0).clone());
+ }
+
+ // Remove the move-exception from the original block.
+ block.getInsns().remove(0);
+ }
+ }
+ }
+
+ /**
+ * Inserts Z nodes for every node that needs a new
+ * successor.
+ *
+ * @param result {@code non-null;} method to process
+ */
+ private static void edgeSplitSuccessors(SsaMethod result) {
+ ArrayList<SsaBasicBlock> blocks = result.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i--) {
+ SsaBasicBlock block = blocks.get(i);
+
+ // Successors list is modified in loop below.
+ BitSet successors = (BitSet) block.getSuccessors().clone();
+ for (int j = successors.nextSetBit(0); j >= 0; j = successors.nextSetBit(j + 1)) {
+
+ SsaBasicBlock succ = blocks.get(j);
+
+ if (needsNewSuccessor(block, succ)) {
+ block.insertNewSuccessor(succ);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if block and successor need a Z-node
+ * between them. Presently, this is {@code true} if the final
+ * instruction has any sources or results and the current
+ * successor block has more than one predecessor.
+ *
+ * @param block predecessor node
+ * @param succ successor node
+ * @return {@code true} if a Z node is needed
+ */
+ private static boolean needsNewSuccessor(SsaBasicBlock block, SsaBasicBlock succ) {
+ ArrayList<SsaInsn> insns = block.getInsns();
+ SsaInsn lastInsn = insns.get(insns.size() - 1);
+
+ return ((lastInsn.getResult() != null) || (lastInsn.getSources().size() > 0))
+ && succ.getPredecessors().cardinality() > 1;
+ }
+
+ /**
+ * See Appel algorithm 19.6:
+ *
+ * Place Phi functions in appropriate locations.
+ *
+ * @param ssaMeth {@code non-null;} method to process.
+ * Modifications are made in-place.
+ * @param localInfo {@code non-null;} local variable info, used
+ * when placing phis
+ * @param threshold registers below this number are ignored
+ */
+ private static void placePhiFunctions(SsaMethod ssaMeth, LocalVariableInfo localInfo,
+ int threshold) {
+ ArrayList<SsaBasicBlock> ssaBlocks;
+ int regCount;
+ int blockCount;
+
+ ssaBlocks = ssaMeth.getBlocks();
+ blockCount = ssaBlocks.size();
+ regCount = ssaMeth.getRegCount() - threshold;
+
+ DomFront df = new DomFront(ssaMeth);
+ DomFront.DomInfo[] domInfos = df.run();
+
+ // Bit set of registers vs block index "definition sites"
+ BitSet[] defsites = new BitSet[regCount];
+
+ // Bit set of registers vs block index "phi placement sites"
+ BitSet[] phisites = new BitSet[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ defsites[i] = new BitSet(blockCount);
+ phisites[i] = new BitSet(blockCount);
}
- /**
- * Updates an SSA representation, placing phi functions and renaming all
- * registers above a certain threshold number.
- *
- * @param ssaMeth input
- * @param threshold registers below this number are unchanged
+ /*
+ * For each register, build a set of all basic blocks where
+ * containing an assignment to that register.
*/
- public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
- LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
- placePhiFunctions(ssaMeth, localInfo, threshold);
- new SsaRenamer(ssaMeth, threshold).run();
+ for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
+ SsaBasicBlock b = ssaBlocks.get(bi);
+
+ for (SsaInsn insn : b.getInsns()) {
+ RegisterSpec rs = insn.getResult();
+
+ if (rs != null && rs.getReg() - threshold >= 0) {
+ defsites[rs.getReg() - threshold].set(bi);
+ }
+ }
}
- /**
- * Returns an SSA represention with only the edge-splitter run.
- *
- * @param rmeth method to process
- * @param paramWidth width of all arguments in the method
- * @param isStatic {@code true} if this method has no {@code this}
- * pointer argument
- * @return an SSA represention with only the edge-splitter run
- */
- public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth,
- boolean isStatic) {
- SsaMethod result;
+ if (DEBUG) {
+ System.out.println("defsites");
- result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
-
- edgeSplit(result);
- return result;
+ for (int i = 0; i < regCount; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('v').append(i).append(": ");
+ sb.append(defsites[i].toString());
+ System.out.println(sb);
+ }
}
- /**
- * Returns an SSA represention with only the steps through the
- * phi placement run.
- *
- * @param rmeth method to process
- * @param paramWidth width of all arguments in the method
- * @param isStatic {@code true} if this method has no {@code this}
- * pointer argument
- * @return an SSA represention with only the edge-splitter run
+ BitSet worklist;
+
+ /*
+ * For each register, compute all locations for phi placement
+ * based on dominance-frontier algorithm.
*/
- public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth,
- boolean isStatic) {
- SsaMethod result;
+ for (int reg = 0, s = regCount; reg < s; reg++) {
+ int workBlockIndex;
- result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+ /* Worklist set starts out with each node where reg is assigned. */
- edgeSplit(result);
+worklist =
+ (BitSet) (defsites[reg].clone());
- LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+ while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
+ worklist.clear(workBlockIndex);
+ IntIterator dfIterator = domInfos[workBlockIndex].dominanceFrontiers.iterator();
- placePhiFunctions(result, localInfo, 0);
- return result;
- }
+ while (dfIterator.hasNext()) {
+ int dfBlockIndex = dfIterator.next();
- /**
- * See Appel section 19.1:
- *
- * Converts CFG into "edge-split" form, such that each node either a
- * unique successor or unique predecessor.<p>
- *
- * In addition, the SSA form we use enforces a further constraint,
- * requiring each block with a final instruction that returns a
- * value to have a primary successor that has no other
- * predecessor. This ensures move statements can always be
- * inserted correctly when phi statements are removed.
- *
- * @param result method to process
- */
- private static void edgeSplit(SsaMethod result) {
- edgeSplitPredecessors(result);
- edgeSplitMoveExceptionsAndResults(result);
- edgeSplitSuccessors(result);
- }
+ if (!phisites[reg].get(dfBlockIndex)) {
+ phisites[reg].set(dfBlockIndex);
- /**
- * Inserts Z nodes as new predecessors for every node that has multiple
- * successors and multiple predecessors.
- *
- * @param result {@code non-null;} method to process
- */
- private static void edgeSplitPredecessors(SsaMethod result) {
- ArrayList<SsaBasicBlock> blocks = result.getBlocks();
+ int tReg = reg + threshold;
+ RegisterSpec rs = localInfo.getStarts(dfBlockIndex).get(tReg);
- /*
- * New blocks are added to the end of the block list during
- * this iteration.
- */
- for (int i = blocks.size() - 1; i >= 0; i-- ) {
- SsaBasicBlock block = blocks.get(i);
- if (nodeNeedsUniquePredecessor(block)) {
- block.insertNewPredecessor();
+ if (rs == null) {
+ ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
+ } else {
+ ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
}
+
+ if (!defsites[reg].get(dfBlockIndex)) {
+ worklist.set(dfBlockIndex);
+ }
+ }
}
+ }
}
- /**
- * @param block {@code non-null;} block in question
- * @return {@code true} if this node needs to have a unique
- * predecessor created for it
- */
- private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
- /*
- * Any block with that has both multiple successors and multiple
- * predecessors needs a new predecessor node.
- */
+ if (DEBUG) {
+ System.out.println("phisites");
- int countPredecessors = block.getPredecessors().cardinality();
- int countSuccessors = block.getSuccessors().cardinality();
-
- return (countPredecessors > 1 && countSuccessors > 1);
+ for (int i = 0; i < regCount; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('v').append(i).append(": ");
+ sb.append(phisites[i].toString());
+ System.out.println(sb);
+ }
}
-
- /**
- * In ROP form, move-exception must occur as the first insn in a block
- * immediately succeeding the insn that could thrown an exception.
- * We may need room to insert move insns later, so make sure to split
- * any block that starts with a move-exception such that there is a
- * unique move-exception block for each predecessor.
- *
- * @param ssaMeth method to process
- */
- private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
- ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
-
- /*
- * New blocks are added to the end of the block list during
- * this iteration.
- */
- for (int i = blocks.size() - 1; i >= 0; i-- ) {
- SsaBasicBlock block = blocks.get(i);
-
- /*
- * Any block that starts with a move-exception and has more than
- * one predecessor...
- */
- if (!block.isExitBlock()
- && block.getPredecessors().cardinality() > 1
- && block.getInsns().get(0).isMoveException()) {
-
- // block.getPredecessors() is changed in the loop below.
- BitSet preds = (BitSet)block.getPredecessors().clone();
- for (int j = preds.nextSetBit(0); j >= 0;
- j = preds.nextSetBit(j + 1)) {
- SsaBasicBlock predecessor = blocks.get(j);
- SsaBasicBlock zNode
- = predecessor.insertNewSuccessor(block);
-
- /*
- * Make sure to place the move-exception as the
- * first insn.
- */
- zNode.getInsns().add(0, block.getInsns().get(0).clone());
- }
-
- // Remove the move-exception from the original block.
- block.getInsns().remove(0);
- }
- }
- }
-
- /**
- * Inserts Z nodes for every node that needs a new
- * successor.
- *
- * @param result {@code non-null;} method to process
- */
- private static void edgeSplitSuccessors(SsaMethod result) {
- ArrayList<SsaBasicBlock> blocks = result.getBlocks();
-
- /*
- * New blocks are added to the end of the block list during
- * this iteration.
- */
- for (int i = blocks.size() - 1; i >= 0; i-- ) {
- SsaBasicBlock block = blocks.get(i);
-
- // Successors list is modified in loop below.
- BitSet successors = (BitSet)block.getSuccessors().clone();
- for (int j = successors.nextSetBit(0);
- j >= 0; j = successors.nextSetBit(j+1)) {
-
- SsaBasicBlock succ = blocks.get(j);
-
- if (needsNewSuccessor(block, succ)) {
- block.insertNewSuccessor(succ);
- }
- }
- }
- }
-
- /**
- * Returns {@code true} if block and successor need a Z-node
- * between them. Presently, this is {@code true} if the final
- * instruction has any sources or results and the current
- * successor block has more than one predecessor.
- *
- * @param block predecessor node
- * @param succ successor node
- * @return {@code true} if a Z node is needed
- */
- private static boolean needsNewSuccessor(SsaBasicBlock block,
- SsaBasicBlock succ) {
- ArrayList<SsaInsn> insns = block.getInsns();
- SsaInsn lastInsn = insns.get(insns.size() - 1);
-
- return ((lastInsn.getResult() != null)
- || (lastInsn.getSources().size() > 0))
- && succ.getPredecessors().cardinality() > 1;
- }
-
- /**
- * See Appel algorithm 19.6:
- *
- * Place Phi functions in appropriate locations.
- *
- * @param ssaMeth {@code non-null;} method to process.
- * Modifications are made in-place.
- * @param localInfo {@code non-null;} local variable info, used
- * when placing phis
- * @param threshold registers below this number are ignored
- */
- private static void placePhiFunctions (SsaMethod ssaMeth,
- LocalVariableInfo localInfo, int threshold) {
- ArrayList<SsaBasicBlock> ssaBlocks;
- int regCount;
- int blockCount;
-
- ssaBlocks = ssaMeth.getBlocks();
- blockCount = ssaBlocks.size();
- regCount = ssaMeth.getRegCount() - threshold;
-
- DomFront df = new DomFront(ssaMeth);
- DomFront.DomInfo[] domInfos = df.run();
-
- // Bit set of registers vs block index "definition sites"
- BitSet[] defsites = new BitSet[regCount];
-
- // Bit set of registers vs block index "phi placement sites"
- BitSet[] phisites = new BitSet[regCount];
-
- for (int i = 0; i < regCount; i++) {
- defsites[i] = new BitSet(blockCount);
- phisites[i] = new BitSet(blockCount);
- }
-
- /*
- * For each register, build a set of all basic blocks where
- * containing an assignment to that register.
- */
- for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
- SsaBasicBlock b = ssaBlocks.get(bi);
-
- for (SsaInsn insn : b.getInsns()) {
- RegisterSpec rs = insn.getResult();
-
- if (rs != null && rs.getReg() - threshold >= 0) {
- defsites[rs.getReg() - threshold].set(bi);
- }
- }
- }
-
- if (DEBUG) {
- System.out.println("defsites");
-
- for (int i = 0; i < regCount; i++) {
- StringBuilder sb = new StringBuilder();
- sb.append('v').append(i).append(": ");
- sb.append(defsites[i].toString());
- System.out.println(sb);
- }
- }
-
- BitSet worklist;
-
- /*
- * For each register, compute all locations for phi placement
- * based on dominance-frontier algorithm.
- */
- for (int reg = 0, s = regCount; reg < s; reg++) {
- int workBlockIndex;
-
- /* Worklist set starts out with each node where reg is assigned. */
-
- worklist = (BitSet) (defsites[reg].clone());
-
- while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
- worklist.clear(workBlockIndex);
- IntIterator dfIterator
- = domInfos[workBlockIndex].dominanceFrontiers.iterator();
-
- while (dfIterator.hasNext()) {
- int dfBlockIndex = dfIterator.next();
-
- if (!phisites[reg].get(dfBlockIndex)) {
- phisites[reg].set(dfBlockIndex);
-
- int tReg = reg + threshold;
- RegisterSpec rs
- = localInfo.getStarts(dfBlockIndex).get(tReg);
-
- if (rs == null) {
- ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
- } else {
- ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
- }
-
- if (!defsites[reg].get(dfBlockIndex)) {
- worklist.set(dfBlockIndex);
- }
- }
- }
- }
- }
-
- if (DEBUG) {
- System.out.println("phisites");
-
- for (int i = 0; i < regCount; i++) {
- StringBuilder sb = new StringBuilder();
- sb.append('v').append(i).append(": ");
- sb.append(phisites[i].toString());
- System.out.println(sb);
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SsaInsn.java b/dx/src/com/android/jack/dx/ssa/SsaInsn.java
index bf76db2..403e56d 100644
--- a/dx/src/com/android/jack/dx/ssa/SsaInsn.java
+++ b/dx/src/com/android/jack/dx/ssa/SsaInsn.java
@@ -16,274 +16,276 @@
package com.android.jack.dx.ssa;
-import com.android.jack.dx.rop.code.*;
+import com.android.jack.dx.rop.code.Insn;
+import com.android.jack.dx.rop.code.LocalItem;
+import com.android.jack.dx.rop.code.RegisterSpec;
+import com.android.jack.dx.rop.code.RegisterSpecList;
+import com.android.jack.dx.rop.code.Rop;
import com.android.jack.dx.util.ToHuman;
/**
* An instruction in SSA form
*/
public abstract class SsaInsn implements ToHuman, Cloneable {
- /** {@code non-null;} the block that contains this instance */
- private final SsaBasicBlock block;
+ /** {@code non-null;} the block that contains this instance */
+ private final SsaBasicBlock block;
- /** {@code null-ok;} result register */
- private RegisterSpec result;
+ /** {@code null-ok;} result register */
+ private RegisterSpec result;
- /**
- * Constructs an instance.
- *
- * @param result {@code null-ok;} initial result register. May be changed.
- * @param block {@code non-null;} block containing this insn. Can
- * never change.
- */
- protected SsaInsn(RegisterSpec result, SsaBasicBlock block) {
- if (block == null) {
- throw new NullPointerException("block == null");
- }
-
- this.block = block;
- this.result = result;
+ /**
+ * Constructs an instance.
+ *
+ * @param result {@code null-ok;} initial result register. May be changed.
+ * @param block {@code non-null;} block containing this insn. Can
+ * never change.
+ */
+ protected SsaInsn(RegisterSpec result, SsaBasicBlock block) {
+ if (block == null) {
+ throw new NullPointerException("block == null");
}
- /**
- * Makes a new SSA insn form a rop insn.
- *
- * @param insn {@code non-null;} rop insn
- * @param block {@code non-null;} owning block
- * @return {@code non-null;} an appropriately constructed instance
- */
- public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
- return new NormalSsaInsn(insn, block);
+ this.block = block;
+ this.result = result;
+ }
+
+ /**
+ * Makes a new SSA insn form a rop insn.
+ *
+ * @param insn {@code non-null;} rop insn
+ * @param block {@code non-null;} owning block
+ * @return {@code non-null;} an appropriately constructed instance
+ */
+ public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
+ return new NormalSsaInsn(insn, block);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public SsaInsn clone() {
+ try {
+ return (SsaInsn) super.clone();
+ } catch (CloneNotSupportedException ex) {
+ throw new RuntimeException("unexpected", ex);
+ }
+ }
+
+ /**
+ * Like {@link com.android.jack.dx.rop.code.Insn getResult()}.
+ *
+ * @return result register
+ */
+ public RegisterSpec getResult() {
+ return result;
+ }
+
+ /**
+ * Set the result register.
+ *
+ * @param result {@code non-null;} the new result register
+ */
+ protected void setResult(RegisterSpec result) {
+ if (result == null) {
+ throw new NullPointerException("result == null");
}
- /** {@inheritDoc} */
- @Override
- public SsaInsn clone() {
- try {
- return (SsaInsn)super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new RuntimeException ("unexpected", ex);
- }
+ this.result = result;
+ }
+
+ /**
+ * Like {@link com.android.jack.dx.rop.code.Insn getSources()}.
+ *
+ * @return {@code non-null;} sources list
+ */
+ public abstract RegisterSpecList getSources();
+
+ /**
+ * Gets the block to which this insn instance belongs.
+ *
+ * @return owning block
+ */
+ public SsaBasicBlock getBlock() {
+ return block;
+ }
+
+ /**
+ * Returns whether or not the specified reg is the result reg.
+ *
+ * @param reg register to test
+ * @return true if there is a result and it is stored in the specified
+ * register
+ */
+ public boolean isResultReg(int reg) {
+ return result != null && result.getReg() == reg;
+ }
+
+
+ /**
+ * Changes the result register if this insn has a result. This is used
+ * during renaming.
+ *
+ * @param reg new result register
+ */
+ public void changeResultReg(int reg) {
+ if (result != null) {
+ result = result.withReg(reg);
+ }
+ }
+
+ /**
+ * Sets the local association for the result of this insn. This is
+ * sometimes updated during the SsaRenamer process.
+ *
+ * @param local {@code null-ok;} new debug/local variable info
+ */
+ public final void setResultLocal(LocalItem local) {
+ LocalItem oldItem = result.getLocalItem();
+
+ if (local != oldItem && (local == null || !local.equals(result.getLocalItem()))) {
+ result = RegisterSpec.makeLocalOptional(result.getReg(), result.getType(), local);
+ }
+ }
+
+ /**
+ * Map registers after register allocation.
+ *
+ * @param mapper {@code non-null;} mapping from old to new registers
+ */
+ public final void mapRegisters(RegisterMapper mapper) {
+ RegisterSpec oldResult = result;
+
+ result = mapper.map(result);
+ block.getParent().updateOneDefinition(this, oldResult);
+ mapSourceRegisters(mapper);
+ }
+
+ /**
+ * Maps only source registers.
+ *
+ * @param mapper new mapping
+ */
+ public abstract void mapSourceRegisters(RegisterMapper mapper);
+
+ /**
+ * Returns the Rop opcode for this insn, or null if this is a phi insn.
+ *
+ * TODO(dx team): Move this up into NormalSsaInsn.
+ *
+ * @return {@code null-ok;} Rop opcode if there is one.
+ */
+ public abstract Rop getOpcode();
+
+ /**
+ * Returns the original Rop insn for this insn, or null if this is
+ * a phi insn.
+ *
+ * TODO(dx team): Move this up into NormalSsaInsn.
+ *
+ * @return {@code null-ok;} Rop insn if there is one.
+ */
+ public abstract Insn getOriginalRopInsn();
+
+ /**
+ * Gets the spec of a local variable assignment that occurs at this
+ * instruction, or null if no local variable assignment occurs. This
+ * may be the result register, or for {@code mark-local} insns
+ * it may be the source.
+ *
+ * @see com.android.jack.dx.rop.code.Insn#getLocalAssignment()
+ *
+ * @return {@code null-ok;} a local-associated register spec or null
+ */
+ public RegisterSpec getLocalAssignment() {
+ if (result != null && result.getLocalItem() != null) {
+ return result;
}
+ return null;
+ }
+
+ /**
+ * Indicates whether the specified register is amongst the registers
+ * used as sources for this instruction.
+ *
+ * @param reg the register in question
+ * @return true if the reg is a source
+ */
+ public boolean isRegASource(int reg) {
+ return null != getSources().specForRegister(reg);
+ }
+
+ /**
+ * Transform back to ROP form.
+ *
+ * TODO(dx team): Move this up into NormalSsaInsn.
+ *
+ * @return {@code non-null;} a ROP representation of this instruction, with
+ * updated registers.
+ */
+ public abstract Insn toRopInsn();
+
+ /**
+ * @return true if this is a PhiInsn or a normal move insn
+ */
+ public abstract boolean isPhiOrMove();
+
+ /**
+ * Returns true if this insn is considered to have a side effect beyond
+ * that of assigning to the result reg.
+ *
+ * @return true if this insn is considered to have a side effect beyond
+ * that of assigning to the result reg.
+ */
+ public abstract boolean hasSideEffect();
+
+ /**
+ * @return true if this is a move (but not a move-operand or
+ * move-exception) instruction
+ */
+ public boolean isNormalMoveInsn() {
+ return false;
+ }
+
+ /**
+ * @return true if this is a move-exception instruction.
+ * These instructions must immediately follow a preceeding invoke*
+ */
+ public boolean isMoveException() {
+ return false;
+ }
+
+ /**
+ * @return true if this instruction can throw.
+ */
+ public abstract boolean canThrow();
+
+ /**
+ * Accepts a visitor.
+ *
+ * @param v {@code non-null} the visitor
+ */
+ public abstract void accept(Visitor v);
+
+ /**
+ * Visitor interface for this class.
+ */
+ public static interface Visitor {
/**
- * Like {@link com.android.jack.dx.rop.code.Insn getResult()}.
- *
- * @return result register
+ * Any non-phi move instruction
+ * @param insn {@code non-null;} the instruction to visit
*/
- public RegisterSpec getResult() {
- return result;
- }
+ public void visitMoveInsn(NormalSsaInsn insn);
/**
- * Set the result register.
- *
- * @param result {@code non-null;} the new result register
+ * Any phi insn
+ * @param insn {@code non-null;} the instruction to visit
*/
- protected void setResult(RegisterSpec result) {
- if (result == null) {
- throw new NullPointerException("result == null");
- }
-
- this.result = result;
- }
+ public void visitPhiInsn(PhiInsn insn);
/**
- * Like {@link com.android.jack.dx.rop.code.Insn getSources()}.
- *
- * @return {@code non-null;} sources list
+ * Any insn that isn't a move or a phi (which is also a move).
+ * @param insn {@code non-null;} the instruction to visit
*/
- abstract public RegisterSpecList getSources();
-
- /**
- * Gets the block to which this insn instance belongs.
- *
- * @return owning block
- */
- public SsaBasicBlock getBlock() {
- return block;
- }
-
- /**
- * Returns whether or not the specified reg is the result reg.
- *
- * @param reg register to test
- * @return true if there is a result and it is stored in the specified
- * register
- */
- public boolean isResultReg(int reg) {
- return result != null && result.getReg() == reg;
- }
-
-
- /**
- * Changes the result register if this insn has a result. This is used
- * during renaming.
- *
- * @param reg new result register
- */
- public void changeResultReg(int reg) {
- if (result != null) {
- result = result.withReg(reg);
- }
- }
-
- /**
- * Sets the local association for the result of this insn. This is
- * sometimes updated during the SsaRenamer process.
- *
- * @param local {@code null-ok;} new debug/local variable info
- */
- public final void setResultLocal(LocalItem local) {
- LocalItem oldItem = result.getLocalItem();
-
- if (local != oldItem && (local == null
- || !local.equals(result.getLocalItem()))) {
- result = RegisterSpec.makeLocalOptional(
- result.getReg(), result.getType(), local);
- }
- }
-
- /**
- * Map registers after register allocation.
- *
- * @param mapper {@code non-null;} mapping from old to new registers
- */
- public final void mapRegisters(RegisterMapper mapper) {
- RegisterSpec oldResult = result;
-
- result = mapper.map(result);
- block.getParent().updateOneDefinition(this, oldResult);
- mapSourceRegisters(mapper);
- }
-
- /**
- * Maps only source registers.
- *
- * @param mapper new mapping
- */
- abstract public void mapSourceRegisters(RegisterMapper mapper);
-
- /**
- * Returns the Rop opcode for this insn, or null if this is a phi insn.
- *
- * TODO: Move this up into NormalSsaInsn.
- *
- * @return {@code null-ok;} Rop opcode if there is one.
- */
- abstract public Rop getOpcode();
-
- /**
- * Returns the original Rop insn for this insn, or null if this is
- * a phi insn.
- *
- * TODO: Move this up into NormalSsaInsn.
- *
- * @return {@code null-ok;} Rop insn if there is one.
- */
- abstract public Insn getOriginalRopInsn();
-
- /**
- * Gets the spec of a local variable assignment that occurs at this
- * instruction, or null if no local variable assignment occurs. This
- * may be the result register, or for {@code mark-local} insns
- * it may be the source.
- *
- * @see com.android.jack.dx.rop.code.Insn#getLocalAssignment()
- *
- * @return {@code null-ok;} a local-associated register spec or null
- */
- public RegisterSpec getLocalAssignment() {
- if (result != null && result.getLocalItem() != null) {
- return result;
- }
-
- return null;
- }
-
- /**
- * Indicates whether the specified register is amongst the registers
- * used as sources for this instruction.
- *
- * @param reg the register in question
- * @return true if the reg is a source
- */
- public boolean isRegASource(int reg) {
- return null != getSources().specForRegister(reg);
- }
-
- /**
- * Transform back to ROP form.
- *
- * TODO: Move this up into NormalSsaInsn.
- *
- * @return {@code non-null;} a ROP representation of this instruction, with
- * updated registers.
- */
- public abstract Insn toRopInsn();
-
- /**
- * @return true if this is a PhiInsn or a normal move insn
- */
- public abstract boolean isPhiOrMove();
-
- /**
- * Returns true if this insn is considered to have a side effect beyond
- * that of assigning to the result reg.
- *
- * @return true if this insn is considered to have a side effect beyond
- * that of assigning to the result reg.
- */
- public abstract boolean hasSideEffect();
-
- /**
- * @return true if this is a move (but not a move-operand or
- * move-exception) instruction
- */
- public boolean isNormalMoveInsn() {
- return false;
- }
-
- /**
- * @return true if this is a move-exception instruction.
- * These instructions must immediately follow a preceeding invoke*
- */
- public boolean isMoveException() {
- return false;
- }
-
- /**
- * @return true if this instruction can throw.
- */
- abstract public boolean canThrow();
-
- /**
- * Accepts a visitor.
- *
- * @param v {@code non-null} the visitor
- */
- public abstract void accept(Visitor v);
-
- /**
- * Visitor interface for this class.
- */
- public static interface Visitor {
- /**
- * Any non-phi move instruction
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitMoveInsn(NormalSsaInsn insn);
-
- /**
- * Any phi insn
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitPhiInsn(PhiInsn insn);
-
- /**
- * Any insn that isn't a move or a phi (which is also a move).
- * @param insn {@code non-null;} the instruction to visit
- */
- public void visitNonMoveInsn(NormalSsaInsn insn);
- }
+ public void visitNonMoveInsn(NormalSsaInsn insn);
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SsaMethod.java b/dx/src/com/android/jack/dx/ssa/SsaMethod.java
index f0166df..314bddb 100644
--- a/dx/src/com/android/jack/dx/ssa/SsaMethod.java
+++ b/dx/src/com/android/jack/dx/ssa/SsaMethod.java
@@ -39,835 +39,839 @@
* A method in SSA form.
*/
public final class SsaMethod {
- /** basic blocks, indexed by block index */
- private ArrayList<SsaBasicBlock> blocks;
+ /** basic blocks, indexed by block index */
+ private ArrayList<SsaBasicBlock> blocks;
- /** Index of first executed block in method */
- private int entryBlockIndex;
+ /** Index of first executed block in method */
+ private int entryBlockIndex;
- /**
- * Index of exit block, which exists only in SSA form,
- * or or {@code -1} if there is none
- */
- private int exitBlockIndex;
+ /**
+ * Index of exit block, which exists only in SSA form,
+ * or or {@code -1} if there is none
+ */
+ private int exitBlockIndex;
- /** total number of registers required */
- private int registerCount;
+ /** total number of registers required */
+ private int registerCount;
- /** first register number to use for any temporary "spares" */
- private int spareRegisterBase;
+ /** first register number to use for any temporary "spares" */
+ private int spareRegisterBase;
- /** current count of spare registers used */
- private int borrowedSpareRegisters;
+ /** current count of spare registers used */
+ private int borrowedSpareRegisters;
- /** really one greater than the max label */
- private int maxLabel;
+ /** really one greater than the max label */
+ private int maxLabel;
- /** the total width, in register-units, of the method's parameters */
- private final int paramWidth;
+ /** the total width, in register-units, of the method's parameters */
+ private final int paramWidth;
- /** true if this method has no {@code this} pointer argument */
- private final boolean isStatic;
+ /** true if this method has no {@code this} pointer argument */
+ private final boolean isStatic;
- /**
- * indexed by register: the insn where said register is defined or null
- * if undefined. null until (lazily) created.
- */
- private SsaInsn[] definitionList;
+ /**
+ * indexed by register: the insn where said register is defined or null
+ * if undefined. null until (lazily) created.
+ */
+ private SsaInsn[] definitionList;
- /** indexed by register: the list of all insns that use a register */
- private ArrayList<SsaInsn>[] useList;
+ /** indexed by register: the list of all insns that use a register */
+ private ArrayList<SsaInsn>[] useList;
- /** A version of useList with each List unmodifiable */
- private List<SsaInsn>[] unmodifiableUseList;
+ /** A version of useList with each List unmodifiable */
+ private List<SsaInsn>[] unmodifiableUseList;
- /**
- * "back-convert mode". Set during back-conversion when registers
- * are about to be mapped into a non-SSA namespace. When true,
- * use and def lists are unavailable.
- *
- * TODO: Remove this mode, and place the functionality elsewhere
- */
- private boolean backMode;
+ /**
+ * "back-convert mode". Set during back-conversion when registers
+ * are about to be mapped into a non-SSA namespace. When true,
+ * use and def lists are unavailable.
+ *
+ * TODO(dx team): Remove this mode, and place the functionality elsewhere
+ */
+ private boolean backMode;
- /**
- * @param ropMethod rop-form method to convert from
- * @param paramWidth the total width, in register-units, of the
- * method's parameters
- * @param isStatic {@code true} if this method has no {@code this}
- * pointer argument
- */
- public static SsaMethod newFromRopMethod(RopMethod ropMethod,
- int paramWidth, boolean isStatic) {
- SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
+ /**
+ * @param ropMethod rop-form method to convert from
+ * @param paramWidth the total width, in register-units, of the
+ * method's parameters
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ */
+ public static SsaMethod newFromRopMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) {
+ SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
- result.convertRopToSsaBlocks(ropMethod);
+ result.convertRopToSsaBlocks(ropMethod);
- return result;
+ return result;
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param ropMethod {@code non-null;} the original rop-form method that
+ * this instance is based on
+ * @param paramWidth the total width, in register-units, of the
+ * method's parameters
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ */
+ private SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) {
+ this.paramWidth = paramWidth;
+ this.isStatic = isStatic;
+ this.backMode = false;
+ this.maxLabel = ropMethod.getBlocks().getMaxLabel();
+ this.registerCount = ropMethod.getBlocks().getRegCount();
+ this.spareRegisterBase = registerCount;
+ }
+
+ /**
+ * Builds a BitSet of block indices from a basic block list and a list
+ * of labels taken from Rop form.
+ *
+ * @param blocks Rop blocks
+ * @param labelList list of rop block labels
+ * @return BitSet of block indices
+ */
+ static BitSet bitSetFromLabelList(BasicBlockList blocks, IntList labelList) {
+ BitSet result = new BitSet(blocks.size());
+
+ for (int i = 0, sz = labelList.size(); i < sz; i++) {
+ result.set(blocks.indexOfLabel(labelList.get(i)));
}
- /**
- * Constructs an instance.
- *
- * @param ropMethod {@code non-null;} the original rop-form method that
- * this instance is based on
- * @param paramWidth the total width, in register-units, of the
- * method's parameters
- * @param isStatic {@code true} if this method has no {@code this}
- * pointer argument
- */
- private SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) {
- this.paramWidth = paramWidth;
- this.isStatic = isStatic;
- this.backMode = false;
- this.maxLabel = ropMethod.getBlocks().getMaxLabel();
- this.registerCount = ropMethod.getBlocks().getRegCount();
- this.spareRegisterBase = registerCount;
+ return result;
+ }
+
+ /**
+ * Builds an IntList of block indices from a basic block list and a list
+ * of labels taken from Rop form.
+ *
+ * @param ropBlocks Rop blocks
+ * @param labelList list of rop block labels
+ * @return IntList of block indices
+ */
+ public static IntList indexListFromLabelList(BasicBlockList ropBlocks, IntList labelList) {
+
+ IntList result = new IntList(labelList.size());
+
+ for (int i = 0, sz = labelList.size(); i < sz; i++) {
+ result.add(ropBlocks.indexOfLabel(labelList.get(i)));
}
- /**
- * Builds a BitSet of block indices from a basic block list and a list
- * of labels taken from Rop form.
- *
- * @param blocks Rop blocks
- * @param labelList list of rop block labels
- * @return BitSet of block indices
- */
- static BitSet bitSetFromLabelList(BasicBlockList blocks,
- IntList labelList) {
- BitSet result = new BitSet(blocks.size());
+ return result;
+ }
- for (int i = 0, sz = labelList.size(); i < sz; i++) {
- result.set(blocks.indexOfLabel(labelList.get(i)));
+ private void convertRopToSsaBlocks(RopMethod rmeth) {
+ BasicBlockList ropBlocks = rmeth.getBlocks();
+ int sz = ropBlocks.size();
+
+ blocks = new ArrayList<SsaBasicBlock>(sz + 2);
+
+ for (int i = 0; i < sz; i++) {
+ SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
+ blocks.add(sbb);
+ }
+
+ // Add an no-op entry block.
+ int origEntryBlockIndex = rmeth.getBlocks().indexOfLabel(rmeth.getFirstLabel());
+
+ SsaBasicBlock entryBlock = blocks.get(origEntryBlockIndex).insertNewPredecessor();
+
+ entryBlockIndex = entryBlock.getIndex();
+ exitBlockIndex = -1; // This gets made later.
+ }
+
+ /**
+ * Creates an exit block and attaches it to the CFG if this method
+ * exits. Methods that never exit will not have an exit block. This
+ * is called after edge-splitting and phi insertion, since the edges
+ * going into the exit block should not be considered in those steps.
+ */
+ /*package*/void makeExitBlock() {
+ if (exitBlockIndex >= 0) {
+ throw new RuntimeException("must be called at most once");
+ }
+
+ exitBlockIndex = blocks.size();
+ SsaBasicBlock exitBlock = new SsaBasicBlock(exitBlockIndex, maxLabel++, this);
+
+ blocks.add(exitBlock);
+
+ for (SsaBasicBlock block : blocks) {
+ block.exitBlockFixup(exitBlock);
+ }
+
+ if (exitBlock.getPredecessors().cardinality() == 0) {
+ // In cases where there is no exit...
+ blocks.remove(exitBlockIndex);
+ exitBlockIndex = -1;
+ maxLabel--;
+ }
+ }
+
+ /**
+ * Gets a new {@code GOTO} insn.
+ *
+ * @param block block to which this GOTO will be added
+ * (not it's destination!)
+ * @return an appropriately-constructed instance.
+ */
+ private static SsaInsn getGoto(SsaBasicBlock block) {
+ return new NormalSsaInsn(
+ new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY), block);
+ }
+
+ /**
+ * Makes a new basic block for this method, which is empty besides
+ * a single {@code GOTO}. Successors and predecessors are not yet
+ * set.
+ *
+ * @return new block
+ */
+ public SsaBasicBlock makeNewGotoBlock() {
+ int newIndex = blocks.size();
+ SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this);
+
+ newBlock.getInsns().add(getGoto(newBlock));
+ blocks.add(newBlock);
+
+ return newBlock;
+ }
+
+ /**
+ * @return block index of first execution block
+ */
+ public int getEntryBlockIndex() {
+ return entryBlockIndex;
+ }
+
+ /**
+ * @return first execution block
+ */
+ public SsaBasicBlock getEntryBlock() {
+ return blocks.get(entryBlockIndex);
+ }
+
+ /**
+ * @return block index of exit block or {@code -1} if there is none
+ */
+ public int getExitBlockIndex() {
+ return exitBlockIndex;
+ }
+
+ /**
+ * @return {@code null-ok;} block of exit block or {@code null} if
+ * there is none
+ */
+ public SsaBasicBlock getExitBlock() {
+ return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex);
+ }
+
+ /**
+ * @param bi block index or {@code -1} for none
+ * @return rop label or {code -1} if {@code bi} was {@code -1}
+ */
+ public int blockIndexToRopLabel(int bi) {
+ if (bi < 0) {
+ return -1;
+ }
+ return blocks.get(bi).getRopLabel();
+ }
+
+ /**
+ * @return count of registers used in this method
+ */
+ public int getRegCount() {
+ return registerCount;
+ }
+
+ /**
+ * @return the total width, in register units, of the method's
+ * parameters
+ */
+ public int getParamWidth() {
+ return paramWidth;
+ }
+
+ /**
+ * Returns {@code true} if this is a static method.
+ *
+ * @return {@code true} if this is a static method
+ */
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ /**
+ * Borrows a register to use as a temp. Used in the phi removal process.
+ * Call returnSpareRegisters() when done.
+ *
+ * @param category width (1 or 2) of the register
+ * @return register number to use
+ */
+ public int borrowSpareRegister(int category) {
+ int result = spareRegisterBase + borrowedSpareRegisters;
+
+ borrowedSpareRegisters += category;
+ registerCount = Math.max(registerCount, result + category);
+
+ return result;
+ }
+
+ /**
+ * Returns all borrowed registers.
+ */
+ public void returnSpareRegisters() {
+ borrowedSpareRegisters = 0;
+ }
+
+ /**
+ * @return {@code non-null;} basic block list. Do not modify.
+ */
+ public ArrayList<SsaBasicBlock> getBlocks() {
+ return blocks;
+ }
+
+ /**
+ * Returns the count of reachable blocks in this method: blocks that have
+ * predecessors (or are the start block)
+ *
+ * @return {@code >= 0;} number of reachable basic blocks
+ */
+ public int getCountReachableBlocks() {
+ int ret = 0;
+
+ for (SsaBasicBlock b : blocks) {
+ // Blocks that have been disconnected don't count.
+ if (b.isReachable()) {
+ ret++;
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Computes reachability for all blocks in the method. First clears old
+ * values from all blocks, then starts with the entry block and walks down
+ * the control flow graph, marking all blocks it finds as reachable.
+ */
+ public void computeReachability() {
+ for (SsaBasicBlock block : blocks) {
+ block.setReachable(0);
+ }
+
+ ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
+ blockList.add(this.getEntryBlock());
+
+ while (!blockList.isEmpty()) {
+ SsaBasicBlock block = blockList.remove(0);
+ if (block.isReachable()) {
+ continue;
+ }
+
+ block.setReachable(1);
+ BitSet succs = block.getSuccessors();
+ for (int i = succs.nextSetBit(0); i >= 0; i = succs.nextSetBit(i + 1)) {
+ blockList.add(blocks.get(i));
+ }
+ }
+ }
+
+ /**
+ * Remaps unversioned registers.
+ *
+ * @param mapper maps old registers to new.
+ */
+ public void mapRegisters(RegisterMapper mapper) {
+ for (SsaBasicBlock block : getBlocks()) {
+ for (SsaInsn insn : block.getInsns()) {
+ insn.mapRegisters(mapper);
+ }
+ }
+
+ registerCount = mapper.getNewRegisterCount();
+ spareRegisterBase = registerCount;
+ }
+
+ /**
+ * Returns the insn that defines the given register
+ * @param reg register in question
+ * @return insn (actual instance from code) that defined this reg or null
+ * if reg is not defined.
+ */
+ public SsaInsn getDefinitionForRegister(int reg) {
+ if (backMode) {
+ throw new RuntimeException("No def list in back mode");
+ }
+
+ if (definitionList != null) {
+ return definitionList[reg];
+ }
+
+ definitionList = new SsaInsn[getRegCount()];
+
+ forEachInsn(new SsaInsn.Visitor() {
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ definitionList[insn.getResult().getReg()] = insn;
+ }
+
+ @Override
+ public void visitPhiInsn(PhiInsn phi) {
+ definitionList[phi.getResult().getReg()] = phi;
+ }
+
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ RegisterSpec result = insn.getResult();
+ if (result != null) {
+ definitionList[insn.getResult().getReg()] = insn;
}
+ }
+ });
- return result;
+ return definitionList[reg];
+ }
+
+ /**
+ * Builds useList and unmodifiableUseList.
+ */
+ @SuppressWarnings("unchecked")
+ private void buildUseList() {
+ if (backMode) {
+ throw new RuntimeException("No use list in back mode");
}
- /**
- * Builds an IntList of block indices from a basic block list and a list
- * of labels taken from Rop form.
- *
- * @param ropBlocks Rop blocks
- * @param labelList list of rop block labels
- * @return IntList of block indices
- */
- public static IntList indexListFromLabelList(BasicBlockList ropBlocks,
- IntList labelList) {
+ useList = new ArrayList[registerCount];
- IntList result = new IntList(labelList.size());
-
- for (int i = 0, sz = labelList.size(); i < sz; i++) {
- result.add(ropBlocks.indexOfLabel(labelList.get(i)));
- }
-
- return result;
+ for (int i = 0; i < registerCount; i++) {
+ useList[i] = new ArrayList<SsaInsn>();
}
- private void convertRopToSsaBlocks(RopMethod rmeth) {
- BasicBlockList ropBlocks = rmeth.getBlocks();
- int sz = ropBlocks.size();
+ forEachInsn(new SsaInsn.Visitor() {
+ /** {@inheritDoc} */
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ addToUses(insn);
+ }
- blocks = new ArrayList<SsaBasicBlock>(sz + 2);
+ /** {@inheritDoc} */
+ @Override
+ public void visitPhiInsn(PhiInsn phi) {
+ addToUses(phi);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ addToUses(insn);
+ }
+
+ /**
+ * Adds specified insn to the uses list for all of its sources.
+ * @param insn {@code non-null;} insn to process
+ */
+ private void addToUses(SsaInsn insn) {
+ RegisterSpecList rl = insn.getSources();
+ int sz = rl.size();
for (int i = 0; i < sz; i++) {
- SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
- blocks.add(sbb);
+ useList[rl.get(i).getReg()].add(insn);
}
+ }
+ });
- // Add an no-op entry block.
- int origEntryBlockIndex = rmeth.getBlocks()
- .indexOfLabel(rmeth.getFirstLabel());
+ unmodifiableUseList = new List[registerCount];
- SsaBasicBlock entryBlock
- = blocks.get(origEntryBlockIndex).insertNewPredecessor();
+ for (int i = 0; i < registerCount; i++) {
+ unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
+ }
+ }
- entryBlockIndex = entryBlock.getIndex();
- exitBlockIndex = -1; // This gets made later.
+ /**
+ * Updates the use list for a single change in source register.
+ *
+ * @param insn {@code non-null;} insn being changed
+ * @param oldSource {@code null-ok;} The source that was used, if
+ * applicable
+ * @param newSource {@code non-null;} the new source being used
+ */
+ /*package*/void onSourceChanged(SsaInsn insn, RegisterSpec oldSource, RegisterSpec newSource) {
+ if (useList == null) {
+ return;
}
- /**
- * Creates an exit block and attaches it to the CFG if this method
- * exits. Methods that never exit will not have an exit block. This
- * is called after edge-splitting and phi insertion, since the edges
- * going into the exit block should not be considered in those steps.
- */
- /*package*/ void makeExitBlock() {
- if (exitBlockIndex >= 0) {
- throw new RuntimeException("must be called at most once");
+ if (oldSource != null) {
+ int reg = oldSource.getReg();
+ useList[reg].remove(insn);
+ }
+
+ int reg = newSource.getReg();
+ if (useList.length <= reg) {
+ useList = null;
+ return;
+ }
+ useList[reg].add(insn);
+ }
+
+ /**
+ * Updates the use list for a source list change.
+ *
+ * @param insn {@code insn non-null;} insn being changed.
+ * {@code insn.getSources()} must return the new source list.
+ * @param oldSources {@code null-ok;} list of sources that were
+ * previously used
+ */
+ /*package*/void onSourcesChanged(SsaInsn insn, RegisterSpecList oldSources) {
+ if (useList == null) {
+ return;
+ }
+
+ if (oldSources != null) {
+ removeFromUseList(insn, oldSources);
+ }
+
+ RegisterSpecList sources = insn.getSources();
+ int szNew = sources.size();
+
+ for (int i = 0; i < szNew; i++) {
+ int reg = sources.get(i).getReg();
+ useList[reg].add(insn);
+ }
+ }
+
+ /**
+ * Removes a given {@code insn} from the use lists for the given
+ * {@code oldSources} (rather than the sources currently
+ * returned by insn.getSources()).
+ *
+ * @param insn {@code non-null;} insn in question
+ * @param oldSources {@code null-ok;} registers whose use lists
+ * {@code insn} should be removed form
+ */
+ private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) {
+ if (oldSources == null) {
+ return;
+ }
+
+ int szNew = oldSources.size();
+ for (int i = 0; i < szNew; i++) {
+ if (!useList[oldSources.get(i).getReg()].remove(insn)) {
+ throw new RuntimeException("use not found");
+ }
+ }
+ }
+
+ /**
+ * Adds an insn to both the use and def lists. For use when adding
+ * a new insn to the method.
+ *
+ * @param insn {@code non-null;} insn to add
+ */
+ /*package*/void onInsnAdded(SsaInsn insn) {
+ onSourcesChanged(insn, null);
+ updateOneDefinition(insn, null);
+ }
+
+ /**
+ * Removes an instruction from use and def lists. For use during
+ * instruction removal.
+ *
+ * @param insn {@code non-null;} insn to remove
+ */
+ /*package*/void onInsnRemoved(SsaInsn insn) {
+ if (useList != null) {
+ removeFromUseList(insn, insn.getSources());
+ }
+
+ RegisterSpec resultReg = insn.getResult();
+ if (definitionList != null && resultReg != null) {
+ definitionList[resultReg.getReg()] = null;
+ }
+ }
+
+ /**
+ * Indicates that the instruction list has changed or the SSA register
+ * count has increased, so that internal datastructures that rely on
+ * it should be rebuild. In general, the various other on* methods
+ * should be called in preference when changes occur if they are
+ * applicable.
+ */
+ public void onInsnsChanged() {
+ // Definition list will need to be recomputed
+ definitionList = null;
+
+ // Use list will need to be recomputed
+ useList = null;
+ unmodifiableUseList = null;
+ }
+
+ /**
+ * Updates a single definition.
+ *
+ * @param insn {@code non-null;} insn who's result should be recorded as
+ * a definition
+ * @param oldResult {@code null-ok;} a previous result that should
+ * be no longer considered a definition by this insn
+ */
+ /*package*/void updateOneDefinition(SsaInsn insn, RegisterSpec oldResult) {
+ if (definitionList == null) {
+ return;
+ }
+
+ if (oldResult != null) {
+ int reg = oldResult.getReg();
+ definitionList[reg] = null;
+ }
+
+ RegisterSpec resultReg = insn.getResult();
+
+ if (resultReg != null) {
+ int reg = resultReg.getReg();
+
+ if (definitionList[reg] != null) {
+ throw new RuntimeException("Duplicate add of insn");
+ } else {
+ definitionList[resultReg.getReg()] = insn;
+ }
+ }
+ }
+
+ /**
+ * Returns the list of all source uses (not results) for a register.
+ *
+ * @param reg register in question
+ * @return unmodifiable instruction list
+ */
+ public List<SsaInsn> getUseListForRegister(int reg) {
+
+ if (unmodifiableUseList == null) {
+ buildUseList();
+ }
+
+ return unmodifiableUseList[reg];
+ }
+
+ /**
+ * Returns a modifiable copy of the register use list.
+ *
+ * @return modifiable copy of the use-list, indexed by register
+ */
+ public ArrayList<SsaInsn>[] getUseListCopy() {
+ if (useList == null) {
+ buildUseList();
+ }
+
+ @SuppressWarnings("unchecked")
+ ArrayList<SsaInsn>[] useListCopy = new ArrayList[registerCount];
+
+ for (int i = 0; i < registerCount; i++) {
+ useListCopy[i] = new ArrayList<SsaInsn>(useList[i]);
+ }
+
+ return useListCopy;
+ }
+
+ /**
+ * Checks to see if the given SSA reg is ever associated with a local
+ * local variable. Each SSA reg may be associated with at most one
+ * local var.
+ *
+ * @param spec {@code non-null;} ssa reg
+ * @return true if reg is ever associated with a local
+ */
+ public boolean isRegALocal(RegisterSpec spec) {
+ SsaInsn defn = getDefinitionForRegister(spec.getReg());
+
+ if (defn == null) {
+ // version 0 registers are never used as locals
+ return false;
+ }
+
+ // Does the definition have a local associated with it?
+ if (defn.getLocalAssignment() != null) {
+ return true;
+ }
+
+ // If not, is there a mark-local insn?
+ for (SsaInsn use : getUseListForRegister(spec.getReg())) {
+ Insn insn = use.getOriginalRopInsn();
+
+ if (insn != null && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets the new register count after renaming.
+ *
+ * @param newRegCount new register count
+ */
+ /*package*/void setNewRegCount(int newRegCount) {
+ registerCount = newRegCount;
+ spareRegisterBase = registerCount;
+ onInsnsChanged();
+ }
+
+ /**
+ * Makes a new SSA register. For use after renaming has completed.
+ *
+ * @return {@code >=0;} new SSA register.
+ */
+ public int makeNewSsaReg() {
+ int reg = registerCount++;
+ spareRegisterBase = registerCount;
+ onInsnsChanged();
+ return reg;
+ }
+
+ /**
+ * Visits all insns in this method.
+ *
+ * @param visitor {@code non-null;} callback interface
+ */
+ public void forEachInsn(SsaInsn.Visitor visitor) {
+ for (SsaBasicBlock block : blocks) {
+ block.forEachInsn(visitor);
+ }
+ }
+
+ /**
+ * Visits each phi insn in this method
+ * @param v {@code non-null;} callback.
+ *
+ */
+ public void forEachPhiInsn(PhiInsn.Visitor v) {
+ for (SsaBasicBlock block : blocks) {
+ block.forEachPhiInsn(v);
+ }
+ }
+
+
+ /**
+ * Walks the basic block tree in depth-first order, calling the visitor
+ * method once for every block. This depth-first walk may be run forward
+ * from the method entry point or backwards from the method exit points.
+ *
+ * @param reverse true if this should walk backwards from the exit points
+ * @param v {@code non-null;} callback interface. {@code parent} is set
+ * unless this is the root node
+ */
+ public void forEachBlockDepthFirst(boolean reverse, SsaBasicBlock.Visitor v) {
+ BitSet visited = new BitSet(blocks.size());
+
+ // We push the parent first, then the child on the stack.
+ Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
+
+ SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
+
+ if (rootBlock == null) {
+ // in the case there's no exit block
+ return;
+ }
+
+ stack.add(null); // Start with null parent.
+ stack.add(rootBlock);
+
+ while (stack.size() > 0) {
+ SsaBasicBlock cur = stack.pop();
+ SsaBasicBlock parent = stack.pop();
+
+ if (!visited.get(cur.getIndex())) {
+ BitSet children = reverse ? cur.getPredecessors() : cur.getSuccessors();
+ for (int i = children.nextSetBit(0); i >= 0; i = children.nextSetBit(i + 1)) {
+ stack.add(cur);
+ stack.add(blocks.get(i));
}
+ visited.set(cur.getIndex());
+ v.visitBlock(cur, parent);
+ }
+ }
+ }
- exitBlockIndex = blocks.size();
- SsaBasicBlock exitBlock
- = new SsaBasicBlock(exitBlockIndex, maxLabel++, this);
+ /**
+ * Visits blocks in dom-tree order, starting at the current node.
+ * The {@code parent} parameter of the Visitor.visitBlock callback
+ * is currently always set to null.
+ *
+ * @param v {@code non-null;} callback interface
+ */
+ public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
+ BitSet visited = new BitSet(getBlocks().size());
+ Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
- blocks.add(exitBlock);
+ stack.add(getEntryBlock());
- for (SsaBasicBlock block : blocks) {
- block.exitBlockFixup(exitBlock);
+ while (stack.size() > 0) {
+ SsaBasicBlock cur = stack.pop();
+ ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
+
+ if (!visited.get(cur.getIndex())) {
+ // We walk the tree this way for historical reasons...
+ for (int i = curDomChildren.size() - 1; i >= 0; i--) {
+ SsaBasicBlock child = curDomChildren.get(i);
+ stack.add(child);
}
+ visited.set(cur.getIndex());
+ v.visitBlock(cur, null);
+ }
+ }
+ }
- if (exitBlock.getPredecessors().cardinality() == 0) {
- // In cases where there is no exit...
- blocks.remove(exitBlockIndex);
- exitBlockIndex = -1;
- maxLabel--;
+ /**
+ * Deletes all insns in the set from this method.
+ *
+ * @param deletedInsns {@code non-null;} insns to delete
+ */
+ public void deleteInsns(Set<SsaInsn> deletedInsns) {
+ for (SsaBasicBlock block : getBlocks()) {
+ ArrayList<SsaInsn> insns = block.getInsns();
+
+ for (int i = insns.size() - 1; i >= 0; i--) {
+ SsaInsn insn = insns.get(i);
+
+ if (deletedInsns.contains(insn)) {
+ onInsnRemoved(insn);
+ insns.remove(i);
}
- }
+ }
- /**
- * Gets a new {@code GOTO} insn.
- *
- * @param block block to which this GOTO will be added
- * (not it's destination!)
- * @return an appropriately-constructed instance.
- */
- private static SsaInsn getGoto(SsaBasicBlock block) {
- return new NormalSsaInsn (
- new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO,
- null, RegisterSpecList.EMPTY), block);
- }
+ // Check to see if we need to add a GOTO
- /**
- * Makes a new basic block for this method, which is empty besides
- * a single {@code GOTO}. Successors and predecessors are not yet
- * set.
- *
- * @return new block
- */
- public SsaBasicBlock makeNewGotoBlock() {
- int newIndex = blocks.size();
- SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this);
+ int insnsSz = insns.size();
+ SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
- newBlock.getInsns().add(getGoto(newBlock));
- blocks.add(newBlock);
+ if (block != getExitBlock() && (insnsSz == 0 || lastInsn.getOriginalRopInsn() == null
+ || lastInsn.getOriginalRopInsn().getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
+ // We managed to eat a throwable insn
- return newBlock;
- }
+ Insn gotoInsn =
+ new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
+ insns.add(SsaInsn.makeFromRop(gotoInsn, block));
- /**
- * @return block index of first execution block
- */
- public int getEntryBlockIndex() {
- return entryBlockIndex;
- }
-
- /**
- * @return first execution block
- */
- public SsaBasicBlock getEntryBlock() {
- return blocks.get(entryBlockIndex);
- }
-
- /**
- * @return block index of exit block or {@code -1} if there is none
- */
- public int getExitBlockIndex() {
- return exitBlockIndex;
- }
-
- /**
- * @return {@code null-ok;} block of exit block or {@code null} if
- * there is none
- */
- public SsaBasicBlock getExitBlock() {
- return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex);
- }
-
- /**
- * @param bi block index or {@code -1} for none
- * @return rop label or {code -1} if {@code bi} was {@code -1}
- */
- public int blockIndexToRopLabel(int bi) {
- if (bi < 0) {
- return -1;
+ // Remove secondary successors from this block
+ BitSet succs = block.getSuccessors();
+ for (int i = succs.nextSetBit(0); i >= 0; i = succs.nextSetBit(i + 1)) {
+ if (i != block.getPrimarySuccessorIndex()) {
+ block.removeSuccessor(i);
+ }
}
- return blocks.get(bi).getRopLabel();
+ }
}
+ }
- /**
- * @return count of registers used in this method
- */
- public int getRegCount() {
- return registerCount;
- }
-
- /**
- * @return the total width, in register units, of the method's
- * parameters
- */
- public int getParamWidth() {
- return paramWidth;
- }
-
- /**
- * Returns {@code true} if this is a static method.
- *
- * @return {@code true} if this is a static method
- */
- public boolean isStatic() {
- return isStatic;
- }
-
- /**
- * Borrows a register to use as a temp. Used in the phi removal process.
- * Call returnSpareRegisters() when done.
- *
- * @param category width (1 or 2) of the register
- * @return register number to use
- */
- public int borrowSpareRegister(int category) {
- int result = spareRegisterBase + borrowedSpareRegisters;
-
- borrowedSpareRegisters += category;
- registerCount = Math.max(registerCount, result + category);
-
- return result;
- }
-
- /**
- * Returns all borrowed registers.
- */
- public void returnSpareRegisters() {
- borrowedSpareRegisters = 0;
- }
-
- /**
- * @return {@code non-null;} basic block list. Do not modify.
- */
- public ArrayList<SsaBasicBlock> getBlocks() {
- return blocks;
- }
-
- /**
- * Returns the count of reachable blocks in this method: blocks that have
- * predecessors (or are the start block)
- *
- * @return {@code >= 0;} number of reachable basic blocks
- */
- public int getCountReachableBlocks() {
- int ret = 0;
-
- for (SsaBasicBlock b : blocks) {
- // Blocks that have been disconnected don't count.
- if (b.isReachable()) {
- ret++;
- }
- }
-
- return ret;
- }
-
- /**
- * Computes reachability for all blocks in the method. First clears old
- * values from all blocks, then starts with the entry block and walks down
- * the control flow graph, marking all blocks it finds as reachable.
- */
- public void computeReachability() {
- for (SsaBasicBlock block : blocks) {
- block.setReachable(0);
- }
-
- ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
- blockList.add(this.getEntryBlock());
-
- while (!blockList.isEmpty()) {
- SsaBasicBlock block = blockList.remove(0);
- if (block.isReachable()) continue;
-
- block.setReachable(1);
- BitSet succs = block.getSuccessors();
- for (int i = succs.nextSetBit(0); i >= 0;
- i = succs.nextSetBit(i + 1)) {
- blockList.add(blocks.get(i));
- }
- }
- }
-
- /**
- * Remaps unversioned registers.
- *
- * @param mapper maps old registers to new.
- */
- public void mapRegisters(RegisterMapper mapper) {
- for (SsaBasicBlock block : getBlocks()) {
- for (SsaInsn insn : block.getInsns()) {
- insn.mapRegisters(mapper);
- }
- }
-
- registerCount = mapper.getNewRegisterCount();
- spareRegisterBase = registerCount;
- }
-
- /**
- * Returns the insn that defines the given register
- * @param reg register in question
- * @return insn (actual instance from code) that defined this reg or null
- * if reg is not defined.
- */
- public SsaInsn getDefinitionForRegister(int reg) {
- if (backMode) {
- throw new RuntimeException("No def list in back mode");
- }
-
- if (definitionList != null) {
- return definitionList[reg];
- }
-
- definitionList = new SsaInsn[getRegCount()];
-
- forEachInsn(new SsaInsn.Visitor() {
- public void visitMoveInsn (NormalSsaInsn insn) {
- definitionList[insn.getResult().getReg()] = insn;
- }
- public void visitPhiInsn (PhiInsn phi) {
- definitionList[phi.getResult().getReg()] = phi;
- }
- public void visitNonMoveInsn (NormalSsaInsn insn) {
- RegisterSpec result = insn.getResult();
- if (result != null) {
- definitionList[insn.getResult().getReg()] = insn;
- }
- }
- });
-
- return definitionList[reg];
- }
-
- /**
- * Builds useList and unmodifiableUseList.
- */
- private void buildUseList() {
- if (backMode) {
- throw new RuntimeException("No use list in back mode");
- }
-
- useList = new ArrayList[registerCount];
-
- for (int i = 0; i < registerCount; i++) {
- useList[i] = new ArrayList();
- }
-
- forEachInsn(new SsaInsn.Visitor() {
- /** {@inheritDoc} */
- public void visitMoveInsn (NormalSsaInsn insn) {
- addToUses(insn);
- }
- /** {@inheritDoc} */
- public void visitPhiInsn (PhiInsn phi) {
- addToUses(phi);
- }
- /** {@inheritDoc} */
- public void visitNonMoveInsn (NormalSsaInsn insn) {
- addToUses(insn);
- }
- /**
- * Adds specified insn to the uses list for all of its sources.
- * @param insn {@code non-null;} insn to process
- */
- private void addToUses(SsaInsn insn) {
- RegisterSpecList rl = insn.getSources();
- int sz = rl.size();
-
- for (int i = 0; i < sz; i++) {
- useList[rl.get(i).getReg()].add(insn);
- }
- }
- });
-
- unmodifiableUseList = new List[registerCount];
-
- for (int i = 0; i < registerCount; i++) {
- unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
- }
- }
-
- /**
- * Updates the use list for a single change in source register.
- *
- * @param insn {@code non-null;} insn being changed
- * @param oldSource {@code null-ok;} The source that was used, if
- * applicable
- * @param newSource {@code non-null;} the new source being used
- */
- /*package*/ void onSourceChanged(SsaInsn insn,
- RegisterSpec oldSource, RegisterSpec newSource) {
- if (useList == null) return;
-
- if (oldSource != null) {
- int reg = oldSource.getReg();
- useList[reg].remove(insn);
- }
-
- int reg = newSource.getReg();
- if (useList.length <= reg) {
- useList = null;
- return;
- }
- useList[reg].add(insn);
- }
-
- /**
- * Updates the use list for a source list change.
- *
- * @param insn {@code insn non-null;} insn being changed.
- * {@code insn.getSources()} must return the new source list.
- * @param oldSources {@code null-ok;} list of sources that were
- * previously used
- */
- /*package*/ void onSourcesChanged(SsaInsn insn,
- RegisterSpecList oldSources) {
- if (useList == null) return;
-
- if (oldSources != null) {
- removeFromUseList(insn, oldSources);
- }
-
- RegisterSpecList sources = insn.getSources();
- int szNew = sources.size();
-
- for (int i = 0; i < szNew; i++) {
- int reg = sources.get(i).getReg();
- useList[reg].add(insn);
- }
- }
-
- /**
- * Removes a given {@code insn} from the use lists for the given
- * {@code oldSources} (rather than the sources currently
- * returned by insn.getSources()).
- *
- * @param insn {@code non-null;} insn in question
- * @param oldSources {@code null-ok;} registers whose use lists
- * {@code insn} should be removed form
- */
- private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) {
- if (oldSources == null) {
- return;
- }
-
- int szNew = oldSources.size();
- for (int i = 0; i < szNew; i++) {
- if (!useList[oldSources.get(i).getReg()].remove(insn)) {
- throw new RuntimeException("use not found");
- }
- }
- }
-
- /**
- * Adds an insn to both the use and def lists. For use when adding
- * a new insn to the method.
- *
- * @param insn {@code non-null;} insn to add
- */
- /*package*/ void onInsnAdded(SsaInsn insn) {
- onSourcesChanged(insn, null);
- updateOneDefinition(insn, null);
- }
-
- /**
- * Removes an instruction from use and def lists. For use during
- * instruction removal.
- *
- * @param insn {@code non-null;} insn to remove
- */
- /*package*/ void onInsnRemoved(SsaInsn insn) {
- if (useList != null) {
- removeFromUseList(insn, insn.getSources());
- }
-
- RegisterSpec resultReg = insn.getResult();
- if (definitionList != null && resultReg != null) {
- definitionList[resultReg.getReg()] = null;
- }
- }
-
- /**
- * Indicates that the instruction list has changed or the SSA register
- * count has increased, so that internal datastructures that rely on
- * it should be rebuild. In general, the various other on* methods
- * should be called in preference when changes occur if they are
- * applicable.
- */
- public void onInsnsChanged() {
- // Definition list will need to be recomputed
- definitionList = null;
-
- // Use list will need to be recomputed
- useList = null;
- unmodifiableUseList = null;
- }
-
- /**
- * Updates a single definition.
- *
- * @param insn {@code non-null;} insn who's result should be recorded as
- * a definition
- * @param oldResult {@code null-ok;} a previous result that should
- * be no longer considered a definition by this insn
- */
- /*package*/ void updateOneDefinition(SsaInsn insn,
- RegisterSpec oldResult) {
- if (definitionList == null) return;
-
- if (oldResult != null) {
- int reg = oldResult.getReg();
- definitionList[reg] = null;
- }
-
- RegisterSpec resultReg = insn.getResult();
-
- if (resultReg != null) {
- int reg = resultReg.getReg();
-
- if (definitionList[reg] != null) {
- throw new RuntimeException("Duplicate add of insn");
- } else {
- definitionList[resultReg.getReg()] = insn;
- }
- }
- }
-
- /**
- * Returns the list of all source uses (not results) for a register.
- *
- * @param reg register in question
- * @return unmodifiable instruction list
- */
- public List<SsaInsn> getUseListForRegister(int reg) {
-
- if (unmodifiableUseList == null) {
- buildUseList();
- }
-
- return unmodifiableUseList[reg];
- }
-
- /**
- * Returns a modifiable copy of the register use list.
- *
- * @return modifiable copy of the use-list, indexed by register
- */
- public ArrayList<SsaInsn>[] getUseListCopy() {
- if (useList == null) {
- buildUseList();
- }
-
- ArrayList<SsaInsn>[] useListCopy
- = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]);
-
- for (int i = 0; i < registerCount; i++) {
- useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i]));
- }
-
- return useListCopy;
- }
-
- /**
- * Checks to see if the given SSA reg is ever associated with a local
- * local variable. Each SSA reg may be associated with at most one
- * local var.
- *
- * @param spec {@code non-null;} ssa reg
- * @return true if reg is ever associated with a local
- */
- public boolean isRegALocal(RegisterSpec spec) {
- SsaInsn defn = getDefinitionForRegister(spec.getReg());
-
- if (defn == null) {
- // version 0 registers are never used as locals
- return false;
- }
-
- // Does the definition have a local associated with it?
- if (defn.getLocalAssignment() != null) return true;
-
- // If not, is there a mark-local insn?
- for (SsaInsn use : getUseListForRegister(spec.getReg())) {
- Insn insn = use.getOriginalRopInsn();
-
- if (insn != null
- && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Sets the new register count after renaming.
- *
- * @param newRegCount new register count
- */
- /*package*/ void setNewRegCount(int newRegCount) {
- registerCount = newRegCount;
- spareRegisterBase = registerCount;
- onInsnsChanged();
- }
-
- /**
- * Makes a new SSA register. For use after renaming has completed.
- *
- * @return {@code >=0;} new SSA register.
- */
- public int makeNewSsaReg() {
- int reg = registerCount++;
- spareRegisterBase = registerCount;
- onInsnsChanged();
- return reg;
- }
-
- /**
- * Visits all insns in this method.
- *
- * @param visitor {@code non-null;} callback interface
- */
- public void forEachInsn(SsaInsn.Visitor visitor) {
- for (SsaBasicBlock block : blocks) {
- block.forEachInsn(visitor);
- }
- }
-
- /**
- * Visits each phi insn in this method
- * @param v {@code non-null;} callback.
- *
- */
- public void forEachPhiInsn(PhiInsn.Visitor v) {
- for (SsaBasicBlock block : blocks) {
- block.forEachPhiInsn(v);
- }
- }
-
-
- /**
- * Walks the basic block tree in depth-first order, calling the visitor
- * method once for every block. This depth-first walk may be run forward
- * from the method entry point or backwards from the method exit points.
- *
- * @param reverse true if this should walk backwards from the exit points
- * @param v {@code non-null;} callback interface. {@code parent} is set
- * unless this is the root node
- */
- public void forEachBlockDepthFirst(boolean reverse,
- SsaBasicBlock.Visitor v) {
- BitSet visited = new BitSet(blocks.size());
-
- // We push the parent first, then the child on the stack.
- Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
-
- SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
-
- if (rootBlock == null) {
- // in the case there's no exit block
- return;
- }
-
- stack.add(null); // Start with null parent.
- stack.add(rootBlock);
-
- while (stack.size() > 0) {
- SsaBasicBlock cur = stack.pop();
- SsaBasicBlock parent = stack.pop();
-
- if (!visited.get(cur.getIndex())) {
- BitSet children
- = reverse ? cur.getPredecessors() : cur.getSuccessors();
- for (int i = children.nextSetBit(0); i >= 0
- ; i = children.nextSetBit(i + 1)) {
- stack.add(cur);
- stack.add(blocks.get(i));
- }
- visited.set(cur.getIndex());
- v.visitBlock(cur, parent);
- }
- }
- }
-
- /**
- * Visits blocks in dom-tree order, starting at the current node.
- * The {@code parent} parameter of the Visitor.visitBlock callback
- * is currently always set to null.
- *
- * @param v {@code non-null;} callback interface
- */
- public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
- BitSet visited = new BitSet(getBlocks().size());
- Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
-
- stack.add(getEntryBlock());
-
- while (stack.size() > 0) {
- SsaBasicBlock cur = stack.pop();
- ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
-
- if (!visited.get(cur.getIndex())) {
- // We walk the tree this way for historical reasons...
- for (int i = curDomChildren.size() - 1; i >= 0; i--) {
- SsaBasicBlock child = curDomChildren.get(i);
- stack.add(child);
- }
- visited.set(cur.getIndex());
- v.visitBlock(cur, null);
- }
- }
- }
-
- /**
- * Deletes all insns in the set from this method.
- *
- * @param deletedInsns {@code non-null;} insns to delete
- */
- public void deleteInsns(Set<SsaInsn> deletedInsns) {
- for (SsaBasicBlock block : getBlocks()) {
- ArrayList<SsaInsn> insns = block.getInsns();
-
- for (int i = insns.size() - 1; i >= 0; i--) {
- SsaInsn insn = insns.get(i);
-
- if (deletedInsns.contains(insn)) {
- onInsnRemoved(insn);
- insns.remove(i);
- }
- }
-
- // Check to see if we need to add a GOTO
-
- int insnsSz = insns.size();
- SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
-
- if (block != getExitBlock() && (insnsSz == 0
- || lastInsn.getOriginalRopInsn() == null
- || lastInsn.getOriginalRopInsn().getOpcode()
- .getBranchingness() == Rop.BRANCH_NONE)) {
- // We managed to eat a throwable insn
-
- Insn gotoInsn = new PlainInsn(Rops.GOTO,
- SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
- insns.add(SsaInsn.makeFromRop(gotoInsn, block));
-
- // Remove secondary successors from this block
- BitSet succs = block.getSuccessors();
- for (int i = succs.nextSetBit(0); i >= 0;
- i = succs.nextSetBit(i + 1)) {
- if (i != block.getPrimarySuccessorIndex()) {
- block.removeSuccessor(i);
- }
- }
- }
- }
- }
-
- /**
- * Sets "back-convert mode". Set during back-conversion when registers
- * are about to be mapped into a non-SSA namespace. When true,
- * use and def lists are unavailable.
- */
- public void setBackMode() {
- backMode = true;
- useList = null;
- definitionList = null;
- }
+ /**
+ * Sets "back-convert mode". Set during back-conversion when registers
+ * are about to be mapped into a non-SSA namespace. When true,
+ * use and def lists are unavailable.
+ */
+ public void setBackMode() {
+ backMode = true;
+ useList = null;
+ definitionList = null;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/SsaRenamer.java b/dx/src/com/android/jack/dx/ssa/SsaRenamer.java
index be9c51b..e1c5d78 100644
--- a/dx/src/com/android/jack/dx/ssa/SsaRenamer.java
+++ b/dx/src/com/android/jack/dx/ssa/SsaRenamer.java
@@ -60,603 +60,595 @@
* and used as the initial state for child blocks.<p>
*/
public class SsaRenamer implements Runnable {
- /** debug flag */
- private static final boolean DEBUG = false;
+ /** debug flag */
+ private static final boolean DEBUG = false;
- /** method we're processing */
- private final SsaMethod ssaMeth;
+ /** method we're processing */
+ private final SsaMethod ssaMeth;
- /** next available SSA register */
- private int nextSsaReg;
+ /** next available SSA register */
+ private int nextSsaReg;
- /** the number of original rop registers */
- private final int ropRegCount;
+ /** the number of original rop registers */
+ private final int ropRegCount;
- /** work only on registers above this value */
- private int threshold;
+ /** work only on registers above this value */
+ private int threshold;
- /**
- * indexed by block index; register version state for each block start.
- * This list is updated by each dom parent for its children. The only
- * sub-arrays that exist at any one time are the start states for blocks
- * yet to be processed by a {@code BlockRenamer} instance.
+ /**
+ * indexed by block index; register version state for each block start.
+ * This list is updated by each dom parent for its children. The only
+ * sub-arrays that exist at any one time are the start states for blocks
+ * yet to be processed by a {@code BlockRenamer} instance.
+ */
+ private final RegisterSpec[][] startsForBlocks;
+
+ /** map of SSA register number to debug (local var names) or null of n/a */
+ private final ArrayList<LocalItem> ssaRegToLocalItems;
+
+ /**
+ * maps SSA registers back to the original rop number. Used for
+ * debug only.
+ */
+ private IntList ssaRegToRopReg;
+
+ /**
+ * Constructs an instance of the renamer
+ *
+ * @param ssaMeth {@code non-null;} un-renamed SSA method that will
+ * be renamed.
+ */
+ public SsaRenamer(SsaMethod ssaMeth) {
+ ropRegCount = ssaMeth.getRegCount();
+
+ this.ssaMeth = ssaMeth;
+
+ /*
+ * Reserve the first N registers in the SSA register space for
+ * "version 0" registers.
*/
- private final RegisterSpec[][] startsForBlocks;
+ nextSsaReg = ropRegCount;
+ threshold = 0;
+ startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][];
- /** map of SSA register number to debug (local var names) or null of n/a */
- private final ArrayList<LocalItem> ssaRegToLocalItems;
+ ssaRegToLocalItems = new ArrayList<LocalItem>();
- /**
- * maps SSA registers back to the original rop number. Used for
- * debug only.
- */
- private IntList ssaRegToRopReg;
+ if (DEBUG) {
+ ssaRegToRopReg = new IntList(ropRegCount);
+ }
- /**
- * Constructs an instance of the renamer
+ /*
+ * Appel 19.7
*
- * @param ssaMeth {@code non-null;} un-renamed SSA method that will
- * be renamed.
+ * Initialization:
+ * for each variable a // register i
+ * Count[a] <- 0 // nextSsaReg, flattened
+ * Stack[a] <- 0 // versionStack
+ * push 0 onto Stack[a]
+ *
*/
- public SsaRenamer(SsaMethod ssaMeth) {
- ropRegCount = ssaMeth.getRegCount();
- this.ssaMeth = ssaMeth;
+// top entry for the version stack is version 0
+ RegisterSpec[] initialRegMapping = new RegisterSpec[ropRegCount];
+ for (int i = 0; i < ropRegCount; i++) {
+ // everyone starts with a version 0 register
+ initialRegMapping[i] = RegisterSpec.make(i, Type.VOID);
- /*
- * Reserve the first N registers in the SSA register space for
- * "version 0" registers.
- */
- nextSsaReg = ropRegCount;
- threshold = 0;
- startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][];
+ if (DEBUG) {
+ ssaRegToRopReg.add(i);
+ }
+ }
- ssaRegToLocalItems = new ArrayList<LocalItem>();
+ // Initial state for entry block
+ startsForBlocks[ssaMeth.getEntryBlockIndex()] = initialRegMapping;
+ }
+ /**
+ * Constructs an instance of the renamer with threshold set
+ *
+ * @param ssaMeth {@code non-null;} un-renamed SSA method that will
+ * be renamed.
+ * @param thresh registers below this number are unchanged
+ */
+ public SsaRenamer(SsaMethod ssaMeth, int thresh) {
+ this(ssaMeth);
+ threshold = thresh;
+ }
+
+ /**
+ * Performs renaming transformation, modifying the method's instructions
+ * in-place.
+ */
+ @Override
+ public void run() {
+ // Rename each block in dom-tree DFS order.
+ ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
+ @Override
+ public void visitBlock(SsaBasicBlock block, SsaBasicBlock unused) {
+ new BlockRenamer(block).process();
+ }
+ });
+
+ ssaMeth.setNewRegCount(nextSsaReg);
+ ssaMeth.onInsnsChanged();
+
+ if (DEBUG) {
+ System.out.println("SSA\tRop");
+ /*
+ * We're going to compute the version of the rop register
+ * by keeping a running total of how many times the rop
+ * register has been mapped.
+ */
+ int[] versions = new int[ropRegCount];
+
+ int sz = ssaRegToRopReg.size();
+ for (int i = 0; i < sz; i++) {
+ int ropReg = ssaRegToRopReg.get(i);
+ System.out.println(i + "\t" + ropReg + "[" + versions[ropReg] + "]");
+ versions[ropReg]++;
+ }
+ }
+ }
+
+ /**
+ * Duplicates a RegisterSpec array.
+ *
+ * @param orig {@code non-null;} array to duplicate
+ * @return {@code non-null;} new instance
+ */
+ private static RegisterSpec[] dupArray(RegisterSpec[] orig) {
+ RegisterSpec[] copy = new RegisterSpec[orig.length];
+
+ System.arraycopy(orig, 0, copy, 0, orig.length);
+
+ return copy;
+ }
+
+ /**
+ * Gets a local variable item for a specified register.
+ *
+ * @param ssaReg register in SSA name space
+ * @return {@code null-ok;} Local variable name or null if none
+ */
+ private LocalItem getLocalForNewReg(int ssaReg) {
+ if (ssaReg < ssaRegToLocalItems.size()) {
+ return ssaRegToLocalItems.get(ssaReg);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Records a debug (local variable) name for a specified register.
+ *
+ * @param ssaReg non-null named register spec in SSA name space
+ */
+ private void setNameForSsaReg(RegisterSpec ssaReg) {
+ int reg = ssaReg.getReg();
+ LocalItem local = ssaReg.getLocalItem();
+
+ ssaRegToLocalItems.ensureCapacity(reg + 1);
+ while (ssaRegToLocalItems.size() <= reg) {
+ ssaRegToLocalItems.add(null);
+ }
+
+ ssaRegToLocalItems.set(reg, local);
+ }
+
+ /**
+ * Returns true if this SSA register is below the specified threshold.
+ * Used when most code is already in SSA form, and renaming is needed only
+ * for registers above a certain threshold.
+ *
+ * @param ssaReg the SSA register in question
+ * @return {@code true} if its register number is below the threshold
+ */
+ private boolean isBelowThresholdRegister(int ssaReg) {
+ return ssaReg < threshold;
+ }
+
+ /**
+ * Returns true if this SSA register is a "version 0"
+ * register. All version 0 registers are assigned the first N register
+ * numbers, where N is the count of original rop registers.
+ *
+ * @param ssaReg the SSA register in question
+ * @return true if it is a version 0 register.
+ */
+ private boolean isVersionZeroRegister(int ssaReg) {
+ return ssaReg < ropRegCount;
+ }
+
+ /**
+ * Returns true if a and b are equal or are both null.
+ *
+ * @param a null-ok
+ * @param b null-ok
+ * @return Returns true if a and b are equal or are both null
+ */
+ private static boolean equalsHandlesNulls(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /**
+ * Processes all insns in a block and renames their registers
+ * as appropriate.
+ */
+ private class BlockRenamer implements SsaInsn.Visitor {
+ /** {@code non-null;} block we're processing. */
+ private final SsaBasicBlock block;
+
+ /**
+ * {@code non-null;} indexed by old register name. The current
+ * top of the version stack as seen by this block. It's
+ * initialized from the ending state of its dom parent,
+ * updated as the block's instructions are processed, and then
+ * copied to each one of its dom children.
+ */
+ private final RegisterSpec[] currentMapping;
+
+ /**
+ * contains the set of moves we need to keep to preserve local
+ * var info. All other moves will be deleted.
+ */
+ private final HashSet<SsaInsn> movesToKeep;
+
+ /**
+ * maps the set of insns to replace after renaming is finished
+ * on the block.
+ */
+ private final HashMap<SsaInsn, SsaInsn> insnsToReplace;
+
+ private final RenamingMapper mapper;
+
+ /**
+ * Constructs a block renamer instance. Call {@code process}
+ * to process.
+ *
+ * @param block {@code non-null;} block to process
+ */
+ BlockRenamer(final SsaBasicBlock block) {
+ this.block = block;
+ currentMapping = startsForBlocks[block.getIndex()];
+ movesToKeep = new HashSet<SsaInsn>();
+ insnsToReplace = new HashMap<SsaInsn, SsaInsn>();
+ mapper = new RenamingMapper();
+
+ // We don't need our own start state anymore
+ startsForBlocks[block.getIndex()] = null;
+ }
+
+ /**
+ * Provides a register mapping between the old register space
+ * and the current renaming mapping. The mapping is updated
+ * as the current block's instructions are processed.
+ */
+ private class RenamingMapper extends RegisterMapper {
+ public RenamingMapper() {
+ // This space intentionally left blank.
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getNewRegisterCount() {
+ return nextSsaReg;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegisterSpec map(RegisterSpec registerSpec) {
+ if (registerSpec == null) {
+ return null;
+ }
+
+ int reg = registerSpec.getReg();
+
+ // For debugging: assert that the mapped types are compatible.
if (DEBUG) {
- ssaRegToRopReg = new IntList(ropRegCount);
+ RegisterSpec newVersion = currentMapping[reg];
+ if (newVersion.getBasicType() != Type.BT_VOID
+ && registerSpec.getBasicFrameType() != newVersion.getBasicFrameType()) {
+
+ throw new RuntimeException("mapping registers of incompatible types! " + registerSpec
+ + " " + currentMapping[reg]);
+ }
}
+ return registerSpec.withReg(currentMapping[reg].getReg());
+ }
+ }
+
+ /**
+ * Renames all the variables in this block and inserts appriopriate
+ * phis in successor blocks.
+ */
+ public void process() {
+ /*
+ * From Appel:
+ *
+ * Rename(n) =
+ * for each statement S in block n // 'statement' in 'block'
+ */
+
+block.forEachInsn(this);
+
+ updateSuccessorPhis();
+
+ // Delete all move insns in this block.
+ ArrayList<SsaInsn> insns = block.getInsns();
+ int szInsns = insns.size();
+
+ for (int i = szInsns - 1; i >= 0; i--) {
+ SsaInsn insn = insns.get(i);
+ SsaInsn replaceInsn;
+
+ replaceInsn = insnsToReplace.get(insn);
+
+ if (replaceInsn != null) {
+ insns.set(i, replaceInsn);
+ } else if (insn.isNormalMoveInsn() && !movesToKeep.contains(insn)) {
+ insns.remove(i);
+ }
+ }
+
+ // Store the start states for our dom children.
+ boolean first = true;
+ for (SsaBasicBlock child : block.getDomChildren()) {
+ if (child != block) {
+ // Don't bother duplicating the array for the first child.
+ RegisterSpec[] childStart = first ? currentMapping : dupArray(currentMapping);
+
+ startsForBlocks[child.getIndex()] = childStart;
+ first = false;
+ }
+ }
+
+ // currentMapping is owned by a child now.
+ }
+
+ /**
+ * Enforces a few contraints when a register mapping is added.
+ *
+ * <ol>
+ * <li> Ensures that all new SSA registers specs in the mapping
+ * table with the same register number are identical. In effect, once
+ * an SSA register spec has received or lost a local variable name,
+ * then every old-namespace register that maps to it should gain or
+ * lose its local variable name as well.
+ * <li> Records the local name associated with the
+ * register so that a register is never associated with more than one
+ * local.
+ * <li> ensures that only one SSA register
+ * at a time is considered to be associated with a local variable. When
+ * {@code currentMapping} is updated and the newly added element
+ * is named, strip that name from any other SSA registers.
+ * </ol>
+ *
+ * @param ropReg {@code >= 0;} rop register number
+ * @param ssaReg {@code non-null;} an SSA register that has just
+ * been added to {@code currentMapping}
+ */
+ private void addMapping(int ropReg, RegisterSpec ssaReg) {
+ int ssaRegNum = ssaReg.getReg();
+ LocalItem ssaRegLocal = ssaReg.getLocalItem();
+
+ currentMapping[ropReg] = ssaReg;
+
+ /*
+ * Ensure all SSA register specs with the same reg are identical.
+ */
+ for (int i = currentMapping.length - 1; i >= 0; i--) {
+ RegisterSpec cur = currentMapping[i];
+
+ if (ssaRegNum == cur.getReg()) {
+ currentMapping[i] = ssaReg;
+ }
+ }
+
+ // All further steps are for registers with local information.
+ if (ssaRegLocal == null) {
+ return;
+ }
+
+ // Record that this SSA reg has been associated with a local.
+ setNameForSsaReg(ssaReg);
+
+ // Ensure that no other SSA regs are associated with this local.
+ for (int i = currentMapping.length - 1; i >= 0; i--) {
+ RegisterSpec cur = currentMapping[i];
+
+ if (ssaRegNum != cur.getReg() && ssaRegLocal.equals(cur.getLocalItem())) {
+ currentMapping[i] = cur.withLocalItem(null);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Phi insns have their result registers renamed.
+ */
+ @Override
+ public void visitPhiInsn(PhiInsn phi) {
+ /* don't process sources for phi's */
+ processResultReg(phi);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Move insns are treated as a simple mapping operation, and
+ * will later be removed unless they represent a local variable
+ * assignment. If they represent a local variable assignement, they
+ * are preserved.
+ */
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ /*
+ * For moves: copy propogate the move if we can, but don't
+ * if we need to preserve local variable info and the
+ * result has a different name than the source.
+ */
+
+RegisterSpec ropResult = insn.getResult();
+ int ropResultReg = ropResult.getReg();
+ int ropSourceReg = insn.getSources().get(0).getReg();
+
+ insn.mapSourceRegisters(mapper);
+ int ssaSourceReg = insn.getSources().get(0).getReg();
+
+ LocalItem sourceLocal = currentMapping[ropSourceReg].getLocalItem();
+ LocalItem resultLocal = ropResult.getLocalItem();
+
+ /*
+ * A move from a register that's currently associated with a local
+ * to one that will not be associated with a local does not need
+ * to be preserved, but the local association should remain.
+ * Hence, we inherit the sourceLocal where the resultLocal is null.
+ */
+
+LocalItem newLocal = (resultLocal == null) ? sourceLocal : resultLocal;
+ LocalItem associatedLocal = getLocalForNewReg(ssaSourceReg);
+
+ /*
+ * If we take the new local, will only one local have ever
+ * been associated with this SSA reg?
+ */
+ boolean onlyOneAssociatedLocal =
+ associatedLocal == null || newLocal == null || newLocal.equals(associatedLocal);
+
+ /*
+ * If we're going to copy-propogate, then the ssa register
+ * spec that's going to go into the mapping is made up of
+ * the source register number mapped from above, the type
+ * of the result, and the name either from the result (if
+ * specified) or inherited from the existing mapping.
+ *
+ * The move source has incomplete type information in null
+ * object cases, so the result type is used.
+ */
+ RegisterSpec ssaReg =
+ RegisterSpec.makeLocalOptional(ssaSourceReg, ropResult.getType(), newLocal);
+
+ if (!Optimizer.getPreserveLocals()
+ || (onlyOneAssociatedLocal && equalsHandlesNulls(newLocal, sourceLocal))
+ && threshold == 0) {
/*
- * Appel 19.7
- *
- * Initialization:
- * for each variable a // register i
- * Count[a] <- 0 // nextSsaReg, flattened
- * Stack[a] <- 0 // versionStack
- * push 0 onto Stack[a]
- *
+ * We don't have to keep this move to preserve local
+ * information. Either the name is the same, or the result
+ * register spec is unnamed.
*/
- // top entry for the version stack is version 0
- RegisterSpec[] initialRegMapping = new RegisterSpec[ropRegCount];
- for (int i = 0; i < ropRegCount; i++) {
- // everyone starts with a version 0 register
- initialRegMapping[i] = RegisterSpec.make(i, Type.VOID);
+addMapping(ropResultReg, ssaReg);
+ } else if (onlyOneAssociatedLocal && sourceLocal == null && threshold == 0) {
+ /*
+ * The register was previously unnamed. This means that a
+ * local starts after it's first assignment in SSA form
+ */
- if (DEBUG) {
- ssaRegToRopReg.add(i);
- }
- }
+RegisterSpecList ssaSources =
+ RegisterSpecList.make(RegisterSpec.make(ssaReg.getReg(), ssaReg.getType(), newLocal));
- // Initial state for entry block
- startsForBlocks[ssaMeth.getEntryBlockIndex()] = initialRegMapping;
+ SsaInsn newInsn = SsaInsn.makeFromRop(
+ new PlainInsn(Rops.opMarkLocal(ssaReg), SourcePosition.NO_INFO, null, ssaSources),
+ block);
+
+ insnsToReplace.put(insn, newInsn);
+
+ // Just map as above.
+ addMapping(ropResultReg, ssaReg);
+ } else {
+ /*
+ * Do not copy-propogate, since the two registers have
+ * two different local-variable names.
+ */
+ processResultReg(insn);
+
+ movesToKeep.add(insn);
+ }
}
/**
- * Constructs an instance of the renamer with threshold set
- *
- * @param ssaMeth {@code non-null;} un-renamed SSA method that will
- * be renamed.
- * @param thresh registers below this number are unchanged
- */
- public SsaRenamer(SsaMethod ssaMeth, int thresh) {
- this(ssaMeth);
- threshold = thresh;
- }
-
- /**
- * Performs renaming transformation, modifying the method's instructions
- * in-place.
- */
- public void run() {
- // Rename each block in dom-tree DFS order.
- ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
- public void visitBlock (SsaBasicBlock block,
- SsaBasicBlock unused) {
- new BlockRenamer(block).process();
- }
- });
-
- ssaMeth.setNewRegCount(nextSsaReg);
- ssaMeth.onInsnsChanged();
-
- if (DEBUG) {
- System.out.println("SSA\tRop");
- /*
- * We're going to compute the version of the rop register
- * by keeping a running total of how many times the rop
- * register has been mapped.
- */
- int[] versions = new int[ropRegCount];
-
- int sz = ssaRegToRopReg.size();
- for (int i = 0; i < sz; i++) {
- int ropReg = ssaRegToRopReg.get(i);
- System.out.println(i + "\t" + ropReg + "["
- + versions[ropReg] + "]");
- versions[ropReg]++;
- }
- }
- }
-
- /**
- * Duplicates a RegisterSpec array.
+ * {@inheritDoc}
*
- * @param orig {@code non-null;} array to duplicate
- * @return {@code non-null;} new instance
+ * All insns that are not move or phi insns have their source registers
+ * mapped ot the current mapping. Their result registers are then
+ * renamed to a new SSA register which is then added to the current
+ * register mapping.
*/
- private static RegisterSpec[] dupArray(RegisterSpec[] orig) {
- RegisterSpec[] copy = new RegisterSpec[orig.length];
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ /* for each use of some variable X in S */
+ insn.mapSourceRegisters(mapper);
- System.arraycopy(orig, 0, copy, 0, orig.length);
-
- return copy;
+ processResultReg(insn);
}
/**
- * Gets a local variable item for a specified register.
+ * Renames the result register of this insn and updates the
+ * current register mapping. Does nothing if this insn has no result.
+ * Applied to all non-move insns.
*
- * @param ssaReg register in SSA name space
- * @return {@code null-ok;} Local variable name or null if none
+ * @param insn insn to process.
*/
- private LocalItem getLocalForNewReg(int ssaReg) {
- if (ssaReg < ssaRegToLocalItems.size()) {
- return ssaRegToLocalItems.get(ssaReg);
- } else {
- return null;
- }
+ void processResultReg(SsaInsn insn) {
+ RegisterSpec ropResult = insn.getResult();
+
+ if (ropResult == null) {
+ return;
+ }
+
+ int ropReg = ropResult.getReg();
+ if (isBelowThresholdRegister(ropReg)) {
+ return;
+ }
+
+ insn.changeResultReg(nextSsaReg);
+ addMapping(ropReg, insn.getResult());
+
+ if (DEBUG) {
+ ssaRegToRopReg.add(ropReg);
+ }
+
+ nextSsaReg++;
}
/**
- * Records a debug (local variable) name for a specified register.
- *
- * @param ssaReg non-null named register spec in SSA name space
+ * Updates the phi insns in successor blocks with operands based
+ * on the current mapping of the rop register the phis represent.
*/
- private void setNameForSsaReg(RegisterSpec ssaReg) {
- int reg = ssaReg.getReg();
- LocalItem local = ssaReg.getLocalItem();
+ private void updateSuccessorPhis() {
+ PhiInsn.Visitor visitor = new PhiInsn.Visitor() {
+ @Override
+ public void visitPhiInsn(PhiInsn insn) {
+ int ropReg;
- ssaRegToLocalItems.ensureCapacity(reg + 1);
- while (ssaRegToLocalItems.size() <= reg) {
- ssaRegToLocalItems.add(null);
+ ropReg = insn.getRopResultReg();
+ if (isBelowThresholdRegister(ropReg)) {
+ return;
+ }
+
+ /*
+ * Never add a version 0 register as a phi
+ * operand. Version 0 registers represent the
+ * initial register state, and thus are never
+ * significant. Furthermore, the register liveness
+ * algorithm doesn't properly count them as "live
+ * in" at the beginning of the method.
+ */
+
+RegisterSpec stackTop = currentMapping[ropReg];
+ if (!isVersionZeroRegister(stackTop.getReg())) {
+ insn.addPhiOperand(stackTop, block);
+ }
}
+ };
- ssaRegToLocalItems.set(reg, local);
+ BitSet successors = block.getSuccessors();
+ for (int i = successors.nextSetBit(0); i >= 0; i = successors.nextSetBit(i + 1)) {
+ SsaBasicBlock successor = ssaMeth.getBlocks().get(i);
+ successor.forEachPhiInsn(visitor);
+ }
}
-
- /**
- * Returns true if this SSA register is below the specified threshold.
- * Used when most code is already in SSA form, and renaming is needed only
- * for registers above a certain threshold.
- *
- * @param ssaReg the SSA register in question
- * @return {@code true} if its register number is below the threshold
- */
- private boolean isBelowThresholdRegister(int ssaReg) {
- return ssaReg < threshold;
- }
-
- /**
- * Returns true if this SSA register is a "version 0"
- * register. All version 0 registers are assigned the first N register
- * numbers, where N is the count of original rop registers.
- *
- * @param ssaReg the SSA register in question
- * @return true if it is a version 0 register.
- */
- private boolean isVersionZeroRegister(int ssaReg) {
- return ssaReg < ropRegCount;
- }
-
- /**
- * Returns true if a and b are equal or are both null.
- *
- * @param a null-ok
- * @param b null-ok
- * @return Returns true if a and b are equal or are both null
- */
- private static boolean equalsHandlesNulls(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
- }
-
- /**
- * Processes all insns in a block and renames their registers
- * as appropriate.
- */
- private class BlockRenamer implements SsaInsn.Visitor{
- /** {@code non-null;} block we're processing. */
- private final SsaBasicBlock block;
-
- /**
- * {@code non-null;} indexed by old register name. The current
- * top of the version stack as seen by this block. It's
- * initialized from the ending state of its dom parent,
- * updated as the block's instructions are processed, and then
- * copied to each one of its dom children.
- */
- private final RegisterSpec[] currentMapping;
-
- /**
- * contains the set of moves we need to keep to preserve local
- * var info. All other moves will be deleted.
- */
- private final HashSet<SsaInsn> movesToKeep;
-
- /**
- * maps the set of insns to replace after renaming is finished
- * on the block.
- */
- private final HashMap<SsaInsn, SsaInsn> insnsToReplace;
-
- private final RenamingMapper mapper;
-
- /**
- * Constructs a block renamer instance. Call {@code process}
- * to process.
- *
- * @param block {@code non-null;} block to process
- */
- BlockRenamer(final SsaBasicBlock block) {
- this.block = block;
- currentMapping = startsForBlocks[block.getIndex()];
- movesToKeep = new HashSet<SsaInsn>();
- insnsToReplace = new HashMap<SsaInsn, SsaInsn>();
- mapper = new RenamingMapper();
-
- // We don't need our own start state anymore
- startsForBlocks[block.getIndex()] = null;
- }
-
- /**
- * Provides a register mapping between the old register space
- * and the current renaming mapping. The mapping is updated
- * as the current block's instructions are processed.
- */
- private class RenamingMapper extends RegisterMapper {
- public RenamingMapper() {
- // This space intentionally left blank.
- }
-
- /** {@inheritDoc} */
- @Override
- public int getNewRegisterCount() {
- return nextSsaReg;
- }
-
- /** {@inheritDoc} */
- @Override
- public RegisterSpec map(RegisterSpec registerSpec) {
- if (registerSpec == null) return null;
-
- int reg = registerSpec.getReg();
-
- // For debugging: assert that the mapped types are compatible.
- if (DEBUG) {
- RegisterSpec newVersion = currentMapping[reg];
- if (newVersion.getBasicType() != Type.BT_VOID
- && registerSpec.getBasicFrameType()
- != newVersion.getBasicFrameType()) {
-
- throw new RuntimeException(
- "mapping registers of incompatible types! "
- + registerSpec
- + " " + currentMapping[reg]);
- }
- }
-
- return registerSpec.withReg(currentMapping[reg].getReg());
- }
- }
-
- /**
- * Renames all the variables in this block and inserts appriopriate
- * phis in successor blocks.
- */
- public void process() {
- /*
- * From Appel:
- *
- * Rename(n) =
- * for each statement S in block n // 'statement' in 'block'
- */
-
- block.forEachInsn(this);
-
- updateSuccessorPhis();
-
- // Delete all move insns in this block.
- ArrayList<SsaInsn> insns = block.getInsns();
- int szInsns = insns.size();
-
- for (int i = szInsns - 1; i >= 0 ; i--) {
- SsaInsn insn = insns.get(i);
- SsaInsn replaceInsn;
-
- replaceInsn = insnsToReplace.get(insn);
-
- if (replaceInsn != null) {
- insns.set(i, replaceInsn);
- } else if (insn.isNormalMoveInsn()
- && !movesToKeep.contains(insn)) {
- insns.remove(i);
- }
- }
-
- // Store the start states for our dom children.
- boolean first = true;
- for (SsaBasicBlock child : block.getDomChildren()) {
- if (child != block) {
- // Don't bother duplicating the array for the first child.
- RegisterSpec[] childStart = first ? currentMapping
- : dupArray(currentMapping);
-
- startsForBlocks[child.getIndex()] = childStart;
- first = false;
- }
- }
-
- // currentMapping is owned by a child now.
- }
-
- /**
- * Enforces a few contraints when a register mapping is added.
- *
- * <ol>
- * <li> Ensures that all new SSA registers specs in the mapping
- * table with the same register number are identical. In effect, once
- * an SSA register spec has received or lost a local variable name,
- * then every old-namespace register that maps to it should gain or
- * lose its local variable name as well.
- * <li> Records the local name associated with the
- * register so that a register is never associated with more than one
- * local.
- * <li> ensures that only one SSA register
- * at a time is considered to be associated with a local variable. When
- * {@code currentMapping} is updated and the newly added element
- * is named, strip that name from any other SSA registers.
- * </ol>
- *
- * @param ropReg {@code >= 0;} rop register number
- * @param ssaReg {@code non-null;} an SSA register that has just
- * been added to {@code currentMapping}
- */
- private void addMapping(int ropReg, RegisterSpec ssaReg) {
- int ssaRegNum = ssaReg.getReg();
- LocalItem ssaRegLocal = ssaReg.getLocalItem();
-
- currentMapping[ropReg] = ssaReg;
-
- /*
- * Ensure all SSA register specs with the same reg are identical.
- */
- for (int i = currentMapping.length - 1; i >= 0; i--) {
- RegisterSpec cur = currentMapping[i];
-
- if (ssaRegNum == cur.getReg()) {
- currentMapping[i] = ssaReg;
- }
- }
-
- // All further steps are for registers with local information.
- if (ssaRegLocal == null) {
- return;
- }
-
- // Record that this SSA reg has been associated with a local.
- setNameForSsaReg(ssaReg);
-
- // Ensure that no other SSA regs are associated with this local.
- for (int i = currentMapping.length - 1; i >= 0; i--) {
- RegisterSpec cur = currentMapping[i];
-
- if (ssaRegNum != cur.getReg()
- && ssaRegLocal.equals(cur.getLocalItem())) {
- currentMapping[i] = cur.withLocalItem(null);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Phi insns have their result registers renamed.
- */
- public void visitPhiInsn(PhiInsn phi) {
- /* don't process sources for phi's */
- processResultReg(phi);
- }
-
- /**
- * {@inheritDoc}
- *
- * Move insns are treated as a simple mapping operation, and
- * will later be removed unless they represent a local variable
- * assignment. If they represent a local variable assignement, they
- * are preserved.
- */
- public void visitMoveInsn(NormalSsaInsn insn) {
- /*
- * For moves: copy propogate the move if we can, but don't
- * if we need to preserve local variable info and the
- * result has a different name than the source.
- */
-
- RegisterSpec ropResult = insn.getResult();
- int ropResultReg = ropResult.getReg();
- int ropSourceReg = insn.getSources().get(0).getReg();
-
- insn.mapSourceRegisters(mapper);
- int ssaSourceReg = insn.getSources().get(0).getReg();
-
- LocalItem sourceLocal
- = currentMapping[ropSourceReg].getLocalItem();
- LocalItem resultLocal = ropResult.getLocalItem();
-
- /*
- * A move from a register that's currently associated with a local
- * to one that will not be associated with a local does not need
- * to be preserved, but the local association should remain.
- * Hence, we inherit the sourceLocal where the resultLocal is null.
- */
-
- LocalItem newLocal
- = (resultLocal == null) ? sourceLocal : resultLocal;
- LocalItem associatedLocal = getLocalForNewReg(ssaSourceReg);
-
- /*
- * If we take the new local, will only one local have ever
- * been associated with this SSA reg?
- */
- boolean onlyOneAssociatedLocal
- = associatedLocal == null || newLocal == null
- || newLocal.equals(associatedLocal);
-
- /*
- * If we're going to copy-propogate, then the ssa register
- * spec that's going to go into the mapping is made up of
- * the source register number mapped from above, the type
- * of the result, and the name either from the result (if
- * specified) or inherited from the existing mapping.
- *
- * The move source has incomplete type information in null
- * object cases, so the result type is used.
- */
- RegisterSpec ssaReg
- = RegisterSpec.makeLocalOptional(
- ssaSourceReg, ropResult.getType(), newLocal);
-
- if (!Optimizer.getPreserveLocals() || (onlyOneAssociatedLocal
- && equalsHandlesNulls(newLocal, sourceLocal)) &&
- threshold == 0) {
- /*
- * We don't have to keep this move to preserve local
- * information. Either the name is the same, or the result
- * register spec is unnamed.
- */
-
- addMapping(ropResultReg, ssaReg);
- } else if (onlyOneAssociatedLocal && sourceLocal == null &&
- threshold == 0) {
- /*
- * The register was previously unnamed. This means that a
- * local starts after it's first assignment in SSA form
- */
-
- RegisterSpecList ssaSources = RegisterSpecList.make(
- RegisterSpec.make(ssaReg.getReg(),
- ssaReg.getType(), newLocal));
-
- SsaInsn newInsn
- = SsaInsn.makeFromRop(
- new PlainInsn(Rops.opMarkLocal(ssaReg),
- SourcePosition.NO_INFO, null, ssaSources),block);
-
- insnsToReplace.put(insn, newInsn);
-
- // Just map as above.
- addMapping(ropResultReg, ssaReg);
- } else {
- /*
- * Do not copy-propogate, since the two registers have
- * two different local-variable names.
- */
- processResultReg(insn);
-
- movesToKeep.add(insn);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * All insns that are not move or phi insns have their source registers
- * mapped ot the current mapping. Their result registers are then
- * renamed to a new SSA register which is then added to the current
- * register mapping.
- */
- public void visitNonMoveInsn(NormalSsaInsn insn) {
- /* for each use of some variable X in S */
- insn.mapSourceRegisters(mapper);
-
- processResultReg(insn);
- }
-
- /**
- * Renames the result register of this insn and updates the
- * current register mapping. Does nothing if this insn has no result.
- * Applied to all non-move insns.
- *
- * @param insn insn to process.
- */
- void processResultReg(SsaInsn insn) {
- RegisterSpec ropResult = insn.getResult();
-
- if (ropResult == null) {
- return;
- }
-
- int ropReg = ropResult.getReg();
- if (isBelowThresholdRegister(ropReg)) {
- return;
- }
-
- insn.changeResultReg(nextSsaReg);
- addMapping(ropReg, insn.getResult());
-
- if (DEBUG) {
- ssaRegToRopReg.add(ropReg);
- }
-
- nextSsaReg++;
- }
-
- /**
- * Updates the phi insns in successor blocks with operands based
- * on the current mapping of the rop register the phis represent.
- */
- private void updateSuccessorPhis() {
- PhiInsn.Visitor visitor = new PhiInsn.Visitor() {
- public void visitPhiInsn (PhiInsn insn) {
- int ropReg;
-
- ropReg = insn.getRopResultReg();
- if (isBelowThresholdRegister(ropReg)) {
- return;
- }
-
- /*
- * Never add a version 0 register as a phi
- * operand. Version 0 registers represent the
- * initial register state, and thus are never
- * significant. Furthermore, the register liveness
- * algorithm doesn't properly count them as "live
- * in" at the beginning of the method.
- */
-
- RegisterSpec stackTop = currentMapping[ropReg];
- if (!isVersionZeroRegister(stackTop.getReg())) {
- insn.addPhiOperand(stackTop, block);
- }
- }
- };
-
- BitSet successors = block.getSuccessors();
- for (int i = successors.nextSetBit(0); i >= 0;
- i = successors.nextSetBit(i + 1)) {
- SsaBasicBlock successor = ssaMeth.getBlocks().get(i);
- successor.forEachPhiInsn(visitor);
- }
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/FirstFitAllocator.java b/dx/src/com/android/jack/dx/ssa/back/FirstFitAllocator.java
index 4fed8f2..3795077 100644
--- a/dx/src/com/android/jack/dx/ssa/back/FirstFitAllocator.java
+++ b/dx/src/com/android/jack/dx/ssa/back/FirstFitAllocator.java
@@ -26,7 +26,6 @@
import com.android.jack.dx.util.IntSet;
import java.util.BitSet;
-import java.util.ArrayList;
/**
* Allocates registers via a naive n^2 register allocator.
@@ -34,118 +33,112 @@
* intelligently with different size register uses.
*/
public class FirstFitAllocator extends RegisterAllocator {
- /**
- * If true, allocator places parameters at the top of the frame
- * in calling-convention order.
- */
- private static final boolean PRESLOT_PARAMS = true;
+ /**
+ * If true, allocator places parameters at the top of the frame
+ * in calling-convention order.
+ */
+ private static final boolean PRESLOT_PARAMS = true;
- /** indexed by old reg; the set of old regs we've mapped */
- private final BitSet mapped;
+ /** indexed by old reg; the set of old regs we've mapped */
+ private final BitSet mapped;
- /** {@inheritDoc} */
- public FirstFitAllocator(
- final SsaMethod ssaMeth, final InterferenceGraph interference) {
- super(ssaMeth, interference);
+ /** {@inheritDoc} */
+ public FirstFitAllocator(final SsaMethod ssaMeth, final InterferenceGraph interference) {
+ super(ssaMeth, interference);
- mapped = new BitSet(ssaMeth.getRegCount());
+ mapped = new BitSet(ssaMeth.getRegCount());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean wantsParamsMovedHigh() {
+ return PRESLOT_PARAMS;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegisterMapper allocateRegisters() {
+ int oldRegCount = ssaMeth.getRegCount();
+
+ BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount);
+
+ int nextNewRegister = 0;
+
+ if (PRESLOT_PARAMS) {
+ /*
+ * Reserve space for the params at the bottom of the register
+ * space. Later, we'll flip the params to the end of the register
+ * space.
+ */
+
+nextNewRegister = ssaMeth.getParamWidth();
}
- /** {@inheritDoc} */
- @Override
- public boolean wantsParamsMovedHigh() {
- return PRESLOT_PARAMS;
- }
+ for (int i = 0; i < oldRegCount; i++) {
+ if (mapped.get(i)) {
+ // we already got this one
+ continue;
+ }
- /** {@inheritDoc} */
- @Override
- public RegisterMapper allocateRegisters() {
- int oldRegCount = ssaMeth.getRegCount();
+ int maxCategory = getCategoryForSsaReg(i);
+ IntSet current = new BitIntSet(oldRegCount);
- BasicRegisterMapper mapper
- = new BasicRegisterMapper(oldRegCount);
+ interference.mergeInterferenceSet(i, current);
- int nextNewRegister = 0;
+ boolean isPreslotted = false;
+ int newReg = 0;
- if (PRESLOT_PARAMS) {
- /*
- * Reserve space for the params at the bottom of the register
- * space. Later, we'll flip the params to the end of the register
- * space.
- */
+ if (PRESLOT_PARAMS && isDefinitionMoveParam(i)) {
+ // Any move-param definition must be a NormalSsaInsn
+ NormalSsaInsn defInsn = (NormalSsaInsn) ssaMeth.getDefinitionForRegister(i);
- nextNewRegister = ssaMeth.getParamWidth();
+ newReg = paramNumberFromMoveParam(defInsn);
+
+ mapper.addMapping(i, newReg, maxCategory);
+ isPreslotted = true;
+ } else {
+ mapper.addMapping(i, nextNewRegister, maxCategory);
+ newReg = nextNewRegister;
+ }
+
+ for (int j = i + 1; j < oldRegCount; j++) {
+ if (mapped.get(j) || isDefinitionMoveParam(j)) {
+ continue;
}
- for (int i = 0; i < oldRegCount; i++) {
- if (mapped.get(i)) {
- // we already got this one
- continue;
- }
+ /*
+ * If reg j doesn't interfere with the current mapping.
+ * Also, if this is a pre-slotted method parameter, we
+ * can't use more than the original param width.
+ */
+ if (!current.has(j) && !(isPreslotted && (maxCategory < getCategoryForSsaReg(j)))) {
- int maxCategory = getCategoryForSsaReg(i);
- IntSet current = new BitIntSet(oldRegCount);
+ interference.mergeInterferenceSet(j, current);
- interference.mergeInterferenceSet(i, current);
+ maxCategory = Math.max(maxCategory, getCategoryForSsaReg(j));
- boolean isPreslotted = false;
- int newReg = 0;
-
- if (PRESLOT_PARAMS && isDefinitionMoveParam(i)) {
- // Any move-param definition must be a NormalSsaInsn
- NormalSsaInsn defInsn = (NormalSsaInsn)
- ssaMeth.getDefinitionForRegister(i);
-
- newReg = paramNumberFromMoveParam(defInsn);
-
- mapper.addMapping(i, newReg, maxCategory);
- isPreslotted = true;
- } else {
- mapper.addMapping(i, nextNewRegister, maxCategory);
- newReg = nextNewRegister;
- }
-
- for (int j = i + 1; j < oldRegCount; j++) {
- if (mapped.get(j) || isDefinitionMoveParam(j)) {
- continue;
- }
-
- /*
- * If reg j doesn't interfere with the current mapping.
- * Also, if this is a pre-slotted method parameter, we
- * can't use more than the original param width.
- */
- if (!current.has(j)
- && !(isPreslotted
- && (maxCategory < getCategoryForSsaReg(j)))) {
-
- interference.mergeInterferenceSet(j, current);
-
- maxCategory = Math.max(maxCategory,
- getCategoryForSsaReg(j));
-
- mapper.addMapping(j, newReg, maxCategory);
- mapped.set(j);
- }
- }
-
- mapped.set(i);
- if (!isPreslotted) {
- nextNewRegister += maxCategory;
- }
+ mapper.addMapping(j, newReg, maxCategory);
+ mapped.set(j);
}
+ }
- return mapper;
+ mapped.set(i);
+ if (!isPreslotted) {
+ nextNewRegister += maxCategory;
+ }
}
- /**
- * Returns the parameter number that this move-param insn refers to
- * @param ndefInsn a move-param insn (otherwise, exceptions will be thrown)
- * @return parameter number (offset in the total parameter width)
- */
- private int paramNumberFromMoveParam(NormalSsaInsn ndefInsn) {
- CstInsn origInsn = (CstInsn) ndefInsn.getOriginalRopInsn();
+ return mapper;
+ }
- return ((CstInteger) origInsn.getConstant()).getValue();
- }
+ /**
+ * Returns the parameter number that this move-param insn refers to
+ * @param ndefInsn a move-param insn (otherwise, exceptions will be thrown)
+ * @return parameter number (offset in the total parameter width)
+ */
+ private int paramNumberFromMoveParam(NormalSsaInsn ndefInsn) {
+ CstInsn origInsn = (CstInsn) ndefInsn.getOriginalRopInsn();
+
+ return ((CstInteger) origInsn.getConstant()).getValue();
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/FirstFitLocalCombiningAllocator.java b/dx/src/com/android/jack/dx/ssa/back/FirstFitLocalCombiningAllocator.java
index 65a5d1d..837bee3 100644
--- a/dx/src/com/android/jack/dx/ssa/back/FirstFitLocalCombiningAllocator.java
+++ b/dx/src/com/android/jack/dx/ssa/back/FirstFitLocalCombiningAllocator.java
@@ -16,7 +16,12 @@
package com.android.jack.dx.ssa.back;
-import com.android.jack.dx.rop.code.*;
+import com.android.jack.dx.rop.code.CstInsn;
+import com.android.jack.dx.rop.code.LocalItem;
+import com.android.jack.dx.rop.code.RegOps;
+import com.android.jack.dx.rop.code.RegisterSpec;
+import com.android.jack.dx.rop.code.RegisterSpecList;
+import com.android.jack.dx.rop.code.Rop;
import com.android.jack.dx.rop.cst.CstInteger;
import com.android.jack.dx.ssa.InterferenceRegisterMapper;
import com.android.jack.dx.ssa.NormalSsaInsn;
@@ -40,1100 +45,1079 @@
* kept together if possible.
*/
public class FirstFitLocalCombiningAllocator extends RegisterAllocator {
- /** local debug flag */
- private static final boolean DEBUG = false;
+ /** local debug flag */
+ private static final boolean DEBUG = false;
- /** maps local variable to a list of associated SSA registers */
- private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables;
+ /** maps local variable to a list of associated SSA registers */
+ private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables;
- /** list of move-result-pesudo instructions seen in this method */
- private final ArrayList<NormalSsaInsn> moveResultPseudoInsns;
+ /** list of move-result-pesudo instructions seen in this method */
+ private final ArrayList<NormalSsaInsn> moveResultPseudoInsns;
- /** list of invoke-range instructions seen in this method */
- private final ArrayList<NormalSsaInsn> invokeRangeInsns;
+ /** list of invoke-range instructions seen in this method */
+ private final ArrayList<NormalSsaInsn> invokeRangeInsns;
- /** list of phi instructions seen in this method */
- private final ArrayList<PhiInsn> phiInsns;
+ /** list of phi instructions seen in this method */
+ private final ArrayList<PhiInsn> phiInsns;
- /** indexed by SSA reg; the set of SSA regs we've mapped */
- private final BitSet ssaRegsMapped;
+ /** indexed by SSA reg; the set of SSA regs we've mapped */
+ private final BitSet ssaRegsMapped;
- /** Register mapper which will be our result */
- private final InterferenceRegisterMapper mapper;
+ /** Register mapper which will be our result */
+ private final InterferenceRegisterMapper mapper;
- /** end of rop registers range (starting at 0) reserved for parameters */
- private final int paramRangeEnd;
+ /** end of rop registers range (starting at 0) reserved for parameters */
+ private final int paramRangeEnd;
- /** set of rop registers reserved for parameters or local variables */
- private final BitSet reservedRopRegs;
+ /** set of rop registers reserved for parameters or local variables */
+ private final BitSet reservedRopRegs;
- /** set of rop registers that have been used by anything */
- private final BitSet usedRopRegs;
+ /** set of rop registers that have been used by anything */
+ private final BitSet usedRopRegs;
- /** true if converter should take steps to minimize rop-form registers */
- private final boolean minimizeRegisters;
+ /**
+ * Constructs instance.
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @param interference non-null interference graph for SSA registers
+ * @param minimizeRegisters true if converter should take steps to
+ * minimize rop-form registers
+ */
+ public FirstFitLocalCombiningAllocator(SsaMethod ssaMeth, InterferenceGraph interference,
+ boolean minimizeRegisters) {
+ super(ssaMeth, interference);
- /**
- * Constructs instance.
- *
- * @param ssaMeth {@code non-null;} method to process
- * @param interference non-null interference graph for SSA registers
- * @param minimizeRegisters true if converter should take steps to
- * minimize rop-form registers
+ ssaRegsMapped = new BitSet(ssaMeth.getRegCount());
+
+ mapper = new InterferenceRegisterMapper(interference, ssaMeth.getRegCount());
+
+ /*
+ * Reserve space for the params at the bottom of the register
+ * space. Later, we'll flip the params to the end of the register
+ * space.
*/
- public FirstFitLocalCombiningAllocator(
- SsaMethod ssaMeth, InterferenceGraph interference,
- boolean minimizeRegisters) {
- super(ssaMeth, interference);
- ssaRegsMapped = new BitSet(ssaMeth.getRegCount());
+ paramRangeEnd = ssaMeth.getParamWidth();
- mapper = new InterferenceRegisterMapper(
- interference, ssaMeth.getRegCount());
+ reservedRopRegs = new BitSet(paramRangeEnd * 2);
+ reservedRopRegs.set(0, paramRangeEnd);
+ usedRopRegs = new BitSet(paramRangeEnd * 2);
+ localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>();
+ moveResultPseudoInsns = new ArrayList<NormalSsaInsn>();
+ invokeRangeInsns = new ArrayList<NormalSsaInsn>();
+ phiInsns = new ArrayList<PhiInsn>();
+ }
- this.minimizeRegisters = minimizeRegisters;
+ /** {@inheritDoc} */
+ @Override
+ public boolean wantsParamsMovedHigh() {
+ return true;
+ }
- /*
- * Reserve space for the params at the bottom of the register
- * space. Later, we'll flip the params to the end of the register
- * space.
- */
+ /** {@inheritDoc} */
+ @Override
+ public RegisterMapper allocateRegisters() {
- paramRangeEnd = ssaMeth.getParamWidth();
+ analyzeInstructions();
- reservedRopRegs = new BitSet(paramRangeEnd * 2);
- reservedRopRegs.set(0, paramRangeEnd);
- usedRopRegs = new BitSet(paramRangeEnd * 2);
- localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>();
- moveResultPseudoInsns = new ArrayList<NormalSsaInsn>();
- invokeRangeInsns = new ArrayList<NormalSsaInsn>();
- phiInsns = new ArrayList<PhiInsn>();
+ if (DEBUG) {
+ printLocalVars();
}
- /** {@inheritDoc} */
- @Override
- public boolean wantsParamsMovedHigh() {
- return true;
+ if (DEBUG) {
+ System.out.println("--->Mapping local-associated params");
}
+ handleLocalAssociatedParams();
- /** {@inheritDoc} */
- @Override
- public RegisterMapper allocateRegisters() {
-
- analyzeInstructions();
-
- if (DEBUG) {
- printLocalVars();
- }
-
- if (DEBUG) System.out.println("--->Mapping local-associated params");
- handleLocalAssociatedParams();
-
- if (DEBUG) System.out.println("--->Mapping other params");
- handleUnassociatedParameters();
-
- if (DEBUG) System.out.println("--->Mapping invoke-range");
- handleInvokeRangeInsns();
-
- if (DEBUG) {
- System.out.println("--->Mapping local-associated non-params");
- }
- handleLocalAssociatedOther();
-
- if (DEBUG) System.out.println("--->Mapping check-cast results");
- handleCheckCastResults();
-
- if (DEBUG) System.out.println("--->Mapping phis");
- handlePhiInsns();
-
- if (DEBUG) System.out.println("--->Mapping others");
- handleNormalUnassociated();
-
- return mapper;
+ if (DEBUG) {
+ System.out.println("--->Mapping other params");
}
+ handleUnassociatedParameters();
- /**
- * Dumps local variable table to stdout for debugging.
- */
- private void printLocalVars() {
- System.out.println("Printing local vars");
- for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e :
- localVariables.entrySet()) {
- StringBuilder regs = new StringBuilder();
-
- regs.append('{');
- regs.append(' ');
- for (RegisterSpec reg : e.getValue()) {
- regs.append('v');
- regs.append(reg.getReg());
- regs.append(' ');
- }
- regs.append('}');
- System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs);
- }
+ if (DEBUG) {
+ System.out.println("--->Mapping invoke-range");
}
+ handleInvokeRangeInsns();
- /**
- * Maps all local-associated parameters to rop registers.
- */
- private void handleLocalAssociatedParams() {
- for (ArrayList<RegisterSpec> ssaRegs : localVariables.values()) {
- int sz = ssaRegs.size();
- int paramIndex = -1;
- int paramCategory = 0;
-
- // First, find out if this local variable is a parameter.
- for (int i = 0; i < sz; i++) {
- RegisterSpec ssaSpec = ssaRegs.get(i);
- int ssaReg = ssaSpec.getReg();
-
- paramIndex = getParameterIndexForReg(ssaReg);
-
- if (paramIndex >= 0) {
- paramCategory = ssaSpec.getCategory();
- addMapping(ssaSpec, paramIndex);
- break;
- }
- }
-
- if (paramIndex < 0) {
- // This local wasn't a parameter.
- continue;
- }
-
- // Any remaining local-associated registers will be mapped later.
- tryMapRegs(ssaRegs, paramIndex, paramCategory, true);
- }
+ if (DEBUG) {
+ System.out.println("--->Mapping local-associated non-params");
}
+ handleLocalAssociatedOther();
- /**
- * Gets the parameter index for SSA registers that are method parameters.
- * {@code -1} is returned for non-parameter registers.
- *
- * @param ssaReg {@code >=0;} SSA register to look up
- * @return parameter index or {@code -1} if not a parameter
- */
- private int getParameterIndexForReg(int ssaReg) {
- SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
- if (defInsn == null) {
- return -1;
- }
-
- Rop opcode = defInsn.getOpcode();
-
- // opcode == null for phi insns.
- if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
- CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
- return ((CstInteger) origInsn.getConstant()).getValue();
- }
-
- return -1;
+ if (DEBUG) {
+ System.out.println("--->Mapping check-cast results");
}
+ handleCheckCastResults();
- /**
- * Maps all local-associated registers that are not parameters.
- * Tries to find an unreserved range that's wide enough for all of
- * the SSA registers, and then tries to map them all to that
- * range. If not all fit, a new range is tried until all registers
- * have been fit.
- */
- private void handleLocalAssociatedOther() {
- for (ArrayList<RegisterSpec> specs : localVariables.values()) {
- int ropReg = paramRangeEnd;
-
- boolean done = false;
- do {
- int maxCategory = 1;
-
- // Compute max category for remaining unmapped registers.
- int sz = specs.size();
- for (int i = 0; i < sz; i++) {
- RegisterSpec ssaSpec = specs.get(i);
- int category = ssaSpec.getCategory();
- if (!ssaRegsMapped.get(ssaSpec.getReg())
- && category > maxCategory) {
- maxCategory = category;
- }
- }
-
- ropReg = findRopRegForLocal(ropReg, maxCategory);
- if (canMapRegs(specs, ropReg)) {
- done = tryMapRegs(specs, ropReg, maxCategory, true);
- }
-
- // Increment for next call to findRopRegForLocal.
- ropReg++;
- } while (!done);
- }
+ if (DEBUG) {
+ System.out.println("--->Mapping phis");
}
+ handlePhiInsns();
- /**
- * Tries to map a list of SSA registers into the a rop reg, marking
- * used rop space as reserved. SSA registers that don't fit are left
- * unmapped.
- *
- * @param specs {@code non-null;} SSA registers to attempt to map
- * @param ropReg {@code >=0;} rop register to map to
- * @param maxAllowedCategory {@code 1..2;} maximum category
- * allowed in mapping.
- * @param markReserved do so if {@code true}
- * @return {@code true} if all registers were mapped, {@code false}
- * if some remain unmapped
- */
- private boolean tryMapRegs(
- ArrayList<RegisterSpec> specs, int ropReg,
- int maxAllowedCategory, boolean markReserved) {
- boolean remaining = false;
- for (RegisterSpec spec : specs) {
- if (ssaRegsMapped.get(spec.getReg())) {
- continue;
- }
-
- boolean succeeded;
- succeeded = tryMapReg(spec, ropReg, maxAllowedCategory);
- remaining = !succeeded || remaining;
- if (succeeded && markReserved) {
- // This only needs to be called once really with
- // the widest category used, but <shrug>
- markReserved(ropReg, spec.getCategory());
- }
- }
- return !remaining;
+ if (DEBUG) {
+ System.out.println("--->Mapping others");
}
+ handleNormalUnassociated();
- /**
- * Tries to map an SSA register to a rop register.
- *
- * @param ssaSpec {@code non-null;} SSA register
- * @param ropReg {@code >=0;} rop register
- * @param maxAllowedCategory {@code 1..2;} the maximum category
- * that the SSA register is allowed to be
- * @return {@code true} if map succeeded, {@code false} if not
- */
- private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg,
- int maxAllowedCategory) {
- if (ssaSpec.getCategory() <= maxAllowedCategory
- && !ssaRegsMapped.get(ssaSpec.getReg())
- && canMapReg(ssaSpec, ropReg)) {
- addMapping(ssaSpec, ropReg);
- return true;
- }
+ return mapper;
+ }
- return false;
+ /**
+ * Dumps local variable table to stdout for debugging.
+ */
+ private void printLocalVars() {
+ System.out.println("Printing local vars");
+ for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e : localVariables.entrySet()) {
+ StringBuilder regs = new StringBuilder();
+
+ regs.append('{');
+ regs.append(' ');
+ for (RegisterSpec reg : e.getValue()) {
+ regs.append('v');
+ regs.append(reg.getReg());
+ regs.append(' ');
+ }
+ regs.append('}');
+ System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs);
}
+ }
- /**
- * Marks a range of rop registers as "reserved for a local variable."
- *
- * @param ropReg {@code >= 0;} rop register to reserve
- * @param category {@code > 0;} width to reserve
- */
- private void markReserved(int ropReg, int category) {
- reservedRopRegs.set(ropReg, ropReg + category, true);
- }
+ /**
+ * Maps all local-associated parameters to rop registers.
+ */
+ private void handleLocalAssociatedParams() {
+ for (ArrayList<RegisterSpec> ssaRegs : localVariables.values()) {
+ int sz = ssaRegs.size();
+ int paramIndex = -1;
+ int paramCategory = 0;
- /**
- * Checks to see if any rop registers in the specified range are reserved
- * for local variables or parameters.
- *
- * @param ropRangeStart {@code >= 0;} lowest rop register
- * @param width {@code > 0;} number of rop registers in range.
- * @return {@code true} if any register in range is marked reserved
- */
- private boolean rangeContainsReserved(int ropRangeStart, int width) {
- for (int i = ropRangeStart; i < (ropRangeStart + width); i++) {
- if (reservedRopRegs.get(i)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if given rop register represents the {@code this} pointer
- * for a non-static method.
- *
- * @param startReg rop register
- * @return true if the "this" pointer is located here.
- */
- private boolean isThisPointerReg(int startReg) {
- // "this" is always the first parameter.
- return startReg == 0 && !ssaMeth.isStatic();
- }
-
- /**
- * Finds a range of unreserved rop registers.
- *
- * @param startReg {@code >= 0;} a rop register to start the search at
- * @param width {@code > 0;} the width, in registers, required.
- * @return {@code >= 0;} start of available register range.
- */
- private int findNextUnreservedRopReg(int startReg, int width) {
- int reg;
-
- reg = reservedRopRegs.nextClearBit(startReg);
-
- while (true) {
- int i = 1;
-
- while (i < width && !reservedRopRegs.get(reg + i)) {
- i++;
- }
-
- if (i == width) {
- return reg;
- }
-
- reg = reservedRopRegs.nextClearBit(reg + i);
- }
- }
-
- /**
- * Finds a range of rop regs that can be used for local variables.
- * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any
- * rop register that has not yet been used.
- *
- * @param startReg {@code >= 0;} a rop register to start the search at
- * @param width {@code > 0;} the width, in registers, required.
- * @return {@code >= 0;} start of available register range.
- */
- private int findRopRegForLocal(int startReg, int width) {
- int reg;
-
- reg = usedRopRegs.nextClearBit(startReg);
-
- while (true) {
- int i = 1;
-
- while (i < width && !usedRopRegs.get(reg + i)) {
- i++;
- }
-
- if (i == width) {
- return reg;
- }
-
- reg = usedRopRegs.nextClearBit(reg + i);
- }
- }
-
- /**
- * Maps any parameter that isn't local-associated, which can happen
- * in the case where there is no java debug info.
- */
- private void handleUnassociatedParameters() {
- int szSsaRegs = ssaMeth.getRegCount();
-
- for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
- if (ssaRegsMapped.get(ssaReg)) {
- // We already did this one above
- continue;
- }
-
- int paramIndex = getParameterIndexForReg(ssaReg);
-
- RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
- if (paramIndex >= 0) {
- addMapping(ssaSpec, paramIndex);
- }
- }
- }
-
- /**
- * Handles all insns that want a register range for their sources.
- */
- private void handleInvokeRangeInsns() {
- for (NormalSsaInsn insn : invokeRangeInsns) {
- adjustAndMapSourceRangeRange(insn);
- }
- }
-
- /**
- * Handles check cast results to reuse the same source register.
- * Inserts a move if it can't map the same register to both and the
- * check cast is not caught.
- */
- private void handleCheckCastResults() {
- for (NormalSsaInsn insn : moveResultPseudoInsns) {
- RegisterSpec moveRegSpec = insn.getResult();
- int moveReg = moveRegSpec.getReg();
- BitSet predBlocks = insn.getBlock().getPredecessors();
-
- // Expect one predecessor block only
- if (predBlocks.cardinality() != 1) {
- continue;
- }
-
- SsaBasicBlock predBlock =
- ssaMeth.getBlocks().get(predBlocks.nextSetBit(0));
- ArrayList<SsaInsn> insnList = predBlock.getInsns();
-
- /**
- * If the predecessor block has a check-cast, it will be the last
- * instruction
- */
- SsaInsn checkCastInsn = insnList.get(insnList.size() - 1);
- if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) {
- continue;
- }
-
- RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0);
- int checkReg = checkRegSpec.getReg();
-
- /**
- * See if either register is already mapped. Most likely the move
- * result will be mapped already since the cast result is stored
- * in a local variable.
- */
- int category = checkRegSpec.getCategory();
- boolean moveMapped = ssaRegsMapped.get(moveReg);
- boolean checkMapped = ssaRegsMapped.get(checkReg);
- if (moveMapped & !checkMapped) {
- int moveRopReg = mapper.oldToNew(moveReg);
- checkMapped = tryMapReg(checkRegSpec, moveRopReg, category);
- }
- if (checkMapped & !moveMapped) {
- int checkRopReg = mapper.oldToNew(checkReg);
- moveMapped = tryMapReg(moveRegSpec, checkRopReg, category);
- }
-
- // Map any unmapped registers to anything available
- if (!moveMapped || !checkMapped) {
- int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
- ArrayList<RegisterSpec> ssaRegs =
- new ArrayList<RegisterSpec>(2);
- ssaRegs.add(moveRegSpec);
- ssaRegs.add(checkRegSpec);
-
- while (!tryMapRegs(ssaRegs, ropReg, category, false)) {
- ropReg = findNextUnreservedRopReg(ropReg + 1, category);
- }
- }
-
- /*
- * If source and result have a different mapping, insert a move so
- * they can have the same mapping. Don't do this if the check cast
- * is caught, since it will overwrite a potentially live value.
- */
- boolean hasExceptionHandlers =
- checkCastInsn.getOriginalRopInsn().getCatches().size() != 0;
- int moveRopReg = mapper.oldToNew(moveReg);
- int checkRopReg = mapper.oldToNew(checkReg);
- if (moveRopReg != checkRopReg && !hasExceptionHandlers) {
- ((NormalSsaInsn) checkCastInsn).changeOneSource(0,
- insertMoveBefore(checkCastInsn, checkRegSpec));
- addMapping(checkCastInsn.getSources().get(0), moveRopReg);
- }
- }
- }
-
- /**
- * Handles all phi instructions, trying to map them to a common register.
- */
- private void handlePhiInsns() {
- for (PhiInsn insn : phiInsns) {
- processPhiInsn(insn);
- }
- }
-
- /**
- * Maps all non-parameter, non-local variable registers.
- */
- private void handleNormalUnassociated() {
- int szSsaRegs = ssaMeth.getRegCount();
-
- for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
- if (ssaRegsMapped.get(ssaReg)) {
- // We already did this one
- continue;
- }
-
- RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
-
- if (ssaSpec == null) continue;
-
- int category = ssaSpec.getCategory();
- // Find a rop reg that does not interfere
- int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
- while (!canMapReg(ssaSpec, ropReg)) {
- ropReg = findNextUnreservedRopReg(ropReg + 1, category);
- }
-
- addMapping(ssaSpec, ropReg);
- }
- }
-
- /**
- * Checks to see if a list of SSA registers can all be mapped into
- * the same rop reg. Ignores registers that have already been mapped,
- * and checks the interference graph and ensures the range does not
- * cross the parameter range.
- *
- * @param specs {@code non-null;} SSA registers to check
- * @param ropReg {@code >=0;} rop register to check mapping to
- * @return {@code true} if all unmapped registers can be mapped
- */
- private boolean canMapRegs(ArrayList<RegisterSpec> specs, int ropReg) {
- for (RegisterSpec spec : specs) {
- if (ssaRegsMapped.get(spec.getReg())) continue;
- if (!canMapReg(spec, ropReg)) return false;
- }
- return true;
- }
-
- /**
- * Checks to see if {@code ssaSpec} can be mapped to
- * {@code ropReg}. Checks interference graph and ensures
- * the range does not cross the parameter range.
- *
- * @param ssaSpec {@code non-null;} SSA spec
- * @param ropReg prosepctive new-namespace reg
- * @return {@code true} if mapping is possible
- */
- private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) {
- int category = ssaSpec.getCategory();
- return !(spansParamRange(ropReg, category)
- || mapper.interferes(ssaSpec, ropReg));
- }
-
- /**
- * Returns true if the specified rop register + category
- * will cross the boundry between the lower {@code paramWidth}
- * registers reserved for method params and the upper registers. We cannot
- * allocate a register that spans the param block and the normal block,
- * because we will be moving the param block to high registers later.
- *
- * @param ssaReg register in new namespace
- * @param category width that the register will have
- * @return {@code true} in the case noted above
- */
- private boolean spansParamRange(int ssaReg, int category) {
- return ((ssaReg < paramRangeEnd)
- && ((ssaReg + category) > paramRangeEnd));
- }
-
- /**
- * Analyze each instruction and find out all the local variable assignments
- * and move-result-pseudo/invoke-range instrucitons.
- */
- private void analyzeInstructions() {
- ssaMeth.forEachInsn(new SsaInsn.Visitor() {
- /** {@inheritDoc} */
- public void visitMoveInsn(NormalSsaInsn insn) {
- processInsn(insn);
- }
-
- /** {@inheritDoc} */
- public void visitPhiInsn(PhiInsn insn) {
- processInsn(insn);
- }
-
- /** {@inheritDoc} */
- public void visitNonMoveInsn(NormalSsaInsn insn) {
- processInsn(insn);
- }
-
- /**
- * This method collects three types of instructions:
- *
- * 1) Adds a local variable assignment to the
- * {@code localVariables} map.
- * 2) Add move-result-pseudo to the
- * {@code moveResultPseudoInsns} list.
- * 3) Add invoke-range to the
- * {@code invokeRangeInsns} list.
- *
- * @param insn {@code non-null;} insn that may represent a
- * local variable assignment
- */
- private void processInsn(SsaInsn insn) {
- RegisterSpec assignment;
- assignment = insn.getLocalAssignment();
-
- if (assignment != null) {
- LocalItem local = assignment.getLocalItem();
-
- ArrayList<RegisterSpec> regList
- = localVariables.get(local);
-
- if (regList == null) {
- regList = new ArrayList<RegisterSpec>();
- localVariables.put(local, regList);
- }
-
- regList.add(assignment);
- }
-
- if (insn instanceof NormalSsaInsn) {
- if (insn.getOpcode().getOpcode() ==
- RegOps.MOVE_RESULT_PSEUDO) {
- moveResultPseudoInsns.add((NormalSsaInsn) insn);
- } else if (Optimizer.getAdvice().requiresSourcesInOrder(
- insn.getOriginalRopInsn().getOpcode(),
- insn.getSources())) {
- invokeRangeInsns.add((NormalSsaInsn) insn);
- }
- } else if (insn instanceof PhiInsn) {
- phiInsns.add((PhiInsn) insn);
- }
-
- }
- });
- }
-
- /**
- * Adds a mapping from an SSA register to a rop register.
- * {@link #canMapReg} should have already been called.
- *
- * @param ssaSpec {@code non-null;} SSA register to map from
- * @param ropReg {@code >=0;} rop register to map to
- */
- private void addMapping(RegisterSpec ssaSpec, int ropReg) {
+ // First, find out if this local variable is a parameter.
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec ssaSpec = ssaRegs.get(i);
int ssaReg = ssaSpec.getReg();
- // An assertion.
- if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) {
- throw new RuntimeException(
- "attempt to add invalid register mapping");
- }
+ paramIndex = getParameterIndexForReg(ssaReg);
- if (DEBUG) {
- System.out.printf("Add mapping s%d -> v%d c:%d\n",
- ssaSpec.getReg(), ropReg, ssaSpec.getCategory());
+ if (paramIndex >= 0) {
+ paramCategory = ssaSpec.getCategory();
+ addMapping(ssaSpec, paramIndex);
+ break;
}
+ }
- int category = ssaSpec.getCategory();
- mapper.addMapping(ssaSpec.getReg(), ropReg, category);
- ssaRegsMapped.set(ssaReg);
- usedRopRegs.set(ropReg, ropReg + category);
+ if (paramIndex < 0) {
+ // This local wasn't a parameter.
+ continue;
+ }
+
+ // Any remaining local-associated registers will be mapped later.
+ tryMapRegs(ssaRegs, paramIndex, paramCategory, true);
+ }
+ }
+
+ /**
+ * Gets the parameter index for SSA registers that are method parameters.
+ * {@code -1} is returned for non-parameter registers.
+ *
+ * @param ssaReg {@code >=0;} SSA register to look up
+ * @return parameter index or {@code -1} if not a parameter
+ */
+ private int getParameterIndexForReg(int ssaReg) {
+ SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
+ if (defInsn == null) {
+ return -1;
}
+ Rop opcode = defInsn.getOpcode();
- /**
- * Maps the source registers of the specified instruction such that they
- * will fall in a contiguous range in rop form. Moves are inserted as
- * necessary to allow the range to be allocated.
- *
- * @param insn {@code non-null;} insn whos sources to process
- */
- private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) {
- int newRegStart = findRangeAndAdjust(insn);
-
- RegisterSpecList sources = insn.getSources();
- int szSources = sources.size();
- int nextRopReg = newRegStart;
-
- for (int i = 0; i < szSources; i++) {
- RegisterSpec source = sources.get(i);
- int sourceReg = source.getReg();
- int category = source.getCategory();
- int curRopReg = nextRopReg;
- nextRopReg += category;
-
- if (ssaRegsMapped.get(sourceReg)) {
- continue;
- }
-
- LocalItem localItem = getLocalItemForReg(sourceReg);
- addMapping(source, curRopReg);
-
- if (localItem != null) {
- markReserved(curRopReg, category);
- ArrayList<RegisterSpec> similarRegisters
- = localVariables.get(localItem);
-
- int szSimilar = similarRegisters.size();
-
- /*
- * Try to map all SSA registers also associated with
- * this local.
- */
- for (int j = 0; j < szSimilar; j++) {
- RegisterSpec similarSpec = similarRegisters.get(j);
- int similarReg = similarSpec.getReg();
-
- // Don't map anything that's also a source.
- if (-1 != sources.indexOfRegister(similarReg)) {
- continue;
- }
-
- // Registers left unmapped will get handled later.
- tryMapReg(similarSpec, curRopReg, category);
- }
- }
- }
+ // opcode == null for phi insns.
+ if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
+ CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
+ return ((CstInteger) origInsn.getConstant()).getValue();
}
- /**
- * Find a contiguous rop register range that fits the specified
- * instruction's sources. First, try to center the range around
- * sources that have already been mapped to rop registers. If that fails,
- * just find a new contiguous range that doesn't interfere.
- *
- * @param insn {@code non-null;} the insn whose sources need to
- * fit. Must be last insn in basic block.
- * @return {@code >= 0;} rop register of start of range
- */
- private int findRangeAndAdjust(NormalSsaInsn insn) {
- RegisterSpecList sources = insn.getSources();
- int szSources = sources.size();
- // the category for each source index
- int categoriesForIndex[] = new int[szSources];
- int rangeLength = 0;
+ return -1;
+ }
- // Compute rangeLength and categoriesForIndex
- for (int i = 0; i < szSources; i++) {
- int category = sources.get(i).getCategory();
- categoriesForIndex[i] = category;
- rangeLength += categoriesForIndex[i];
+ /**
+ * Maps all local-associated registers that are not parameters.
+ * Tries to find an unreserved range that's wide enough for all of
+ * the SSA registers, and then tries to map them all to that
+ * range. If not all fit, a new range is tried until all registers
+ * have been fit.
+ */
+ private void handleLocalAssociatedOther() {
+ for (ArrayList<RegisterSpec> specs : localVariables.values()) {
+ int ropReg = paramRangeEnd;
+
+ boolean done = false;
+ do {
+ int maxCategory = 1;
+
+ // Compute max category for remaining unmapped registers.
+ int sz = specs.size();
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec ssaSpec = specs.get(i);
+ int category = ssaSpec.getCategory();
+ if (!ssaRegsMapped.get(ssaSpec.getReg()) && category > maxCategory) {
+ maxCategory = category;
+ }
}
- // the highest score of fits tried so far
- int maxScore = Integer.MIN_VALUE;
- // the high scoring range's start
- int resultRangeStart = -1;
- // by source index: set of sources needing moves in high scoring plan
- BitSet resultMovesRequired = null;
+ ropReg = findRopRegForLocal(ropReg, maxCategory);
+ if (canMapRegs(specs, ropReg)) {
+ done = tryMapRegs(specs, ropReg, maxCategory, true);
+ }
+
+ // Increment for next call to findRopRegForLocal.
+ ropReg++;
+ } while (!done);
+ }
+ }
+
+ /**
+ * Tries to map a list of SSA registers into the a rop reg, marking
+ * used rop space as reserved. SSA registers that don't fit are left
+ * unmapped.
+ *
+ * @param specs {@code non-null;} SSA registers to attempt to map
+ * @param ropReg {@code >=0;} rop register to map to
+ * @param maxAllowedCategory {@code 1..2;} maximum category
+ * allowed in mapping.
+ * @param markReserved do so if {@code true}
+ * @return {@code true} if all registers were mapped, {@code false}
+ * if some remain unmapped
+ */
+ private boolean tryMapRegs(ArrayList<RegisterSpec> specs, int ropReg, int maxAllowedCategory,
+ boolean markReserved) {
+ boolean remaining = false;
+ for (RegisterSpec spec : specs) {
+ if (ssaRegsMapped.get(spec.getReg())) {
+ continue;
+ }
+
+ boolean succeeded;
+ succeeded = tryMapReg(spec, ropReg, maxAllowedCategory);
+ remaining = !succeeded || remaining;
+ if (succeeded && markReserved) {
+ // This only needs to be called once really with
+ // the widest category used, but <shrug>
+ markReserved(ropReg, spec.getCategory());
+ }
+ }
+ return !remaining;
+ }
+
+ /**
+ * Tries to map an SSA register to a rop register.
+ *
+ * @param ssaSpec {@code non-null;} SSA register
+ * @param ropReg {@code >=0;} rop register
+ * @param maxAllowedCategory {@code 1..2;} the maximum category
+ * that the SSA register is allowed to be
+ * @return {@code true} if map succeeded, {@code false} if not
+ */
+ private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg, int maxAllowedCategory) {
+ if (ssaSpec.getCategory() <= maxAllowedCategory && !ssaRegsMapped.get(ssaSpec.getReg())
+ && canMapReg(ssaSpec, ropReg)) {
+ addMapping(ssaSpec, ropReg);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Marks a range of rop registers as "reserved for a local variable."
+ *
+ * @param ropReg {@code >= 0;} rop register to reserve
+ * @param category {@code > 0;} width to reserve
+ */
+ private void markReserved(int ropReg, int category) {
+ reservedRopRegs.set(ropReg, ropReg + category, true);
+ }
+
+ /**
+ * Checks to see if any rop registers in the specified range are reserved
+ * for local variables or parameters.
+ *
+ * @param ropRangeStart {@code >= 0;} lowest rop register
+ * @param width {@code > 0;} number of rop registers in range.
+ * @return {@code true} if any register in range is marked reserved
+ */
+ private boolean rangeContainsReserved(int ropRangeStart, int width) {
+ for (int i = ropRangeStart; i < (ropRangeStart + width); i++) {
+ if (reservedRopRegs.get(i)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds a range of unreserved rop registers.
+ *
+ * @param startReg {@code >= 0;} a rop register to start the search at
+ * @param width {@code > 0;} the width, in registers, required.
+ * @return {@code >= 0;} start of available register range.
+ */
+ private int findNextUnreservedRopReg(int startReg, int width) {
+ int reg;
+
+ reg = reservedRopRegs.nextClearBit(startReg);
+
+ while (true) {
+ int i = 1;
+
+ while (i < width && !reservedRopRegs.get(reg + i)) {
+ i++;
+ }
+
+ if (i == width) {
+ return reg;
+ }
+
+ reg = reservedRopRegs.nextClearBit(reg + i);
+ }
+ }
+
+ /**
+ * Finds a range of rop regs that can be used for local variables.
+ * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any
+ * rop register that has not yet been used.
+ *
+ * @param startReg {@code >= 0;} a rop register to start the search at
+ * @param width {@code > 0;} the width, in registers, required.
+ * @return {@code >= 0;} start of available register range.
+ */
+ private int findRopRegForLocal(int startReg, int width) {
+ int reg;
+
+ reg = usedRopRegs.nextClearBit(startReg);
+
+ while (true) {
+ int i = 1;
+
+ while (i < width && !usedRopRegs.get(reg + i)) {
+ i++;
+ }
+
+ if (i == width) {
+ return reg;
+ }
+
+ reg = usedRopRegs.nextClearBit(reg + i);
+ }
+ }
+
+ /**
+ * Maps any parameter that isn't local-associated, which can happen
+ * in the case where there is no java debug info.
+ */
+ private void handleUnassociatedParameters() {
+ int szSsaRegs = ssaMeth.getRegCount();
+
+ for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
+ if (ssaRegsMapped.get(ssaReg)) {
+ // We already did this one above
+ continue;
+ }
+
+ int paramIndex = getParameterIndexForReg(ssaReg);
+
+ RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
+ if (paramIndex >= 0) {
+ addMapping(ssaSpec, paramIndex);
+ }
+ }
+ }
+
+ /**
+ * Handles all insns that want a register range for their sources.
+ */
+ private void handleInvokeRangeInsns() {
+ for (NormalSsaInsn insn : invokeRangeInsns) {
+ adjustAndMapSourceRangeRange(insn);
+ }
+ }
+
+ /**
+ * Handles check cast results to reuse the same source register.
+ * Inserts a move if it can't map the same register to both and the
+ * check cast is not caught.
+ */
+ private void handleCheckCastResults() {
+ for (NormalSsaInsn insn : moveResultPseudoInsns) {
+ RegisterSpec moveRegSpec = insn.getResult();
+ int moveReg = moveRegSpec.getReg();
+ BitSet predBlocks = insn.getBlock().getPredecessors();
+
+ // Expect one predecessor block only
+ if (predBlocks.cardinality() != 1) {
+ continue;
+ }
+
+ SsaBasicBlock predBlock = ssaMeth.getBlocks().get(predBlocks.nextSetBit(0));
+ ArrayList<SsaInsn> insnList = predBlock.getInsns();
+
+ /**
+ * If the predecessor block has a check-cast, it will be the last
+ * instruction
+ */
+ SsaInsn checkCastInsn = insnList.get(insnList.size() - 1);
+ if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) {
+ continue;
+ }
+
+ RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0);
+ int checkReg = checkRegSpec.getReg();
+
+ /**
+ * See if either register is already mapped. Most likely the move
+ * result will be mapped already since the cast result is stored
+ * in a local variable.
+ */
+ int category = checkRegSpec.getCategory();
+ boolean moveMapped = ssaRegsMapped.get(moveReg);
+ boolean checkMapped = ssaRegsMapped.get(checkReg);
+ if (moveMapped & !checkMapped) {
+ int moveRopReg = mapper.oldToNew(moveReg);
+ checkMapped = tryMapReg(checkRegSpec, moveRopReg, category);
+ }
+ if (checkMapped & !moveMapped) {
+ int checkRopReg = mapper.oldToNew(checkReg);
+ moveMapped = tryMapReg(moveRegSpec, checkRopReg, category);
+ }
+
+ // Map any unmapped registers to anything available
+ if (!moveMapped || !checkMapped) {
+ int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
+ ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>(2);
+ ssaRegs.add(moveRegSpec);
+ ssaRegs.add(checkRegSpec);
+
+ while (!tryMapRegs(ssaRegs, ropReg, category, false)) {
+ ropReg = findNextUnreservedRopReg(ropReg + 1, category);
+ }
+ }
+
+ /*
+ * If source and result have a different mapping, insert a move so
+ * they can have the same mapping. Don't do this if the check cast
+ * is caught, since it will overwrite a potentially live value.
+ */
+ boolean hasExceptionHandlers = checkCastInsn.getOriginalRopInsn().getCatches().size() != 0;
+ int moveRopReg = mapper.oldToNew(moveReg);
+ int checkRopReg = mapper.oldToNew(checkReg);
+ if (moveRopReg != checkRopReg && !hasExceptionHandlers) {
+ ((NormalSsaInsn) checkCastInsn).changeOneSource(0,
+ insertMoveBefore(checkCastInsn, checkRegSpec));
+ addMapping(checkCastInsn.getSources().get(0), moveRopReg);
+ }
+ }
+ }
+
+ /**
+ * Handles all phi instructions, trying to map them to a common register.
+ */
+ private void handlePhiInsns() {
+ for (PhiInsn insn : phiInsns) {
+ processPhiInsn(insn);
+ }
+ }
+
+ /**
+ * Maps all non-parameter, non-local variable registers.
+ */
+ private void handleNormalUnassociated() {
+ int szSsaRegs = ssaMeth.getRegCount();
+
+ for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
+ if (ssaRegsMapped.get(ssaReg)) {
+ // We already did this one
+ continue;
+ }
+
+ RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
+
+ if (ssaSpec == null) {
+ continue;
+ }
+
+ int category = ssaSpec.getCategory();
+ // Find a rop reg that does not interfere
+ int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
+ while (!canMapReg(ssaSpec, ropReg)) {
+ ropReg = findNextUnreservedRopReg(ropReg + 1, category);
+ }
+
+ addMapping(ssaSpec, ropReg);
+ }
+ }
+
+ /**
+ * Checks to see if a list of SSA registers can all be mapped into
+ * the same rop reg. Ignores registers that have already been mapped,
+ * and checks the interference graph and ensures the range does not
+ * cross the parameter range.
+ *
+ * @param specs {@code non-null;} SSA registers to check
+ * @param ropReg {@code >=0;} rop register to check mapping to
+ * @return {@code true} if all unmapped registers can be mapped
+ */
+ private boolean canMapRegs(ArrayList<RegisterSpec> specs, int ropReg) {
+ for (RegisterSpec spec : specs) {
+ if (ssaRegsMapped.get(spec.getReg())) {
+ continue;
+ }
+ if (!canMapReg(spec, ropReg)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks to see if {@code ssaSpec} can be mapped to
+ * {@code ropReg}. Checks interference graph and ensures
+ * the range does not cross the parameter range.
+ *
+ * @param ssaSpec {@code non-null;} SSA spec
+ * @param ropReg prosepctive new-namespace reg
+ * @return {@code true} if mapping is possible
+ */
+ private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) {
+ int category = ssaSpec.getCategory();
+ return !(spansParamRange(ropReg, category) || mapper.interferes(ssaSpec, ropReg));
+ }
+
+ /**
+ * Returns true if the specified rop register + category
+ * will cross the boundry between the lower {@code paramWidth}
+ * registers reserved for method params and the upper registers. We cannot
+ * allocate a register that spans the param block and the normal block,
+ * because we will be moving the param block to high registers later.
+ *
+ * @param ssaReg register in new namespace
+ * @param category width that the register will have
+ * @return {@code true} in the case noted above
+ */
+ private boolean spansParamRange(int ssaReg, int category) {
+ return ((ssaReg < paramRangeEnd) && ((ssaReg + category) > paramRangeEnd));
+ }
+
+ /**
+ * Analyze each instruction and find out all the local variable assignments
+ * and move-result-pseudo/invoke-range instrucitons.
+ */
+ private void analyzeInstructions() {
+ ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+ /** {@inheritDoc} */
+ @Override
+ public void visitMoveInsn(NormalSsaInsn insn) {
+ processInsn(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitPhiInsn(PhiInsn insn) {
+ processInsn(insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitNonMoveInsn(NormalSsaInsn insn) {
+ processInsn(insn);
+ }
+
+ /**
+ * This method collects three types of instructions:
+ *
+ * 1) Adds a local variable assignment to the
+ * {@code localVariables} map.
+ * 2) Add move-result-pseudo to the
+ * {@code moveResultPseudoInsns} list.
+ * 3) Add invoke-range to the
+ * {@code invokeRangeInsns} list.
+ *
+ * @param insn {@code non-null;} insn that may represent a
+ * local variable assignment
+ */
+ private void processInsn(SsaInsn insn) {
+ RegisterSpec assignment;
+ assignment = insn.getLocalAssignment();
+
+ if (assignment != null) {
+ LocalItem local = assignment.getLocalItem();
+
+ ArrayList<RegisterSpec> regList = localVariables.get(local);
+
+ if (regList == null) {
+ regList = new ArrayList<RegisterSpec>();
+ localVariables.put(local, regList);
+ }
+
+ regList.add(assignment);
+ }
+
+ if (insn instanceof NormalSsaInsn) {
+ if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+ moveResultPseudoInsns.add((NormalSsaInsn) insn);
+ } else if (Optimizer.getAdvice().requiresSourcesInOrder(
+ insn.getOriginalRopInsn().getOpcode(), insn.getSources())) {
+ invokeRangeInsns.add((NormalSsaInsn) insn);
+ }
+ } else if (insn instanceof PhiInsn) {
+ phiInsns.add((PhiInsn) insn);
+ }
+
+ }
+ });
+ }
+
+ /**
+ * Adds a mapping from an SSA register to a rop register.
+ * {@link #canMapReg} should have already been called.
+ *
+ * @param ssaSpec {@code non-null;} SSA register to map from
+ * @param ropReg {@code >=0;} rop register to map to
+ */
+ private void addMapping(RegisterSpec ssaSpec, int ropReg) {
+ int ssaReg = ssaSpec.getReg();
+
+ // An assertion.
+ if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) {
+ throw new RuntimeException("attempt to add invalid register mapping");
+ }
+
+ if (DEBUG) {
+ System.out.printf("Add mapping s%d -> v%d c:%d\n", ssaSpec.getReg(), ropReg,
+ ssaSpec.getCategory());
+ }
+
+ int category = ssaSpec.getCategory();
+ mapper.addMapping(ssaSpec.getReg(), ropReg, category);
+ ssaRegsMapped.set(ssaReg);
+ usedRopRegs.set(ropReg, ropReg + category);
+ }
+
+
+ /**
+ * Maps the source registers of the specified instruction such that they
+ * will fall in a contiguous range in rop form. Moves are inserted as
+ * necessary to allow the range to be allocated.
+ *
+ * @param insn {@code non-null;} insn whos sources to process
+ */
+ private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) {
+ int newRegStart = findRangeAndAdjust(insn);
+
+ RegisterSpecList sources = insn.getSources();
+ int szSources = sources.size();
+ int nextRopReg = newRegStart;
+
+ for (int i = 0; i < szSources; i++) {
+ RegisterSpec source = sources.get(i);
+ int sourceReg = source.getReg();
+ int category = source.getCategory();
+ int curRopReg = nextRopReg;
+ nextRopReg += category;
+
+ if (ssaRegsMapped.get(sourceReg)) {
+ continue;
+ }
+
+ LocalItem localItem = getLocalItemForReg(sourceReg);
+ addMapping(source, curRopReg);
+
+ if (localItem != null) {
+ markReserved(curRopReg, category);
+ ArrayList<RegisterSpec> similarRegisters = localVariables.get(localItem);
+
+ int szSimilar = similarRegisters.size();
/*
- * First, go through each source that's already been mapped. Try
- * to center the range around the rop register this source is mapped
- * to.
+ * Try to map all SSA registers also associated with
+ * this local.
*/
- int rangeStartOffset = 0;
- for (int i = 0; i < szSources; i++) {
- int ssaCenterReg = sources.get(i).getReg();
+ for (int j = 0; j < szSimilar; j++) {
+ RegisterSpec similarSpec = similarRegisters.get(j);
+ int similarReg = similarSpec.getReg();
- if (i != 0) {
- rangeStartOffset -= categoriesForIndex[i - 1];
- }
- if (!ssaRegsMapped.get(ssaCenterReg)) {
- continue;
- }
+ // Don't map anything that's also a source.
+ if (-1 != sources.indexOfRegister(similarReg)) {
+ continue;
+ }
- int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset;
-
- if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) {
- continue;
- }
-
- BitSet curMovesRequired = new BitSet(szSources);
-
- int fitWidth
- = fitPlanForRange(rangeStart, insn, categoriesForIndex,
- curMovesRequired);
-
- if (fitWidth < 0) {
- continue;
- }
-
- int score = fitWidth - curMovesRequired.cardinality();
-
- if (score > maxScore) {
- maxScore = score;
- resultRangeStart = rangeStart;
- resultMovesRequired = curMovesRequired;
- }
-
- if (fitWidth == rangeLength) {
- // We can't do any better than this, so stop here
- break;
- }
+ // Registers left unmapped will get handled later.
+ tryMapReg(similarSpec, curRopReg, category);
}
+ }
+ }
+ }
+ /**
+ * Find a contiguous rop register range that fits the specified
+ * instruction's sources. First, try to center the range around
+ * sources that have already been mapped to rop registers. If that fails,
+ * just find a new contiguous range that doesn't interfere.
+ *
+ * @param insn {@code non-null;} the insn whose sources need to
+ * fit. Must be last insn in basic block.
+ * @return {@code >= 0;} rop register of start of range
+ */
+ private int findRangeAndAdjust(NormalSsaInsn insn) {
+ RegisterSpecList sources = insn.getSources();
+ int szSources = sources.size();
+ // the category for each source index
+ int categoriesForIndex[] = new int[szSources];
+ int rangeLength = 0;
+
+ // Compute rangeLength and categoriesForIndex
+ for (int i = 0; i < szSources; i++) {
+ int category = sources.get(i).getCategory();
+ categoriesForIndex[i] = category;
+ rangeLength += categoriesForIndex[i];
+ }
+
+ // the highest score of fits tried so far
+ int maxScore = Integer.MIN_VALUE;
+ // the high scoring range's start
+ int resultRangeStart = -1;
+ // by source index: set of sources needing moves in high scoring plan
+ BitSet resultMovesRequired = null;
+
+ /*
+ * First, go through each source that's already been mapped. Try
+ * to center the range around the rop register this source is mapped
+ * to.
+ */
+ int rangeStartOffset = 0;
+ for (int i = 0; i < szSources; i++) {
+ int ssaCenterReg = sources.get(i).getReg();
+
+ if (i != 0) {
+ rangeStartOffset -= categoriesForIndex[i - 1];
+ }
+ if (!ssaRegsMapped.get(ssaCenterReg)) {
+ continue;
+ }
+
+ int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset;
+
+ if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) {
+ continue;
+ }
+
+ BitSet curMovesRequired = new BitSet(szSources);
+
+ int fitWidth = fitPlanForRange(rangeStart, insn, categoriesForIndex, curMovesRequired);
+
+ if (fitWidth < 0) {
+ continue;
+ }
+
+ int score = fitWidth - curMovesRequired.cardinality();
+
+ if (score > maxScore) {
+ maxScore = score;
+ resultRangeStart = rangeStart;
+ resultMovesRequired = curMovesRequired;
+ }
+
+ if (fitWidth == rangeLength) {
+ // We can't do any better than this, so stop here
+ break;
+ }
+ }
+
+ /*
+ * If we were unable to find a plan for a fit centered around
+ * an already-mapped source, just try to find a range of
+ * registers we can move the range into.
+ */
+
+if (resultRangeStart == -1) {
+ resultMovesRequired = new BitSet(szSources);
+
+ resultRangeStart =
+ findAnyFittingRange(insn, rangeLength, categoriesForIndex, resultMovesRequired);
+ }
+
+ /*
+ * Now, insert any moves required.
+ */
+
+for (int i = resultMovesRequired.nextSetBit(0); i >= 0;
+ i = resultMovesRequired.nextSetBit(i + 1)) {
+ insn.changeOneSource(i, insertMoveBefore(insn, sources.get(i)));
+ }
+
+ return resultRangeStart;
+ }
+
+ /**
+ * Finds an unreserved range that will fit the sources of the
+ * specified instruction. Does not bother trying to center the range
+ * around an already-mapped source register;
+ *
+ * @param insn {@code non-null;} insn to build range for
+ * @param rangeLength {@code >=0;} length required in register units
+ * @param categoriesForIndex {@code non-null;} indexed by source index;
+ * the category for each source
+ * @param outMovesRequired {@code non-null;} an output parameter indexed by
+ * source index that will contain the set of sources which need
+ * moves inserted
+ * @return the rop register that starts the fitting range
+ */
+ private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength, int[] categoriesForIndex,
+ BitSet outMovesRequired) {
+ int rangeStart = paramRangeEnd;
+ while (true) {
+ rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength);
+ int fitWidth = fitPlanForRange(rangeStart, insn, categoriesForIndex, outMovesRequired);
+
+ if (fitWidth >= 0) {
+ break;
+ }
+ rangeStart++;
+ outMovesRequired.clear();
+ }
+ return rangeStart;
+ }
+
+ /**
+ * Attempts to build a plan for fitting a range of sources into rop
+ * registers.
+ *
+ * @param ropReg {@code >= 0;} rop reg that begins range
+ * @param insn {@code non-null;} insn to plan range for
+ * @param categoriesForIndex {@code non-null;} indexed by source index;
+ * the category for each source
+ * @param outMovesRequired {@code non-null;} an output parameter indexed by
+ * source index that will contain the set of sources which need
+ * moves inserted
+ * @return the width of the fit that that does not involve added moves or
+ * {@code -1} if "no fit possible"
+ */
+ private int fitPlanForRange(int ropReg, NormalSsaInsn insn, int[] categoriesForIndex,
+ BitSet outMovesRequired) {
+ RegisterSpecList sources = insn.getSources();
+ int szSources = sources.size();
+ int fitWidth = 0;
+ IntSet liveOut = insn.getBlock().getLiveOutRegs();
+ RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut);
+
+ // An SSA reg may only be mapped into a range once.
+ BitSet seen = new BitSet(ssaMeth.getRegCount());
+
+ for (int i = 0; i < szSources; i++) {
+ RegisterSpec ssaSpec = sources.get(i);
+ int ssaReg = ssaSpec.getReg();
+ int category = categoriesForIndex[i];
+
+ if (i != 0) {
+ ropReg += categoriesForIndex[i - 1];
+ }
+
+ if (ssaRegsMapped.get(ssaReg) && mapper.oldToNew(ssaReg) == ropReg) {
+ // This is a register that is already mapped appropriately.
+ fitWidth += category;
+ } else if (rangeContainsReserved(ropReg, category)) {
+ fitWidth = -1;
+ break;
+ } else if (!ssaRegsMapped.get(ssaReg) && canMapReg(ssaSpec, ropReg) && !seen.get(ssaReg)) {
+ // This is a register that can be mapped appropriately.
+ fitWidth += category;
+ } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category)
+ && !mapper.areAnyPinned(sources, ropReg, category)) {
/*
- * If we were unable to find a plan for a fit centered around
- * an already-mapped source, just try to find a range of
- * registers we can move the range into.
- */
-
- if (resultRangeStart == -1) {
- resultMovesRequired = new BitSet(szSources);
-
- resultRangeStart = findAnyFittingRange(insn, rangeLength,
- categoriesForIndex, resultMovesRequired);
- }
-
- /*
- * Now, insert any moves required.
- */
-
- for (int i = resultMovesRequired.nextSetBit(0); i >= 0;
- i = resultMovesRequired.nextSetBit(i+1)) {
- insn.changeOneSource(i, insertMoveBefore(insn, sources.get(i)));
- }
-
- return resultRangeStart;
- }
-
- /**
- * Finds an unreserved range that will fit the sources of the
- * specified instruction. Does not bother trying to center the range
- * around an already-mapped source register;
- *
- * @param insn {@code non-null;} insn to build range for
- * @param rangeLength {@code >=0;} length required in register units
- * @param categoriesForIndex {@code non-null;} indexed by source index;
- * the category for each source
- * @param outMovesRequired {@code non-null;} an output parameter indexed by
- * source index that will contain the set of sources which need
- * moves inserted
- * @return the rop register that starts the fitting range
- */
- private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength,
- int[] categoriesForIndex, BitSet outMovesRequired) {
- int rangeStart = paramRangeEnd;
- while (true) {
- rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength);
- int fitWidth
- = fitPlanForRange(rangeStart, insn,
- categoriesForIndex, outMovesRequired);
-
- if (fitWidth >= 0) {
- break;
- }
- rangeStart++;
- outMovesRequired.clear();
- }
- return rangeStart;
- }
-
- /**
- * Attempts to build a plan for fitting a range of sources into rop
- * registers.
- *
- * @param ropReg {@code >= 0;} rop reg that begins range
- * @param insn {@code non-null;} insn to plan range for
- * @param categoriesForIndex {@code non-null;} indexed by source index;
- * the category for each source
- * @param outMovesRequired {@code non-null;} an output parameter indexed by
- * source index that will contain the set of sources which need
- * moves inserted
- * @return the width of the fit that that does not involve added moves or
- * {@code -1} if "no fit possible"
- */
- private int fitPlanForRange(int ropReg, NormalSsaInsn insn,
- int[] categoriesForIndex, BitSet outMovesRequired) {
- RegisterSpecList sources = insn.getSources();
- int szSources = sources.size();
- int fitWidth = 0;
- IntSet liveOut = insn.getBlock().getLiveOutRegs();
- RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut);
-
- // An SSA reg may only be mapped into a range once.
- BitSet seen = new BitSet(ssaMeth.getRegCount());
-
- for (int i = 0; i < szSources ; i++) {
- RegisterSpec ssaSpec = sources.get(i);
- int ssaReg = ssaSpec.getReg();
- int category = categoriesForIndex[i];
-
- if (i != 0) {
- ropReg += categoriesForIndex[i-1];
- }
-
- if (ssaRegsMapped.get(ssaReg)
- && mapper.oldToNew(ssaReg) == ropReg) {
- // This is a register that is already mapped appropriately.
- fitWidth += category;
- } else if (rangeContainsReserved(ropReg, category)) {
- fitWidth = -1;
- break;
- } else if (!ssaRegsMapped.get(ssaReg)
- && canMapReg(ssaSpec, ropReg)
- && !seen.get(ssaReg)) {
- // This is a register that can be mapped appropriately.
- fitWidth += category;
- } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category)
- && !mapper.areAnyPinned(sources, ropReg, category)) {
- /*
- * This is a source that can be moved. We can insert a
- * move as long as:
- *
- * * no SSA register pinned to the desired rop reg
- * is live out on the block
- *
- * * no SSA register pinned to desired rop reg is
- * a source of this insn (since this may require
- * overlapping moves, which we can't presently handle)
- */
-
- outMovesRequired.set(i);
- } else {
- fitWidth = -1;
- break;
- }
-
- seen.set(ssaReg);
- }
- return fitWidth;
- }
-
- /**
- * Converts a bit set of SSA registers into a RegisterSpecList containing
- * the definition specs of all the registers.
- *
- * @param ssaSet {@code non-null;} set of SSA registers
- * @return list of RegisterSpecs as noted above
- */
- RegisterSpecList ssaSetToSpecs(IntSet ssaSet) {
- RegisterSpecList result = new RegisterSpecList(ssaSet.elements());
-
- IntIterator iter = ssaSet.iterator();
-
- int i = 0;
- while (iter.hasNext()) {
- result.set(i++, getDefinitionSpecForSsaReg(iter.next()));
- }
-
- return result;
- }
-
- /**
- * Gets a local item associated with an ssa register, if one exists.
- *
- * @param ssaReg {@code >= 0;} SSA register
- * @return {@code null-ok;} associated local item or null
- */
- private LocalItem getLocalItemForReg(int ssaReg) {
- for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry :
- localVariables.entrySet()) {
- for (RegisterSpec spec : entry.getValue()) {
- if (spec.getReg() == ssaReg) {
- return entry.getKey();
- }
- }
- }
-
- return null;
- }
-
- /**
- * Attempts to map the sources and result of a phi to a common register.
- * Will try existing mappings first, from most to least common. If none
- * of the registers have mappings yet, a new mapping is created.
- */
- private void processPhiInsn(PhiInsn insn) {
- RegisterSpec result = insn.getResult();
- int resultReg = result.getReg();
- int category = result.getCategory();
-
- RegisterSpecList sources = insn.getSources();
- int sourcesSize = sources.size();
-
- // List of phi sources / result that need mapping
- ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>();
-
- // Track how many times a particular mapping is found
- Multiset mapSet = new Multiset(sourcesSize + 1);
-
- /*
- * If the result of the phi has an existing mapping, get it.
- * Otherwise, add it to the list of regs that need mapping.
- */
- if (ssaRegsMapped.get(resultReg)) {
- mapSet.add(mapper.oldToNew(resultReg));
- } else {
- ssaRegs.add(result);
- }
-
- for (int i = 0; i < sourcesSize; i++) {
- RegisterSpec source = sources.get(i);
- SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg());
- RegisterSpec sourceDef = def.getResult();
- int sourceReg = sourceDef.getReg();
-
- /*
- * If a source of the phi has an existing mapping, get it.
- * Otherwise, add it to the list of regs that need mapping.
- */
- if (ssaRegsMapped.get(sourceReg)) {
- mapSet.add(mapper.oldToNew(sourceReg));
- } else {
- ssaRegs.add(sourceDef);
- }
- }
-
- // Try all existing mappings, with the most common ones first
- for (int i = 0; i < mapSet.getSize(); i++) {
- int maxReg = mapSet.getAndRemoveHighestCount();
- tryMapRegs(ssaRegs, maxReg, category, false);
- }
-
- // Map any remaining unmapped regs with whatever fits
- int mapReg = findNextUnreservedRopReg(paramRangeEnd, category);
- while (!tryMapRegs(ssaRegs, mapReg, category, false)) {
- mapReg = findNextUnreservedRopReg(mapReg + 1, category);
- }
- }
-
- // A set that tracks how often elements are added to it.
- private static class Multiset {
- private final int[] reg;
- private final int[] count;
- private int size;
-
- /**
- * Constructs an instance.
+ * This is a source that can be moved. We can insert a
+ * move as long as:
*
- * @param maxSize the maximum distinct elements the set may have
- */
- public Multiset(int maxSize) {
- reg = new int[maxSize];
- count = new int[maxSize];
- size = 0;
- }
-
- /**
- * Adds an element to the set.
+ * * no SSA register pinned to the desired rop reg
+ * is live out on the block
*
- * @param element element to add
+ * * no SSA register pinned to desired rop reg is
+ * a source of this insn (since this may require
+ * overlapping moves, which we can't presently handle)
*/
- public void add(int element) {
- for (int i = 0; i < size; i++) {
- if (reg[i] == element) {
- count[i]++;
- return;
- }
- }
- reg[size] = element;
- count[size] = 1;
- size++;
- }
+outMovesRequired.set(i);
+ } else {
+ fitWidth = -1;
+ break;
+ }
- /**
- * Searches the set for the element that has been added the most.
- * In the case of a tie, the element that was added first is returned.
- * Then, it clears the count on that element. The size of the set
- * remains unchanged.
- *
- * @return element with the highest count
- */
- public int getAndRemoveHighestCount() {
- int maxIndex = -1;
- int maxReg = -1;
- int maxCount = 0;
-
- for (int i = 0; i < size; i++) {
- if (maxCount < count[i]) {
- maxIndex = i;
- maxReg = reg[i];
- maxCount = count[i];
- }
- }
-
- count[maxIndex] = 0;
- return maxReg;
- }
-
- /**
- * Gets the number of distinct elements in the set.
- *
- * @return size of the set
- */
- public int getSize() {
- return size;
- }
+ seen.set(ssaReg);
}
+ return fitWidth;
+ }
+
+ /**
+ * Converts a bit set of SSA registers into a RegisterSpecList containing
+ * the definition specs of all the registers.
+ *
+ * @param ssaSet {@code non-null;} set of SSA registers
+ * @return list of RegisterSpecs as noted above
+ */
+ RegisterSpecList ssaSetToSpecs(IntSet ssaSet) {
+ RegisterSpecList result = new RegisterSpecList(ssaSet.elements());
+
+ IntIterator iter = ssaSet.iterator();
+
+ int i = 0;
+ while (iter.hasNext()) {
+ result.set(i++, getDefinitionSpecForSsaReg(iter.next()));
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets a local item associated with an ssa register, if one exists.
+ *
+ * @param ssaReg {@code >= 0;} SSA register
+ * @return {@code null-ok;} associated local item or null
+ */
+ private LocalItem getLocalItemForReg(int ssaReg) {
+ for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry : localVariables.entrySet()) {
+ for (RegisterSpec spec : entry.getValue()) {
+ if (spec.getReg() == ssaReg) {
+ return entry.getKey();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Attempts to map the sources and result of a phi to a common register.
+ * Will try existing mappings first, from most to least common. If none
+ * of the registers have mappings yet, a new mapping is created.
+ */
+ private void processPhiInsn(PhiInsn insn) {
+ RegisterSpec result = insn.getResult();
+ int resultReg = result.getReg();
+ int category = result.getCategory();
+
+ RegisterSpecList sources = insn.getSources();
+ int sourcesSize = sources.size();
+
+ // List of phi sources / result that need mapping
+ ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>();
+
+ // Track how many times a particular mapping is found
+ Multiset mapSet = new Multiset(sourcesSize + 1);
+
+ /*
+ * If the result of the phi has an existing mapping, get it.
+ * Otherwise, add it to the list of regs that need mapping.
+ */
+ if (ssaRegsMapped.get(resultReg)) {
+ mapSet.add(mapper.oldToNew(resultReg));
+ } else {
+ ssaRegs.add(result);
+ }
+
+ for (int i = 0; i < sourcesSize; i++) {
+ RegisterSpec source = sources.get(i);
+ SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg());
+ RegisterSpec sourceDef = def.getResult();
+ int sourceReg = sourceDef.getReg();
+
+ /*
+ * If a source of the phi has an existing mapping, get it.
+ * Otherwise, add it to the list of regs that need mapping.
+ */
+ if (ssaRegsMapped.get(sourceReg)) {
+ mapSet.add(mapper.oldToNew(sourceReg));
+ } else {
+ ssaRegs.add(sourceDef);
+ }
+ }
+
+ // Try all existing mappings, with the most common ones first
+ for (int i = 0; i < mapSet.getSize(); i++) {
+ int maxReg = mapSet.getAndRemoveHighestCount();
+ tryMapRegs(ssaRegs, maxReg, category, false);
+ }
+
+ // Map any remaining unmapped regs with whatever fits
+ int mapReg = findNextUnreservedRopReg(paramRangeEnd, category);
+ while (!tryMapRegs(ssaRegs, mapReg, category, false)) {
+ mapReg = findNextUnreservedRopReg(mapReg + 1, category);
+ }
+ }
+
+ // A set that tracks how often elements are added to it.
+ private static class Multiset {
+ private final int[] reg;
+ private final int[] count;
+ private int size;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param maxSize the maximum distinct elements the set may have
+ */
+ public Multiset(int maxSize) {
+ reg = new int[maxSize];
+ count = new int[maxSize];
+ size = 0;
+ }
+
+ /**
+ * Adds an element to the set.
+ *
+ * @param element element to add
+ */
+ public void add(int element) {
+ for (int i = 0; i < size; i++) {
+ if (reg[i] == element) {
+ count[i]++;
+ return;
+ }
+ }
+
+ reg[size] = element;
+ count[size] = 1;
+ size++;
+ }
+
+ /**
+ * Searches the set for the element that has been added the most.
+ * In the case of a tie, the element that was added first is returned.
+ * Then, it clears the count on that element. The size of the set
+ * remains unchanged.
+ *
+ * @return element with the highest count
+ */
+ public int getAndRemoveHighestCount() {
+ int maxIndex = -1;
+ int maxReg = -1;
+ int maxCount = 0;
+
+ for (int i = 0; i < size; i++) {
+ if (maxCount < count[i]) {
+ maxIndex = i;
+ maxReg = reg[i];
+ maxCount = count[i];
+ }
+ }
+
+ count[maxIndex] = 0;
+ return maxReg;
+ }
+
+ /**
+ * Gets the number of distinct elements in the set.
+ *
+ * @return size of the set
+ */
+ public int getSize() {
+ return size;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/IdenticalBlockCombiner.java b/dx/src/com/android/jack/dx/ssa/back/IdenticalBlockCombiner.java
index c679d61..9e8b870 100644
--- a/dx/src/com/android/jack/dx/ssa/back/IdenticalBlockCombiner.java
+++ b/dx/src/com/android/jack/dx/ssa/back/IdenticalBlockCombiner.java
@@ -18,12 +18,8 @@
import com.android.jack.dx.rop.code.BasicBlock;
import com.android.jack.dx.rop.code.BasicBlockList;
-import com.android.jack.dx.rop.code.CstInsn;
-import com.android.jack.dx.rop.code.Insn;
-import com.android.jack.dx.rop.code.InsnList;
import com.android.jack.dx.rop.code.RegOps;
import com.android.jack.dx.rop.code.RopMethod;
-import com.android.jack.dx.rop.code.SwitchInsn;
import com.android.jack.dx.util.IntList;
import java.util.BitSet;
@@ -35,148 +31,145 @@
* frequently are created when catch blocks are edge-split.
*/
public class IdenticalBlockCombiner {
- private final RopMethod ropMethod;
- private final BasicBlockList blocks;
- private final BasicBlockList newBlocks;
+ private final RopMethod ropMethod;
+ private final BasicBlockList blocks;
+ private final BasicBlockList newBlocks;
- /**
- * Constructs instance. Call {@code process()} to run.
- *
- * @param rm {@code non-null;} instance to process
- */
- public IdenticalBlockCombiner(RopMethod rm) {
- ropMethod = rm;
- blocks = ropMethod.getBlocks();
- newBlocks = blocks.getMutableCopy();
- }
+ /**
+ * Constructs instance. Call {@code process()} to run.
+ *
+ * @param rm {@code non-null;} instance to process
+ */
+ public IdenticalBlockCombiner(RopMethod rm) {
+ ropMethod = rm;
+ blocks = ropMethod.getBlocks();
+ newBlocks = blocks.getMutableCopy();
+ }
- /**
- * Runs algorithm. TODO: This is n^2, and could be made linear-ish with
- * a hash. In particular, hash the contents of each block and only
- * compare blocks with the same hash.
- *
- * @return {@code non-null;} new method that has been processed
- */
- public RopMethod process() {
- int szBlocks = blocks.size();
- // indexed by label
- BitSet toDelete = new BitSet(blocks.getMaxLabel());
+ /**
+ * Runs algorithm. TODO(dx team): This is n^2, and could be made linear-ish with
+ * a hash. In particular, hash the contents of each block and only
+ * compare blocks with the same hash.
+ *
+ * @return {@code non-null;} new method that has been processed
+ */
+ public RopMethod process() {
+ int szBlocks = blocks.size();
+ // indexed by label
+ BitSet toDelete = new BitSet(blocks.getMaxLabel());
- // For each non-deleted block...
- for (int bindex = 0; bindex < szBlocks; bindex++) {
- BasicBlock b = blocks.get(bindex);
+ // For each non-deleted block...
+ for (int bindex = 0; bindex < szBlocks; bindex++) {
+ BasicBlock b = blocks.get(bindex);
- if (toDelete.get(b.getLabel())) {
- // doomed block
- continue;
- }
+ if (toDelete.get(b.getLabel())) {
+ // doomed block
+ continue;
+ }
- IntList preds = ropMethod.labelToPredecessors(b.getLabel());
+ IntList preds = ropMethod.labelToPredecessors(b.getLabel());
- // ...look at all of it's predecessors that have only one succ...
- int szPreds = preds.size();
- for (int i = 0; i < szPreds; i++) {
- int iLabel = preds.get(i);
+ // ...look at all of it's predecessors that have only one succ...
+ int szPreds = preds.size();
+ for (int i = 0; i < szPreds; i++) {
+ int iLabel = preds.get(i);
- BasicBlock iBlock = blocks.labelToBlock(iLabel);
+ BasicBlock iBlock = blocks.labelToBlock(iLabel);
- if (toDelete.get(iLabel)
- || iBlock.getSuccessors().size() > 1
- || iBlock.getFirstInsn().getOpcode().getOpcode() ==
- RegOps.MOVE_RESULT) {
- continue;
- }
-
- IntList toCombine = new IntList();
-
- // ...and see if they can be combined with any other preds...
- for (int j = i + 1; j < szPreds; j++) {
- int jLabel = preds.get(j);
- BasicBlock jBlock = blocks.labelToBlock(jLabel);
-
- if (jBlock.getSuccessors().size() == 1
- && compareInsns(iBlock, jBlock)) {
-
- toCombine.add(jLabel);
- toDelete.set(jLabel);
- }
- }
-
- combineBlocks(iLabel, toCombine);
- }
+ if (toDelete.get(iLabel) || iBlock.getSuccessors().size() > 1
+ || iBlock.getFirstInsn().getOpcode().getOpcode() == RegOps.MOVE_RESULT) {
+ continue;
}
- for (int i = szBlocks - 1; i >= 0; i--) {
- if (toDelete.get(newBlocks.get(i).getLabel())) {
- newBlocks.set(i, null);
- }
+ IntList toCombine = new IntList();
+
+ // ...and see if they can be combined with any other preds...
+ for (int j = i + 1; j < szPreds; j++) {
+ int jLabel = preds.get(j);
+ BasicBlock jBlock = blocks.labelToBlock(jLabel);
+
+ if (jBlock.getSuccessors().size() == 1 && compareInsns(iBlock, jBlock)) {
+
+ toCombine.add(jLabel);
+ toDelete.set(jLabel);
+ }
}
- newBlocks.shrinkToFit();
- newBlocks.setImmutable();
-
- return new RopMethod(newBlocks, ropMethod.getFirstLabel());
+ combineBlocks(iLabel, toCombine);
+ }
}
- /**
- * Helper method to compare the contents of two blocks.
- *
- * @param a {@code non-null;} a block to compare
- * @param b {@code non-null;} another block to compare
- * @return {@code true} iff the two blocks' instructions are the same
- */
- private static boolean compareInsns(BasicBlock a, BasicBlock b) {
- return a.getInsns().contentEquals(b.getInsns());
+ for (int i = szBlocks - 1; i >= 0; i--) {
+ if (toDelete.get(newBlocks.get(i).getLabel())) {
+ newBlocks.set(i, null);
+ }
}
- /**
- * Combines blocks proven identical into one alpha block, re-writing
- * all of the successor links that point to the beta blocks to point
- * to the alpha block instead.
- *
- * @param alphaLabel block that will replace all the beta block
- * @param betaLabels label list of blocks to combine
- */
- private void combineBlocks(int alphaLabel, IntList betaLabels) {
- int szBetas = betaLabels.size();
+ newBlocks.shrinkToFit();
+ newBlocks.setImmutable();
- for (int i = 0; i < szBetas; i++) {
- int betaLabel = betaLabels.get(i);
- BasicBlock bb = blocks.labelToBlock(betaLabel);
- IntList preds = ropMethod.labelToPredecessors(bb.getLabel());
- int szPreds = preds.size();
+ return new RopMethod(newBlocks, ropMethod.getFirstLabel());
+ }
- for (int j = 0; j < szPreds; j++) {
- BasicBlock predBlock = newBlocks.labelToBlock(preds.get(j));
- replaceSucc(predBlock, betaLabel, alphaLabel);
- }
- }
+ /**
+ * Helper method to compare the contents of two blocks.
+ *
+ * @param a {@code non-null;} a block to compare
+ * @param b {@code non-null;} another block to compare
+ * @return {@code true} iff the two blocks' instructions are the same
+ */
+ private static boolean compareInsns(BasicBlock a, BasicBlock b) {
+ return a.getInsns().contentEquals(b.getInsns());
+ }
+
+ /**
+ * Combines blocks proven identical into one alpha block, re-writing
+ * all of the successor links that point to the beta blocks to point
+ * to the alpha block instead.
+ *
+ * @param alphaLabel block that will replace all the beta block
+ * @param betaLabels label list of blocks to combine
+ */
+ private void combineBlocks(int alphaLabel, IntList betaLabels) {
+ int szBetas = betaLabels.size();
+
+ for (int i = 0; i < szBetas; i++) {
+ int betaLabel = betaLabels.get(i);
+ BasicBlock bb = blocks.labelToBlock(betaLabel);
+ IntList preds = ropMethod.labelToPredecessors(bb.getLabel());
+ int szPreds = preds.size();
+
+ for (int j = 0; j < szPreds; j++) {
+ BasicBlock predBlock = newBlocks.labelToBlock(preds.get(j));
+ replaceSucc(predBlock, betaLabel, alphaLabel);
+ }
+ }
+ }
+
+ /**
+ * Replaces one of a block's successors with a different label. Constructs
+ * an updated BasicBlock instance and places it in {@code newBlocks}.
+ *
+ * @param block block to replace
+ * @param oldLabel label of successor to replace
+ * @param newLabel label of new successor
+ */
+ private void replaceSucc(BasicBlock block, int oldLabel, int newLabel) {
+ IntList newSuccessors = block.getSuccessors().mutableCopy();
+ int newPrimarySuccessor;
+
+ newSuccessors.set(newSuccessors.indexOf(oldLabel), newLabel);
+ newPrimarySuccessor = block.getPrimarySuccessor();
+
+ if (newPrimarySuccessor == oldLabel) {
+ newPrimarySuccessor = newLabel;
}
- /**
- * Replaces one of a block's successors with a different label. Constructs
- * an updated BasicBlock instance and places it in {@code newBlocks}.
- *
- * @param block block to replace
- * @param oldLabel label of successor to replace
- * @param newLabel label of new successor
- */
- private void replaceSucc(BasicBlock block, int oldLabel, int newLabel) {
- IntList newSuccessors = block.getSuccessors().mutableCopy();
- int newPrimarySuccessor;
+ newSuccessors.setImmutable();
- newSuccessors.set(newSuccessors.indexOf(oldLabel), newLabel);
- newPrimarySuccessor = block.getPrimarySuccessor();
+ BasicBlock newBB =
+ new BasicBlock(block.getLabel(), block.getInsns(), newSuccessors, newPrimarySuccessor);
- if (newPrimarySuccessor == oldLabel) {
- newPrimarySuccessor = newLabel;
- }
-
- newSuccessors.setImmutable();
-
- BasicBlock newBB = new BasicBlock(block.getLabel(),
- block.getInsns(), newSuccessors, newPrimarySuccessor);
-
- newBlocks.set(newBlocks.indexOfLabel(block.getLabel()), newBB);
- }
+ newBlocks.set(newBlocks.indexOfLabel(block.getLabel()), newBB);
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/InterferenceGraph.java b/dx/src/com/android/jack/dx/ssa/back/InterferenceGraph.java
index 00a2c69..a93a2a7 100644
--- a/dx/src/com/android/jack/dx/ssa/back/InterferenceGraph.java
+++ b/dx/src/com/android/jack/dx/ssa/back/InterferenceGraph.java
@@ -16,98 +16,89 @@
package com.android.jack.dx.ssa.back;
-import com.android.jack.dx.rop.code.RegisterSpec;
-import com.android.jack.dx.ssa.PhiInsn;
import com.android.jack.dx.ssa.SetFactory;
-import com.android.jack.dx.ssa.SsaBasicBlock;
-import com.android.jack.dx.ssa.SsaInsn;
-import com.android.jack.dx.ssa.SsaMethod;
-import com.android.jack.dx.util.BitIntSet;
import com.android.jack.dx.util.IntSet;
-import com.android.jack.dx.util.ListIntSet;
-import java.util.BitSet;
-import java.util.List;
import java.util.ArrayList;
/**
* A register interference graph
*/
public class InterferenceGraph {
- /**
- * {@code non-null;} interference graph, indexed by register in
- * both dimensions
- */
- private final ArrayList<IntSet> interference;
+ /**
+ * {@code non-null;} interference graph, indexed by register in
+ * both dimensions
+ */
+ private final ArrayList<IntSet> interference;
- /**
- * Creates a new graph.
- *
- * @param countRegs {@code >= 0;} the start count of registers in
- * the namespace. New registers can be added subsequently.
- */
- public InterferenceGraph(int countRegs) {
- interference = new ArrayList<IntSet>(countRegs);
+ /**
+ * Creates a new graph.
+ *
+ * @param countRegs {@code >= 0;} the start count of registers in
+ * the namespace. New registers can be added subsequently.
+ */
+ public InterferenceGraph(int countRegs) {
+ interference = new ArrayList<IntSet>(countRegs);
- for (int i = 0; i < countRegs; i++) {
- interference.add(SetFactory.makeInterferenceSet(countRegs));
- }
+ for (int i = 0; i < countRegs; i++) {
+ interference.add(SetFactory.makeInterferenceSet(countRegs));
}
+ }
- /**
- * Adds a register pair to the interference/liveness graph. Parameter
- * order is insignificant.
- *
- * @param regV one register index
- * @param regW another register index
- */
- public void add(int regV, int regW) {
- ensureCapacity(Math.max(regV, regW) + 1);
+ /**
+ * Adds a register pair to the interference/liveness graph. Parameter
+ * order is insignificant.
+ *
+ * @param regV one register index
+ * @param regW another register index
+ */
+ public void add(int regV, int regW) {
+ ensureCapacity(Math.max(regV, regW) + 1);
- interference.get(regV).add(regW);
- interference.get(regW).add(regV);
+ interference.get(regV).add(regW);
+ interference.get(regW).add(regV);
+ }
+
+ /**
+ * Dumps interference graph to stdout for debugging.
+ */
+ public void dumpToStdout() {
+ int oldRegCount = interference.size();
+
+ for (int i = 0; i < oldRegCount; i++) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Reg " + i + ":" + interference.get(i).toString());
+
+ System.out.println(sb.toString());
}
+ }
- /**
- * Dumps interference graph to stdout for debugging.
- */
- public void dumpToStdout() {
- int oldRegCount = interference.size();
-
- for (int i = 0; i < oldRegCount; i++) {
- StringBuilder sb = new StringBuilder();
-
- sb.append("Reg " + i + ":" + interference.get(i).toString());
-
- System.out.println(sb.toString());
- }
+ /**
+ * Merges the interference set for a register into a given bit set
+ *
+ * @param reg {@code >= 0;} register
+ * @param set {@code non-null;} interference set; will be merged
+ * with set for given register
+ */
+ public void mergeInterferenceSet(int reg, IntSet set) {
+ if (reg < interference.size()) {
+ set.merge(interference.get(reg));
}
+ }
- /**
- * Merges the interference set for a register into a given bit set
- *
- * @param reg {@code >= 0;} register
- * @param set {@code non-null;} interference set; will be merged
- * with set for given register
- */
- public void mergeInterferenceSet(int reg, IntSet set) {
- if (reg < interference.size()) {
- set.merge(interference.get(reg));
- }
+ /**
+ * Ensures that the interference graph is appropriately sized.
+ *
+ * @param size requested minumum size
+ */
+ private void ensureCapacity(int size) {
+ int countRegs = interference.size();
+
+ interference.ensureCapacity(size);
+
+ for (int i = countRegs; i < size; i++) {
+ interference.add(SetFactory.makeInterferenceSet(size));
}
-
- /**
- * Ensures that the interference graph is appropriately sized.
- *
- * @param size requested minumum size
- */
- private void ensureCapacity(int size) {
- int countRegs = interference.size();
-
- interference.ensureCapacity(size);
-
- for (int i = countRegs; i < size; i++) {
- interference.add(SetFactory.makeInterferenceSet(size));
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/LivenessAnalyzer.java b/dx/src/com/android/jack/dx/ssa/back/LivenessAnalyzer.java
index 44c9964..5c37f07 100644
--- a/dx/src/com/android/jack/dx/ssa/back/LivenessAnalyzer.java
+++ b/dx/src/com/android/jack/dx/ssa/back/LivenessAnalyzer.java
@@ -22,9 +22,9 @@
import com.android.jack.dx.ssa.SsaInsn;
import com.android.jack.dx.ssa.SsaMethod;
+import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
-import java.util.ArrayList;
/**
* From Appel "Modern Compiler Implementation in Java" algorithm 19.17
@@ -35,253 +35,244 @@
* M = visitedBlocks <p>
*/
public class LivenessAnalyzer {
- /**
- * {@code non-null;} index by basic block indexed set of basic blocks
- * that have already been visited. "M" as written in the original Appel
- * algorithm.
- */
- private final BitSet visitedBlocks;
+ /**
+ * {@code non-null;} index by basic block indexed set of basic blocks
+ * that have already been visited. "M" as written in the original Appel
+ * algorithm.
+ */
+ private final BitSet visitedBlocks;
- /**
- * {@code non-null;} set of blocks remaing to visit as "live out as block"
- */
- private final BitSet liveOutBlocks;
+ /**
+ * {@code non-null;} set of blocks remaing to visit as "live out as block"
+ */
+ private final BitSet liveOutBlocks;
- /**
- * {@code >=0;} SSA register currently being analyzed.
- * "v" in the original Appel algorithm.
- */
- private final int regV;
+ /**
+ * {@code >=0;} SSA register currently being analyzed.
+ * "v" in the original Appel algorithm.
+ */
+ private final int regV;
- /** method to process */
- private final SsaMethod ssaMeth;
+ /** method to process */
+ private final SsaMethod ssaMeth;
- /** interference graph being updated */
- private final InterferenceGraph interference;
+ /** interference graph being updated */
+ private final InterferenceGraph interference;
- /** block "n" in Appel 19.17 */
- private SsaBasicBlock blockN;
+ /** block "n" in Appel 19.17 */
+ private SsaBasicBlock blockN;
- /** index of statement {@code s} in {@code blockN} */
- private int statementIndex;
+ /** index of statement {@code s} in {@code blockN} */
+ private int statementIndex;
- /** the next function to call */
- private NextFunction nextFunction;
+ /** the next function to call */
+ private NextFunction nextFunction;
- /** constants for {@link #nextFunction} */
- private static enum NextFunction {
- LIVE_IN_AT_STATEMENT,
- LIVE_OUT_AT_STATEMENT,
- LIVE_OUT_AT_BLOCK,
- DONE;
+ /** constants for {@link #nextFunction} */
+ private static enum NextFunction {
+ LIVE_IN_AT_STATEMENT, LIVE_OUT_AT_STATEMENT, LIVE_OUT_AT_BLOCK, DONE;
+ }
+
+ /**
+ * Runs register liveness algorithm for a method, updating the
+ * live in/out information in {@code SsaBasicBlock} instances and
+ * returning an interference graph.
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @return {@code non-null;} interference graph indexed by SSA
+ * registers in both directions
+ */
+ public static InterferenceGraph constructInterferenceGraph(SsaMethod ssaMeth) {
+ int szRegs = ssaMeth.getRegCount();
+ InterferenceGraph interference = new InterferenceGraph(szRegs);
+
+ for (int i = 0; i < szRegs; i++) {
+ new LivenessAnalyzer(ssaMeth, i, interference).run();
}
- /**
- * Runs register liveness algorithm for a method, updating the
- * live in/out information in {@code SsaBasicBlock} instances and
- * returning an interference graph.
- *
- * @param ssaMeth {@code non-null;} method to process
- * @return {@code non-null;} interference graph indexed by SSA
- * registers in both directions
- */
- public static InterferenceGraph constructInterferenceGraph(
- SsaMethod ssaMeth) {
- int szRegs = ssaMeth.getRegCount();
- InterferenceGraph interference = new InterferenceGraph(szRegs);
+ coInterferePhis(ssaMeth, interference);
- for (int i = 0; i < szRegs; i++) {
- new LivenessAnalyzer(ssaMeth, i, interference).run();
+ return interference;
+ }
+
+ /**
+ * Makes liveness analyzer instance for specific register.
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @param reg register whose liveness to analyze
+ * @param interference {@code non-null;} indexed by SSA reg in
+ * both dimensions; graph to update
+ *
+ */
+ private LivenessAnalyzer(SsaMethod ssaMeth, int reg, InterferenceGraph interference) {
+ int blocksSz = ssaMeth.getBlocks().size();
+
+ this.ssaMeth = ssaMeth;
+ this.regV = reg;
+ visitedBlocks = new BitSet(blocksSz);
+ liveOutBlocks = new BitSet(blocksSz);
+ this.interference = interference;
+ }
+
+ /**
+ * The algorithm in Appel is presented in partial tail-recursion
+ * form. Obviously, that's not efficient in java, so this function
+ * serves as the dispatcher instead.
+ */
+ private void handleTailRecursion() {
+ while (nextFunction != NextFunction.DONE) {
+ switch (nextFunction) {
+ case LIVE_IN_AT_STATEMENT:
+ nextFunction = NextFunction.DONE;
+ liveInAtStatement();
+ break;
+
+ case LIVE_OUT_AT_STATEMENT:
+ nextFunction = NextFunction.DONE;
+ liveOutAtStatement();
+ break;
+
+ case LIVE_OUT_AT_BLOCK:
+ nextFunction = NextFunction.DONE;
+ liveOutAtBlock();
+ break;
+
+ default:
+ }
+ }
+ }
+
+ /**
+ * From Appel algorithm 19.17.
+ */
+ public void run() {
+ List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV);
+
+ for (SsaInsn insn : useList) {
+ nextFunction = NextFunction.DONE;
+
+ if (insn instanceof PhiInsn) {
+ // If s is a phi-function with V as it's ith argument.
+ PhiInsn phi = (PhiInsn) insn;
+
+ for (SsaBasicBlock pred : phi.predBlocksForReg(regV, ssaMeth)) {
+ blockN = pred;
+
+ nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
+ handleTailRecursion();
+ }
+ } else {
+ // Special management for registers of category 2, indeed they use
+ // two 32-bits registers thus there is an implicit interference between
+ // the result register and operands contrary to category 1 where there
+ // is no writing of registers before all operands are read.
+ RegisterSpec resultSpec = insn.getResult();
+ if (resultSpec != null && resultSpec.getCategory() == 2
+ && insn.getSources().specForRegister(regV).getCategory() == 2) {
+ interference.add(regV, resultSpec.getReg());
}
- coInterferePhis(ssaMeth, interference);
+ blockN = insn.getBlock();
+ statementIndex = blockN.getInsns().indexOf(insn);
- return interference;
- }
-
- /**
- * Makes liveness analyzer instance for specific register.
- *
- * @param ssaMeth {@code non-null;} method to process
- * @param reg register whose liveness to analyze
- * @param interference {@code non-null;} indexed by SSA reg in
- * both dimensions; graph to update
- *
- */
- private LivenessAnalyzer(SsaMethod ssaMeth, int reg,
- InterferenceGraph interference) {
- int blocksSz = ssaMeth.getBlocks().size();
-
- this.ssaMeth = ssaMeth;
- this.regV = reg;
- visitedBlocks = new BitSet(blocksSz);
- liveOutBlocks = new BitSet(blocksSz);
- this.interference = interference;
- }
-
- /**
- * The algorithm in Appel is presented in partial tail-recursion
- * form. Obviously, that's not efficient in java, so this function
- * serves as the dispatcher instead.
- */
- private void handleTailRecursion() {
- while (nextFunction != NextFunction.DONE) {
- switch (nextFunction) {
- case LIVE_IN_AT_STATEMENT:
- nextFunction = NextFunction.DONE;
- liveInAtStatement();
- break;
-
- case LIVE_OUT_AT_STATEMENT:
- nextFunction = NextFunction.DONE;
- liveOutAtStatement();
- break;
-
- case LIVE_OUT_AT_BLOCK:
- nextFunction = NextFunction.DONE;
- liveOutAtBlock();
- break;
-
- default:
- }
- }
- }
-
- /**
- * From Appel algorithm 19.17.
- */
- public void run() {
- List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV);
-
- for (SsaInsn insn : useList) {
- nextFunction = NextFunction.DONE;
-
- if (insn instanceof PhiInsn) {
- // If s is a phi-function with V as it's ith argument.
- PhiInsn phi = (PhiInsn) insn;
-
- for (SsaBasicBlock pred :
- phi.predBlocksForReg(regV, ssaMeth)) {
- blockN = pred;
-
- nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
- handleTailRecursion();
- }
- } else {
- // Special management for registers of category 2, indeed they use
- // two 32-bits registers thus there is an implicit interference between
- // the result register and operands contrary to category 1 where there
- // is no writing of registers before all operands are read.
- RegisterSpec resultSpec = insn.getResult();
- if (resultSpec != null && resultSpec.getCategory() == 2
- && insn.getSources().specForRegister(regV).getCategory() == 2) {
- interference.add(regV, resultSpec.getReg());
- }
-
- blockN = insn.getBlock();
- statementIndex = blockN.getInsns().indexOf(insn);
-
- if (statementIndex < 0) {
- throw new RuntimeException(
- "insn not found in it's own block");
- }
-
- nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
- handleTailRecursion();
- }
+ if (statementIndex < 0) {
+ throw new RuntimeException("insn not found in it's own block");
}
- int nextLiveOutBlock;
- while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) {
- blockN = ssaMeth.getBlocks().get(nextLiveOutBlock);
- liveOutBlocks.clear(nextLiveOutBlock);
- nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
- handleTailRecursion();
- }
+ nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
+ handleTailRecursion();
+ }
}
- /**
- * "v is live-out at n."
- */
- private void liveOutAtBlock() {
- if (! visitedBlocks.get(blockN.getIndex())) {
- visitedBlocks.set(blockN.getIndex());
-
- blockN.addLiveOut(regV);
-
- ArrayList<SsaInsn> insns;
-
- insns = blockN.getInsns();
-
- // Live out at last statement in blockN
- statementIndex = insns.size() - 1;
- nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
- }
+ int nextLiveOutBlock;
+ while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) {
+ blockN = ssaMeth.getBlocks().get(nextLiveOutBlock);
+ liveOutBlocks.clear(nextLiveOutBlock);
+ nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
+ handleTailRecursion();
}
+ }
- /**
- * "v is live-in at s."
- */
- private void liveInAtStatement() {
- // if s is the first statement in block N
- if (statementIndex == 0) {
- // v is live-in at n
- blockN.addLiveIn(regV);
+ /**
+ * "v is live-out at n."
+ */
+ private void liveOutAtBlock() {
+ if (!visitedBlocks.get(blockN.getIndex())) {
+ visitedBlocks.set(blockN.getIndex());
- BitSet preds = blockN.getPredecessors();
+ blockN.addLiveOut(regV);
- liveOutBlocks.or(preds);
- } else {
- // Let s' be the statement preceeding s
- statementIndex -= 1;
- nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
- }
+ ArrayList<SsaInsn> insns;
+
+ insns = blockN.getInsns();
+
+ // Live out at last statement in blockN
+ statementIndex = insns.size() - 1;
+ nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
}
+ }
- /**
- * "v is live-out at s."
- */
- private void liveOutAtStatement() {
- SsaInsn statement = blockN.getInsns().get(statementIndex);
- RegisterSpec rs = statement.getResult();
+ /**
+ * "v is live-in at s."
+ */
+ private void liveInAtStatement() {
+ // if s is the first statement in block N
+ if (statementIndex == 0) {
+ // v is live-in at n
+ blockN.addLiveIn(regV);
- if (!statement.isResultReg(regV)) {
- if (rs != null) {
- interference.add(regV, rs.getReg());
- }
- nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
- }
+ BitSet preds = blockN.getPredecessors();
+
+ liveOutBlocks.or(preds);
+ } else {
+ // Let s' be the statement preceeding s
+ statementIndex -= 1;
+ nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
}
+ }
- /**
- * Ensures that all the phi result registers for all the phis in the
- * same basic block interfere with each other. This is needed since
- * the dead code remover has allowed through "dead-end phis" whose
- * results are not used except as local assignments. Without this step,
- * a the result of a dead-end phi might be assigned the same register
- * as the result of another phi, and the phi removal move scheduler may
- * generate moves that over-write the live result.
- *
- * @param ssaMeth {@code non-null;} method to pricess
- * @param interference {@code non-null;} interference graph
- */
- private static void coInterferePhis(SsaMethod ssaMeth,
- InterferenceGraph interference) {
- for (SsaBasicBlock b : ssaMeth.getBlocks()) {
- List<SsaInsn> phis = b.getPhiInsns();
+ /**
+ * "v is live-out at s."
+ */
+ private void liveOutAtStatement() {
+ SsaInsn statement = blockN.getInsns().get(statementIndex);
+ RegisterSpec rs = statement.getResult();
- int szPhis = phis.size();
-
- for (int i = 0; i < szPhis; i++) {
- for (int j = 0; j < szPhis; j++) {
- if (i == j) {
- continue;
- }
-
- interference.add(phis.get(i).getResult().getReg(),
- phis.get(j).getResult().getReg());
- }
- }
- }
+ if (!statement.isResultReg(regV)) {
+ if (rs != null) {
+ interference.add(regV, rs.getReg());
+ }
+ nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
}
+ }
+
+ /**
+ * Ensures that all the phi result registers for all the phis in the
+ * same basic block interfere with each other. This is needed since
+ * the dead code remover has allowed through "dead-end phis" whose
+ * results are not used except as local assignments. Without this step,
+ * a the result of a dead-end phi might be assigned the same register
+ * as the result of another phi, and the phi removal move scheduler may
+ * generate moves that over-write the live result.
+ *
+ * @param ssaMeth {@code non-null;} method to pricess
+ * @param interference {@code non-null;} interference graph
+ */
+ private static void coInterferePhis(SsaMethod ssaMeth, InterferenceGraph interference) {
+ for (SsaBasicBlock b : ssaMeth.getBlocks()) {
+ List<SsaInsn> phis = b.getPhiInsns();
+
+ int szPhis = phis.size();
+
+ for (int i = 0; i < szPhis; i++) {
+ for (int j = 0; j < szPhis; j++) {
+ if (i == j) {
+ continue;
+ }
+
+ interference.add(phis.get(i).getResult().getReg(), phis.get(j).getResult().getReg());
+ }
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/NullRegisterAllocator.java b/dx/src/com/android/jack/dx/ssa/back/NullRegisterAllocator.java
index 28b2000..051a159 100644
--- a/dx/src/com/android/jack/dx/ssa/back/NullRegisterAllocator.java
+++ b/dx/src/com/android/jack/dx/ssa/back/NullRegisterAllocator.java
@@ -20,39 +20,35 @@
import com.android.jack.dx.ssa.RegisterMapper;
import com.android.jack.dx.ssa.SsaMethod;
-import java.util.BitSet;
-import java.util.ArrayList;
-
/**
* A register allocator that maps SSA register n to Rop register 2*n,
* essentially preserving the original mapping and remaining agnostic
* about normal or wide categories. Used for debugging.
*/
public class NullRegisterAllocator extends RegisterAllocator {
- /** {@inheritDoc} */
- public NullRegisterAllocator(SsaMethod ssaMeth,
- InterferenceGraph interference) {
- super(ssaMeth, interference);
+ /** {@inheritDoc} */
+ public NullRegisterAllocator(SsaMethod ssaMeth, InterferenceGraph interference) {
+ super(ssaMeth, interference);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean wantsParamsMovedHigh() {
+ // We're not smart enough for this.
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegisterMapper allocateRegisters() {
+ int oldRegCount = ssaMeth.getRegCount();
+
+ BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount);
+
+ for (int i = 0; i < oldRegCount; i++) {
+ mapper.addMapping(i, i * 2, 2);
}
- /** {@inheritDoc} */
- @Override
- public boolean wantsParamsMovedHigh() {
- // We're not smart enough for this.
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public RegisterMapper allocateRegisters() {
- int oldRegCount = ssaMeth.getRegCount();
-
- BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount);
-
- for (int i = 0; i < oldRegCount; i++) {
- mapper.addMapping(i, i*2, 2);
- }
-
- return mapper;
- }
+ return mapper;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/RegisterAllocator.java b/dx/src/com/android/jack/dx/ssa/back/RegisterAllocator.java
index e81a9d6..9a13b8b 100644
--- a/dx/src/com/android/jack/dx/ssa/back/RegisterAllocator.java
+++ b/dx/src/com/android/jack/dx/ssa/back/RegisterAllocator.java
@@ -30,168 +30,160 @@
import com.android.jack.dx.util.IntIterator;
import com.android.jack.dx.util.IntSet;
-import java.util.BitSet;
import java.util.ArrayList;
/**
* Base class of all register allocators.
*/
public abstract class RegisterAllocator {
- /** method being processed */
- protected final SsaMethod ssaMeth;
+ /** method being processed */
+ protected final SsaMethod ssaMeth;
- /** interference graph, indexed by register in both dimensions */
- protected final InterferenceGraph interference;
+ /** interference graph, indexed by register in both dimensions */
+ protected final InterferenceGraph interference;
- /**
- * Creates an instance. Call {@code allocateRegisters} to run.
- * @param ssaMeth method to process.
- * @param interference Interference graph, indexed by register in both
- * dimensions.
- */
- public RegisterAllocator(SsaMethod ssaMeth,
- InterferenceGraph interference) {
- this.ssaMeth = ssaMeth;
- this.interference = interference;
+ /**
+ * Creates an instance. Call {@code allocateRegisters} to run.
+ * @param ssaMeth method to process.
+ * @param interference Interference graph, indexed by register in both
+ * dimensions.
+ */
+ public RegisterAllocator(SsaMethod ssaMeth, InterferenceGraph interference) {
+ this.ssaMeth = ssaMeth;
+ this.interference = interference;
+ }
+
+ /**
+ * Indicates whether the method params were allocated at the bottom
+ * of the namespace, and thus should be moved up to the top of the
+ * namespace after phi removal.
+ *
+ * @return {@code true} if params should be moved from low to high
+ */
+ public abstract boolean wantsParamsMovedHigh();
+
+ /**
+ * Runs the algorithm.
+ *
+ * @return a register mapper to apply to the {@code SsaMethod}
+ */
+ public abstract RegisterMapper allocateRegisters();
+
+ /**
+ * Returns the category (width) of the definition site of the register.
+ * Returns {@code 1} for undefined registers.
+ *
+ * @param reg register
+ * @return {@code 1..2}
+ */
+ protected final int getCategoryForSsaReg(int reg) {
+ SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
+
+ if (definition == null) {
+ // an undefined reg
+ return 1;
+ } else {
+ return definition.getResult().getCategory();
+ }
+ }
+
+ /**
+ * Returns the RegisterSpec of the definition of the register.
+ *
+ * @param reg {@code >= 0;} SSA register
+ * @return definition spec of the register or null if it is never defined
+ * (for the case of "version 0" SSA registers)
+ */
+ protected final RegisterSpec getDefinitionSpecForSsaReg(int reg) {
+ SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
+
+ return definition == null ? null : definition.getResult();
+ }
+
+ /**
+ * Returns true if the definition site of this register is a
+ * move-param (ie, this is a method parameter).
+ *
+ * @param reg register in question
+ * @return {@code true} if this is a method parameter
+ */
+ protected boolean isDefinitionMoveParam(int reg) {
+ SsaInsn defInsn = ssaMeth.getDefinitionForRegister(reg);
+
+ if (defInsn instanceof NormalSsaInsn) {
+ NormalSsaInsn ndefInsn = (NormalSsaInsn) defInsn;
+
+ return ndefInsn.getOpcode().getOpcode() == RegOps.MOVE_PARAM;
}
- /**
- * Indicates whether the method params were allocated at the bottom
- * of the namespace, and thus should be moved up to the top of the
- * namespace after phi removal.
- *
- * @return {@code true} if params should be moved from low to high
- */
- public abstract boolean wantsParamsMovedHigh();
+ return false;
+ }
- /**
- * Runs the algorithm.
- *
- * @return a register mapper to apply to the {@code SsaMethod}
- */
- public abstract RegisterMapper allocateRegisters();
+ /**
+ * Inserts a move instruction for a specified SSA register before a
+ * specified instruction, creating a new SSA register and adjusting the
+ * interference graph in the process. The insn currently must be the
+ * last insn in a block.
+ *
+ * @param insn {@code non-null;} insn to insert move before, must
+ * be last insn in block
+ * @param reg {@code non-null;} SSA register to duplicate
+ * @return {@code non-null;} spec of new SSA register created by move
+ */
+ protected final RegisterSpec insertMoveBefore(SsaInsn insn, RegisterSpec reg) {
+ SsaBasicBlock block = insn.getBlock();
+ ArrayList<SsaInsn> insns = block.getInsns();
+ int insnIndex = insns.indexOf(insn);
- /**
- * Returns the category (width) of the definition site of the register.
- * Returns {@code 1} for undefined registers.
- *
- * @param reg register
- * @return {@code 1..2}
- */
- protected final int getCategoryForSsaReg(int reg) {
- SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
-
- if (definition == null) {
- // an undefined reg
- return 1;
- } else {
- return definition.getResult().getCategory();
- }
+ if (insnIndex < 0) {
+ throw new IllegalArgumentException("specified insn is not in this block");
}
- /**
- * Returns the RegisterSpec of the definition of the register.
- *
- * @param reg {@code >= 0;} SSA register
- * @return definition spec of the register or null if it is never defined
- * (for the case of "version 0" SSA registers)
- */
- protected final RegisterSpec getDefinitionSpecForSsaReg(int reg) {
- SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
-
- return definition == null ? null : definition.getResult();
+ if (insnIndex != insns.size() - 1) {
+ /*
+ * Presently, the interference updater only works when
+ * adding before the last insn, and the last insn must have no
+ * result
+ */
+ throw new IllegalArgumentException("Adding move here not supported:" + insn.toHuman());
}
- /**
- * Returns true if the definition site of this register is a
- * move-param (ie, this is a method parameter).
- *
- * @param reg register in question
- * @return {@code true} if this is a method parameter
+ /*
+ * Get new register and make new move instruction.
*/
- protected boolean isDefinitionMoveParam(int reg) {
- SsaInsn defInsn = ssaMeth.getDefinitionForRegister(reg);
- if (defInsn instanceof NormalSsaInsn) {
- NormalSsaInsn ndefInsn = (NormalSsaInsn) defInsn;
+// The new result must not have an associated local variable.
+ RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(), reg.getTypeBearer());
- return ndefInsn.getOpcode().getOpcode() == RegOps.MOVE_PARAM;
- }
+ SsaInsn toAdd = SsaInsn.makeFromRop(new PlainInsn(Rops.opMove(newRegSpec.getType()),
+ SourcePosition.NO_INFO, newRegSpec, RegisterSpecList.make(reg)), block);
- return false;
+ insns.add(insnIndex, toAdd);
+
+ int newReg = newRegSpec.getReg();
+
+ /*
+ * Adjust interference graph based on what's live out of the current
+ * block and what's used by the final instruction.
+ */
+
+IntSet liveOut = block.getLiveOutRegs();
+ IntIterator liveOutIter = liveOut.iterator();
+
+ while (liveOutIter.hasNext()) {
+ interference.add(newReg, liveOutIter.next());
}
- /**
- * Inserts a move instruction for a specified SSA register before a
- * specified instruction, creating a new SSA register and adjusting the
- * interference graph in the process. The insn currently must be the
- * last insn in a block.
- *
- * @param insn {@code non-null;} insn to insert move before, must
- * be last insn in block
- * @param reg {@code non-null;} SSA register to duplicate
- * @return {@code non-null;} spec of new SSA register created by move
- */
- protected final RegisterSpec insertMoveBefore(SsaInsn insn,
- RegisterSpec reg) {
- SsaBasicBlock block = insn.getBlock();
- ArrayList<SsaInsn> insns = block.getInsns();
- int insnIndex = insns.indexOf(insn);
+ // Everything that's a source in the last insn interferes.
+ RegisterSpecList sources = insn.getSources();
+ int szSources = sources.size();
- if (insnIndex < 0) {
- throw new IllegalArgumentException (
- "specified insn is not in this block");
- }
-
- if (insnIndex != insns.size() - 1) {
- /*
- * Presently, the interference updater only works when
- * adding before the last insn, and the last insn must have no
- * result
- */
- throw new IllegalArgumentException(
- "Adding move here not supported:" + insn.toHuman());
- }
-
- /*
- * Get new register and make new move instruction.
- */
-
- // The new result must not have an associated local variable.
- RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(),
- reg.getTypeBearer());
-
- SsaInsn toAdd = SsaInsn.makeFromRop(
- new PlainInsn(Rops.opMove(newRegSpec.getType()),
- SourcePosition.NO_INFO, newRegSpec,
- RegisterSpecList.make(reg)), block);
-
- insns.add(insnIndex, toAdd);
-
- int newReg = newRegSpec.getReg();
-
- /*
- * Adjust interference graph based on what's live out of the current
- * block and what's used by the final instruction.
- */
-
- IntSet liveOut = block.getLiveOutRegs();
- IntIterator liveOutIter = liveOut.iterator();
-
- while (liveOutIter.hasNext()) {
- interference.add(newReg, liveOutIter.next());
- }
-
- // Everything that's a source in the last insn interferes.
- RegisterSpecList sources = insn.getSources();
- int szSources = sources.size();
-
- for (int i = 0; i < szSources; i++) {
- interference.add(newReg, sources.get(i).getReg());
- }
-
- ssaMeth.onInsnsChanged();
-
- return newRegSpec;
+ for (int i = 0; i < szSources; i++) {
+ interference.add(newReg, sources.get(i).getReg());
}
+
+ ssaMeth.onInsnsChanged();
+
+ return newRegSpec;
+ }
}
diff --git a/dx/src/com/android/jack/dx/ssa/back/SsaToRop.java b/dx/src/com/android/jack/dx/ssa/back/SsaToRop.java
index 2c63a55..9d984f9 100644
--- a/dx/src/com/android/jack/dx/ssa/back/SsaToRop.java
+++ b/dx/src/com/android/jack/dx/ssa/back/SsaToRop.java
@@ -42,339 +42,326 @@
* Converts a method in SSA form to ROP form.
*/
public class SsaToRop {
- /** local debug flag */
- private static final boolean DEBUG = false;
+ /** local debug flag */
+ private static final boolean DEBUG = false;
- /** {@code non-null;} method to process */
- private final SsaMethod ssaMeth;
+ /** {@code non-null;} method to process */
+ private final SsaMethod ssaMeth;
- /**
- * {@code true} if the converter should attempt to minimize
- * the rop-form register count
- */
- private final boolean minimizeRegisters;
+ /**
+ * {@code true} if the converter should attempt to minimize
+ * the rop-form register count
+ */
+ private final boolean minimizeRegisters;
- /** {@code non-null;} interference graph */
- private final InterferenceGraph interference;
+ /** {@code non-null;} interference graph */
+ private final InterferenceGraph interference;
- /**
- * Converts a method in SSA form to ROP form.
- *
- * @param ssaMeth {@code non-null;} method to process
- * @param minimizeRegisters {@code true} if the converter should
- * attempt to minimize the rop-form register count
- * @return {@code non-null;} rop-form output
- */
- public static RopMethod convertToRopMethod(SsaMethod ssaMeth,
- boolean minimizeRegisters) {
- return new SsaToRop(ssaMeth, minimizeRegisters).convert();
+ /**
+ * Converts a method in SSA form to ROP form.
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @param minimizeRegisters {@code true} if the converter should
+ * attempt to minimize the rop-form register count
+ * @return {@code non-null;} rop-form output
+ */
+ public static RopMethod convertToRopMethod(SsaMethod ssaMeth, boolean minimizeRegisters) {
+ return new SsaToRop(ssaMeth, minimizeRegisters).convert();
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @param minimizeRegisters {@code true} if the converter should
+ * attempt to minimize the rop-form register count
+ */
+ private SsaToRop(SsaMethod ssaMethod, boolean minimizeRegisters) {
+ this.minimizeRegisters = minimizeRegisters;
+ this.ssaMeth = ssaMethod;
+ this.interference = LivenessAnalyzer.constructInterferenceGraph(ssaMethod);
+ }
+
+ /**
+ * Performs the conversion.
+ *
+ * @return {@code non-null;} rop-form output
+ */
+ private RopMethod convert() {
+ if (DEBUG) {
+ interference.dumpToStdout();
}
- /**
- * Constructs an instance.
- *
- * @param ssaMeth {@code non-null;} method to process
- * @param minimizeRegisters {@code true} if the converter should
- * attempt to minimize the rop-form register count
- */
- private SsaToRop(SsaMethod ssaMethod, boolean minimizeRegisters) {
- this.minimizeRegisters = minimizeRegisters;
- this.ssaMeth = ssaMethod;
- this.interference =
- LivenessAnalyzer.constructInterferenceGraph(ssaMethod);
+ // These are other allocators for debugging or historical comparison:
+ // allocator = new NullRegisterAllocator(ssaMeth, interference);
+ // allocator = new FirstFitAllocator(ssaMeth, interference);
+
+ RegisterAllocator allocator =
+ new FirstFitLocalCombiningAllocator(ssaMeth, interference, minimizeRegisters);
+
+ RegisterMapper mapper = allocator.allocateRegisters();
+
+ if (DEBUG) {
+ System.out.println("Printing reg map");
+ System.out.println(((BasicRegisterMapper) mapper).toHuman());
}
- /**
- * Performs the conversion.
- *
- * @return {@code non-null;} rop-form output
- */
- private RopMethod convert() {
- if (DEBUG) {
- interference.dumpToStdout();
- }
+ ssaMeth.setBackMode();
- // These are other allocators for debugging or historical comparison:
- // allocator = new NullRegisterAllocator(ssaMeth, interference);
- // allocator = new FirstFitAllocator(ssaMeth, interference);
+ ssaMeth.mapRegisters(mapper);
- RegisterAllocator allocator =
- new FirstFitLocalCombiningAllocator(ssaMeth, interference,
- minimizeRegisters);
+ removePhiFunctions();
- RegisterMapper mapper = allocator.allocateRegisters();
-
- if (DEBUG) {
- System.out.println("Printing reg map");
- System.out.println(((BasicRegisterMapper)mapper).toHuman());
- }
-
- ssaMeth.setBackMode();
-
- ssaMeth.mapRegisters(mapper);
-
- removePhiFunctions();
-
- if (allocator.wantsParamsMovedHigh()) {
- moveParametersToHighRegisters();
- }
-
- removeEmptyGotos();
-
- RopMethod ropMethod = new RopMethod(convertBasicBlocks(),
- ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
- ropMethod = new IdenticalBlockCombiner(ropMethod).process();
-
- return ropMethod;
+ if (allocator.wantsParamsMovedHigh()) {
+ moveParametersToHighRegisters();
}
- /**
- * Removes all blocks containing only GOTOs from the control flow.
- * Although much of this work will be done later when converting
- * from rop to dex, not all simplification cases can be handled
- * there. Furthermore, any no-op block between the exit block and
- * blocks containing the real return or throw statements must be
- * removed.
- */
- private void removeEmptyGotos() {
- final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+ removeEmptyGotos();
- ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() {
- public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) {
- ArrayList<SsaInsn> insns = b.getInsns();
+ RopMethod ropMethod = new RopMethod(convertBasicBlocks(),
+ ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
+ ropMethod = new IdenticalBlockCombiner(ropMethod).process();
- if ((insns.size() == 1)
- && (insns.get(0).getOpcode() == Rops.GOTO)) {
- BitSet preds = (BitSet) b.getPredecessors().clone();
+ return ropMethod;
+ }
- for (int i = preds.nextSetBit(0); i >= 0;
- i = preds.nextSetBit(i + 1)) {
- SsaBasicBlock pb = blocks.get(i);
- pb.replaceSuccessor(b.getIndex(),
- b.getPrimarySuccessorIndex());
- }
- }
- }
- });
- }
+ /**
+ * Removes all blocks containing only GOTOs from the control flow.
+ * Although much of this work will be done later when converting
+ * from rop to dex, not all simplification cases can be handled
+ * there. Furthermore, any no-op block between the exit block and
+ * blocks containing the real return or throw statements must be
+ * removed.
+ */
+ private void removeEmptyGotos() {
+ final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
- /**
- * See Appel 19.6. To remove the phi instructions in an edge-split
- * SSA representation we know we can always insert a move in a
- * predecessor block.
- */
- private void removePhiFunctions() {
- ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
-
- for (SsaBasicBlock block : blocks) {
- // Add moves in all the pred blocks for each phi insn.
- block.forEachPhiInsn(new PhiVisitor(blocks));
-
- // Delete the phi insns.
- block.removeAllPhiInsns();
- }
-
- /*
- * After all move insns have been added, sort them so they don't
- * destructively interfere.
- */
- for (SsaBasicBlock block : blocks) {
- block.scheduleMovesFromPhis();
- }
- }
-
- /**
- * Helper for {@link #removePhiFunctions}: PhiSuccessorUpdater for
- * adding move instructions to predecessors based on phi insns.
- */
- private static class PhiVisitor implements PhiInsn.Visitor {
- private final ArrayList<SsaBasicBlock> blocks;
-
- public PhiVisitor(ArrayList<SsaBasicBlock> blocks) {
- this.blocks = blocks;
- }
-
- public void visitPhiInsn(PhiInsn insn) {
- RegisterSpecList sources = insn.getSources();
- RegisterSpec result = insn.getResult();
- int sz = sources.size();
-
- for (int i = 0; i < sz; i++) {
- RegisterSpec source = sources.get(i);
- SsaBasicBlock predBlock = blocks.get(
- insn.predBlockIndexForSourcesIndex(i));
-
- predBlock.addMoveToEnd(result, source);
- }
- }
- }
-
- /**
- * Moves the parameter registers, which allocateRegisters() places
- * at the bottom of the frame, up to the top of the frame to match
- * Dalvik calling convention.
- */
- private void moveParametersToHighRegisters() {
- int paramWidth = ssaMeth.getParamWidth();
- BasicRegisterMapper mapper
- = new BasicRegisterMapper(ssaMeth.getRegCount());
- int regCount = ssaMeth.getRegCount();
-
- for (int i = 0; i < regCount; i++) {
- if (i < paramWidth) {
- mapper.addMapping(i, regCount - paramWidth + i, 1);
- } else {
- mapper.addMapping(i, i - paramWidth, 1);
- }
- }
-
- if (DEBUG) {
- System.out.printf("Moving %d registers from 0 to %d\n",
- paramWidth, regCount - paramWidth);
- }
-
- ssaMeth.mapRegisters(mapper);
- }
-
- /**
- * @return rop-form basic block list
- */
- private BasicBlockList convertBasicBlocks() {
- ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
-
- // Exit block may be null.
- SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
-
- ssaMeth.computeReachability();
- int ropBlockCount = ssaMeth.getCountReachableBlocks();
-
- // Don't count the exit block, if it exists and is reachable.
- ropBlockCount -= (exitBlock != null && exitBlock.isReachable()) ? 1 : 0;
-
- BasicBlockList result = new BasicBlockList(ropBlockCount);
-
- // Convert all the reachable blocks except the exit block.
- int ropBlockIndex = 0;
- for (SsaBasicBlock b : blocks) {
- if (b.isReachable() && b != exitBlock) {
- result.set(ropBlockIndex++, convertBasicBlock(b));
- }
- }
-
- // The exit block, which is discarded, must do nothing.
- if (exitBlock != null && exitBlock.getInsns().size() != 0) {
- throw new RuntimeException(
- "Exit block must have no insns when leaving SSA form");
- }
-
- return result;
- }
-
- /**
- * Validates that a basic block is a valid end predecessor. It must
- * end in a RETURN or a THROW. Throws a runtime exception on error.
- *
- * @param b {@code non-null;} block to validate
- * @throws RuntimeException on error
- */
- private void verifyValidExitPredecessor(SsaBasicBlock b) {
+ ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() {
+ @Override
+ public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) {
ArrayList<SsaInsn> insns = b.getInsns();
- SsaInsn lastInsn = insns.get(insns.size() - 1);
- Rop opcode = lastInsn.getOpcode();
- if (opcode.getBranchingness() != Rop.BRANCH_RETURN
- && opcode != Rops.THROW) {
- throw new RuntimeException("Exit predecessor must end"
- + " in valid exit statement.");
+ if ((insns.size() == 1) && (insns.get(0).getOpcode() == Rops.GOTO)) {
+ BitSet preds = (BitSet) b.getPredecessors().clone();
+
+ for (int i = preds.nextSetBit(0); i >= 0; i = preds.nextSetBit(i + 1)) {
+ SsaBasicBlock pb = blocks.get(i);
+ pb.replaceSuccessor(b.getIndex(), b.getPrimarySuccessorIndex());
+ }
}
+ }
+ });
+ }
+
+ /**
+ * See Appel 19.6. To remove the phi instructions in an edge-split
+ * SSA representation we know we can always insert a move in a
+ * predecessor block.
+ */
+ private void removePhiFunctions() {
+ ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+ for (SsaBasicBlock block : blocks) {
+ // Add moves in all the pred blocks for each phi insn.
+ block.forEachPhiInsn(new PhiVisitor(blocks));
+
+ // Delete the phi insns.
+ block.removeAllPhiInsns();
}
- /**
- * Converts a single basic block to rop form.
- *
- * @param block SSA block to process
- * @return {@code non-null;} ROP block
+ /*
+ * After all move insns have been added, sort them so they don't
+ * destructively interfere.
*/
- private BasicBlock convertBasicBlock(SsaBasicBlock block) {
- IntList successorList = block.getRopLabelSuccessorList();
- int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
+ for (SsaBasicBlock block : blocks) {
+ block.scheduleMovesFromPhis();
+ }
+ }
- // Filter out any reference to the SSA form's exit block.
+ /**
+ * Helper for {@link #removePhiFunctions}: PhiSuccessorUpdater for
+ * adding move instructions to predecessors based on phi insns.
+ */
+ private static class PhiVisitor implements PhiInsn.Visitor {
+ private final ArrayList<SsaBasicBlock> blocks;
- // Exit block may be null.
- SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
- int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel();
-
- if (successorList.contains(exitRopLabel)) {
- if (successorList.size() > 1) {
- throw new RuntimeException(
- "Exit predecessor must have no other successors"
- + Hex.u2(block.getRopLabel()));
- } else {
- successorList = IntList.EMPTY;
- primarySuccessorLabel = -1;
-
- verifyValidExitPredecessor(block);
- }
- }
-
- successorList.setImmutable();
-
- BasicBlock result = new BasicBlock(
- block.getRopLabel(), convertInsns(block.getInsns()),
- successorList,
- primarySuccessorLabel);
-
- return result;
+ public PhiVisitor(ArrayList<SsaBasicBlock> blocks) {
+ this.blocks = blocks;
}
- /**
- * Converts an insn list to rop form.
- *
- * @param ssaInsns {@code non-null;} old instructions
- * @return {@code non-null;} immutable instruction list
- */
- private InsnList convertInsns(ArrayList<SsaInsn> ssaInsns) {
- int insnCount = ssaInsns.size();
- InsnList result = new InsnList(insnCount);
+ @Override
+ public void visitPhiInsn(PhiInsn insn) {
+ RegisterSpecList sources = insn.getSources();
+ RegisterSpec result = insn.getResult();
+ int sz = sources.size();
- for (int i = 0; i < insnCount; i++) {
- result.set(i, ssaInsns.get(i).toRopInsn());
- }
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec source = sources.get(i);
+ SsaBasicBlock predBlock = blocks.get(insn.predBlockIndexForSourcesIndex(i));
- result.setImmutable();
+ predBlock.addMoveToEnd(result, source);
+ }
+ }
+ }
- return result;
+ /**
+ * Moves the parameter registers, which allocateRegisters() places
+ * at the bottom of the frame, up to the top of the frame to match
+ * Dalvik calling convention.
+ */
+ private void moveParametersToHighRegisters() {
+ int paramWidth = ssaMeth.getParamWidth();
+ BasicRegisterMapper mapper = new BasicRegisterMapper(ssaMeth.getRegCount());
+ int regCount = ssaMeth.getRegCount();
+
+ for (int i = 0; i < regCount; i++) {
+ if (i < paramWidth) {
+ mapper.addMapping(i, regCount - paramWidth + i, 1);
+ } else {
+ mapper.addMapping(i, i - paramWidth, 1);
+ }
}
- /**
- * <b>Note:</b> This method is not presently used.
- *
- * @return a list of registers ordered by most-frequently-used to
- * least-frequently-used. Each register is listed once and only
- * once.
- */
- public int[] getRegistersByFrequency() {
- int regCount = ssaMeth.getRegCount();
- Integer[] ret = new Integer[regCount];
-
- for (int i = 0; i < regCount; i++) {
- ret[i] = i;
- }
-
- Arrays.sort(ret, new Comparator<Integer>() {
- public int compare(Integer o1, Integer o2) {
- return ssaMeth.getUseListForRegister(o2).size()
- - ssaMeth.getUseListForRegister(o1).size();
- }
- });
-
- int result[] = new int[regCount];
-
- for (int i = 0; i < regCount; i++) {
- result[i] = ret[i];
- }
-
- return result;
+ if (DEBUG) {
+ System.out.printf("Moving %d registers from 0 to %d\n", paramWidth, regCount - paramWidth);
}
+
+ ssaMeth.mapRegisters(mapper);
+ }
+
+ /**
+ * @return rop-form basic block list
+ */
+ private BasicBlockList convertBasicBlocks() {
+ ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+ // Exit block may be null.
+ SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
+
+ ssaMeth.computeReachability();
+ int ropBlockCount = ssaMeth.getCountReachableBlocks();
+
+ // Don't count the exit block, if it exists and is reachable.
+ ropBlockCount -= (exitBlock != null && exitBlock.isReachable()) ? 1 : 0;
+
+ BasicBlockList result = new BasicBlockList(ropBlockCount);
+
+ // Convert all the reachable blocks except the exit block.
+ int ropBlockIndex = 0;
+ for (SsaBasicBlock b : blocks) {
+ if (b.isReachable() && b != exitBlock) {
+ result.set(ropBlockIndex++, convertBasicBlock(b));
+ }
+ }
+
+ // The exit block, which is discarded, must do nothing.
+ if (exitBlock != null && exitBlock.getInsns().size() != 0) {
+ throw new RuntimeException("Exit block must have no insns when leaving SSA form");
+ }
+
+ return result;
+ }
+
+ /**
+ * Validates that a basic block is a valid end predecessor. It must
+ * end in a RETURN or a THROW. Throws a runtime exception on error.
+ *
+ * @param b {@code non-null;} block to validate
+ * @throws RuntimeException on error
+ */
+ private void verifyValidExitPredecessor(SsaBasicBlock b) {
+ ArrayList<SsaInsn> insns = b.getInsns();
+ SsaInsn lastInsn = insns.get(insns.size() - 1);
+ Rop opcode = lastInsn.getOpcode();
+
+ if (opcode.getBranchingness() != Rop.BRANCH_RETURN && opcode != Rops.THROW) {
+ throw new RuntimeException("Exit predecessor must end" + " in valid exit statement.");
+ }
+ }
+
+ /**
+ * Converts a single basic block to rop form.
+ *
+ * @param block SSA block to process
+ * @return {@code non-null;} ROP block
+ */
+ private BasicBlock convertBasicBlock(SsaBasicBlock block) {
+ IntList successorList = block.getRopLabelSuccessorList();
+ int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
+
+ // Filter out any reference to the SSA form's exit block.
+
+ // Exit block may be null.
+ SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
+ int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel();
+
+ if (successorList.contains(exitRopLabel)) {
+ if (successorList.size() > 1) {
+ throw new RuntimeException(
+ "Exit predecessor must have no other successors" + Hex.u2(block.getRopLabel()));
+ } else {
+ successorList = IntList.EMPTY;
+ primarySuccessorLabel = -1;
+
+ verifyValidExitPredecessor(block);
+ }
+ }
+
+ successorList.setImmutable();
+
+ BasicBlock result = new BasicBlock(block.getRopLabel(), convertInsns(block.getInsns()),
+ successorList, primarySuccessorLabel);
+
+ return result;
+ }
+
+ /**
+ * Converts an insn list to rop form.
+ *
+ * @param ssaInsns {@code non-null;} old instructions
+ * @return {@code non-null;} immutable instruction list
+ */
+ private InsnList convertInsns(ArrayList<SsaInsn> ssaInsns) {
+ int insnCount = ssaInsns.size();
+ InsnList result = new InsnList(insnCount);
+
+ for (int i = 0; i < insnCount; i++) {
+ result.set(i, ssaInsns.get(i).toRopInsn());
+ }
+
+ result.setImmutable();
+
+ return result;
+ }
+
+ /**
+ * <b>Note:</b> This method is not presently used.
+ *
+ * @return a list of registers ordered by most-frequently-used to
+ * least-frequently-used. Each register is listed once and only
+ * once.
+ */
+ public int[] getRegistersByFrequency() {
+ int regCount = ssaMeth.getRegCount();
+ Integer[] ret = new Integer[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ ret[i] = i;
+ }
+
+ Arrays.sort(ret, new Comparator<Integer>() {
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return ssaMeth.getUseListForRegister(o2).size() - ssaMeth.getUseListForRegister(o1).size();
+ }
+ });
+
+ int result[] = new int[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ result[i] = ret[i];
+ }
+
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/AnnotatedOutput.java b/dx/src/com/android/jack/dx/util/AnnotatedOutput.java
index 6bbe4b7..b8374b4 100644
--- a/dx/src/com/android/jack/dx/util/AnnotatedOutput.java
+++ b/dx/src/com/android/jack/dx/util/AnnotatedOutput.java
@@ -20,60 +20,59 @@
* Interface for a binary output destination that may be augmented
* with textual annotations.
*/
-public interface AnnotatedOutput
- extends Output {
- /**
- * Get whether this instance will actually keep annotations.
- *
- * @return {@code true} iff annotations are being kept
- */
- public boolean annotates();
+public interface AnnotatedOutput extends Output {
+ /**
+ * Get whether this instance will actually keep annotations.
+ *
+ * @return {@code true} iff annotations are being kept
+ */
+ public boolean annotates();
- /**
- * Get whether this instance is intended to keep verbose annotations.
- * Annotators may use the result of calling this method to inform their
- * annotation activity.
- *
- * @return {@code true} iff annotations are to be verbose
- */
- public boolean isVerbose();
+ /**
+ * Get whether this instance is intended to keep verbose annotations.
+ * Annotators may use the result of calling this method to inform their
+ * annotation activity.
+ *
+ * @return {@code true} iff annotations are to be verbose
+ */
+ public boolean isVerbose();
- /**
- * Add an annotation for the subsequent output. Any previously
- * open annotation will be closed by this call, and the new
- * annotation marks all subsequent output until another annotation
- * call.
- *
- * @param msg {@code non-null;} the annotation message
- */
- public void annotate(String msg);
+ /**
+ * Add an annotation for the subsequent output. Any previously
+ * open annotation will be closed by this call, and the new
+ * annotation marks all subsequent output until another annotation
+ * call.
+ *
+ * @param msg {@code non-null;} the annotation message
+ */
+ public void annotate(String msg);
- /**
- * Add an annotation for a specified amount of subsequent
- * output. Any previously open annotation will be closed by this
- * call. If there is already pending annotation from one or more
- * previous calls to this method, the new call "consumes" output
- * after all the output covered by the previous calls.
- *
- * @param amt {@code >= 0;} the amount of output for this annotation to
- * cover
- * @param msg {@code non-null;} the annotation message
- */
- public void annotate(int amt, String msg);
+ /**
+ * Add an annotation for a specified amount of subsequent
+ * output. Any previously open annotation will be closed by this
+ * call. If there is already pending annotation from one or more
+ * previous calls to this method, the new call "consumes" output
+ * after all the output covered by the previous calls.
+ *
+ * @param amt {@code >= 0;} the amount of output for this annotation to
+ * cover
+ * @param msg {@code non-null;} the annotation message
+ */
+ public void annotate(int amt, String msg);
- /**
- * End the most recent annotation. Subsequent output will be unannotated,
- * until the next call to {@link #annotate}.
- */
- public void endAnnotation();
+ /**
+ * End the most recent annotation. Subsequent output will be unannotated,
+ * until the next call to {@link #annotate}.
+ */
+ public void endAnnotation();
- /**
- * Get the maximum width of the annotated output. This is advisory:
- * Implementations of this interface are encouraged to deal with too-wide
- * output, but annotaters are encouraged to attempt to avoid exceeding
- * the indicated width.
- *
- * @return {@code >= 1;} the maximum width
- */
- public int getAnnotationWidth();
+ /**
+ * Get the maximum width of the annotated output. This is advisory:
+ * Implementations of this interface are encouraged to deal with too-wide
+ * output, but annotaters are encouraged to attempt to avoid exceeding
+ * the indicated width.
+ *
+ * @return {@code >= 1;} the maximum width
+ */
+ public int getAnnotationWidth();
}
diff --git a/dx/src/com/android/jack/dx/util/BitIntSet.java b/dx/src/com/android/jack/dx/util/BitIntSet.java
index a4f5156..b19a387 100644
--- a/dx/src/com/android/jack/dx/util/BitIntSet.java
+++ b/dx/src/com/android/jack/dx/util/BitIntSet.java
@@ -23,123 +23,129 @@
*/
public class BitIntSet implements IntSet {
- /** also accessed in ListIntSet */
- int[] bits;
+ /** also accessed in ListIntSet */
+ int[] bits;
- /**
- * Constructs an instance.
- *
- * @param max the maximum value of ints in this set.
- */
- public BitIntSet(int max) {
- bits = Bits.makeBitSet(max);
+ /**
+ * Constructs an instance.
+ *
+ * @param max the maximum value of ints in this set.
+ */
+ public BitIntSet(int max) {
+ bits = Bits.makeBitSet(max);
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void add(int value) {
+ ensureCapacity(value);
+ Bits.set(bits, value, true);
+ }
+
+ /**
+ * Ensures that the bit set has the capacity to represent the given value.
+ *
+ * @param value {@code >= 0;} value to represent
+ */
+ private void ensureCapacity(int value) {
+ if (value >= Bits.getMax(bits)) {
+ int[] newBits = Bits.makeBitSet(Math.max(value + 1, 2 * Bits.getMax(bits)));
+ System.arraycopy(bits, 0, newBits, 0, bits.length);
+ bits = newBits;
}
+ }
- /** @inheritDoc */
- public void add(int value) {
- ensureCapacity(value);
- Bits.set(bits, value, true);
+ /** @inheritDoc */
+ @Override
+ public void remove(int value) {
+ if (value < Bits.getMax(bits)) {
+ Bits.set(bits, value, false);
}
+ }
- /**
- * Ensures that the bit set has the capacity to represent the given value.
- *
- * @param value {@code >= 0;} value to represent
- */
- private void ensureCapacity(int value) {
- if (value >= Bits.getMax(bits)) {
- int[] newBits = Bits.makeBitSet(
- Math.max(value + 1, 2 * Bits.getMax(bits)));
- System.arraycopy(bits, 0, newBits, 0, bits.length);
- bits = newBits;
- }
+ /** @inheritDoc */
+ @Override
+ public boolean has(int value) {
+ return (value < Bits.getMax(bits)) && Bits.get(bits, value);
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void merge(IntSet other) {
+ if (other instanceof BitIntSet) {
+ BitIntSet o = (BitIntSet) other;
+ ensureCapacity(Bits.getMax(o.bits) + 1);
+ Bits.or(bits, o.bits);
+ } else if (other instanceof ListIntSet) {
+ ListIntSet o = (ListIntSet) other;
+ int sz = o.ints.size();
+
+ if (sz > 0) {
+ ensureCapacity(o.ints.get(sz - 1));
+ }
+ for (int i = 0; i < o.ints.size(); i++) {
+ Bits.set(bits, o.ints.get(i), true);
+ }
+ } else {
+ IntIterator iter = other.iterator();
+ while (iter.hasNext()) {
+ add(iter.next());
+ }
}
+ }
- /** @inheritDoc */
- public void remove(int value) {
- if (value < Bits.getMax(bits)) {
- Bits.set(bits, value, false);
- }
- }
+ /** @inheritDoc */
+ @Override
+ public int elements() {
+ return Bits.bitCount(bits);
+ }
- /** @inheritDoc */
- public boolean has(int value) {
- return (value < Bits.getMax(bits)) && Bits.get(bits, value);
- }
+ /** @inheritDoc */
+ @Override
+ public IntIterator iterator() {
+ return new IntIterator() {
+ private int idx = Bits.findFirst(bits, 0);
- /** @inheritDoc */
- public void merge(IntSet other) {
- if (other instanceof BitIntSet) {
- BitIntSet o = (BitIntSet) other;
- ensureCapacity(Bits.getMax(o.bits) + 1);
- Bits.or(bits, o.bits);
- } else if (other instanceof ListIntSet) {
- ListIntSet o = (ListIntSet) other;
- int sz = o.ints.size();
+ /** @inheritDoc */
+ @Override
+ public boolean hasNext() {
+ return idx >= 0;
+ }
- if (sz > 0) {
- ensureCapacity(o.ints.get(sz - 1));
- }
- for (int i = 0; i < o.ints.size(); i++) {
- Bits.set(bits, o.ints.get(i), true);
- }
- } else {
- IntIterator iter = other.iterator();
- while (iter.hasNext()) {
- add(iter.next());
- }
- }
- }
-
- /** @inheritDoc */
- public int elements() {
- return Bits.bitCount(bits);
- }
-
- /** @inheritDoc */
- public IntIterator iterator() {
- return new IntIterator() {
- private int idx = Bits.findFirst(bits, 0);
-
- /** @inheritDoc */
- public boolean hasNext() {
- return idx >= 0;
- }
-
- /** @inheritDoc */
- public int next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
-
- int ret = idx;
-
- idx = Bits.findFirst(bits, idx+1);
-
- return ret;
- }
- };
- }
-
- /** @inheritDoc */
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append('{');
-
- boolean first = true;
- for (int i = Bits.findFirst(bits, 0)
- ; i >= 0
- ; i = Bits.findFirst(bits, i + 1)) {
- if (!first) {
- sb.append(", ");
- }
- first = false;
- sb.append(i);
+ /** @inheritDoc */
+ @Override
+ public int next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
}
- sb.append('}');
+ int ret = idx;
- return sb.toString();
+ idx = Bits.findFirst(bits, idx + 1);
+
+ return ret;
+ }
+ };
+ }
+
+ /** @inheritDoc */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append('{');
+
+ boolean first = true;
+ for (int i = Bits.findFirst(bits, 0); i >= 0; i = Bits.findFirst(bits, i + 1)) {
+ if (!first) {
+ sb.append(", ");
+ }
+ first = false;
+ sb.append(i);
}
+
+ sb.append('}');
+
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Bits.java b/dx/src/com/android/jack/dx/util/Bits.java
index 629d5cf..ea77735 100644
--- a/dx/src/com/android/jack/dx/util/Bits.java
+++ b/dx/src/com/android/jack/dx/util/Bits.java
@@ -20,217 +20,217 @@
* Utilities for treating {@code int[]}s as bit sets.
*/
public final class Bits {
- /**
- * This class is uninstantiable.
- */
- private Bits() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private Bits() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Constructs a bit set to contain bits up to the given index (exclusive).
+ *
+ * @param max {@code >= 0;} the maximum bit index (exclusive)
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static int[] makeBitSet(int max) {
+ int size = (max + 0x1f) >> 5;
+ return new int[size];
+ }
+
+ /**
+ * Gets the maximum index (exclusive) for the given bit set.
+ *
+ * @param bits {@code non-null;} bit set in question
+ * @return {@code >= 0;} the maximum index (exclusive) that may be set
+ */
+ public static int getMax(int[] bits) {
+ return bits.length * 0x20;
+ }
+
+ /**
+ * Gets the value of the bit at the given index.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
+ * @return the value of the indicated bit
+ */
+ public static boolean get(int[] bits, int idx) {
+ int arrayIdx = idx >> 5;
+ int bit = 1 << (idx & 0x1f);
+ return (bits[arrayIdx] & bit) != 0;
+ }
+
+ /**
+ * Sets the given bit to the given value.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
+ * @param value the new value for the bit
+ */
+ public static void set(int[] bits, int idx, boolean value) {
+ int arrayIdx = idx >> 5;
+ int bit = 1 << (idx & 0x1f);
+
+ if (value) {
+ bits[arrayIdx] |= bit;
+ } else {
+ bits[arrayIdx] &= ~bit;
+ }
+ }
+
+ /**
+ * Sets the given bit to {@code true}.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
+ */
+ public static void set(int[] bits, int idx) {
+ int arrayIdx = idx >> 5;
+ int bit = 1 << (idx & 0x1f);
+ bits[arrayIdx] |= bit;
+ }
+
+ /**
+ * Sets the given bit to {@code false}.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
+ */
+ public static void clear(int[] bits, int idx) {
+ int arrayIdx = idx >> 5;
+ int bit = 1 << (idx & 0x1f);
+ bits[arrayIdx] &= ~bit;
+ }
+
+ /**
+ * Returns whether or not the given bit set is empty, that is, whether
+ * no bit is set to {@code true}.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @return {@code true} iff all bits are {@code false}
+ */
+ public static boolean isEmpty(int[] bits) {
+ int len = bits.length;
+
+ for (int i = 0; i < len; i++) {
+ if (bits[i] != 0) {
+ return false;
+ }
}
- /**
- * Constructs a bit set to contain bits up to the given index (exclusive).
- *
- * @param max {@code >= 0;} the maximum bit index (exclusive)
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public static int[] makeBitSet(int max) {
- int size = (max + 0x1f) >> 5;
- return new int[size];
+ return true;
+ }
+
+ /**
+ * Gets the number of bits set to {@code true} in the given bit set.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @return {@code >= 0;} the bit count (aka population count) of the set
+ */
+ public static int bitCount(int[] bits) {
+ int len = bits.length;
+ int count = 0;
+
+ for (int i = 0; i < len; i++) {
+ count += Integer.bitCount(bits[i]);
}
- /**
- * Gets the maximum index (exclusive) for the given bit set.
- *
- * @param bits {@code non-null;} bit set in question
- * @return {@code >= 0;} the maximum index (exclusive) that may be set
- */
- public static int getMax(int[] bits) {
- return bits.length * 0x20;
- }
+ return count;
+ }
- /**
- * Gets the value of the bit at the given index.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param idx {@code >= 0, < getMax(set);} which bit
- * @return the value of the indicated bit
- */
- public static boolean get(int[] bits, int idx) {
- int arrayIdx = idx >> 5;
- int bit = 1 << (idx & 0x1f);
- return (bits[arrayIdx] & bit) != 0;
- }
+ /**
+ * Returns whether any bits are set to {@code true} in the
+ * specified range.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param start {@code >= 0;} index of the first bit in the range (inclusive)
+ * @param end {@code >= 0;} index of the last bit in the range (exclusive)
+ * @return {@code true} if any bit is set to {@code true} in
+ * the indicated range
+ */
+ public static boolean anyInRange(int[] bits, int start, int end) {
+ int idx = findFirst(bits, start);
+ return (idx >= 0) && (idx < end);
+ }
- /**
- * Sets the given bit to the given value.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param idx {@code >= 0, < getMax(set);} which bit
- * @param value the new value for the bit
- */
- public static void set(int[] bits, int idx, boolean value) {
- int arrayIdx = idx >> 5;
- int bit = 1 << (idx & 0x1f);
+ /**
+ * Finds the lowest-order bit set at or after the given index in the
+ * given bit set.
+ *
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0;} minimum index to return
+ * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+ * or {@code -1} if there is no appropriate bit index to return
+ */
+ public static int findFirst(int[] bits, int idx) {
+ int len = bits.length;
+ int minBit = idx & 0x1f;
- if (value) {
- bits[arrayIdx] |= bit;
- } else {
- bits[arrayIdx] &= ~bit;
+ for (int arrayIdx = idx >> 5; arrayIdx < len; arrayIdx++) {
+ int word = bits[arrayIdx];
+ if (word != 0) {
+ int bitIdx = findFirst(word, minBit);
+ if (bitIdx >= 0) {
+ return (arrayIdx << 5) + bitIdx;
}
+ }
+ minBit = 0;
}
- /**
- * Sets the given bit to {@code true}.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param idx {@code >= 0, < getMax(set);} which bit
- */
- public static void set(int[] bits, int idx) {
- int arrayIdx = idx >> 5;
- int bit = 1 << (idx & 0x1f);
- bits[arrayIdx] |= bit;
+ return -1;
+ }
+
+ /**
+ * Finds the lowest-order bit set at or after the given index in the
+ * given {@code int}.
+ *
+ * @param value the value in question
+ * @param idx 0..31 the minimum bit index to return
+ * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+ * or {@code -1} if there is no appropriate bit index to return
+ */
+ public static int findFirst(int value, int idx) {
+ value &= ~((1 << idx) - 1); // Mask off too-low bits.
+ int result = Integer.numberOfTrailingZeros(value);
+ return (result == 32) ? -1 : result;
+ }
+
+ /**
+ * Ors bit array {@code b} into bit array {@code a}.
+ * {@code a.length} must be greater than or equal to
+ * {@code b.length}.
+ *
+ * @param a {@code non-null;} int array to be ored with other argument. This
+ * argument is modified.
+ * @param b {@code non-null;} int array to be ored into {@code a}. This
+ * argument is not modified.
+ */
+ public static void or(int[] a, int[] b) {
+ for (int i = 0; i < b.length; i++) {
+ a[i] |= b[i];
}
+ }
- /**
- * Sets the given bit to {@code false}.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param idx {@code >= 0, < getMax(set);} which bit
- */
- public static void clear(int[] bits, int idx) {
- int arrayIdx = idx >> 5;
- int bit = 1 << (idx & 0x1f);
- bits[arrayIdx] &= ~bit;
- }
+ public static String toHuman(int[] bits) {
+ StringBuilder sb = new StringBuilder();
- /**
- * Returns whether or not the given bit set is empty, that is, whether
- * no bit is set to {@code true}.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @return {@code true} iff all bits are {@code false}
- */
- public static boolean isEmpty(int[] bits) {
- int len = bits.length;
+ boolean needsComma = false;
- for (int i = 0; i < len; i++) {
- if (bits[i] != 0) {
- return false;
- }
+ sb.append('{');
+
+ int bitsLength = 32 * bits.length;
+ for (int i = 0; i < bitsLength; i++) {
+ if (Bits.get(bits, i)) {
+ if (needsComma) {
+ sb.append(',');
}
-
- return true;
+ needsComma = true;
+ sb.append(i);
+ }
}
+ sb.append('}');
- /**
- * Gets the number of bits set to {@code true} in the given bit set.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @return {@code >= 0;} the bit count (aka population count) of the set
- */
- public static int bitCount(int[] bits) {
- int len = bits.length;
- int count = 0;
-
- for (int i = 0; i < len; i++) {
- count += Integer.bitCount(bits[i]);
- }
-
- return count;
- }
-
- /**
- * Returns whether any bits are set to {@code true} in the
- * specified range.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param start {@code >= 0;} index of the first bit in the range (inclusive)
- * @param end {@code >= 0;} index of the last bit in the range (exclusive)
- * @return {@code true} if any bit is set to {@code true} in
- * the indicated range
- */
- public static boolean anyInRange(int[] bits, int start, int end) {
- int idx = findFirst(bits, start);
- return (idx >= 0) && (idx < end);
- }
-
- /**
- * Finds the lowest-order bit set at or after the given index in the
- * given bit set.
- *
- * @param bits {@code non-null;} bit set to operate on
- * @param idx {@code >= 0;} minimum index to return
- * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
- * or {@code -1} if there is no appropriate bit index to return
- */
- public static int findFirst(int[] bits, int idx) {
- int len = bits.length;
- int minBit = idx & 0x1f;
-
- for (int arrayIdx = idx >> 5; arrayIdx < len; arrayIdx++) {
- int word = bits[arrayIdx];
- if (word != 0) {
- int bitIdx = findFirst(word, minBit);
- if (bitIdx >= 0) {
- return (arrayIdx << 5) + bitIdx;
- }
- }
- minBit = 0;
- }
-
- return -1;
- }
-
- /**
- * Finds the lowest-order bit set at or after the given index in the
- * given {@code int}.
- *
- * @param value the value in question
- * @param idx 0..31 the minimum bit index to return
- * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
- * or {@code -1} if there is no appropriate bit index to return
- */
- public static int findFirst(int value, int idx) {
- value &= ~((1 << idx) - 1); // Mask off too-low bits.
- int result = Integer.numberOfTrailingZeros(value);
- return (result == 32) ? -1 : result;
- }
-
- /**
- * Ors bit array {@code b} into bit array {@code a}.
- * {@code a.length} must be greater than or equal to
- * {@code b.length}.
- *
- * @param a {@code non-null;} int array to be ored with other argument. This
- * argument is modified.
- * @param b {@code non-null;} int array to be ored into {@code a}. This
- * argument is not modified.
- */
- public static void or(int[] a, int[] b) {
- for (int i = 0; i < b.length; i++) {
- a[i] |= b[i];
- }
- }
-
- public static String toHuman(int[] bits) {
- StringBuilder sb = new StringBuilder();
-
- boolean needsComma = false;
-
- sb.append('{');
-
- int bitsLength = 32 * bits.length;
- for (int i = 0; i < bitsLength; i++) {
- if (Bits.get(bits, i)) {
- if (needsComma) {
- sb.append(',');
- }
- needsComma = true;
- sb.append(i);
- }
- }
- sb.append('}');
-
- return sb.toString();
- }
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ByteArray.java b/dx/src/com/android/jack/dx/util/ByteArray.java
index b5ff800..e696542 100644
--- a/dx/src/com/android/jack/dx/util/ByteArray.java
+++ b/dx/src/com/android/jack/dx/util/ByteArray.java
@@ -27,335 +27,328 @@
* <b>Note:</b> Multibyte accessors all use big-endian order.
*/
public final class ByteArray {
- /** {@code non-null;} underlying array */
- private final byte[] bytes;
+ /** {@code non-null;} underlying array */
+ private final byte[] bytes;
- /** {@code >= 0}; start index of the slice (inclusive) */
- private final int start;
+ /** {@code >= 0}; start index of the slice (inclusive) */
+ private final int start;
- /** {@code >= 0, <= bytes.length}; size computed as
- * {@code end - start} (in the constructor) */
- private final int size;
+ /** {@code >= 0, <= bytes.length}; size computed as
+ * {@code end - start} (in the constructor) */
+ private final int size;
+ /**
+ * Constructs an instance.
+ *
+ * @param bytes {@code non-null;} the underlying array
+ * @param start {@code >= 0;} start index of the slice (inclusive)
+ * @param end {@code >= start, <= bytes.length;} end index of
+ * the slice (exclusive)
+ */
+ public ByteArray(byte[] bytes, int start, int end) {
+ if (bytes == null) {
+ throw new NullPointerException("bytes == null");
+ }
+
+ if (start < 0) {
+ throw new IllegalArgumentException("start < 0");
+ }
+
+ if (end < start) {
+ throw new IllegalArgumentException("end < start");
+ }
+
+ if (end > bytes.length) {
+ throw new IllegalArgumentException("end > bytes.length");
+ }
+
+ this.bytes = bytes;
+ this.start = start;
+ this.size = end - start;
+ }
+
+ /**
+ * Constructs an instance from an entire {@code byte[]}.
+ *
+ * @param bytes {@code non-null;} the underlying array
+ */
+ public ByteArray(byte[] bytes) {
+ this(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Gets the size of the array, in bytes.
+ *
+ * @return {@code >= 0;} the size
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Returns a slice (that is, a sub-array) of this instance.
+ *
+ * @param start {@code >= 0;} start index of the slice (inclusive)
+ * @param end {@code >= start, <= size();} end index of
+ * the slice (exclusive)
+ * @return {@code non-null;} the slice
+ */
+ public ByteArray slice(int start, int end) {
+ checkOffsets(start, end);
+ return new ByteArray(bytes, start + this.start, end + this.start);
+ }
+
+ /**
+ * Returns the offset into the given array represented by the given
+ * offset into this instance.
+ *
+ * @param offset offset into this instance
+ * @param bytes {@code non-null;} (alleged) underlying array
+ * @return corresponding offset into {@code bytes}
+ * @throws IllegalArgumentException thrown if {@code bytes} is
+ * not the underlying array of this instance
+ */
+ public int underlyingOffset(int offset, byte[] bytes) {
+ if (bytes != this.bytes) {
+ throw new IllegalArgumentException("wrong bytes");
+ }
+
+ return start + offset;
+ }
+
+ /**
+ * Gets the {@code signed byte} value at a particular offset.
+ *
+ * @param off {@code >= 0, < size();} offset to fetch
+ * @return {@code signed byte} at that offset
+ */
+ public int getByte(int off) {
+ checkOffsets(off, off + 1);
+ return getByte0(off);
+ }
+
+ /**
+ * Gets the {@code signed short} value at a particular offset.
+ *
+ * @param off {@code >= 0, < (size() - 1);} offset to fetch
+ * @return {@code signed short} at that offset
+ */
+ public int getShort(int off) {
+ checkOffsets(off, off + 2);
+ return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
+ }
+
+ /**
+ * Gets the {@code signed int} value at a particular offset.
+ *
+ * @param off {@code >= 0, < (size() - 3);} offset to fetch
+ * @return {@code signed int} at that offset
+ */
+ public int getInt(int off) {
+ checkOffsets(off, off + 4);
+ return (getByte0(off) << 24) | (getUnsignedByte0(off + 1) << 16)
+ | (getUnsignedByte0(off + 2) << 8) | getUnsignedByte0(off + 3);
+ }
+
+ /**
+ * Gets the {@code signed long} value at a particular offset.
+ *
+ * @param off {@code >= 0, < (size() - 7);} offset to fetch
+ * @return {@code signed int} at that offset
+ */
+ public long getLong(int off) {
+ checkOffsets(off, off + 8);
+ int part1 = (getByte0(off) << 24) | (getUnsignedByte0(off + 1) << 16)
+ | (getUnsignedByte0(off + 2) << 8) | getUnsignedByte0(off + 3);
+ int part2 = (getByte0(off + 4) << 24) | (getUnsignedByte0(off + 5) << 16)
+ | (getUnsignedByte0(off + 6) << 8) | getUnsignedByte0(off + 7);
+
+ return (part2 & 0xffffffffL) | ((long) part1) << 32;
+ }
+
+ /**
+ * Gets the {@code unsigned byte} value at a particular offset.
+ *
+ * @param off {@code >= 0, < size();} offset to fetch
+ * @return {@code unsigned byte} at that offset
+ */
+ public int getUnsignedByte(int off) {
+ checkOffsets(off, off + 1);
+ return getUnsignedByte0(off);
+ }
+
+ /**
+ * Gets the {@code unsigned short} value at a particular offset.
+ *
+ * @param off {@code >= 0, < (size() - 1);} offset to fetch
+ * @return {@code unsigned short} at that offset
+ */
+ public int getUnsignedShort(int off) {
+ checkOffsets(off, off + 2);
+ return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
+ }
+
+ /**
+ * Copies the contents of this instance into the given raw
+ * {@code byte[]} at the given offset. The given array must be
+ * large enough.
+ *
+ * @param out {@code non-null;} array to hold the output
+ * @param offset {@code non-null;} index into {@code out} for the first
+ * byte of output
+ */
+ public void getBytes(byte[] out, int offset) {
+ if ((out.length - offset) < size) {
+ throw new IndexOutOfBoundsException("(out.length - offset) < " + "size()");
+ }
+
+ System.arraycopy(bytes, start, out, offset, size);
+ }
+
+ /**
+ * Checks a range of offsets for validity, throwing if invalid.
+ *
+ * @param s start offset (inclusive)
+ * @param e end offset (exclusive)
+ */
+ private void checkOffsets(int s, int e) {
+ if ((s < 0) || (e < s) || (e > size)) {
+ throw new IllegalArgumentException("bad range: " + s + ".." + e + "; actual size " + size);
+ }
+ }
+
+ /**
+ * Gets the {@code signed byte} value at the given offset,
+ * without doing any argument checking.
+ *
+ * @param off offset to fetch
+ * @return byte at that offset
+ */
+ private int getByte0(int off) {
+ return bytes[start + off];
+ }
+
+ /**
+ * Gets the {@code unsigned byte} value at the given offset,
+ * without doing any argument checking.
+ *
+ * @param off offset to fetch
+ * @return byte at that offset
+ */
+ private int getUnsignedByte0(int off) {
+ return bytes[start + off] & 0xff;
+ }
+
+ /**
+ * Gets a {@code DataInputStream} that reads from this instance,
+ * with the cursor starting at the beginning of this instance's data.
+ * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
+ * if needed.
+ *
+ * @return {@code non-null;} an appropriately-constructed
+ * {@code DataInputStream} instance
+ */
+ public MyDataInputStream makeDataInputStream() {
+ return new MyDataInputStream(makeInputStream());
+ }
+
+ /**
+ * Gets a {@code InputStream} that reads from this instance,
+ * with the cursor starting at the beginning of this instance's data.
+ * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
+ * if needed.
+ *
+ * @return {@code non-null;} an appropriately-constructed
+ * {@code InputStream} instancex
+ */
+ public MyInputStream makeInputStream() {
+ return new MyInputStream();
+ }
+
+ /**
+ * Helper interface that allows one to get the cursor (of a stream).
+ */
+ public interface GetCursor {
/**
- * Constructs an instance.
+ * Gets the current cursor.
*
- * @param bytes {@code non-null;} the underlying array
- * @param start {@code >= 0;} start index of the slice (inclusive)
- * @param end {@code >= start, <= bytes.length;} end index of
- * the slice (exclusive)
+ * @return {@code 0..size();} the cursor
*/
- public ByteArray(byte[] bytes, int start, int end) {
- if (bytes == null) {
- throw new NullPointerException("bytes == null");
- }
+ public int getCursor();
+ }
- if (start < 0) {
- throw new IllegalArgumentException("start < 0");
- }
+ /**
+ * Helper class for {@link #makeInputStream}, which implements the
+ * stream functionality.
+ */
+ public class MyInputStream extends InputStream {
+ /** 0..size; the cursor */
+ private int cursor;
- if (end < start) {
- throw new IllegalArgumentException("end < start");
- }
+ /** 0..size; the mark */
+ private int mark;
- if (end > bytes.length) {
- throw new IllegalArgumentException("end > bytes.length");
- }
-
- this.bytes = bytes;
- this.start = start;
- this.size = end - start;
+ public MyInputStream() {
+ cursor = 0;
+ mark = 0;
}
- /**
- * Constructs an instance from an entire {@code byte[]}.
- *
- * @param bytes {@code non-null;} the underlying array
- */
- public ByteArray(byte[] bytes) {
- this(bytes, 0, bytes.length);
+ @Override
+ public int read() throws IOException {
+ if (cursor >= size) {
+ return -1;
+ }
+
+ int result = getUnsignedByte0(cursor);
+ cursor++;
+ return result;
}
- /**
- * Gets the size of the array, in bytes.
- *
- * @return {@code >= 0;} the size
- */
- public int size() {
- return size;
+ @Override
+ public int read(byte[] arr, int offset, int length) {
+ if ((offset + length) > arr.length) {
+ length = arr.length - offset;
+ }
+
+ int maxLength = size - cursor;
+ if (length > maxLength) {
+ length = maxLength;
+ }
+
+ System.arraycopy(bytes, cursor + start, arr, offset, length);
+ cursor += length;
+ return length;
}
- /**
- * Returns a slice (that is, a sub-array) of this instance.
- *
- * @param start {@code >= 0;} start index of the slice (inclusive)
- * @param end {@code >= start, <= size();} end index of
- * the slice (exclusive)
- * @return {@code non-null;} the slice
- */
- public ByteArray slice(int start, int end) {
- checkOffsets(start, end);
- return new ByteArray(bytes, start + this.start, end + this.start);
+ @Override
+ public int available() {
+ return size - cursor;
}
- /**
- * Returns the offset into the given array represented by the given
- * offset into this instance.
- *
- * @param offset offset into this instance
- * @param bytes {@code non-null;} (alleged) underlying array
- * @return corresponding offset into {@code bytes}
- * @throws IllegalArgumentException thrown if {@code bytes} is
- * not the underlying array of this instance
- */
- public int underlyingOffset(int offset, byte[] bytes) {
- if (bytes != this.bytes) {
- throw new IllegalArgumentException("wrong bytes");
- }
-
- return start + offset;
+ @Override
+ public void mark(int reserve) {
+ mark = cursor;
}
- /**
- * Gets the {@code signed byte} value at a particular offset.
- *
- * @param off {@code >= 0, < size();} offset to fetch
- * @return {@code signed byte} at that offset
- */
- public int getByte(int off) {
- checkOffsets(off, off + 1);
- return getByte0(off);
+ @Override
+ public void reset() {
+ cursor = mark;
}
- /**
- * Gets the {@code signed short} value at a particular offset.
- *
- * @param off {@code >= 0, < (size() - 1);} offset to fetch
- * @return {@code signed short} at that offset
- */
- public int getShort(int off) {
- checkOffsets(off, off + 2);
- return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
+ @Override
+ public boolean markSupported() {
+ return true;
}
+ }
- /**
- * Gets the {@code signed int} value at a particular offset.
- *
- * @param off {@code >= 0, < (size() - 3);} offset to fetch
- * @return {@code signed int} at that offset
- */
- public int getInt(int off) {
- checkOffsets(off, off + 4);
- return (getByte0(off) << 24) |
- (getUnsignedByte0(off + 1) << 16) |
- (getUnsignedByte0(off + 2) << 8) |
- getUnsignedByte0(off + 3);
+ /**
+ * Helper class for {@link #makeDataInputStream}. This is used
+ * simply so that the cursor of a wrapped {@link #MyInputStream}
+ * instance may be easily determined.
+ */
+ public static class MyDataInputStream extends DataInputStream {
+ public MyDataInputStream(MyInputStream wrapped) {
+ super(wrapped);
}
-
- /**
- * Gets the {@code signed long} value at a particular offset.
- *
- * @param off {@code >= 0, < (size() - 7);} offset to fetch
- * @return {@code signed int} at that offset
- */
- public long getLong(int off) {
- checkOffsets(off, off + 8);
- int part1 = (getByte0(off) << 24) |
- (getUnsignedByte0(off + 1) << 16) |
- (getUnsignedByte0(off + 2) << 8) |
- getUnsignedByte0(off + 3);
- int part2 = (getByte0(off + 4) << 24) |
- (getUnsignedByte0(off + 5) << 16) |
- (getUnsignedByte0(off + 6) << 8) |
- getUnsignedByte0(off + 7);
-
- return (part2 & 0xffffffffL) | ((long) part1) << 32;
- }
-
- /**
- * Gets the {@code unsigned byte} value at a particular offset.
- *
- * @param off {@code >= 0, < size();} offset to fetch
- * @return {@code unsigned byte} at that offset
- */
- public int getUnsignedByte(int off) {
- checkOffsets(off, off + 1);
- return getUnsignedByte0(off);
- }
-
- /**
- * Gets the {@code unsigned short} value at a particular offset.
- *
- * @param off {@code >= 0, < (size() - 1);} offset to fetch
- * @return {@code unsigned short} at that offset
- */
- public int getUnsignedShort(int off) {
- checkOffsets(off, off + 2);
- return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
- }
-
- /**
- * Copies the contents of this instance into the given raw
- * {@code byte[]} at the given offset. The given array must be
- * large enough.
- *
- * @param out {@code non-null;} array to hold the output
- * @param offset {@code non-null;} index into {@code out} for the first
- * byte of output
- */
- public void getBytes(byte[] out, int offset) {
- if ((out.length - offset) < size) {
- throw new IndexOutOfBoundsException("(out.length - offset) < " +
- "size()");
- }
-
- System.arraycopy(bytes, start, out, offset, size);
- }
-
- /**
- * Checks a range of offsets for validity, throwing if invalid.
- *
- * @param s start offset (inclusive)
- * @param e end offset (exclusive)
- */
- private void checkOffsets(int s, int e) {
- if ((s < 0) || (e < s) || (e > size)) {
- throw new IllegalArgumentException("bad range: " + s + ".." + e +
- "; actual size " + size);
- }
- }
-
- /**
- * Gets the {@code signed byte} value at the given offset,
- * without doing any argument checking.
- *
- * @param off offset to fetch
- * @return byte at that offset
- */
- private int getByte0(int off) {
- return bytes[start + off];
- }
-
- /**
- * Gets the {@code unsigned byte} value at the given offset,
- * without doing any argument checking.
- *
- * @param off offset to fetch
- * @return byte at that offset
- */
- private int getUnsignedByte0(int off) {
- return bytes[start + off] & 0xff;
- }
-
- /**
- * Gets a {@code DataInputStream} that reads from this instance,
- * with the cursor starting at the beginning of this instance's data.
- * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
- * if needed.
- *
- * @return {@code non-null;} an appropriately-constructed
- * {@code DataInputStream} instance
- */
- public MyDataInputStream makeDataInputStream() {
- return new MyDataInputStream(makeInputStream());
- }
-
- /**
- * Gets a {@code InputStream} that reads from this instance,
- * with the cursor starting at the beginning of this instance's data.
- * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
- * if needed.
- *
- * @return {@code non-null;} an appropriately-constructed
- * {@code InputStream} instancex
- */
- public MyInputStream makeInputStream() {
- return new MyInputStream();
- }
-
- /**
- * Helper interface that allows one to get the cursor (of a stream).
- */
- public interface GetCursor {
- /**
- * Gets the current cursor.
- *
- * @return {@code 0..size();} the cursor
- */
- public int getCursor();
- }
-
- /**
- * Helper class for {@link #makeInputStream}, which implements the
- * stream functionality.
- */
- public class MyInputStream extends InputStream {
- /** 0..size; the cursor */
- private int cursor;
-
- /** 0..size; the mark */
- private int mark;
-
- public MyInputStream() {
- cursor = 0;
- mark = 0;
- }
-
- public int read() throws IOException {
- if (cursor >= size) {
- return -1;
- }
-
- int result = getUnsignedByte0(cursor);
- cursor++;
- return result;
- }
-
- public int read(byte[] arr, int offset, int length) {
- if ((offset + length) > arr.length) {
- length = arr.length - offset;
- }
-
- int maxLength = size - cursor;
- if (length > maxLength) {
- length = maxLength;
- }
-
- System.arraycopy(bytes, cursor + start, arr, offset, length);
- cursor += length;
- return length;
- }
-
- public int available() {
- return size - cursor;
- }
-
- public void mark(int reserve) {
- mark = cursor;
- }
-
- public void reset() {
- cursor = mark;
- }
-
- public boolean markSupported() {
- return true;
- }
- }
-
- /**
- * Helper class for {@link #makeDataInputStream}. This is used
- * simply so that the cursor of a wrapped {@link #MyInputStream}
- * instance may be easily determined.
- */
- public static class MyDataInputStream extends DataInputStream {
- /** {@code non-null;} the underlying {@link #MyInputStream} */
- private final MyInputStream wrapped;
-
- public MyDataInputStream(MyInputStream wrapped) {
- super(wrapped);
-
- this.wrapped = wrapped;
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ByteArrayAnnotatedOutput.java b/dx/src/com/android/jack/dx/util/ByteArrayAnnotatedOutput.java
index 09174e0..fcfab9f 100644
--- a/dx/src/com/android/jack/dx/util/ByteArrayAnnotatedOutput.java
+++ b/dx/src/com/android/jack/dx/util/ByteArrayAnnotatedOutput.java
@@ -27,606 +27,622 @@
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
* writes all use little-endian order.</p>
*/
-public final class ByteArrayAnnotatedOutput
- implements AnnotatedOutput, ByteOutput {
- /** default size for stretchy instances */
- private static final int DEFAULT_SIZE = 1000;
+public final class ByteArrayAnnotatedOutput implements AnnotatedOutput, ByteOutput {
+ /** default size for stretchy instances */
+ private static final int DEFAULT_SIZE = 1000;
- /**
- * whether the instance is stretchy, that is, whether its array
- * may be resized to increase capacity
+ /**
+ * whether the instance is stretchy, that is, whether its array
+ * may be resized to increase capacity
+ */
+ private final boolean stretchy;
+
+ /** {@code non-null;} the data itself */
+ private byte[] data;
+
+ /** {@code >= 0;} current output cursor */
+ private int cursor;
+
+ /** whether annotations are to be verbose */
+ private boolean verbose;
+
+ /**
+ * {@code null-ok;} list of annotations, or {@code null} if this instance
+ * isn't keeping them
+ */
+ private ArrayList<Annotation> annotations;
+
+ /** {@code >= 40 (if used);} the desired maximum annotation width */
+ private int annotationWidth;
+
+ /**
+ * {@code >= 8 (if used);} the number of bytes of hex output to use
+ * in annotations
+ */
+ private int hexCols;
+
+ /**
+ * Constructs an instance with a fixed maximum size. Note that the
+ * given array is the only one that will be used to store data. In
+ * particular, no reallocation will occur in order to expand the
+ * capacity of the resulting instance. Also, the constructed
+ * instance does not keep annotations by default.
+ *
+ * @param data {@code non-null;} data array to use for output
+ */
+ public ByteArrayAnnotatedOutput(byte[] data) {
+ this(data, false);
+ }
+
+ /**
+ * Constructs a "stretchy" instance. The underlying array may be
+ * reallocated. The constructed instance does not keep annotations
+ * by default.
+ */
+ public ByteArrayAnnotatedOutput() {
+ this(DEFAULT_SIZE);
+ }
+
+ /**
+ * Constructs a "stretchy" instance with initial size {@code size}. The
+ * underlying array may be reallocated. The constructed instance does not
+ * keep annotations by default.
+ */
+ public ByteArrayAnnotatedOutput(int size) {
+ this(new byte[size], true);
+ }
+
+ /**
+ * Internal constructor.
+ *
+ * @param data {@code non-null;} data array to use for output
+ * @param stretchy whether the instance is to be stretchy
+ */
+ private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
+ if (data == null) {
+ throw new NullPointerException("data == null");
+ }
+
+ this.stretchy = stretchy;
+ this.data = data;
+ this.cursor = 0;
+ this.verbose = false;
+ this.annotations = null;
+ this.annotationWidth = 0;
+ this.hexCols = 0;
+ }
+
+ /**
+ * Gets the underlying {@code byte[]} of this instance, which
+ * may be larger than the number of bytes written
+ *
+ * @see #toByteArray
+ *
+ * @return {@code non-null;} the {@code byte[]}
+ */
+ public byte[] getArray() {
+ return data;
+ }
+
+ /**
+ * Constructs and returns a new {@code byte[]} that contains
+ * the written contents exactly (that is, with no extra unwritten
+ * bytes at the end).
+ *
+ * @see #getArray
+ *
+ * @return {@code non-null;} an appropriately-constructed array
+ */
+ public byte[] toByteArray() {
+ byte[] result = new byte[cursor];
+ System.arraycopy(data, 0, result, 0, cursor);
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getCursor() {
+ return cursor;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void assertCursor(int expectedCursor) {
+ if (cursor != expectedCursor) {
+ throw new ExceptionWithContext(
+ "expected cursor " + expectedCursor + "; actual value: " + cursor);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeByte(int value) {
+ int writeAt = cursor;
+ int end = writeAt + 1;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ data[writeAt] = (byte) value;
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeShort(int value) {
+ int writeAt = cursor;
+ int end = writeAt + 2;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ data[writeAt] = (byte) value;
+ data[writeAt + 1] = (byte) (value >> 8);
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeInt(int value) {
+ int writeAt = cursor;
+ int end = writeAt + 4;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ data[writeAt] = (byte) value;
+ data[writeAt + 1] = (byte) (value >> 8);
+ data[writeAt + 2] = (byte) (value >> 16);
+ data[writeAt + 3] = (byte) (value >> 24);
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeLong(long value) {
+ int writeAt = cursor;
+ int end = writeAt + 8;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ int half = (int) value;
+ data[writeAt] = (byte) half;
+ data[writeAt + 1] = (byte) (half >> 8);
+ data[writeAt + 2] = (byte) (half >> 16);
+ data[writeAt + 3] = (byte) (half >> 24);
+
+ half = (int) (value >> 32);
+ data[writeAt + 4] = (byte) half;
+ data[writeAt + 5] = (byte) (half >> 8);
+ data[writeAt + 6] = (byte) (half >> 16);
+ data[writeAt + 7] = (byte) (half >> 24);
+
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeUleb128(int value) {
+ if (stretchy) {
+ ensureCapacity(cursor + 5); // pessimistic
+ }
+ int cursorBefore = cursor;
+ Leb128Utils.writeUnsignedLeb128(this, value);
+ return (cursor - cursorBefore);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int writeSleb128(int value) {
+ if (stretchy) {
+ ensureCapacity(cursor + 5); // pessimistic
+ }
+ int cursorBefore = cursor;
+ Leb128Utils.writeSignedLeb128(this, value);
+ return (cursor - cursorBefore);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write(ByteArray bytes) {
+ int blen = bytes.size();
+ int writeAt = cursor;
+ int end = writeAt + blen;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ bytes.getBytes(data, writeAt);
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write(byte[] bytes, int offset, int length) {
+ int writeAt = cursor;
+ int end = writeAt + length;
+ int bytesEnd = offset + length;
+
+ // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+ if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
+ throw new IndexOutOfBoundsException(
+ "bytes.length " + bytes.length + "; " + offset + "..!" + end);
+ }
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ System.arraycopy(bytes, offset, data, writeAt, length);
+ cursor = end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write(byte[] bytes) {
+ write(bytes, 0, bytes.length);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeZeroes(int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("count < 0");
+ }
+
+ int end = cursor + count;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ /*
+ * There is no need to actually write zeroes, since the array is
+ * already preinitialized with zeroes.
*/
- private final boolean stretchy;
- /** {@code non-null;} the data itself */
- private byte[] data;
+cursor = end;
+ }
- /** {@code >= 0;} current output cursor */
- private int cursor;
+ /** {@inheritDoc} */
+ @Override
+ public void alignTo(int alignment) {
+ int mask = alignment - 1;
- /** whether annotations are to be verbose */
- private boolean verbose;
+ if ((alignment < 0) || ((mask & alignment) != 0)) {
+ throw new IllegalArgumentException("bogus alignment");
+ }
- /**
- * {@code null-ok;} list of annotations, or {@code null} if this instance
- * isn't keeping them
+ int end = (cursor + mask) & ~mask;
+
+ if (stretchy) {
+ ensureCapacity(end);
+ } else if (end > data.length) {
+ throwBounds();
+ return;
+ }
+
+ /*
+ * There is no need to actually write zeroes, since the array is
+ * already preinitialized with zeroes.
*/
- private ArrayList<Annotation> annotations;
- /** {@code >= 40 (if used);} the desired maximum annotation width */
- private int annotationWidth;
+cursor = end;
+ }
- /**
- * {@code >= 8 (if used);} the number of bytes of hex output to use
- * in annotations
- */
- private int hexCols;
+ /** {@inheritDoc} */
+ @Override
+ public boolean annotates() {
+ return (annotations != null);
+ }
- /**
- * Constructs an instance with a fixed maximum size. Note that the
- * given array is the only one that will be used to store data. In
- * particular, no reallocation will occur in order to expand the
- * capacity of the resulting instance. Also, the constructed
- * instance does not keep annotations by default.
- *
- * @param data {@code non-null;} data array to use for output
- */
- public ByteArrayAnnotatedOutput(byte[] data) {
- this(data, false);
+ /** {@inheritDoc} */
+ @Override
+ public boolean isVerbose() {
+ return verbose;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void annotate(String msg) {
+ if (annotations == null) {
+ return;
}
- /**
- * Constructs a "stretchy" instance. The underlying array may be
- * reallocated. The constructed instance does not keep annotations
- * by default.
- */
- public ByteArrayAnnotatedOutput() {
- this(DEFAULT_SIZE);
+ endAnnotation();
+ annotations.add(new Annotation(cursor, msg));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void annotate(int amt, String msg) {
+ if (annotations == null) {
+ return;
}
- /**
- * Constructs a "stretchy" instance with initial size {@code size}. The
- * underlying array may be reallocated. The constructed instance does not
- * keep annotations by default.
- */
- public ByteArrayAnnotatedOutput(int size) {
- this(new byte[size], true);
+ endAnnotation();
+
+ int asz = annotations.size();
+ int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
+ int startAt;
+
+ if (lastEnd <= cursor) {
+ startAt = cursor;
+ } else {
+ startAt = lastEnd;
}
- /**
- * Internal constructor.
- *
- * @param data {@code non-null;} data array to use for output
- * @param stretchy whether the instance is to be stretchy
- */
- private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
- if (data == null) {
- throw new NullPointerException("data == null");
- }
+ annotations.add(new Annotation(startAt, startAt + amt, msg));
+ }
- this.stretchy = stretchy;
- this.data = data;
- this.cursor = 0;
- this.verbose = false;
- this.annotations = null;
- this.annotationWidth = 0;
- this.hexCols = 0;
+ /** {@inheritDoc} */
+ @Override
+ public void endAnnotation() {
+ if (annotations == null) {
+ return;
}
- /**
- * Gets the underlying {@code byte[]} of this instance, which
- * may be larger than the number of bytes written
- *
- * @see #toByteArray
- *
- * @return {@code non-null;} the {@code byte[]}
- */
- public byte[] getArray() {
- return data;
+ int sz = annotations.size();
+
+ if (sz != 0) {
+ annotations.get(sz - 1).setEndIfUnset(cursor);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getAnnotationWidth() {
+ int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
+
+ return annotationWidth - leftWidth;
+ }
+
+ /**
+ * Indicates that this instance should keep annotations. This method may
+ * be called only once per instance, and only before any data has been
+ * written to the it.
+ *
+ * @param annotationWidth {@code >= 40;} the desired maximum annotation width
+ * @param verbose whether or not to indicate verbose annotations
+ */
+ public void enableAnnotations(int annotationWidth, boolean verbose) {
+ if ((annotations != null) || (cursor != 0)) {
+ throw new RuntimeException("cannot enable annotations");
}
- /**
- * Constructs and returns a new {@code byte[]} that contains
- * the written contents exactly (that is, with no extra unwritten
- * bytes at the end).
- *
- * @see #getArray
- *
- * @return {@code non-null;} an appropriately-constructed array
- */
- public byte[] toByteArray() {
- byte[] result = new byte[cursor];
- System.arraycopy(data, 0, result, 0, cursor);
- return result;
+ if (annotationWidth < 40) {
+ throw new IllegalArgumentException("annotationWidth < 40");
}
- /** {@inheritDoc} */
- public int getCursor() {
- return cursor;
+ int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
+ if (hexCols < 6) {
+ hexCols = 6;
+ } else if (hexCols > 10) {
+ hexCols = 10;
}
- /** {@inheritDoc} */
- public void assertCursor(int expectedCursor) {
- if (cursor != expectedCursor) {
- throw new ExceptionWithContext("expected cursor " +
- expectedCursor + "; actual value: " + cursor);
- }
- }
+ this.annotations = new ArrayList<Annotation>(1000);
+ this.annotationWidth = annotationWidth;
+ this.hexCols = hexCols;
+ this.verbose = verbose;
+ }
- /** {@inheritDoc} */
- public void writeByte(int value) {
- int writeAt = cursor;
- int end = writeAt + 1;
+ /**
+ * Finishes up annotation processing. This closes off any open
+ * annotations and removes annotations that don't refer to written
+ * data.
+ */
+ public void finishAnnotating() {
+ // Close off the final annotation, if any.
+ endAnnotation();
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- data[writeAt] = (byte) value;
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void writeShort(int value) {
- int writeAt = cursor;
- int end = writeAt + 2;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- data[writeAt] = (byte) value;
- data[writeAt + 1] = (byte) (value >> 8);
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void writeInt(int value) {
- int writeAt = cursor;
- int end = writeAt + 4;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- data[writeAt] = (byte) value;
- data[writeAt + 1] = (byte) (value >> 8);
- data[writeAt + 2] = (byte) (value >> 16);
- data[writeAt + 3] = (byte) (value >> 24);
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void writeLong(long value) {
- int writeAt = cursor;
- int end = writeAt + 8;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- int half = (int) value;
- data[writeAt] = (byte) half;
- data[writeAt + 1] = (byte) (half >> 8);
- data[writeAt + 2] = (byte) (half >> 16);
- data[writeAt + 3] = (byte) (half >> 24);
-
- half = (int) (value >> 32);
- data[writeAt + 4] = (byte) half;
- data[writeAt + 5] = (byte) (half >> 8);
- data[writeAt + 6] = (byte) (half >> 16);
- data[writeAt + 7] = (byte) (half >> 24);
-
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public int writeUleb128(int value) {
- if (stretchy) {
- ensureCapacity(cursor + 5); // pessimistic
- }
- int cursorBefore = cursor;
- Leb128Utils.writeUnsignedLeb128(this, value);
- return (cursor - cursorBefore);
- }
-
- /** {@inheritDoc} */
- public int writeSleb128(int value) {
- if (stretchy) {
- ensureCapacity(cursor + 5); // pessimistic
- }
- int cursorBefore = cursor;
- Leb128Utils.writeSignedLeb128(this, value);
- return (cursor - cursorBefore);
- }
-
- /** {@inheritDoc} */
- public void write(ByteArray bytes) {
- int blen = bytes.size();
- int writeAt = cursor;
- int end = writeAt + blen;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- bytes.getBytes(data, writeAt);
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void write(byte[] bytes, int offset, int length) {
- int writeAt = cursor;
- int end = writeAt + length;
- int bytesEnd = offset + length;
-
- // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
- if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
- throw new IndexOutOfBoundsException("bytes.length " +
- bytes.length + "; " +
- offset + "..!" + end);
- }
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- System.arraycopy(bytes, offset, data, writeAt, length);
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void write(byte[] bytes) {
- write(bytes, 0, bytes.length);
- }
-
- /** {@inheritDoc} */
- public void writeZeroes(int count) {
- if (count < 0) {
- throw new IllegalArgumentException("count < 0");
- }
-
- int end = cursor + count;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- /*
- * There is no need to actually write zeroes, since the array is
- * already preinitialized with zeroes.
- */
-
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public void alignTo(int alignment) {
- int mask = alignment - 1;
-
- if ((alignment < 0) || ((mask & alignment) != 0)) {
- throw new IllegalArgumentException("bogus alignment");
- }
-
- int end = (cursor + mask) & ~mask;
-
- if (stretchy) {
- ensureCapacity(end);
- } else if (end > data.length) {
- throwBounds();
- return;
- }
-
- /*
- * There is no need to actually write zeroes, since the array is
- * already preinitialized with zeroes.
- */
-
- cursor = end;
- }
-
- /** {@inheritDoc} */
- public boolean annotates() {
- return (annotations != null);
- }
-
- /** {@inheritDoc} */
- public boolean isVerbose() {
- return verbose;
- }
-
- /** {@inheritDoc} */
- public void annotate(String msg) {
- if (annotations == null) {
- return;
- }
-
- endAnnotation();
- annotations.add(new Annotation(cursor, msg));
- }
-
- /** {@inheritDoc} */
- public void annotate(int amt, String msg) {
- if (annotations == null) {
- return;
- }
-
- endAnnotation();
-
- int asz = annotations.size();
- int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
- int startAt;
-
- if (lastEnd <= cursor) {
- startAt = cursor;
+ // Remove annotations that refer to unwritten data.
+ if (annotations != null) {
+ int asz = annotations.size();
+ while (asz > 0) {
+ Annotation last = annotations.get(asz - 1);
+ if (last.getStart() > cursor) {
+ annotations.remove(asz - 1);
+ asz--;
+ } else if (last.getEnd() > cursor) {
+ last.setEnd(cursor);
+ break;
} else {
- startAt = lastEnd;
+ break;
}
+ }
+ }
+ }
- annotations.add(new Annotation(startAt, startAt + amt, msg));
+ /**
+ * Writes the annotated content of this instance to the given writer.
+ *
+ * @param out {@code non-null;} where to write to
+ */
+ public void writeAnnotationsTo(Writer out) throws IOException {
+ int width2 = getAnnotationWidth();
+ int width1 = annotationWidth - width2 - 1;
+
+ TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
+ Writer left = twoc.getLeft();
+ Writer right = twoc.getRight();
+ int leftAt = 0; // left-hand byte output cursor
+ int rightAt = 0; // right-hand annotation index
+ int rightSz = annotations.size();
+
+ while ((leftAt < cursor) && (rightAt < rightSz)) {
+ Annotation a = annotations.get(rightAt);
+ int start = a.getStart();
+ int end;
+ String text;
+
+ if (leftAt < start) {
+ // This is an area with no annotation.
+ end = start;
+ start = leftAt;
+ text = "";
+ } else {
+ // This is an area with an annotation.
+ end = a.getEnd();
+ text = a.getText();
+ rightAt++;
+ }
+
+ left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
+ right.write(text);
+ twoc.flush();
+ leftAt = end;
}
- /** {@inheritDoc} */
- public void endAnnotation() {
- if (annotations == null) {
- return;
- }
-
- int sz = annotations.size();
-
- if (sz != 0) {
- annotations.get(sz - 1).setEndIfUnset(cursor);
- }
+ if (leftAt < cursor) {
+ // There is unannotated output at the end.
+ left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt, hexCols, 6));
}
- /** {@inheritDoc} */
- public int getAnnotationWidth() {
- int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
-
- return annotationWidth - leftWidth;
+ while (rightAt < rightSz) {
+ // There are zero-byte annotations at the end.
+ right.write(annotations.get(rightAt).getText());
+ rightAt++;
}
+ twoc.flush();
+ }
+
+ /**
+ * Throws the excpetion for when an attempt is made to write past the
+ * end of the instance.
+ */
+ private static void throwBounds() {
+ throw new IndexOutOfBoundsException("attempt to write past the end");
+ }
+
+ /**
+ * Reallocates the underlying array if necessary. Calls to this method
+ * should be guarded by a test of {@link #stretchy}.
+ *
+ * @param desiredSize {@code >= 0;} the desired minimum total size of the array
+ */
+ private void ensureCapacity(int desiredSize) {
+ if (data.length < desiredSize) {
+ byte[] newData = new byte[desiredSize * 2 + 1000];
+ System.arraycopy(data, 0, newData, 0, cursor);
+ data = newData;
+ }
+ }
+
+ /**
+ * Annotation on output.
+ */
+ private static class Annotation {
+ /** {@code >= 0;} start of annotated range (inclusive) */
+ private final int start;
+
/**
- * Indicates that this instance should keep annotations. This method may
- * be called only once per instance, and only before any data has been
- * written to the it.
+ * {@code >= 0;} end of annotated range (exclusive);
+ * {@code Integer.MAX_VALUE} if unclosed
+ */
+ private int end;
+
+ /** {@code non-null;} annotation text */
+ private final String text;
+
+ /**
+ * Constructs an instance.
*
- * @param annotationWidth {@code >= 40;} the desired maximum annotation width
- * @param verbose whether or not to indicate verbose annotations
+ * @param start {@code >= 0;} start of annotated range
+ * @param end {@code >= start;} end of annotated range (exclusive) or
+ * {@code Integer.MAX_VALUE} if unclosed
+ * @param text {@code non-null;} annotation text
*/
- public void enableAnnotations(int annotationWidth, boolean verbose) {
- if ((annotations != null) || (cursor != 0)) {
- throw new RuntimeException("cannot enable annotations");
- }
-
- if (annotationWidth < 40) {
- throw new IllegalArgumentException("annotationWidth < 40");
- }
-
- int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
- if (hexCols < 6) {
- hexCols = 6;
- } else if (hexCols > 10) {
- hexCols = 10;
- }
-
- this.annotations = new ArrayList<Annotation>(1000);
- this.annotationWidth = annotationWidth;
- this.hexCols = hexCols;
- this.verbose = verbose;
+ public Annotation(int start, int end, String text) {
+ this.start = start;
+ this.end = end;
+ this.text = text;
}
/**
- * Finishes up annotation processing. This closes off any open
- * annotations and removes annotations that don't refer to written
- * data.
- */
- public void finishAnnotating() {
- // Close off the final annotation, if any.
- endAnnotation();
-
- // Remove annotations that refer to unwritten data.
- if (annotations != null) {
- int asz = annotations.size();
- while (asz > 0) {
- Annotation last = annotations.get(asz - 1);
- if (last.getStart() > cursor) {
- annotations.remove(asz - 1);
- asz--;
- } else if (last.getEnd() > cursor) {
- last.setEnd(cursor);
- break;
- } else {
- break;
- }
- }
- }
- }
-
- /**
- * Writes the annotated content of this instance to the given writer.
+ * Constructs an instance. It is initally unclosed.
*
- * @param out {@code non-null;} where to write to
+ * @param start {@code >= 0;} start of annotated range
+ * @param text {@code non-null;} annotation text
*/
- public void writeAnnotationsTo(Writer out) throws IOException {
- int width2 = getAnnotationWidth();
- int width1 = annotationWidth - width2 - 1;
-
- TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
- Writer left = twoc.getLeft();
- Writer right = twoc.getRight();
- int leftAt = 0; // left-hand byte output cursor
- int rightAt = 0; // right-hand annotation index
- int rightSz = annotations.size();
-
- while ((leftAt < cursor) && (rightAt < rightSz)) {
- Annotation a = annotations.get(rightAt);
- int start = a.getStart();
- int end;
- String text;
-
- if (leftAt < start) {
- // This is an area with no annotation.
- end = start;
- start = leftAt;
- text = "";
- } else {
- // This is an area with an annotation.
- end = a.getEnd();
- text = a.getText();
- rightAt++;
- }
-
- left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
- right.write(text);
- twoc.flush();
- leftAt = end;
- }
-
- if (leftAt < cursor) {
- // There is unannotated output at the end.
- left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
- hexCols, 6));
- }
-
- while (rightAt < rightSz) {
- // There are zero-byte annotations at the end.
- right.write(annotations.get(rightAt).getText());
- rightAt++;
- }
-
- twoc.flush();
+ public Annotation(int start, String text) {
+ this(start, Integer.MAX_VALUE, text);
}
/**
- * Throws the excpetion for when an attempt is made to write past the
- * end of the instance.
- */
- private static void throwBounds() {
- throw new IndexOutOfBoundsException("attempt to write past the end");
- }
-
- /**
- * Reallocates the underlying array if necessary. Calls to this method
- * should be guarded by a test of {@link #stretchy}.
+ * Sets the end as given, but only if the instance is unclosed;
+ * otherwise, do nothing.
*
- * @param desiredSize {@code >= 0;} the desired minimum total size of the array
+ * @param end {@code >= start;} the end
*/
- private void ensureCapacity(int desiredSize) {
- if (data.length < desiredSize) {
- byte[] newData = new byte[desiredSize * 2 + 1000];
- System.arraycopy(data, 0, newData, 0, cursor);
- data = newData;
- }
+ public void setEndIfUnset(int end) {
+ if (this.end == Integer.MAX_VALUE) {
+ this.end = end;
+ }
}
/**
- * Annotation on output.
+ * Sets the end as given.
+ *
+ * @param end {@code >= start;} the end
*/
- private static class Annotation {
- /** {@code >= 0;} start of annotated range (inclusive) */
- private final int start;
-
- /**
- * {@code >= 0;} end of annotated range (exclusive);
- * {@code Integer.MAX_VALUE} if unclosed
- */
- private int end;
-
- /** {@code non-null;} annotation text */
- private final String text;
-
- /**
- * Constructs an instance.
- *
- * @param start {@code >= 0;} start of annotated range
- * @param end {@code >= start;} end of annotated range (exclusive) or
- * {@code Integer.MAX_VALUE} if unclosed
- * @param text {@code non-null;} annotation text
- */
- public Annotation(int start, int end, String text) {
- this.start = start;
- this.end = end;
- this.text = text;
- }
-
- /**
- * Constructs an instance. It is initally unclosed.
- *
- * @param start {@code >= 0;} start of annotated range
- * @param text {@code non-null;} annotation text
- */
- public Annotation(int start, String text) {
- this(start, Integer.MAX_VALUE, text);
- }
-
- /**
- * Sets the end as given, but only if the instance is unclosed;
- * otherwise, do nothing.
- *
- * @param end {@code >= start;} the end
- */
- public void setEndIfUnset(int end) {
- if (this.end == Integer.MAX_VALUE) {
- this.end = end;
- }
- }
-
- /**
- * Sets the end as given.
- *
- * @param end {@code >= start;} the end
- */
- public void setEnd(int end) {
- this.end = end;
- }
-
- /**
- * Gets the start.
- *
- * @return the start
- */
- public int getStart() {
- return start;
- }
-
- /**
- * Gets the end.
- *
- * @return the end
- */
- public int getEnd() {
- return end;
- }
-
- /**
- * Gets the text.
- *
- * @return {@code non-null;} the text
- */
- public String getText() {
- return text;
- }
+ public void setEnd(int end) {
+ this.end = end;
}
+
+ /**
+ * Gets the start.
+ *
+ * @return the start
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * Gets the end.
+ *
+ * @return the end
+ */
+ public int getEnd() {
+ return end;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return {@code non-null;} the text
+ */
+ public String getText() {
+ return text;
+ }
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ByteArrayByteInput.java b/dx/src/com/android/jack/dx/util/ByteArrayByteInput.java
index 8908997..4d7c7ba 100644
--- a/dx/src/com/android/jack/dx/util/ByteArrayByteInput.java
+++ b/dx/src/com/android/jack/dx/util/ByteArrayByteInput.java
@@ -16,16 +16,20 @@
package com.android.jack.dx.util;
+/**
+ * TODO(jack team)
+ */
public final class ByteArrayByteInput implements ByteInput {
- private final byte[] bytes;
- private int position;
+ private final byte[] bytes;
+ private int position;
- public ByteArrayByteInput(byte... bytes) {
- this.bytes = bytes;
- }
+ public ByteArrayByteInput(byte... bytes) {
+ this.bytes = bytes;
+ }
- @Override public byte readByte() {
- return bytes[position++];
- }
+ @Override
+ public byte readByte() {
+ return bytes[position++];
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ByteInput.java b/dx/src/com/android/jack/dx/util/ByteInput.java
index 00246e6..7abba45 100644
--- a/dx/src/com/android/jack/dx/util/ByteInput.java
+++ b/dx/src/com/android/jack/dx/util/ByteInput.java
@@ -21,10 +21,10 @@
*/
public interface ByteInput {
- /**
- * Returns a byte.
- *
- * @throws IndexOutOfBoundsException if all bytes have been read.
- */
- byte readByte();
+ /**
+ * Returns a byte.
+ *
+ * @throws IndexOutOfBoundsException if all bytes have been read.
+ */
+ byte readByte();
}
diff --git a/dx/src/com/android/jack/dx/util/ByteOutput.java b/dx/src/com/android/jack/dx/util/ByteOutput.java
index 1a2b8f4..7ff9457 100644
--- a/dx/src/com/android/jack/dx/util/ByteOutput.java
+++ b/dx/src/com/android/jack/dx/util/ByteOutput.java
@@ -21,10 +21,10 @@
*/
public interface ByteOutput {
- /**
- * Writes a byte.
- *
- * @throws IndexOutOfBoundsException if all bytes have been written.
- */
- void writeByte(int i);
+ /**
+ * Writes a byte.
+ *
+ * @throws IndexOutOfBoundsException if all bytes have been written.
+ */
+ void writeByte(int i);
}
diff --git a/dx/src/com/android/jack/dx/util/DexException.java b/dx/src/com/android/jack/dx/util/DexException.java
index c06c9f3..d03b92c 100644
--- a/dx/src/com/android/jack/dx/util/DexException.java
+++ b/dx/src/com/android/jack/dx/util/DexException.java
@@ -21,11 +21,14 @@
* processing a dex file.
*/
public final class DexException extends ExceptionWithContext {
- public DexException(String message) {
- super(message);
- }
- public DexException(Throwable cause) {
- super(cause);
- }
+ private static final long serialVersionUID = 1L;
+
+ public DexException(String message) {
+ super(message);
+ }
+
+ public DexException(Throwable cause) {
+ super(cause);
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ExceptionWithContext.java b/dx/src/com/android/jack/dx/util/ExceptionWithContext.java
index 8951eaf..028e917 100644
--- a/dx/src/com/android/jack/dx/util/ExceptionWithContext.java
+++ b/dx/src/com/android/jack/dx/util/ExceptionWithContext.java
@@ -22,128 +22,128 @@
/**
* Exception which carries around structured context.
*/
-public class ExceptionWithContext
- extends RuntimeException {
- /** {@code non-null;} human-oriented context of the exception */
- private StringBuffer context;
+public class ExceptionWithContext extends RuntimeException {
- /**
- * Augments the given exception with the given context, and return the
- * result. The result is either the given exception if it was an
- * {@link ExceptionWithContext}, or a newly-constructed exception if it
- * was not.
- *
- * @param ex {@code non-null;} the exception to augment
- * @param str {@code non-null;} context to add
- * @return {@code non-null;} an appropriate instance
- */
- public static ExceptionWithContext withContext(Throwable ex, String str) {
- ExceptionWithContext ewc;
+ private static final long serialVersionUID = 1L;
- if (ex instanceof ExceptionWithContext) {
- ewc = (ExceptionWithContext) ex;
- } else {
- ewc = new ExceptionWithContext(ex);
- }
+ /** {@code non-null;} human-oriented context of the exception */
+ private StringBuffer context;
- ewc.addContext(str);
- return ewc;
+ /**
+ * Augments the given exception with the given context, and return the
+ * result. The result is either the given exception if it was an
+ * {@link ExceptionWithContext}, or a newly-constructed exception if it
+ * was not.
+ *
+ * @param ex {@code non-null;} the exception to augment
+ * @param str {@code non-null;} context to add
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static ExceptionWithContext withContext(Throwable ex, String str) {
+ ExceptionWithContext ewc;
+
+ if (ex instanceof ExceptionWithContext) {
+ ewc = (ExceptionWithContext) ex;
+ } else {
+ ewc = new ExceptionWithContext(ex);
}
- /**
- * Constructs an instance.
- *
- * @param message human-oriented message
- */
- public ExceptionWithContext(String message) {
- this(message, null);
+ ewc.addContext(str);
+ return ewc;
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param message human-oriented message
+ */
+ public ExceptionWithContext(String message) {
+ this(message, null);
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param cause {@code null-ok;} exception that caused this one
+ */
+ public ExceptionWithContext(Throwable cause) {
+ this(null, cause);
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param message human-oriented message
+ * @param cause {@code null-ok;} exception that caused this one
+ */
+ public ExceptionWithContext(String message, Throwable cause) {
+ super((message != null) ? message : (cause != null) ? cause.getMessage() : null, cause);
+
+ if (cause instanceof ExceptionWithContext) {
+ String ctx = ((ExceptionWithContext) cause).context.toString();
+ context = new StringBuffer(ctx.length() + 200);
+ context.append(ctx);
+ } else {
+ context = new StringBuffer(200);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void printStackTrace(PrintStream out) {
+ super.printStackTrace(out);
+ out.println(context);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void printStackTrace(PrintWriter out) {
+ super.printStackTrace(out);
+ out.println(context);
+ }
+
+ /**
+ * Adds a line of context to this instance.
+ *
+ * @param str {@code non-null;} new context
+ */
+ public void addContext(String str) {
+ if (str == null) {
+ throw new NullPointerException("str == null");
}
- /**
- * Constructs an instance.
- *
- * @param cause {@code null-ok;} exception that caused this one
- */
- public ExceptionWithContext(Throwable cause) {
- this(null, cause);
+ context.append(str);
+ if (!str.endsWith("\n")) {
+ context.append('\n');
}
+ }
- /**
- * Constructs an instance.
- *
- * @param message human-oriented message
- * @param cause {@code null-ok;} exception that caused this one
- */
- public ExceptionWithContext(String message, Throwable cause) {
- super((message != null) ? message :
- (cause != null) ? cause.getMessage() : null,
- cause);
+ /**
+ * Gets the context.
+ *
+ * @return {@code non-null;} the context
+ */
+ public String getContext() {
+ return context.toString();
+ }
- if (cause instanceof ExceptionWithContext) {
- String ctx = ((ExceptionWithContext) cause).context.toString();
- context = new StringBuffer(ctx.length() + 200);
- context.append(ctx);
- } else {
- context = new StringBuffer(200);
- }
- }
+ /**
+ * Prints the message and context.
+ *
+ * @param out {@code non-null;} where to print to
+ */
+ public void printContext(PrintStream out) {
+ out.println(getMessage());
+ out.print(context);
+ }
- /** {@inheritDoc} */
- @Override
- public void printStackTrace(PrintStream out) {
- super.printStackTrace(out);
- out.println(context);
- }
-
- /** {@inheritDoc} */
- @Override
- public void printStackTrace(PrintWriter out) {
- super.printStackTrace(out);
- out.println(context);
- }
-
- /**
- * Adds a line of context to this instance.
- *
- * @param str {@code non-null;} new context
- */
- public void addContext(String str) {
- if (str == null) {
- throw new NullPointerException("str == null");
- }
-
- context.append(str);
- if (!str.endsWith("\n")) {
- context.append('\n');
- }
- }
-
- /**
- * Gets the context.
- *
- * @return {@code non-null;} the context
- */
- public String getContext() {
- return context.toString();
- }
-
- /**
- * Prints the message and context.
- *
- * @param out {@code non-null;} where to print to
- */
- public void printContext(PrintStream out) {
- out.println(getMessage());
- out.print(context);
- }
-
- /**
- * Prints the message and context.
- *
- * @param out {@code non-null;} where to print to
- */
- public void printContext(PrintWriter out) {
- out.println(getMessage());
- out.print(context);
- }
+ /**
+ * Prints the message and context.
+ *
+ * @param out {@code non-null;} where to print to
+ */
+ public void printContext(PrintWriter out) {
+ out.println(getMessage());
+ out.print(context);
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/FileUtils.java b/dx/src/com/android/jack/dx/util/FileUtils.java
index 4c71d52..061f27e 100644
--- a/dx/src/com/android/jack/dx/util/FileUtils.java
+++ b/dx/src/com/android/jack/dx/util/FileUtils.java
@@ -24,78 +24,84 @@
* File I/O utilities.
*/
public final class FileUtils {
- /**
- * This class is uninstantiable.
- */
- private FileUtils() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private FileUtils() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Reads the named file, translating {@link IOException} to a
+ * {@link RuntimeException} of some sort.
+ *
+ * @param fileName {@code non-null;} name of the file to read
+ * @return {@code non-null;} contents of the file
+ */
+ public static byte[] readFile(String fileName) {
+ File file = new File(fileName);
+ return readFile(file);
+ }
+
+ /**
+ * Reads the given file, translating {@link IOException} to a
+ * {@link RuntimeException} of some sort.
+ *
+ * @param file {@code non-null;} the file to read
+ * @return {@code non-null;} contents of the file
+ */
+ public static byte[] readFile(File file) {
+ if (!file.exists()) {
+ throw new RuntimeException(file + ": file not found");
}
- /**
- * Reads the named file, translating {@link IOException} to a
- * {@link RuntimeException} of some sort.
- *
- * @param fileName {@code non-null;} name of the file to read
- * @return {@code non-null;} contents of the file
- */
- public static byte[] readFile(String fileName) {
- File file = new File(fileName);
- return readFile(file);
+ if (!file.isFile()) {
+ throw new RuntimeException(file + ": not a file");
}
- /**
- * Reads the given file, translating {@link IOException} to a
- * {@link RuntimeException} of some sort.
- *
- * @param file {@code non-null;} the file to read
- * @return {@code non-null;} contents of the file
- */
- public static byte[] readFile(File file) {
- if (!file.exists()) {
- throw new RuntimeException(file + ": file not found");
+ if (!file.canRead()) {
+ throw new RuntimeException(file + ": file not readable");
+ }
+
+ long longLength = file.length();
+ int length = (int) longLength;
+ if (length != longLength) {
+ throw new RuntimeException(file + ": file too long");
+ }
+
+ byte[] result = new byte[length];
+
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ int at = 0;
+ while (length > 0) {
+ int amt = in.read(result, at, length);
+ if (amt == -1) {
+ throw new RuntimeException(file + ": unexpected EOF");
}
-
- if (!file.isFile()) {
- throw new RuntimeException(file + ": not a file");
- }
-
- if (!file.canRead()) {
- throw new RuntimeException(file + ": file not readable");
- }
-
- long longLength = file.length();
- int length = (int) longLength;
- if (length != longLength) {
- throw new RuntimeException(file + ": file too long");
- }
-
- byte[] result = new byte[length];
-
+ at += amt;
+ length -= amt;
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(file + ": trouble reading", ex);
+ } finally {
+ if (in != null) {
try {
- FileInputStream in = new FileInputStream(file);
- int at = 0;
- while (length > 0) {
- int amt = in.read(result, at, length);
- if (amt == -1) {
- throw new RuntimeException(file + ": unexpected EOF");
- }
- at += amt;
- length -= amt;
- }
- in.close();
+ in.close();
} catch (IOException ex) {
- throw new RuntimeException(file + ": trouble reading", ex);
+ throw new RuntimeException(file + ": trouble reading", ex);
}
-
- return result;
+ }
}
- /**
- * Returns true if {@code fileName} names a .zip, .jar, or .apk.
- */
- public static boolean hasArchiveSuffix(String fileName) {
- return fileName.endsWith(".zip")
- || fileName.endsWith(".jar")
- || fileName.endsWith(".apk");
- }
+ return result;
+ }
+
+ /**
+ * Returns true if {@code fileName} names a .zip, .jar, or .apk.
+ */
+ public static boolean hasArchiveSuffix(String fileName) {
+ return fileName.endsWith(".zip") || fileName.endsWith(".jar") || fileName.endsWith(".apk");
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/FixedSizeList.java b/dx/src/com/android/jack/dx/util/FixedSizeList.java
index a8badf0..9463877 100644
--- a/dx/src/com/android/jack/dx/util/FixedSizeList.java
+++ b/dx/src/com/android/jack/dx/util/FixedSizeList.java
@@ -21,256 +21,249 @@
/**
* Simple (mostly) fixed-size list of objects, which may be made immutable.
*/
-public class FixedSizeList
- extends MutabilityControl implements ToHuman {
- /** {@code non-null;} array of elements */
- private Object[] arr;
+public class FixedSizeList extends MutabilityControl implements ToHuman {
+ /** {@code non-null;} array of elements */
+ private Object[] arr;
- /**
- * Constructs an instance. All indices initially contain {@code null}.
- *
- * @param size the size of the list
- */
- public FixedSizeList(int size) {
- super(size != 0);
+ /**
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size the size of the list
+ */
+ public FixedSizeList(int size) {
+ super(size != 0);
- try {
- arr = new Object[size];
- } catch (NegativeArraySizeException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("size < 0");
- }
+ try {
+ arr = new Object[size];
+ } catch (NegativeArraySizeException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("size < 0");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ // Easy out.
+ return true;
}
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- // Easy out.
- return true;
- }
-
- if ((other == null) || (getClass() != other.getClass())) {
- // Another easy out.
- return false;
- }
-
- FixedSizeList list = (FixedSizeList) other;
- return Arrays.equals(arr, list.arr);
+ if ((other == null) || (getClass() != other.getClass())) {
+ // Another easy out.
+ return false;
}
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return Arrays.hashCode(arr);
+ FixedSizeList list = (FixedSizeList) other;
+ return Arrays.equals(arr, list.arr);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(arr);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ String name = getClass().getName();
+
+ return toString0(name.substring(name.lastIndexOf('.') + 1) + '{', ", ", "}", false);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This method will only work if every element of the list
+ * implements {@link ToHuman}.
+ */
+ @Override
+ public String toHuman() {
+ String name = getClass().getName();
+
+ return toString0(name.substring(name.lastIndexOf('.') + 1) + '{', ", ", "}", true);
+ }
+
+ /**
+ * Gets a customized string form for this instance.
+ *
+ * @param prefix {@code null-ok;} prefix for the start of the result
+ * @param separator {@code null-ok;} separator to insert between each item
+ * @param suffix {@code null-ok;} suffix for the end of the result
+ * @return {@code non-null;} the custom string
+ */
+ public String toString(String prefix, String separator, String suffix) {
+ return toString0(prefix, separator, suffix, false);
+ }
+
+ /**
+ * Gets a customized human string for this instance. This method will
+ * only work if every element of the list implements {@link
+ * ToHuman}.
+ *
+ * @param prefix {@code null-ok;} prefix for the start of the result
+ * @param separator {@code null-ok;} separator to insert between each item
+ * @param suffix {@code null-ok;} suffix for the end of the result
+ * @return {@code non-null;} the custom string
+ */
+ public String toHuman(String prefix, String separator, String suffix) {
+ return toString0(prefix, separator, suffix, true);
+ }
+
+ /**
+ * Gets the number of elements in this list.
+ */
+ public final int size() {
+ return arr.length;
+ }
+
+ /**
+ * Shrinks this instance to fit, by removing any unset
+ * ({@code null}) elements, leaving the remaining elements in
+ * their original order.
+ */
+ public void shrinkToFit() {
+ int sz = arr.length;
+ int newSz = 0;
+
+ for (int i = 0; i < sz; i++) {
+ if (arr[i] != null) {
+ newSz++;
+ }
}
- /** {@inheritDoc} */
- @Override
- public String toString() {
- String name = getClass().getName();
-
- return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
- ", ",
- "}",
- false);
+ if (sz == newSz) {
+ return;
}
- /**
- * {@inheritDoc}
- *
- * This method will only work if every element of the list
- * implements {@link ToHuman}.
- */
- public String toHuman() {
- String name = getClass().getName();
+ throwIfImmutable();
- return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
- ", ",
- "}",
- true);
+ Object[] newa = new Object[newSz];
+ int at = 0;
+
+ for (int i = 0; i < sz; i++) {
+ Object one = arr[i];
+ if (one != null) {
+ newa[at] = one;
+ at++;
+ }
}
- /**
- * Gets a customized string form for this instance.
- *
- * @param prefix {@code null-ok;} prefix for the start of the result
- * @param separator {@code null-ok;} separator to insert between each item
- * @param suffix {@code null-ok;} suffix for the end of the result
- * @return {@code non-null;} the custom string
- */
- public String toString(String prefix, String separator, String suffix) {
- return toString0(prefix, separator, suffix, false);
+ arr = newa;
+ if (newSz == 0) {
+ setImmutable();
+ }
+ }
+
+ /**
+ * Gets the indicated element. It is an error to call this with the
+ * index for an element which was never set; if you do that, this
+ * will throw {@code NullPointerException}. This method is
+ * protected so that subclasses may offer a safe type-checked
+ * public interface to their clients.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
+ */
+ protected final Object get0(int n) {
+ try {
+ Object result = arr[n];
+
+ if (result == null) {
+ throw new NullPointerException("unset: " + n);
+ }
+
+ return result;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ return throwIndex(n);
+ }
+ }
+
+ /**
+ * Gets the indicated element, allowing {@code null}s to be
+ * returned. This method is protected so that subclasses may
+ * (optionally) offer a safe type-checked public interface to
+ * their clients.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code null-ok;} the indicated element
+ */
+ protected final Object getOrNull0(int n) {
+ return arr[n];
+ }
+
+ /**
+ * Sets the element at the given index, but without doing any type
+ * checks on the element. This method is protected so that
+ * subclasses may offer a safe type-checked public interface to
+ * their clients.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @param obj {@code null-ok;} the value to store
+ */
+ protected final void set0(int n, Object obj) {
+ throwIfImmutable();
+
+ try {
+ arr[n] = obj;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ throwIndex(n);
+ }
+ }
+
+ /**
+ * Throws the appropriate exception for the given index value.
+ *
+ * @param n the index value
+ * @return never
+ * @throws IndexOutOfBoundsException always thrown
+ */
+ private Object throwIndex(int n) {
+ if (n < 0) {
+ throw new IndexOutOfBoundsException("n < 0");
}
- /**
- * Gets a customized human string for this instance. This method will
- * only work if every element of the list implements {@link
- * ToHuman}.
- *
- * @param prefix {@code null-ok;} prefix for the start of the result
- * @param separator {@code null-ok;} separator to insert between each item
- * @param suffix {@code null-ok;} suffix for the end of the result
- * @return {@code non-null;} the custom string
- */
- public String toHuman(String prefix, String separator, String suffix) {
- return toString0(prefix, separator, suffix, true);
+ throw new IndexOutOfBoundsException("n >= size()");
+ }
+
+ /**
+ * Helper for {@link #toString} and {@link #toHuman}, which both of
+ * those call to pretty much do everything.
+ *
+ * @param prefix {@code null-ok;} prefix for the start of the result
+ * @param separator {@code null-ok;} separator to insert between each item
+ * @param suffix {@code null-ok;} suffix for the end of the result
+ * @param human whether the output is to be human
+ * @return {@code non-null;} the custom string
+ */
+ private String toString0(String prefix, String separator, String suffix, boolean human) {
+ int len = arr.length;
+ StringBuffer sb = new StringBuffer(len * 10 + 10);
+
+ if (prefix != null) {
+ sb.append(prefix);
}
- /**
- * Gets the number of elements in this list.
- */
- public final int size() {
- return arr.length;
+ for (int i = 0; i < len; i++) {
+ if ((i != 0) && (separator != null)) {
+ sb.append(separator);
+ }
+
+ if (human) {
+ sb.append(((ToHuman) arr[i]).toHuman());
+ } else {
+ sb.append(arr[i]);
+ }
}
- /**
- * Shrinks this instance to fit, by removing any unset
- * ({@code null}) elements, leaving the remaining elements in
- * their original order.
- */
- public void shrinkToFit() {
- int sz = arr.length;
- int newSz = 0;
-
- for (int i = 0; i < sz; i++) {
- if (arr[i] != null) {
- newSz++;
- }
- }
-
- if (sz == newSz) {
- return;
- }
-
- throwIfImmutable();
-
- Object[] newa = new Object[newSz];
- int at = 0;
-
- for (int i = 0; i < sz; i++) {
- Object one = arr[i];
- if (one != null) {
- newa[at] = one;
- at++;
- }
- }
-
- arr = newa;
- if (newSz == 0) {
- setImmutable();
- }
+ if (suffix != null) {
+ sb.append(suffix);
}
- /**
- * Gets the indicated element. It is an error to call this with the
- * index for an element which was never set; if you do that, this
- * will throw {@code NullPointerException}. This method is
- * protected so that subclasses may offer a safe type-checked
- * public interface to their clients.
- *
- * @param n {@code >= 0, < size();} which element
- * @return {@code non-null;} the indicated element
- */
- protected final Object get0(int n) {
- try {
- Object result = arr[n];
-
- if (result == null) {
- throw new NullPointerException("unset: " + n);
- }
-
- return result;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- return throwIndex(n);
- }
- }
-
- /**
- * Gets the indicated element, allowing {@code null}s to be
- * returned. This method is protected so that subclasses may
- * (optionally) offer a safe type-checked public interface to
- * their clients.
- *
- * @param n {@code >= 0, < size();} which element
- * @return {@code null-ok;} the indicated element
- */
- protected final Object getOrNull0(int n) {
- return arr[n];
- }
-
- /**
- * Sets the element at the given index, but without doing any type
- * checks on the element. This method is protected so that
- * subclasses may offer a safe type-checked public interface to
- * their clients.
- *
- * @param n {@code >= 0, < size();} which element
- * @param obj {@code null-ok;} the value to store
- */
- protected final void set0(int n, Object obj) {
- throwIfImmutable();
-
- try {
- arr[n] = obj;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- throwIndex(n);
- }
- }
-
- /**
- * Throws the appropriate exception for the given index value.
- *
- * @param n the index value
- * @return never
- * @throws IndexOutOfBoundsException always thrown
- */
- private Object throwIndex(int n) {
- if (n < 0) {
- throw new IndexOutOfBoundsException("n < 0");
- }
-
- throw new IndexOutOfBoundsException("n >= size()");
- }
-
- /**
- * Helper for {@link #toString} and {@link #toHuman}, which both of
- * those call to pretty much do everything.
- *
- * @param prefix {@code null-ok;} prefix for the start of the result
- * @param separator {@code null-ok;} separator to insert between each item
- * @param suffix {@code null-ok;} suffix for the end of the result
- * @param human whether the output is to be human
- * @return {@code non-null;} the custom string
- */
- private String toString0(String prefix, String separator, String suffix,
- boolean human) {
- int len = arr.length;
- StringBuffer sb = new StringBuffer(len * 10 + 10);
-
- if (prefix != null) {
- sb.append(prefix);
- }
-
- for (int i = 0; i < len; i++) {
- if ((i != 0) && (separator != null)) {
- sb.append(separator);
- }
-
- if (human) {
- sb.append(((ToHuman) arr[i]).toHuman());
- } else {
- sb.append(arr[i]);
- }
- }
-
- if (suffix != null) {
- sb.append(suffix);
- }
-
- return sb.toString();
- }
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Hex.java b/dx/src/com/android/jack/dx/util/Hex.java
index e928265..740c03c 100644
--- a/dx/src/com/android/jack/dx/util/Hex.java
+++ b/dx/src/com/android/jack/dx/util/Hex.java
@@ -20,284 +20,293 @@
* Utilities for formatting numbers as hexadecimal.
*/
public final class Hex {
- /**
- * This class is uninstantiable.
- */
- private Hex() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private Hex() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Formats a {@code long} as an 8-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u8(long v) {
+ char[] result = new char[16];
+ for (int i = 0; i < 16; i++) {
+ result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats a {@code long} as an 8-byte unsigned hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u8(long v) {
- char[] result = new char[16];
- for (int i = 0; i < 16; i++) {
- result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
- v >>= 4;
- }
+ return new String(result);
+ }
- return new String(result);
+ /**
+ * Formats an {@code int} as a 4-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u4(int v) {
+ char[] result = new char[8];
+ for (int i = 0; i < 8; i++) {
+ result[7 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 4-byte unsigned hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u4(int v) {
- char[] result = new char[8];
- for (int i = 0; i < 8; i++) {
- result[7 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
+ return new String(result);
+ }
- return new String(result);
+ /**
+ * Formats an {@code int} as a 3-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u3(int v) {
+ char[] result = new char[6];
+ for (int i = 0; i < 6; i++) {
+ result[5 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 3-byte unsigned hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u3(int v) {
- char[] result = new char[6];
- for (int i = 0; i < 6; i++) {
- result[5 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
+ return new String(result);
+ }
- return new String(result);
+ /**
+ * Formats an {@code int} as a 2-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u2(int v) {
+ char[] result = new char[4];
+ for (int i = 0; i < 4; i++) {
+ result[3 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 2-byte unsigned hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u2(int v) {
- char[] result = new char[4];
- for (int i = 0; i < 4; i++) {
- result[3 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
+ return new String(result);
+ }
- return new String(result);
+ /**
+ * Formats an {@code int} as either a 2-byte unsigned hex value
+ * (if the value is small enough) or a 4-byte unsigned hex value (if
+ * not).
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u2or4(int v) {
+ if (v == (char) v) {
+ return u2(v);
+ } else {
+ return u4(v);
+ }
+ }
+
+ /**
+ * Formats an {@code int} as a 1-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u1(int v) {
+ char[] result = new char[2];
+ for (int i = 0; i < 2; i++) {
+ result[1 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as either a 2-byte unsigned hex value
- * (if the value is small enough) or a 4-byte unsigned hex value (if
- * not).
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u2or4(int v) {
- if (v == (char) v) {
- return u2(v);
- } else {
- return u4(v);
- }
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 4-bit unsigned hex nibble.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String uNibble(int v) {
+ char[] result = new char[1];
+
+ result[0] = Character.forDigit(v & 0x0f, 16);
+ return new String(result);
+ }
+
+ /**
+ * Formats a {@code long} as an 8-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s8(long v) {
+ char[] result = new char[17];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
}
- /**
- * Formats an {@code int} as a 1-byte unsigned hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String u1(int v) {
- char[] result = new char[2];
- for (int i = 0; i < 2; i++) {
- result[1 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
-
- return new String(result);
+ for (int i = 0; i < 16; i++) {
+ result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 4-bit unsigned hex nibble.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String uNibble(int v) {
- char[] result = new char[1];
+ return new String(result);
+ }
- result[0] = Character.forDigit(v & 0x0f, 16);
- return new String(result);
+ /**
+ * Formats an {@code int} as a 4-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s4(int v) {
+ char[] result = new char[9];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
}
- /**
- * Formats a {@code long} as an 8-byte signed hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String s8(long v) {
- char[] result = new char[17];
-
- if (v < 0) {
- result[0] = '-';
- v = -v;
- } else {
- result[0] = '+';
- }
-
- for (int i = 0; i < 16; i++) {
- result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
- v >>= 4;
- }
-
- return new String(result);
+ for (int i = 0; i < 8; i++) {
+ result[8 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 4-byte signed hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String s4(int v) {
- char[] result = new char[9];
+ return new String(result);
+ }
- if (v < 0) {
- result[0] = '-';
- v = -v;
- } else {
- result[0] = '+';
- }
+ /**
+ * Formats an {@code int} as a 2-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s2(int v) {
+ char[] result = new char[5];
- for (int i = 0; i < 8; i++) {
- result[8 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
-
- return new String(result);
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
}
- /**
- * Formats an {@code int} as a 2-byte signed hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String s2(int v) {
- char[] result = new char[5];
-
- if (v < 0) {
- result[0] = '-';
- v = -v;
- } else {
- result[0] = '+';
- }
-
- for (int i = 0; i < 4; i++) {
- result[4 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
-
- return new String(result);
+ for (int i = 0; i < 4; i++) {
+ result[4 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
- /**
- * Formats an {@code int} as a 1-byte signed hex value.
- *
- * @param v value to format
- * @return {@code non-null;} formatted form
- */
- public static String s1(int v) {
- char[] result = new char[3];
+ return new String(result);
+ }
- if (v < 0) {
- result[0] = '-';
- v = -v;
- } else {
- result[0] = '+';
- }
+ /**
+ * Formats an {@code int} as a 1-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s1(int v) {
+ char[] result = new char[3];
- for (int i = 0; i < 2; i++) {
- result[2 - i] = Character.forDigit(v & 0x0f, 16);
- v >>= 4;
- }
-
- return new String(result);
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
}
- /**
- * Formats a hex dump of a portion of a {@code byte[]}. The result
- * is always newline-terminated, unless the passed-in length was zero,
- * in which case the result is always the empty string ({@code ""}).
- *
- * @param arr {@code non-null;} array to format
- * @param offset {@code >= 0;} offset to the part to dump
- * @param length {@code >= 0;} number of bytes to dump
- * @param outOffset {@code >= 0;} first output offset to print
- * @param bpl {@code >= 0;} number of bytes of output per line
- * @param addressLength {@code {2,4,6,8};} number of characters for each address
- * header
- * @return {@code non-null;} a string of the dump
- */
- public static String dump(byte[] arr, int offset, int length,
- int outOffset, int bpl, int addressLength) {
- int end = offset + length;
-
- // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
- if (((offset | length | end) < 0) || (end > arr.length)) {
- throw new IndexOutOfBoundsException("arr.length " +
- arr.length + "; " +
- offset + "..!" + end);
- }
-
- if (outOffset < 0) {
- throw new IllegalArgumentException("outOffset < 0");
- }
-
- if (length == 0) {
- return "";
- }
-
- StringBuffer sb = new StringBuffer(length * 4 + 6);
- boolean bol = true;
- int col = 0;
-
- while (length > 0) {
- if (col == 0) {
- String astr;
- switch (addressLength) {
- case 2: astr = Hex.u1(outOffset); break;
- case 4: astr = Hex.u2(outOffset); break;
- case 6: astr = Hex.u3(outOffset); break;
- default: astr = Hex.u4(outOffset); break;
- }
- sb.append(astr);
- sb.append(": ");
- } else if ((col & 1) == 0) {
- sb.append(' ');
- }
- sb.append(Hex.u1(arr[offset]));
- outOffset++;
- offset++;
- col++;
- if (col == bpl) {
- sb.append('\n');
- col = 0;
- }
- length--;
- }
-
- if (col != 0) {
- sb.append('\n');
- }
-
- return sb.toString();
+ for (int i = 0; i < 2; i++) {
+ result[2 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
}
+
+ return new String(result);
+ }
+
+ /**
+ * Formats a hex dump of a portion of a {@code byte[]}. The result
+ * is always newline-terminated, unless the passed-in length was zero,
+ * in which case the result is always the empty string ({@code ""}).
+ *
+ * @param arr {@code non-null;} array to format
+ * @param offset {@code >= 0;} offset to the part to dump
+ * @param length {@code >= 0;} number of bytes to dump
+ * @param outOffset {@code >= 0;} first output offset to print
+ * @param bpl {@code >= 0;} number of bytes of output per line
+ * @param addressLength {@code {2,4,6,8};} number of characters for each address
+ * header
+ * @return {@code non-null;} a string of the dump
+ */
+ public static String dump(byte[] arr,
+ int offset,
+ int length,
+ int outOffset,
+ int bpl,
+ int addressLength) {
+ int end = offset + length;
+
+ // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+ if (((offset | length | end) < 0) || (end > arr.length)) {
+ throw new IndexOutOfBoundsException("arr.length " + arr.length + "; " + offset + "..!" + end);
+ }
+
+ if (outOffset < 0) {
+ throw new IllegalArgumentException("outOffset < 0");
+ }
+
+ if (length == 0) {
+ return "";
+ }
+
+ StringBuffer sb = new StringBuffer(length * 4 + 6);
+ int col = 0;
+
+ while (length > 0) {
+ if (col == 0) {
+ String astr;
+ switch (addressLength) {
+ case 2:
+ astr = Hex.u1(outOffset);
+ break;
+ case 4:
+ astr = Hex.u2(outOffset);
+ break;
+ case 6:
+ astr = Hex.u3(outOffset);
+ break;
+ default:
+ astr = Hex.u4(outOffset);
+ break;
+ }
+ sb.append(astr);
+ sb.append(": ");
+ } else if ((col & 1) == 0) {
+ sb.append(' ');
+ }
+ sb.append(Hex.u1(arr[offset]));
+ outOffset++;
+ offset++;
+ col++;
+ if (col == bpl) {
+ sb.append('\n');
+ col = 0;
+ }
+ length--;
+ }
+
+ if (col != 0) {
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/HexParser.java b/dx/src/com/android/jack/dx/util/HexParser.java
index 551180a..71ed283 100644
--- a/dx/src/com/android/jack/dx/util/HexParser.java
+++ b/dx/src/com/android/jack/dx/util/HexParser.java
@@ -20,126 +20,120 @@
* Utilities for parsing hexadecimal text.
*/
public final class HexParser {
- /**
- * This class is uninstantiable.
- */
- private HexParser() {
- // This space intentionally left blank.
- }
+ /**
+ * This class is uninstantiable.
+ */
+ private HexParser() {
+ // This space intentionally left blank.
+ }
- /**
- * Parses the given text as hex, returning a {@code byte[]}
- * corresponding to the text. The format is simple: Each line may
- * start with a hex offset followed by a colon (which is verified
- * and presumably used just as a comment), and then consists of
- * hex digits freely interspersed with whitespace. If a pound sign
- * is encountered, it and the rest of the line are ignored as a
- * comment. If a double quote is encountered, then the ASCII value
- * of the subsequent characters is used, until the next double
- * quote. Quoted strings may not span multiple lines.
- *
- * @param src {@code non-null;} the source string
- * @return {@code non-null;} the parsed form
- */
- public static byte[] parse(String src) {
- int len = src.length();
- byte[] result = new byte[len / 2];
- int at = 0;
- int outAt = 0;
+ /**
+ * Parses the given text as hex, returning a {@code byte[]}
+ * corresponding to the text. The format is simple: Each line may
+ * start with a hex offset followed by a colon (which is verified
+ * and presumably used just as a comment), and then consists of
+ * hex digits freely interspersed with whitespace. If a pound sign
+ * is encountered, it and the rest of the line are ignored as a
+ * comment. If a double quote is encountered, then the ASCII value
+ * of the subsequent characters is used, until the next double
+ * quote. Quoted strings may not span multiple lines.
+ *
+ * @param src {@code non-null;} the source string
+ * @return {@code non-null;} the parsed form
+ */
+ public static byte[] parse(String src) {
+ int len = src.length();
+ byte[] result = new byte[len / 2];
+ int at = 0;
+ int outAt = 0;
- while (at < len) {
- int nlAt = src.indexOf('\n', at);
- if (nlAt < 0) {
- nlAt = len;
- }
- int poundAt = src.indexOf('#', at);
+ while (at < len) {
+ int nlAt = src.indexOf('\n', at);
+ if (nlAt < 0) {
+ nlAt = len;
+ }
+ int poundAt = src.indexOf('#', at);
- String line;
- if ((poundAt >= 0) && (poundAt < nlAt)) {
- line = src.substring(at, poundAt);
- } else {
- line = src.substring(at, nlAt);
- }
- at = nlAt + 1;
+ String line;
+ if ((poundAt >= 0) && (poundAt < nlAt)) {
+ line = src.substring(at, poundAt);
+ } else {
+ line = src.substring(at, nlAt);
+ }
+ at = nlAt + 1;
- int colonAt = line.indexOf(':');
+ int colonAt = line.indexOf(':');
- atCheck:
- if (colonAt != -1) {
- int quoteAt = line.indexOf('\"');
- if ((quoteAt != -1) && (quoteAt < colonAt)) {
- break atCheck;
- }
-
- String atStr = line.substring(0, colonAt).trim();
- line = line.substring(colonAt + 1);
- int alleged = Integer.parseInt(atStr, 16);
- if (alleged != outAt) {
- throw new RuntimeException("bogus offset marker: " +
- atStr);
- }
- }
-
- int lineLen = line.length();
- int value = -1;
- boolean quoteMode = false;
-
- for (int i = 0; i < lineLen; i++) {
- char c = line.charAt(i);
-
- if (quoteMode) {
- if (c == '\"') {
- quoteMode = false;
- } else {
- result[outAt] = (byte) c;
- outAt++;
- }
- continue;
- }
-
- if (c <= ' ') {
- continue;
- }
- if (c == '\"') {
- if (value != -1) {
- throw new RuntimeException("spare digit around " +
- "offset " + Hex.u4(outAt));
- }
- quoteMode = true;
- continue;
- }
-
- int digVal = Character.digit(c, 16);
- if (digVal == -1) {
- throw new RuntimeException("bogus digit character: \"" +
- c + "\"");
- }
- if (value == -1) {
- value = digVal;
- } else {
- result[outAt] = (byte) ((value << 4) | digVal);
- outAt++;
- value = -1;
- }
- }
-
- if (value != -1) {
- throw new RuntimeException("spare digit around offset " +
- Hex.u4(outAt));
- }
-
- if (quoteMode) {
- throw new RuntimeException("unterminated quote around " +
- "offset " + Hex.u4(outAt));
- }
+ atCheck: if (colonAt != -1) {
+ int quoteAt = line.indexOf('\"');
+ if ((quoteAt != -1) && (quoteAt < colonAt)) {
+ break atCheck;
}
- if (outAt < result.length) {
- byte[] newr = new byte[outAt];
- System.arraycopy(result, 0, newr, 0, outAt);
- result = newr;
+ String atStr = line.substring(0, colonAt).trim();
+ line = line.substring(colonAt + 1);
+ int alleged = Integer.parseInt(atStr, 16);
+ if (alleged != outAt) {
+ throw new RuntimeException("bogus offset marker: " + atStr);
+ }
+ }
+
+ int lineLen = line.length();
+ int value = -1;
+ boolean quoteMode = false;
+
+ for (int i = 0; i < lineLen; i++) {
+ char c = line.charAt(i);
+
+ if (quoteMode) {
+ if (c == '\"') {
+ quoteMode = false;
+ } else {
+ result[outAt] = (byte) c;
+ outAt++;
+ }
+ continue;
}
- return result;
+ if (c <= ' ') {
+ continue;
+ }
+ if (c == '\"') {
+ if (value != -1) {
+ throw new RuntimeException("spare digit around " + "offset " + Hex.u4(outAt));
+ }
+ quoteMode = true;
+ continue;
+ }
+
+ int digVal = Character.digit(c, 16);
+ if (digVal == -1) {
+ throw new RuntimeException("bogus digit character: \"" + c + "\"");
+ }
+ if (value == -1) {
+ value = digVal;
+ } else {
+ result[outAt] = (byte) ((value << 4) | digVal);
+ outAt++;
+ value = -1;
+ }
+ }
+
+ if (value != -1) {
+ throw new RuntimeException("spare digit around offset " + Hex.u4(outAt));
+ }
+
+ if (quoteMode) {
+ throw new RuntimeException("unterminated quote around " + "offset " + Hex.u4(outAt));
+ }
}
+
+ if (outAt < result.length) {
+ byte[] newr = new byte[outAt];
+ System.arraycopy(result, 0, newr, 0, outAt);
+ result = newr;
+ }
+
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/IndentingWriter.java b/dx/src/com/android/jack/dx/util/IndentingWriter.java
index 5fa042a..b7a8e41 100644
--- a/dx/src/com/android/jack/dx/util/IndentingWriter.java
+++ b/dx/src/com/android/jack/dx/util/IndentingWriter.java
@@ -27,143 +27,143 @@
* line.
*/
public final class IndentingWriter extends FilterWriter {
- /** {@code null-ok;} optional prefix for every line */
- private final String prefix;
+ /** {@code null-ok;} optional prefix for every line */
+ private final String prefix;
- /** {@code > 0;} the maximum output width */
- private final int width;
+ /** {@code > 0;} the maximum output width */
+ private final int width;
- /** {@code > 0;} the maximum indent */
- private final int maxIndent;
+ /** {@code > 0;} the maximum indent */
+ private final int maxIndent;
- /** {@code >= 0;} current output column (zero-based) */
- private int column;
+ /** {@code >= 0;} current output column (zero-based) */
+ private int column;
- /** whether indent spaces are currently being collected */
- private boolean collectingIndent;
+ /** whether indent spaces are currently being collected */
+ private boolean collectingIndent;
- /** {@code >= 0;} current indent amount */
- private int indent;
+ /** {@code >= 0;} current indent amount */
+ private int indent;
- /**
- * Constructs an instance.
- *
- * @param out {@code non-null;} writer to send final output to
- * @param width {@code >= 0;} the maximum output width (not including
- * {@code prefix}), or {@code 0} for no maximum
- * @param prefix {@code non-null;} the prefix for each line
- */
- public IndentingWriter(Writer out, int width, String prefix) {
- super(out);
+ /**
+ * Constructs an instance.
+ *
+ * @param out {@code non-null;} writer to send final output to
+ * @param width {@code >= 0;} the maximum output width (not including
+ * {@code prefix}), or {@code 0} for no maximum
+ * @param prefix {@code non-null;} the prefix for each line
+ */
+ public IndentingWriter(Writer out, int width, String prefix) {
+ super(out);
- if (out == null) {
- throw new NullPointerException("out == null");
- }
-
- if (width < 0) {
- throw new IllegalArgumentException("width < 0");
- }
-
- if (prefix == null) {
- throw new NullPointerException("prefix == null");
- }
-
- this.width = (width != 0) ? width : Integer.MAX_VALUE;
- this.maxIndent = width >> 1;
- this.prefix = (prefix.length() == 0) ? null : prefix;
-
- bol();
+ if (out == null) {
+ throw new NullPointerException("out == null");
}
- /**
- * Constructs a no-prefix instance.
- *
- * @param out {@code non-null;} writer to send final output to
- * @param width {@code >= 0;} the maximum output width (not including
- * {@code prefix}), or {@code 0} for no maximum
- */
- public IndentingWriter(Writer out, int width) {
- this(out, width, "");
+ if (width < 0) {
+ throw new IllegalArgumentException("width < 0");
}
- /** {@inheritDoc} */
- @Override
- public void write(int c) throws IOException {
- synchronized (lock) {
- if (collectingIndent) {
- if (c == ' ') {
- indent++;
- if (indent >= maxIndent) {
- indent = maxIndent;
- collectingIndent = false;
- }
- } else {
- collectingIndent = false;
- }
- }
+ if (prefix == null) {
+ throw new NullPointerException("prefix == null");
+ }
- if ((column == width) && (c != '\n')) {
- out.write('\n');
- column = 0;
- /*
- * Note: No else, so this should fall through to the next
- * if statement.
- */
- }
+ this.width = (width != 0) ? width : Integer.MAX_VALUE;
+ this.maxIndent = width >> 1;
+ this.prefix = (prefix.length() == 0) ? null : prefix;
- if (column == 0) {
- if (prefix != null) {
- out.write(prefix);
- }
+ bol();
+ }
- if (!collectingIndent) {
- for (int i = 0; i < indent; i++) {
- out.write(' ');
- }
- column = indent;
- }
- }
+ /**
+ * Constructs a no-prefix instance.
+ *
+ * @param out {@code non-null;} writer to send final output to
+ * @param width {@code >= 0;} the maximum output width (not including
+ * {@code prefix}), or {@code 0} for no maximum
+ */
+ public IndentingWriter(Writer out, int width) {
+ this(out, width, "");
+ }
- out.write(c);
-
- if (c == '\n') {
- bol();
- } else {
- column++;
- }
+ /** {@inheritDoc} */
+ @Override
+ public void write(int c) throws IOException {
+ synchronized (lock) {
+ if (collectingIndent) {
+ if (c == ' ') {
+ indent++;
+ if (indent >= maxIndent) {
+ indent = maxIndent;
+ collectingIndent = false;
+ }
+ } else {
+ collectingIndent = false;
}
- }
+ }
- /** {@inheritDoc} */
- @Override
- public void write(char[] cbuf, int off, int len) throws IOException {
- synchronized (lock) {
- while (len > 0) {
- write(cbuf[off]);
- off++;
- len--;
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void write(String str, int off, int len) throws IOException {
- synchronized (lock) {
- while (len > 0) {
- write(str.charAt(off));
- off++;
- len--;
- }
- }
- }
-
- /**
- * Indicates that output is at the beginning of a line.
- */
- private void bol() {
+ if ((column == width) && (c != '\n')) {
+ out.write('\n');
column = 0;
- collectingIndent = (maxIndent != 0);
- indent = 0;
+ /*
+ * Note: No else, so this should fall through to the next
+ * if statement.
+ */
+ }
+
+ if (column == 0) {
+ if (prefix != null) {
+ out.write(prefix);
+ }
+
+ if (!collectingIndent) {
+ for (int i = 0; i < indent; i++) {
+ out.write(' ');
+ }
+ column = indent;
+ }
+ }
+
+ out.write(c);
+
+ if (c == '\n') {
+ bol();
+ } else {
+ column++;
+ }
}
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ synchronized (lock) {
+ while (len > 0) {
+ write(cbuf[off]);
+ off++;
+ len--;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ synchronized (lock) {
+ while (len > 0) {
+ write(str.charAt(off));
+ off++;
+ len--;
+ }
+ }
+ }
+
+ /**
+ * Indicates that output is at the beginning of a line.
+ */
+ private void bol() {
+ column = 0;
+ collectingIndent = (maxIndent != 0);
+ indent = 0;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/IntIterator.java b/dx/src/com/android/jack/dx/util/IntIterator.java
index cd28378..8fca6fc 100644
--- a/dx/src/com/android/jack/dx/util/IntIterator.java
+++ b/dx/src/com/android/jack/dx/util/IntIterator.java
@@ -21,18 +21,18 @@
*/
public interface IntIterator {
- /**
- * Checks to see if the iterator has a next value.
- *
- * @return true if next() will succeed
- */
- boolean hasNext();
+ /**
+ * Checks to see if the iterator has a next value.
+ *
+ * @return true if next() will succeed
+ */
+ boolean hasNext();
- /**
- * Returns the next value in the iterator.
- *
- * @return next value
- * @throws java.util.NoSuchElementException if no next element exists
- */
- int next();
+ /**
+ * Returns the next value in the iterator.
+ *
+ * @return next value
+ * @throws java.util.NoSuchElementException if no next element exists
+ */
+ int next();
}
diff --git a/dx/src/com/android/jack/dx/util/IntList.java b/dx/src/com/android/jack/dx/util/IntList.java
index 0a7ce7c..36e96d0 100644
--- a/dx/src/com/android/jack/dx/util/IntList.java
+++ b/dx/src/com/android/jack/dx/util/IntList.java
@@ -22,432 +22,431 @@
* Simple list of {@code int}s.
*/
public final class IntList extends MutabilityControl {
- /** {@code non-null;} immutable, no-element instance */
- public static final IntList EMPTY = new IntList(0);
+ /** {@code non-null;} immutable, no-element instance */
+ public static final IntList EMPTY = new IntList(0);
- /** {@code non-null;} array of elements */
- private int[] values;
+ /** {@code non-null;} array of elements */
+ private int[] values;
- /** {@code >= 0;} current size of the list */
- private int size;
+ /** {@code >= 0;} current size of the list */
+ private int size;
- /** whether the values are currently sorted */
- private boolean sorted;
+ /** whether the values are currently sorted */
+ private boolean sorted;
- static {
- EMPTY.setImmutable();
+ static {
+ EMPTY.setImmutable();
+ }
+
+ /**
+ * Constructs a new immutable instance with the given element.
+ *
+ * @param value the sole value in the list
+ */
+ public static IntList makeImmutable(int value) {
+ IntList result = new IntList(1);
+
+ result.add(value);
+ result.setImmutable();
+
+ return result;
+ }
+
+ /**
+ * Constructs a new immutable instance with the given elements.
+ *
+ * @param value0 the first value in the list
+ * @param value1 the second value in the list
+ */
+ public static IntList makeImmutable(int value0, int value1) {
+ IntList result = new IntList(2);
+
+ result.add(value0);
+ result.add(value1);
+ result.setImmutable();
+
+ return result;
+ }
+
+ /**
+ * Constructs an empty instance with a default initial capacity.
+ */
+ public IntList() {
+ this(4);
+ }
+
+ /**
+ * Constructs an empty instance.
+ *
+ * @param initialCapacity {@code >= 0;} initial capacity of the list
+ */
+ public IntList(int initialCapacity) {
+ super(true);
+
+ try {
+ values = new int[initialCapacity];
+ } catch (NegativeArraySizeException ex) {
+ // Translate the exception.
+ throw new IllegalArgumentException("size < 0");
}
- /**
- * Constructs a new immutable instance with the given element.
- *
- * @param value the sole value in the list
+ size = 0;
+ sorted = true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ int result = 0;
+
+ for (int i = 0; i < size; i++) {
+ result = (result * 31) + values[i];
+ }
+
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof IntList)) {
+ return false;
+ }
+
+ IntList otherList = (IntList) other;
+
+ if (sorted != otherList.sorted) {
+ return false;
+ }
+
+ if (size != otherList.size) {
+ return false;
+ }
+
+ for (int i = 0; i < size; i++) {
+ if (values[i] != otherList.values[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(size * 5 + 10);
+
+ sb.append('{');
+
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(values[i]);
+ }
+
+ sb.append('}');
+
+ return sb.toString();
+ }
+
+ /**
+ * Gets the number of elements in this list.
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Gets the indicated value.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @return the indicated element's value
+ */
+ public int get(int n) {
+ if (n >= size) {
+ throw new IndexOutOfBoundsException("n >= size()");
+ }
+
+ try {
+ return values[n];
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate exception.
+ throw new IndexOutOfBoundsException("n < 0");
+ }
+ }
+
+ /**
+ * Sets the value at the given index.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @param value value to store
+ */
+ public void set(int n, int value) {
+ throwIfImmutable();
+
+ if (n >= size) {
+ throw new IndexOutOfBoundsException("n >= size()");
+ }
+
+ try {
+ values[n] = value;
+ sorted = false;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Translate the exception.
+ if (n < 0) {
+ throw new IllegalArgumentException("n < 0");
+ }
+ }
+ }
+
+ /**
+ * Adds an element to the end of the list. This will increase the
+ * list's capacity if necessary.
+ *
+ * @param value the value to add
+ */
+ public void add(int value) {
+ throwIfImmutable();
+
+ growIfNeeded();
+
+ values[size++] = value;
+
+ if (sorted && (size > 1)) {
+ sorted = (value >= values[size - 2]);
+ }
+ }
+
+ /**
+ * Inserts element into specified index, moving elements at and above
+ * that index up one. May not be used to insert at an index beyond the
+ * current size (that is, insertion as a last element is legal but
+ * no further).
+ *
+ * @param n {@code >= 0, <=size();} index of where to insert
+ * @param value value to insert
+ */
+ public void insert(int n, int value) {
+ if (n > size) {
+ throw new IndexOutOfBoundsException("n > size()");
+ }
+
+ growIfNeeded();
+
+ System.arraycopy(values, n, values, n + 1, size - n);
+ values[n] = value;
+ size++;
+
+ sorted =
+ sorted && (n == 0 || value > values[n - 1]) && (n == (size - 1) || value < values[n + 1]);
+ }
+
+ /**
+ * Removes an element at a given index, shifting elements at greater
+ * indicies down one.
+ *
+ * @param n {@code >=0, < size();} index of element to remove
+ */
+ public void removeIndex(int n) {
+ if (n >= size) {
+ throw new IndexOutOfBoundsException("n >= size()");
+ }
+
+ System.arraycopy(values, n + 1, values, n, size - n - 1);
+ size--;
+
+ // sort status is unchanged
+ }
+
+ /**
+ * Increases size of array if needed
+ */
+ private void growIfNeeded() {
+ if (size == values.length) {
+ // Resize.
+ int[] newv = new int[size * 3 / 2 + 10];
+ System.arraycopy(values, 0, newv, 0, size);
+ values = newv;
+ }
+ }
+
+ /**
+ * Returns the last element in the array without modifying the array
+ *
+ * @return last value in the array
+ * @throws IndexOutOfBoundsException if stack is empty
+ */
+ public int top() {
+ return get(size - 1);
+ }
+
+ /**
+ * Pops an element off the end of the list and decreasing the size by one.
+ *
+ * @return value from what was the last element
+ * @throws IndexOutOfBoundsException if stack is empty
+ */
+ public int pop() {
+ throwIfImmutable();
+
+ int result;
+
+ result = get(size - 1);
+ size--;
+
+ return result;
+ }
+
+ /**
+ * Pops N elements off the end of the list and decreasing the size by N.
+ *
+ * @param n {@code >= 0;} number of elements to remove from end
+ * @throws IndexOutOfBoundsException if stack is smaller than N
+ */
+ public void pop(int n) {
+ throwIfImmutable();
+
+ size -= n;
+ }
+
+ /**
+ * Shrinks the size of the list.
+ *
+ * @param newSize {@code >= 0;} the new size
+ */
+ public void shrink(int newSize) {
+ if (newSize < 0) {
+ throw new IllegalArgumentException("newSize < 0");
+ }
+
+ if (newSize > size) {
+ throw new IllegalArgumentException("newSize > size");
+ }
+
+ throwIfImmutable();
+
+ size = newSize;
+ }
+
+ /**
+ * Makes and returns a mutable copy of the list.
+ *
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public IntList mutableCopy() {
+ int sz = size;
+ IntList result = new IntList(sz);
+
+ for (int i = 0; i < sz; i++) {
+ result.add(values[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Sorts the elements in the list in-place.
+ */
+ public void sort() {
+ throwIfImmutable();
+
+ if (!sorted) {
+ Arrays.sort(values, 0, size);
+ sorted = true;
+ }
+ }
+
+ /**
+ * Returns the index of the given value, or -1 if the value does not
+ * appear in the list. This will do a binary search if the list is
+ * sorted or a linear search if not.
+ *
+ * @param value value to find
+ * @return index of value or -1
+ */
+ public int indexOf(int value) {
+ int ret = binarysearch(value);
+
+ return ret >= 0 ? ret : -1;
+
+ }
+
+ /**
+ * Performs a binary search on a sorted list, returning the index of
+ * the given value if it is present or
+ * {@code (-(insertion point) - 1)} if the value is not present.
+ * If the list is not sorted, then reverts to linear search and returns
+ * {@code -size()} if the element is not found.
+ *
+ * @param value value to find
+ * @return index of value or {@code (-(insertion point) - 1)} if the
+ * value is not present
+ */
+ public int binarysearch(int value) {
+ int sz = size;
+
+ if (!sorted) {
+ // Linear search.
+ for (int i = 0; i < sz; i++) {
+ if (values[i] == value) {
+ return i;
+ }
+ }
+
+ return -sz;
+ }
+
+ /*
+ * Binary search. This variant does only one value comparison
+ * per iteration but does one more iteration on average than
+ * the variant that includes a value equality check per
+ * iteration.
*/
- public static IntList makeImmutable(int value) {
- IntList result = new IntList(1);
- result.add(value);
- result.setImmutable();
+int min = -1;
+ int max = sz;
- return result;
+ while (max > (min + 1)) {
+ /*
+ * The guessIdx calculation is equivalent to ((min + max)
+ * / 2) but won't go wonky when min and max are close to
+ * Integer.MAX_VALUE.
+ */
+ int guessIdx = min + ((max - min) >> 1);
+ int guess = values[guessIdx];
+
+ if (value <= guess) {
+ max = guessIdx;
+ } else {
+ min = guessIdx;
+ }
}
- /**
- * Constructs a new immutable instance with the given elements.
- *
- * @param value0 the first value in the list
- * @param value1 the second value in the list
- */
- public static IntList makeImmutable(int value0, int value1) {
- IntList result = new IntList(2);
-
- result.add(value0);
- result.add(value1);
- result.setImmutable();
-
- return result;
+ if ((max != sz)) {
+ return (value == values[max]) ? max : (-max - 1);
+ } else {
+ return -sz - 1;
}
+ }
- /**
- * Constructs an empty instance with a default initial capacity.
- */
- public IntList() {
- this(4);
- }
- /**
- * Constructs an empty instance.
- *
- * @param initialCapacity {@code >= 0;} initial capacity of the list
- */
- public IntList(int initialCapacity) {
- super(true);
-
- try {
- values = new int[initialCapacity];
- } catch (NegativeArraySizeException ex) {
- // Translate the exception.
- throw new IllegalArgumentException("size < 0");
- }
-
- size = 0;
- sorted = true;
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- int result = 0;
-
- for (int i = 0; i < size; i++) {
- result = (result * 31) + values[i];
- }
-
- return result;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (! (other instanceof IntList)) {
- return false;
- }
-
- IntList otherList = (IntList) other;
-
- if (sorted != otherList.sorted) {
- return false;
- }
-
- if (size != otherList.size) {
- return false;
- }
-
- for (int i = 0; i < size; i++) {
- if (values[i] != otherList.values[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer(size * 5 + 10);
-
- sb.append('{');
-
- for (int i = 0; i < size; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(values[i]);
- }
-
- sb.append('}');
-
- return sb.toString();
- }
-
- /**
- * Gets the number of elements in this list.
- */
- public int size() {
- return size;
- }
-
- /**
- * Gets the indicated value.
- *
- * @param n {@code >= 0, < size();} which element
- * @return the indicated element's value
- */
- public int get(int n) {
- if (n >= size) {
- throw new IndexOutOfBoundsException("n >= size()");
- }
-
- try {
- return values[n];
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate exception.
- throw new IndexOutOfBoundsException("n < 0");
- }
- }
-
- /**
- * Sets the value at the given index.
- *
- * @param n {@code >= 0, < size();} which element
- * @param value value to store
- */
- public void set(int n, int value) {
- throwIfImmutable();
-
- if (n >= size) {
- throw new IndexOutOfBoundsException("n >= size()");
- }
-
- try {
- values[n] = value;
- sorted = false;
- } catch (ArrayIndexOutOfBoundsException ex) {
- // Translate the exception.
- if (n < 0) {
- throw new IllegalArgumentException("n < 0");
- }
- }
- }
-
- /**
- * Adds an element to the end of the list. This will increase the
- * list's capacity if necessary.
- *
- * @param value the value to add
- */
- public void add(int value) {
- throwIfImmutable();
-
- growIfNeeded();
-
- values[size++] = value;
-
- if (sorted && (size > 1)) {
- sorted = (value >= values[size - 2]);
- }
- }
-
- /**
- * Inserts element into specified index, moving elements at and above
- * that index up one. May not be used to insert at an index beyond the
- * current size (that is, insertion as a last element is legal but
- * no further).
- *
- * @param n {@code >= 0, <=size();} index of where to insert
- * @param value value to insert
- */
- public void insert(int n, int value) {
- if (n > size) {
- throw new IndexOutOfBoundsException("n > size()");
- }
-
- growIfNeeded();
-
- System.arraycopy (values, n, values, n+1, size - n);
- values[n] = value;
- size++;
-
- sorted = sorted
- && (n == 0 || value > values[n-1])
- && (n == (size - 1) || value < values[n+1]);
- }
-
- /**
- * Removes an element at a given index, shifting elements at greater
- * indicies down one.
- *
- * @param n {@code >=0, < size();} index of element to remove
- */
- public void removeIndex(int n) {
- if (n >= size) {
- throw new IndexOutOfBoundsException("n >= size()");
- }
-
- System.arraycopy (values, n + 1, values, n, size - n - 1);
- size--;
-
- // sort status is unchanged
- }
-
- /**
- * Increases size of array if needed
- */
- private void growIfNeeded() {
- if (size == values.length) {
- // Resize.
- int[] newv = new int[size * 3 / 2 + 10];
- System.arraycopy(values, 0, newv, 0, size);
- values = newv;
- }
- }
-
- /**
- * Returns the last element in the array without modifying the array
- *
- * @return last value in the array
- * @throws IndexOutOfBoundsException if stack is empty
- */
- public int top() {
- return get(size - 1);
- }
-
- /**
- * Pops an element off the end of the list and decreasing the size by one.
- *
- * @return value from what was the last element
- * @throws IndexOutOfBoundsException if stack is empty
- */
- public int pop() {
- throwIfImmutable();
-
- int result;
-
- result = get(size-1);
- size--;
-
- return result;
- }
-
- /**
- * Pops N elements off the end of the list and decreasing the size by N.
- *
- * @param n {@code >= 0;} number of elements to remove from end
- * @throws IndexOutOfBoundsException if stack is smaller than N
- */
- public void pop(int n) {
- throwIfImmutable();
-
- size -= n;
- }
-
- /**
- * Shrinks the size of the list.
- *
- * @param newSize {@code >= 0;} the new size
- */
- public void shrink(int newSize) {
- if (newSize < 0) {
- throw new IllegalArgumentException("newSize < 0");
- }
-
- if (newSize > size) {
- throw new IllegalArgumentException("newSize > size");
- }
-
- throwIfImmutable();
-
- size = newSize;
- }
-
- /**
- * Makes and returns a mutable copy of the list.
- *
- * @return {@code non-null;} an appropriately-constructed instance
- */
- public IntList mutableCopy() {
- int sz = size;
- IntList result = new IntList(sz);
-
- for (int i = 0; i < sz; i++) {
- result.add(values[i]);
- }
-
- return result;
- }
-
- /**
- * Sorts the elements in the list in-place.
- */
- public void sort() {
- throwIfImmutable();
-
- if (!sorted) {
- Arrays.sort(values, 0, size);
- sorted = true;
- }
- }
-
- /**
- * Returns the index of the given value, or -1 if the value does not
- * appear in the list. This will do a binary search if the list is
- * sorted or a linear search if not.
- *
- * @param value value to find
- * @return index of value or -1
- */
- public int indexOf(int value) {
- int ret = binarysearch(value);
-
- return ret >= 0 ? ret : -1;
-
- }
-
- /**
- * Performs a binary search on a sorted list, returning the index of
- * the given value if it is present or
- * {@code (-(insertion point) - 1)} if the value is not present.
- * If the list is not sorted, then reverts to linear search and returns
- * {@code -size()} if the element is not found.
- *
- * @param value value to find
- * @return index of value or {@code (-(insertion point) - 1)} if the
- * value is not present
- */
- public int binarysearch(int value) {
- int sz = size;
-
- if (!sorted) {
- // Linear search.
- for (int i = 0; i < sz; i++) {
- if (values[i] == value) {
- return i;
- }
- }
-
- return -sz;
- }
-
- /*
- * Binary search. This variant does only one value comparison
- * per iteration but does one more iteration on average than
- * the variant that includes a value equality check per
- * iteration.
- */
-
- int min = -1;
- int max = sz;
-
- while (max > (min + 1)) {
- /*
- * The guessIdx calculation is equivalent to ((min + max)
- * / 2) but won't go wonky when min and max are close to
- * Integer.MAX_VALUE.
- */
- int guessIdx = min + ((max - min) >> 1);
- int guess = values[guessIdx];
-
- if (value <= guess) {
- max = guessIdx;
- } else {
- min = guessIdx;
- }
- }
-
- if ((max != sz)) {
- return (value == values[max]) ? max : (-max - 1);
- } else {
- return -sz - 1;
- }
- }
-
-
- /**
- * Returns whether or not the given value appears in the list.
- * This will do a binary search if the list is sorted or a linear
- * search if not.
- *
- * @see #sort
- *
- * @param value value to look for
- * @return whether the list contains the given value
- */
- public boolean contains(int value) {
- return indexOf(value) >= 0;
- }
+ /**
+ * Returns whether or not the given value appears in the list.
+ * This will do a binary search if the list is sorted or a linear
+ * search if not.
+ *
+ * @see #sort
+ *
+ * @param value value to look for
+ * @return whether the list contains the given value
+ */
+ public boolean contains(int value) {
+ return indexOf(value) >= 0;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/IntSet.java b/dx/src/com/android/jack/dx/util/IntSet.java
index 9d056fe..71fc7d3 100644
--- a/dx/src/com/android/jack/dx/util/IntSet.java
+++ b/dx/src/com/android/jack/dx/util/IntSet.java
@@ -21,47 +21,47 @@
*/
public interface IntSet {
- /**
- * Adds an int to a set
- *
- * @param value int to add
- */
- void add(int value);
+ /**
+ * Adds an int to a set
+ *
+ * @param value int to add
+ */
+ void add(int value);
- /**
- * Removes an int from a set.
- *
- * @param value int to remove
- */
- void remove(int value);
+ /**
+ * Removes an int from a set.
+ *
+ * @param value int to remove
+ */
+ void remove(int value);
- /**
- * Checks to see if a value is in the set
- *
- * @param value int to check
- * @return true if in set
- */
- boolean has(int value);
+ /**
+ * Checks to see if a value is in the set
+ *
+ * @param value int to check
+ * @return true if in set
+ */
+ boolean has(int value);
- /**
- * Merges {@code other} into this set, so this set becomes the
- * union of the two.
- *
- * @param other {@code non-null;} other set to merge with.
- */
- void merge(IntSet other);
+ /**
+ * Merges {@code other} into this set, so this set becomes the
+ * union of the two.
+ *
+ * @param other {@code non-null;} other set to merge with.
+ */
+ void merge(IntSet other);
- /**
- * Returns the count of unique elements in this set.
- *
- * @return {@code > = 0;} count of unique elements
- */
- int elements();
+ /**
+ * Returns the count of unique elements in this set.
+ *
+ * @return {@code > = 0;} count of unique elements
+ */
+ int elements();
- /**
- * Iterates the set
- *
- * @return {@code non-null;} a set iterator
- */
- IntIterator iterator();
+ /**
+ * Iterates the set
+ *
+ * @return {@code non-null;} a set iterator
+ */
+ IntIterator iterator();
}
diff --git a/dx/src/com/android/jack/dx/util/LabeledItem.java b/dx/src/com/android/jack/dx/util/LabeledItem.java
index 3883e38..d609c40 100644
--- a/dx/src/com/android/jack/dx/util/LabeledItem.java
+++ b/dx/src/com/android/jack/dx/util/LabeledItem.java
@@ -21,10 +21,10 @@
*/
public interface LabeledItem {
- /*
- * Gets the label of this block.
- *
- * @return {@code >= 0;} the label
- */
- public int getLabel();
+ /*
+ * Gets the label of this block.
+ *
+ * @return {@code >= 0;} the label
+ */
+ public int getLabel();
}
diff --git a/dx/src/com/android/jack/dx/util/LabeledList.java b/dx/src/com/android/jack/dx/util/LabeledList.java
index 323d997..3432e2c 100644
--- a/dx/src/com/android/jack/dx/util/LabeledList.java
+++ b/dx/src/com/android/jack/dx/util/LabeledList.java
@@ -22,166 +22,167 @@
* A list of labeled items, allowing easy lookup by label.
*/
public class LabeledList extends FixedSizeList {
- /**
- * Sparse array indexed by label to FixedSizeList index;
- * {@code -1} for an invalid label.
- */
- private final IntList labelToIndex;
+ /**
+ * Sparse array indexed by label to FixedSizeList index;
+ * {@code -1} for an invalid label.
+ */
+ private final IntList labelToIndex;
- /** @inheritDoc */
- public LabeledList(int size) {
- super(size);
+ /** @inheritDoc */
+ public LabeledList(int size) {
+ super(size);
- labelToIndex = new IntList(size);
+ labelToIndex = new IntList(size);
+ }
+
+ /**
+ * Constructs a new instance that is a copy of the old instance.
+ *
+ * @param old instance to copy
+ */
+ public LabeledList(LabeledList old) {
+ super(old.size());
+ labelToIndex = old.labelToIndex.mutableCopy();
+
+ int sz = old.size();
+
+ for (int i = 0; i < sz; i++) {
+ Object one = old.get0(i);
+ if (one != null) {
+ set0(i, one);
+ }
+ }
+ }
+
+ /**
+ * Gets the maximum label (exclusive) of any block added to this instance.
+ *
+ * @return {@code >= 0;} the maximum label
+ */
+ public final int getMaxLabel() {
+ int sz = labelToIndex.size();
+
+ // Gobble any deleted labels that may be at the end.
+ int i;
+ for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--) {
+ /* empty */
}
- /**
- * Constructs a new instance that is a copy of the old instance.
- *
- * @param old instance to copy
- */
- public LabeledList(LabeledList old) {
- super(old.size());
- labelToIndex = old.labelToIndex.mutableCopy();
+ int newSize = i + 1;
- int sz = old.size();
+ labelToIndex.shrink(newSize);
- for (int i = 0; i < sz; i++) {
- Object one = old.get0(i);
- if (one != null) {
- set0(i, one);
- }
- }
+ return newSize;
+ }
+
+ /**
+ * Removes a label from the label-to-index mapping.
+ *
+ * @param oldLabel label to remove
+ */
+ private void removeLabel(int oldLabel) {
+ labelToIndex.set(oldLabel, -1);
+ }
+
+ /**
+ * Adds a label and index to the label-to-index mapping.
+ *
+ * @param label new label
+ * @param index index of block.
+ */
+ private void addLabelIndex(int label, int index) {
+ int origSz = labelToIndex.size();
+
+ for (int i = 0; i <= (label - origSz); i++) {
+ labelToIndex.add(-1);
}
- /**
- * Gets the maximum label (exclusive) of any block added to this instance.
- *
- * @return {@code >= 0;} the maximum label
- */
- public final int getMaxLabel() {
- int sz = labelToIndex.size();
+ labelToIndex.set(label, index);
+ }
- // Gobble any deleted labels that may be at the end.
- int i;
- for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--)
- /*empty*/ ;
+ /**
+ * Gets the index of the first item in the list with the given
+ * label, if any.
+ *
+ * @param label {@code >= 0;} the label to look for
+ * @return {@code >= -1;} the index of the so-labelled item, or {@code -1}
+ * if none is found
+ */
+ public final int indexOfLabel(int label) {
+ if (label >= labelToIndex.size()) {
+ return -1;
+ } else {
+ return labelToIndex.get(label);
+ }
+ }
- int newSize = i + 1;
+ /**
+ * Gets an array containing all of the labels used in this instance,
+ * in order. The returned array is freshly-allocated and so may be
+ * modified safely by the caller without impacting this instance.
+ *
+ * @return {@code non-null;} ordered array of labels
+ * @throws NullPointerException thrown if there are any {@code null}
+ * items in this instance
+ */
+ public final int[] getLabelsInOrder() {
+ int sz = size();
+ int[] result = new int[sz];
- labelToIndex.shrink(newSize);
-
- return newSize;
+ for (int i = 0; i < sz; i++) {
+ LabeledItem li = (LabeledItem) get0(i);
+ if (li == null) {
+ throw new NullPointerException("null at index " + i);
+ }
+ result[i] = li.getLabel();
}
- /**
- * Removes a label from the label-to-index mapping.
- *
- * @param oldLabel label to remove
- */
- private void removeLabel(int oldLabel) {
- labelToIndex.set(oldLabel, -1);
+ Arrays.sort(result);
+ return result;
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void shrinkToFit() {
+ super.shrinkToFit();
+
+ rebuildLabelToIndex();
+ }
+
+ /**
+ * Rebuilds the label-to-index mapping after a {@code shrinkToFit()}.
+ * Note: This assumes that the labels that are in the list are the
+ * same, although the indicies may have changed.
+ */
+ private void rebuildLabelToIndex() {
+ int szItems = size();
+
+ for (int i = 0; i < szItems; i++) {
+ LabeledItem li = (LabeledItem) get0(i);
+
+ if (li != null) {
+ labelToIndex.set(li.getLabel(), i);
+ }
+ }
+ }
+
+ /**
+ * Sets the element at the given index.
+ *
+ * @param n {@code >= 0, < size();} which element
+ * @param item {@code null-ok;} the value to store
+ */
+ protected void set(int n, LabeledItem item) {
+ LabeledItem old = (LabeledItem) getOrNull0(n);
+
+ set0(n, item);
+
+ if (old != null) {
+ removeLabel(old.getLabel());
}
- /**
- * Adds a label and index to the label-to-index mapping.
- *
- * @param label new label
- * @param index index of block.
- */
- private void addLabelIndex(int label, int index) {
- int origSz = labelToIndex.size();
-
- for (int i = 0; i <= (label - origSz); i++) {
- labelToIndex.add(-1);
- }
-
- labelToIndex.set(label, index);
+ if (item != null) {
+ addLabelIndex(item.getLabel(), n);
}
-
- /**
- * Gets the index of the first item in the list with the given
- * label, if any.
- *
- * @param label {@code >= 0;} the label to look for
- * @return {@code >= -1;} the index of the so-labelled item, or {@code -1}
- * if none is found
- */
- public final int indexOfLabel(int label) {
- if (label >= labelToIndex.size()) {
- return -1;
- } else {
- return labelToIndex.get(label);
- }
- }
-
- /**
- * Gets an array containing all of the labels used in this instance,
- * in order. The returned array is freshly-allocated and so may be
- * modified safely by the caller without impacting this instance.
- *
- * @return {@code non-null;} ordered array of labels
- * @throws NullPointerException thrown if there are any {@code null}
- * items in this instance
- */
- public final int[] getLabelsInOrder() {
- int sz = size();
- int[] result = new int[sz];
-
- for (int i = 0; i < sz; i++) {
- LabeledItem li = (LabeledItem) get0(i);
- if (li == null) {
- throw new NullPointerException("null at index " + i);
- }
- result[i] = li.getLabel();
- }
-
- Arrays.sort(result);
- return result;
- }
-
- /** @inheritDoc */
- @Override
- public void shrinkToFit() {
- super.shrinkToFit();
-
- rebuildLabelToIndex();
- }
-
- /**
- * Rebuilds the label-to-index mapping after a {@code shrinkToFit()}.
- * Note: This assumes that the labels that are in the list are the
- * same, although the indicies may have changed.
- */
- private void rebuildLabelToIndex() {
- int szItems = size();
-
- for (int i = 0; i < szItems; i++) {
- LabeledItem li = (LabeledItem) get0(i);
-
- if (li != null) {
- labelToIndex.set(li.getLabel(), i);
- }
- }
- }
-
- /**
- * Sets the element at the given index.
- *
- * @param n {@code >= 0, < size();} which element
- * @param item {@code null-ok;} the value to store
- */
- protected void set(int n, LabeledItem item) {
- LabeledItem old = (LabeledItem) getOrNull0(n);
-
- set0(n, item);
-
- if (old != null) {
- removeLabel(old.getLabel());
- }
-
- if (item != null) {
- addLabelIndex(item.getLabel(), n);
- }
- }
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Leb128Utils.java b/dx/src/com/android/jack/dx/util/Leb128Utils.java
index f6d85d1..9b5ee78 100644
--- a/dx/src/com/android/jack/dx/util/Leb128Utils.java
+++ b/dx/src/com/android/jack/dx/util/Leb128Utils.java
@@ -21,142 +21,140 @@
* section 7.6.
*/
public final class Leb128Utils {
- /**
- * This class is uninstantiable.
- */
- private Leb128Utils() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private Leb128Utils() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Gets the number of bytes in the unsigned LEB128 encoding of the
+ * given value.
+ *
+ * @param value the value in question
+ * @return its write size, in bytes
+ */
+ public static int unsignedLeb128Size(int value) {
+ // TODO(dx team): This could be much cleverer.
+
+ int remaining = value >> 7;
+ int count = 0;
+
+ while (remaining != 0) {
+ remaining >>= 7;
+ count++;
}
- /**
- * Gets the number of bytes in the unsigned LEB128 encoding of the
- * given value.
- *
- * @param value the value in question
- * @return its write size, in bytes
- */
- public static int unsignedLeb128Size(int value) {
- // TODO: This could be much cleverer.
+ return count + 1;
+ }
- int remaining = value >> 7;
- int count = 0;
+ /**
+ * Gets the number of bytes in the signed LEB128 encoding of the
+ * given value.
+ *
+ * @param value the value in question
+ * @return its write size, in bytes
+ */
+ public static int signedLeb128Size(int value) {
+ // TODO(dx team): This could be much cleverer.
- while (remaining != 0) {
- remaining >>= 7;
- count++;
- }
+ int remaining = value >> 7;
+ int count = 0;
+ boolean hasMore = true;
+ int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
- return count + 1;
+ while (hasMore) {
+ hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1));
+
+ value = remaining;
+ remaining >>= 7;
+ count++;
}
- /**
- * Gets the number of bytes in the signed LEB128 encoding of the
- * given value.
- *
- * @param value the value in question
- * @return its write size, in bytes
- */
- public static int signedLeb128Size(int value) {
- // TODO: This could be much cleverer.
+ return count;
+ }
- int remaining = value >> 7;
- int count = 0;
- boolean hasMore = true;
- int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+ /**
+ * Reads an signed integer from {@code in}.
+ */
+ public static int readSignedLeb128(ByteInput in) {
+ int result = 0;
+ int cur;
+ int count = 0;
+ int signBits = -1;
- while (hasMore) {
- hasMore = (remaining != end)
- || ((remaining & 1) != ((value >> 6) & 1));
+ do {
+ cur = in.readByte() & 0xff;
+ result |= (cur & 0x7f) << (count * 7);
+ signBits <<= 7;
+ count++;
+ } while (((cur & 0x80) == 0x80) && count < 5);
- value = remaining;
- remaining >>= 7;
- count++;
- }
-
- return count;
+ if ((cur & 0x80) == 0x80) {
+ throw new DexException("invalid LEB128 sequence");
}
- /**
- * Reads an signed integer from {@code in}.
- */
- public static int readSignedLeb128(ByteInput in) {
- int result = 0;
- int cur;
- int count = 0;
- int signBits = -1;
-
- do {
- cur = in.readByte() & 0xff;
- result |= (cur & 0x7f) << (count * 7);
- signBits <<= 7;
- count++;
- } while (((cur & 0x80) == 0x80) && count < 5);
-
- if ((cur & 0x80) == 0x80) {
- throw new DexException("invalid LEB128 sequence");
- }
-
- // Sign extend if appropriate
- if (((signBits >> 1) & result) != 0 ) {
- result |= signBits;
- }
-
- return result;
+ // Sign extend if appropriate
+ if (((signBits >> 1) & result) != 0) {
+ result |= signBits;
}
- /**
- * Reads an unsigned integer from {@code in}.
- */
- public static int readUnsignedLeb128(ByteInput in) {
- int result = 0;
- int cur;
- int count = 0;
+ return result;
+ }
- do {
- cur = in.readByte() & 0xff;
- result |= (cur & 0x7f) << (count * 7);
- count++;
- } while (((cur & 0x80) == 0x80) && count < 5);
+ /**
+ * Reads an unsigned integer from {@code in}.
+ */
+ public static int readUnsignedLeb128(ByteInput in) {
+ int result = 0;
+ int cur;
+ int count = 0;
- if ((cur & 0x80) == 0x80) {
- throw new DexException("invalid LEB128 sequence");
- }
+ do {
+ cur = in.readByte() & 0xff;
+ result |= (cur & 0x7f) << (count * 7);
+ count++;
+ } while (((cur & 0x80) == 0x80) && count < 5);
- return result;
+ if ((cur & 0x80) == 0x80) {
+ throw new DexException("invalid LEB128 sequence");
}
- /**
- * Writes {@code value} as an unsigned integer to {@code out}, starting at
- * {@code offset}. Returns the number of bytes written.
- */
- public static void writeUnsignedLeb128(ByteOutput out, int value) {
- int remaining = value >>> 7;
+ return result;
+ }
- while (remaining != 0) {
- out.writeByte((byte) ((value & 0x7f) | 0x80));
- value = remaining;
- remaining >>>= 7;
- }
+ /**
+ * Writes {@code value} as an unsigned integer to {@code out}, starting at
+ * {@code offset}. Returns the number of bytes written.
+ */
+ public static void writeUnsignedLeb128(ByteOutput out, int value) {
+ int remaining = value >>> 7;
- out.writeByte((byte) (value & 0x7f));
+ while (remaining != 0) {
+ out.writeByte((byte) ((value & 0x7f) | 0x80));
+ value = remaining;
+ remaining >>>= 7;
}
- /**
- * Writes {@code value} as a signed integer to {@code out}, starting at
- * {@code offset}. Returns the number of bytes written.
- */
- public static void writeSignedLeb128(ByteOutput out, int value) {
- int remaining = value >> 7;
- boolean hasMore = true;
- int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+ out.writeByte((byte) (value & 0x7f));
+ }
- while (hasMore) {
- hasMore = (remaining != end)
- || ((remaining & 1) != ((value >> 6) & 1));
+ /**
+ * Writes {@code value} as a signed integer to {@code out}, starting at
+ * {@code offset}. Returns the number of bytes written.
+ */
+ public static void writeSignedLeb128(ByteOutput out, int value) {
+ int remaining = value >> 7;
+ boolean hasMore = true;
+ int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
- out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
- value = remaining;
- remaining >>= 7;
- }
+ while (hasMore) {
+ hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1));
+
+ out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
+ value = remaining;
+ remaining >>= 7;
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/ListIntSet.java b/dx/src/com/android/jack/dx/util/ListIntSet.java
index 36f1891..bae44e8 100644
--- a/dx/src/com/android/jack/dx/util/ListIntSet.java
+++ b/dx/src/com/android/jack/dx/util/ListIntSet.java
@@ -23,110 +23,119 @@
*/
public class ListIntSet implements IntSet {
- /** also accessed in BitIntSet */
- final IntList ints;
+ /** also accessed in BitIntSet */
+ final IntList ints;
- /**
- * Constructs an instance
- */
- public ListIntSet() {
- ints = new IntList();
- ints.sort();
+ /**
+ * Constructs an instance
+ */
+ public ListIntSet() {
+ ints = new IntList();
+ ints.sort();
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void add(int value) {
+ int index = ints.binarysearch(value);
+
+ if (index < 0) {
+ ints.insert(-(index + 1), value);
}
+ }
- /** @inheritDoc */
- public void add(int value) {
- int index = ints.binarysearch(value);
+ /** @inheritDoc */
+ @Override
+ public void remove(int value) {
+ int index = ints.indexOf(value);
- if (index < 0) {
- ints.insert(-(index + 1), value);
+ if (index >= 0) {
+ ints.removeIndex(index);
+ }
+ }
+
+ /** @inheritDoc */
+ @Override
+ public boolean has(int value) {
+ return ints.indexOf(value) >= 0;
+ }
+
+ /** @inheritDoc */
+ @Override
+ public void merge(IntSet other) {
+ if (other instanceof ListIntSet) {
+ ListIntSet o = (ListIntSet) other;
+ int szThis = ints.size();
+ int szOther = o.ints.size();
+
+ int i = 0;
+ int j = 0;
+
+ while (j < szOther && i < szThis) {
+ while (j < szOther && o.ints.get(j) < ints.get(i)) {
+ add(o.ints.get(j++));
}
- }
-
- /** @inheritDoc */
- public void remove(int value) {
- int index = ints.indexOf(value);
-
- if (index >= 0) {
- ints.removeIndex(index);
+ if (j == szOther) {
+ break;
}
- }
-
- /** @inheritDoc */
- public boolean has(int value) {
- return ints.indexOf(value) >= 0;
- }
-
- /** @inheritDoc */
- public void merge(IntSet other) {
- if (other instanceof ListIntSet) {
- ListIntSet o = (ListIntSet) other;
- int szThis = ints.size();
- int szOther = o.ints.size();
-
- int i = 0;
- int j = 0;
-
- while (j < szOther && i < szThis) {
- while (j < szOther && o.ints.get(j) < ints.get(i)) {
- add(o.ints.get(j++));
- }
- if (j == szOther) {
- break;
- }
- while (i < szThis && o.ints.get(j) >= ints.get(i)) {
- i++;
- }
- }
-
- while (j < szOther) {
- add(o.ints.get(j++));
- }
-
- ints.sort();
- } else if (other instanceof BitIntSet) {
- BitIntSet o = (BitIntSet) other;
-
- for (int i = 0; i >= 0; i = Bits.findFirst(o.bits, i + 1)) {
- ints.add(i);
- }
- ints.sort();
- } else {
- IntIterator iter = other.iterator();
- while (iter.hasNext()) {
- add(iter.next());
- }
+ while (i < szThis && o.ints.get(j) >= ints.get(i)) {
+ i++;
}
+ }
+
+ while (j < szOther) {
+ add(o.ints.get(j++));
+ }
+
+ ints.sort();
+ } else if (other instanceof BitIntSet) {
+ BitIntSet o = (BitIntSet) other;
+
+ for (int i = 0; i >= 0; i = Bits.findFirst(o.bits, i + 1)) {
+ ints.add(i);
+ }
+ ints.sort();
+ } else {
+ IntIterator iter = other.iterator();
+ while (iter.hasNext()) {
+ add(iter.next());
+ }
}
+ }
- /** @inheritDoc */
- public int elements() {
- return ints.size();
- }
+ /** @inheritDoc */
+ @Override
+ public int elements() {
+ return ints.size();
+ }
- /** @inheritDoc */
- public IntIterator iterator() {
- return new IntIterator() {
- private int idx = 0;
+ /** @inheritDoc */
+ @Override
+ public IntIterator iterator() {
+ return new IntIterator() {
+ private int idx = 0;
- /** @inheritDoc */
- public boolean hasNext() {
- return idx < ints.size();
- }
+ /** @inheritDoc */
+ @Override
+ public boolean hasNext() {
+ return idx < ints.size();
+ }
- /** @inheritDoc */
- public int next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
+ /** @inheritDoc */
+ @Override
+ public int next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
- return ints.get(idx++);
- }
- };
- }
+ return ints.get(idx++);
+ }
+ };
+ }
- /** @inheritDoc */
- public String toString() {
- return ints.toString();
- }
+ /** @inheritDoc */
+ @Override
+ public String toString() {
+ return ints.toString();
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/MutabilityControl.java b/dx/src/com/android/jack/dx/util/MutabilityControl.java
index d716ffe..9e56656 100644
--- a/dx/src/com/android/jack/dx/util/MutabilityControl.java
+++ b/dx/src/com/android/jack/dx/util/MutabilityControl.java
@@ -23,67 +23,67 @@
* to the checker in all the right places.
*/
public class MutabilityControl {
- /** whether this instance is mutable */
- private boolean mutable;
+ /** whether this instance is mutable */
+ private boolean mutable;
- /**
- * Constructs an instance. It is initially mutable.
- */
- public MutabilityControl() {
- mutable = true;
- }
+ /**
+ * Constructs an instance. It is initially mutable.
+ */
+ public MutabilityControl() {
+ mutable = true;
+ }
- /**
- * Constructs an instance, explicitly indicating the mutability.
- *
- * @param mutable {@code true} iff this instance is mutable
- */
- public MutabilityControl(boolean mutable) {
- this.mutable = mutable;
- }
+ /**
+ * Constructs an instance, explicitly indicating the mutability.
+ *
+ * @param mutable {@code true} iff this instance is mutable
+ */
+ public MutabilityControl(boolean mutable) {
+ this.mutable = mutable;
+ }
- /**
- * Makes this instance immutable.
- */
- public void setImmutable() {
- mutable = false;
- }
+ /**
+ * Makes this instance immutable.
+ */
+ public void setImmutable() {
+ mutable = false;
+ }
- /**
- * Checks to see whether or not this instance is immutable. This is the
- * same as calling {@code !isMutable()}.
- *
- * @return {@code true} iff this instance is immutable
- */
- public final boolean isImmutable() {
- return !mutable;
- }
+ /**
+ * Checks to see whether or not this instance is immutable. This is the
+ * same as calling {@code !isMutable()}.
+ *
+ * @return {@code true} iff this instance is immutable
+ */
+ public final boolean isImmutable() {
+ return !mutable;
+ }
- /**
- * Checks to see whether or not this instance is mutable.
- *
- * @return {@code true} iff this instance is mutable
- */
- public final boolean isMutable() {
- return mutable;
- }
+ /**
+ * Checks to see whether or not this instance is mutable.
+ *
+ * @return {@code true} iff this instance is mutable
+ */
+ public final boolean isMutable() {
+ return mutable;
+ }
- /**
- * Throws {@link MutabilityException} if this instance is
- * immutable.
- */
- public final void throwIfImmutable() {
- if (!mutable) {
- throw new MutabilityException("immutable instance");
- }
+ /**
+ * Throws {@link MutabilityException} if this instance is
+ * immutable.
+ */
+ public final void throwIfImmutable() {
+ if (!mutable) {
+ throw new MutabilityException("immutable instance");
}
+ }
- /**
- * Throws {@link MutabilityException} if this instance is mutable.
- */
- public final void throwIfMutable() {
- if (mutable) {
- throw new MutabilityException("mutable instance");
- }
+ /**
+ * Throws {@link MutabilityException} if this instance is mutable.
+ */
+ public final void throwIfMutable() {
+ if (mutable) {
+ throw new MutabilityException("mutable instance");
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/MutabilityException.java b/dx/src/com/android/jack/dx/util/MutabilityException.java
index 7e59883..b13a7d7 100644
--- a/dx/src/com/android/jack/dx/util/MutabilityException.java
+++ b/dx/src/com/android/jack/dx/util/MutabilityException.java
@@ -19,17 +19,19 @@
/**
* Exception due to a mutability problem.
*/
-public class MutabilityException
- extends ExceptionWithContext {
- public MutabilityException(String message) {
- super(message);
- }
+public class MutabilityException extends ExceptionWithContext {
- public MutabilityException(Throwable cause) {
- super(cause);
- }
+ private static final long serialVersionUID = 1L;
- public MutabilityException(String message, Throwable cause) {
- super(message, cause);
- }
+ public MutabilityException(String message) {
+ super(message);
+ }
+
+ public MutabilityException(Throwable cause) {
+ super(cause);
+ }
+
+ public MutabilityException(String message, Throwable cause) {
+ super(message, cause);
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Mutf8.java b/dx/src/com/android/jack/dx/util/Mutf8.java
index 5f01693..e279525 100644
--- a/dx/src/com/android/jack/dx/util/Mutf8.java
+++ b/dx/src/com/android/jack/dx/util/Mutf8.java
@@ -24,91 +24,91 @@
* <p>Derived from libcore's MUTF-8 encoder at java.nio.charset.ModifiedUtf8.
*/
public final class Mutf8 {
- private Mutf8() {}
+ private Mutf8() {}
- /**
- * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is
- * encountered. Returns a new string containing the decoded characters.
- */
- public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {
- int s = 0;
- while (true) {
- char a = (char) (in.readByte() & 0xff);
- if (a == 0) {
- return new String(out, 0, s);
- }
- out[s] = a;
- if (a < '\u0080') {
- s++;
- } else if ((a & 0xe0) == 0xc0) {
- int b = in.readByte() & 0xff;
- if ((b & 0xC0) != 0x80) {
- throw new UTFDataFormatException("bad second byte");
- }
- out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
- } else if ((a & 0xf0) == 0xe0) {
- int b = in.readByte() & 0xff;
- int c = in.readByte() & 0xff;
- if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
- throw new UTFDataFormatException("bad second or third byte");
- }
- out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
- } else {
- throw new UTFDataFormatException("bad byte");
- }
+ /**
+ * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is
+ * encountered. Returns a new string containing the decoded characters.
+ */
+ public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {
+ int s = 0;
+ while (true) {
+ char a = (char) (in.readByte() & 0xff);
+ if (a == 0) {
+ return new String(out, 0, s);
+ }
+ out[s] = a;
+ if (a < '\u0080') {
+ s++;
+ } else if ((a & 0xe0) == 0xc0) {
+ int b = in.readByte() & 0xff;
+ if ((b & 0xC0) != 0x80) {
+ throw new UTFDataFormatException("bad second byte");
}
- }
-
- /**
- * Returns the number of bytes the modified UTF8 representation of 's' would take.
- */
- private static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
- long result = 0;
- final int length = s.length();
- for (int i = 0; i < length; ++i) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- ++result;
- } else if (ch <= 2047) {
- result += 2;
- } else {
- result += 3;
- }
- if (shortLength && result > 65535) {
- throw new UTFDataFormatException("String more than 65535 UTF bytes long");
- }
+ out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
+ } else if ((a & 0xf0) == 0xe0) {
+ int b = in.readByte() & 0xff;
+ int c = in.readByte() & 0xff;
+ if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
+ throw new UTFDataFormatException("bad second or third byte");
}
- return result;
+ out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
+ } else {
+ throw new UTFDataFormatException("bad byte");
+ }
}
+ }
- /**
- * Encodes the modified UTF-8 bytes corresponding to {@code s} into {@code
- * dst}, starting at {@code offset}.
- */
- public static void encode(byte[] dst, int offset, String s) {
- final int length = s.length();
- for (int i = 0; i < length; i++) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- dst[offset++] = (byte) ch;
- } else if (ch <= 2047) {
- dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- } else {
- dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12)));
- dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- }
- }
+ /**
+ * Returns the number of bytes the modified UTF8 representation of 's' would take.
+ */
+ private static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
+ long result = 0;
+ final int length = s.length();
+ for (int i = 0; i < length; ++i) {
+ char ch = s.charAt(i);
+ if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
+ ++result;
+ } else if (ch <= 2047) {
+ result += 2;
+ } else {
+ result += 3;
+ }
+ if (shortLength && result > 65535) {
+ throw new UTFDataFormatException("String more than 65535 UTF bytes long");
+ }
}
+ return result;
+ }
- /**
- * Returns an array containing the <i>modified UTF-8</i> form of {@code s}.
- */
- public static byte[] encode(String s) throws UTFDataFormatException {
- int utfCount = (int) countBytes(s, true);
- byte[] result = new byte[utfCount];
- encode(result, 0, s);
- return result;
+ /**
+ * Encodes the modified UTF-8 bytes corresponding to {@code s} into {@code
+ * dst}, starting at {@code offset}.
+ */
+ public static void encode(byte[] dst, int offset, String s) {
+ final int length = s.length();
+ for (int i = 0; i < length; i++) {
+ char ch = s.charAt(i);
+ if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
+ dst[offset++] = (byte) ch;
+ } else if (ch <= 2047) {
+ dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6)));
+ dst[offset++] = (byte) (0x80 | (0x3f & ch));
+ } else {
+ dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12)));
+ dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6)));
+ dst[offset++] = (byte) (0x80 | (0x3f & ch));
+ }
}
+ }
+
+ /**
+ * Returns an array containing the <i>modified UTF-8</i> form of {@code s}.
+ */
+ public static byte[] encode(String s) throws UTFDataFormatException {
+ int utfCount = (int) countBytes(s, true);
+ byte[] result = new byte[utfCount];
+ encode(result, 0, s);
+ return result;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Output.java b/dx/src/com/android/jack/dx/util/Output.java
index 42640b7..d4a1a59 100644
--- a/dx/src/com/android/jack/dx/util/Output.java
+++ b/dx/src/com/android/jack/dx/util/Output.java
@@ -22,108 +22,109 @@
* are declared, and multibyte output is defined to be little-endian.
*/
public interface Output extends ByteOutput {
- /**
- * Gets the current cursor position. This is the same as the number of
- * bytes written to this instance.
- *
- * @return {@code >= 0;} the cursor position
- */
- public int getCursor();
+ /**
+ * Gets the current cursor position. This is the same as the number of
+ * bytes written to this instance.
+ *
+ * @return {@code >= 0;} the cursor position
+ */
+ public int getCursor();
- /**
- * Asserts that the cursor is the given value.
- *
- * @param expectedCursor the expected cursor value
- * @throws RuntimeException thrown if {@code getCursor() !=
- * expectedCursor}
- */
- public void assertCursor(int expectedCursor);
+ /**
+ * Asserts that the cursor is the given value.
+ *
+ * @param expectedCursor the expected cursor value
+ * @throws RuntimeException thrown if {@code getCursor() !=
+ * expectedCursor}
+ */
+ public void assertCursor(int expectedCursor);
- /**
- * Writes a {@code byte} to this instance.
- *
- * @param value the value to write; all but the low 8 bits are ignored
- */
- public void writeByte(int value);
+ /**
+ * Writes a {@code byte} to this instance.
+ *
+ * @param value the value to write; all but the low 8 bits are ignored
+ */
+ @Override
+ public void writeByte(int value);
- /**
- * Writes a {@code short} to this instance.
- *
- * @param value the value to write; all but the low 16 bits are ignored
- */
- public void writeShort(int value);
+ /**
+ * Writes a {@code short} to this instance.
+ *
+ * @param value the value to write; all but the low 16 bits are ignored
+ */
+ public void writeShort(int value);
- /**
- * Writes an {@code int} to this instance.
- *
- * @param value the value to write
- */
- public void writeInt(int value);
+ /**
+ * Writes an {@code int} to this instance.
+ *
+ * @param value the value to write
+ */
+ public void writeInt(int value);
- /**
- * Writes a {@code long} to this instance.
- *
- * @param value the value to write
- */
- public void writeLong(long value);
+ /**
+ * Writes a {@code long} to this instance.
+ *
+ * @param value the value to write
+ */
+ public void writeLong(long value);
- /**
- * Writes a DWARFv3-style unsigned LEB128 integer. For details,
- * see the "Dalvik Executable Format" document or DWARF v3 section
- * 7.6.
- *
- * @param value value to write, treated as an unsigned value
- * @return {@code 1..5;} the number of bytes actually written
- */
- public int writeUleb128(int value);
+ /**
+ * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+ * see the "Dalvik Executable Format" document or DWARF v3 section
+ * 7.6.
+ *
+ * @param value value to write, treated as an unsigned value
+ * @return {@code 1..5;} the number of bytes actually written
+ */
+ public int writeUleb128(int value);
- /**
- * Writes a DWARFv3-style unsigned LEB128 integer. For details,
- * see the "Dalvik Executable Format" document or DWARF v3 section
- * 7.6.
- *
- * @param value value to write
- * @return {@code 1..5;} the number of bytes actually written
- */
- public int writeSleb128(int value);
+ /**
+ * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+ * see the "Dalvik Executable Format" document or DWARF v3 section
+ * 7.6.
+ *
+ * @param value value to write
+ * @return {@code 1..5;} the number of bytes actually written
+ */
+ public int writeSleb128(int value);
- /**
- * Writes a {@link ByteArray} to this instance.
- *
- * @param bytes {@code non-null;} the array to write
- */
- public void write(ByteArray bytes);
+ /**
+ * Writes a {@link ByteArray} to this instance.
+ *
+ * @param bytes {@code non-null;} the array to write
+ */
+ public void write(ByteArray bytes);
- /**
- * Writes a portion of a {@code byte[]} to this instance.
- *
- * @param bytes {@code non-null;} the array to write
- * @param offset {@code >= 0;} offset into {@code bytes} for the first
- * byte to write
- * @param length {@code >= 0;} number of bytes to write
- */
- public void write(byte[] bytes, int offset, int length);
+ /**
+ * Writes a portion of a {@code byte[]} to this instance.
+ *
+ * @param bytes {@code non-null;} the array to write
+ * @param offset {@code >= 0;} offset into {@code bytes} for the first
+ * byte to write
+ * @param length {@code >= 0;} number of bytes to write
+ */
+ public void write(byte[] bytes, int offset, int length);
- /**
- * Writes a {@code byte[]} to this instance. This is just
- * a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
- *
- * @param bytes {@code non-null;} the array to write
- */
- public void write(byte[] bytes);
+ /**
+ * Writes a {@code byte[]} to this instance. This is just
+ * a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
+ *
+ * @param bytes {@code non-null;} the array to write
+ */
+ public void write(byte[] bytes);
- /**
- * Writes the given number of {@code 0} bytes.
- *
- * @param count {@code >= 0;} the number of zeroes to write
- */
- public void writeZeroes(int count);
+ /**
+ * Writes the given number of {@code 0} bytes.
+ *
+ * @param count {@code >= 0;} the number of zeroes to write
+ */
+ public void writeZeroes(int count);
- /**
- * Adds extra bytes if necessary (with value {@code 0}) to
- * force alignment of the output cursor as given.
- *
- * @param alignment {@code > 0;} the alignment; must be a power of two
- */
- public void alignTo(int alignment);
+ /**
+ * Adds extra bytes if necessary (with value {@code 0}) to
+ * force alignment of the output cursor as given.
+ *
+ * @param alignment {@code > 0;} the alignment; must be a power of two
+ */
+ public void alignTo(int alignment);
}
diff --git a/dx/src/com/android/jack/dx/util/ToHuman.java b/dx/src/com/android/jack/dx/util/ToHuman.java
index a74e670..6158789 100644
--- a/dx/src/com/android/jack/dx/util/ToHuman.java
+++ b/dx/src/com/android/jack/dx/util/ToHuman.java
@@ -21,11 +21,11 @@
* a complete but often hard to read) string form.
*/
public interface ToHuman {
- /**
- * Return the "human" string form of this instance. This is
- * generally less "debuggy" than {@code toString()}.
- *
- * @return {@code non-null;} the human string form
- */
- public String toHuman();
+ /**
+ * Return the "human" string form of this instance. This is
+ * generally less "debuggy" than {@code toString()}.
+ *
+ * @return {@code non-null;} the human string form
+ */
+ public String toHuman();
}
diff --git a/dx/src/com/android/jack/dx/util/TwoColumnOutput.java b/dx/src/com/android/jack/dx/util/TwoColumnOutput.java
index afce5bb..204c20f 100644
--- a/dx/src/com/android/jack/dx/util/TwoColumnOutput.java
+++ b/dx/src/com/android/jack/dx/util/TwoColumnOutput.java
@@ -28,227 +28,220 @@
* one which goes on the right.
*/
public final class TwoColumnOutput {
- /** {@code non-null;} underlying writer for final output */
- private final Writer out;
+ /** {@code non-null;} underlying writer for final output */
+ private final Writer out;
- /** {@code > 0;} the left column width */
- private final int leftWidth;
+ /** {@code > 0;} the left column width */
+ private final int leftWidth;
- /** {@code non-null;} pending left column output */
- private final StringBuffer leftBuf;
+ /** {@code non-null;} pending left column output */
+ private final StringBuffer leftBuf;
- /** {@code non-null;} pending right column output */
- private final StringBuffer rightBuf;
+ /** {@code non-null;} pending right column output */
+ private final StringBuffer rightBuf;
- /** {@code non-null;} left column writer */
- private final IndentingWriter leftColumn;
+ /** {@code non-null;} left column writer */
+ private final IndentingWriter leftColumn;
- /** {@code non-null;} right column writer */
- private final IndentingWriter rightColumn;
+ /** {@code non-null;} right column writer */
+ private final IndentingWriter rightColumn;
- /**
- * Turns the given two strings (with widths) and spacer into a formatted
- * two-column string.
- *
- * @param s1 {@code non-null;} first string
- * @param width1 {@code > 0;} width of the first column
- * @param spacer {@code non-null;} spacer string
- * @param s2 {@code non-null;} second string
- * @param width2 {@code > 0;} width of the second column
- * @return {@code non-null;} an appropriately-formatted string
- */
- public static String toString(String s1, int width1, String spacer,
- String s2, int width2) {
- int len1 = s1.length();
- int len2 = s2.length();
+ /**
+ * Turns the given two strings (with widths) and spacer into a formatted
+ * two-column string.
+ *
+ * @param s1 {@code non-null;} first string
+ * @param width1 {@code > 0;} width of the first column
+ * @param spacer {@code non-null;} spacer string
+ * @param s2 {@code non-null;} second string
+ * @param width2 {@code > 0;} width of the second column
+ * @return {@code non-null;} an appropriately-formatted string
+ */
+ public static String toString(String s1, int width1, String spacer, String s2, int width2) {
+ int len1 = s1.length();
+ int len2 = s2.length();
- StringWriter sw = new StringWriter((len1 + len2) * 3);
- TwoColumnOutput twoOut =
- new TwoColumnOutput(sw, width1, width2, spacer);
+ StringWriter sw = new StringWriter((len1 + len2) * 3);
+ TwoColumnOutput twoOut = new TwoColumnOutput(sw, width1, width2, spacer);
- try {
- twoOut.getLeft().write(s1);
- twoOut.getRight().write(s2);
- } catch (IOException ex) {
- throw new RuntimeException("shouldn't happen", ex);
- }
-
- twoOut.flush();
- return sw.toString();
+ try {
+ twoOut.getLeft().write(s1);
+ twoOut.getRight().write(s2);
+ } catch (IOException ex) {
+ throw new RuntimeException("shouldn't happen", ex);
}
- /**
- * Constructs an instance.
- *
- * @param out {@code non-null;} writer to send final output to
- * @param leftWidth {@code > 0;} width of the left column, in characters
- * @param rightWidth {@code > 0;} width of the right column, in characters
- * @param spacer {@code non-null;} spacer string to sit between the two columns
- */
- public TwoColumnOutput(Writer out, int leftWidth, int rightWidth,
- String spacer) {
- if (out == null) {
- throw new NullPointerException("out == null");
- }
+ twoOut.flush();
+ return sw.toString();
+ }
- if (leftWidth < 1) {
- throw new IllegalArgumentException("leftWidth < 1");
- }
-
- if (rightWidth < 1) {
- throw new IllegalArgumentException("rightWidth < 1");
- }
-
- if (spacer == null) {
- throw new NullPointerException("spacer == null");
- }
-
- StringWriter leftWriter = new StringWriter(1000);
- StringWriter rightWriter = new StringWriter(1000);
-
- this.out = out;
- this.leftWidth = leftWidth;
- this.leftBuf = leftWriter.getBuffer();
- this.rightBuf = rightWriter.getBuffer();
- this.leftColumn = new IndentingWriter(leftWriter, leftWidth);
- this.rightColumn =
- new IndentingWriter(rightWriter, rightWidth, spacer);
+ /**
+ * Constructs an instance.
+ *
+ * @param out {@code non-null;} writer to send final output to
+ * @param leftWidth {@code > 0;} width of the left column, in characters
+ * @param rightWidth {@code > 0;} width of the right column, in characters
+ * @param spacer {@code non-null;} spacer string to sit between the two columns
+ */
+ public TwoColumnOutput(Writer out, int leftWidth, int rightWidth, String spacer) {
+ if (out == null) {
+ throw new NullPointerException("out == null");
}
- /**
- * Constructs an instance.
- *
- * @param out {@code non-null;} stream to send final output to
- * @param leftWidth {@code >= 1;} width of the left column, in characters
- * @param rightWidth {@code >= 1;} width of the right column, in characters
- * @param spacer {@code non-null;} spacer string to sit between the two columns
- */
- public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
- String spacer) {
- this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
+ if (leftWidth < 1) {
+ throw new IllegalArgumentException("leftWidth < 1");
}
- /**
- * Gets the writer to use to write to the left column.
- *
- * @return {@code non-null;} the left column writer
- */
- public Writer getLeft() {
- return leftColumn;
+ if (rightWidth < 1) {
+ throw new IllegalArgumentException("rightWidth < 1");
}
- /**
- * Gets the writer to use to write to the right column.
- *
- * @return {@code non-null;} the right column writer
- */
- public Writer getRight() {
- return rightColumn;
+ if (spacer == null) {
+ throw new NullPointerException("spacer == null");
}
- /**
- * Flushes the output. If there are more lines of pending output in one
- * column, then the other column will get filled with blank lines.
- */
- public void flush() {
- try {
- appendNewlineIfNecessary(leftBuf, leftColumn);
- appendNewlineIfNecessary(rightBuf, rightColumn);
- outputFullLines();
- flushLeft();
- flushRight();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
+ StringWriter leftWriter = new StringWriter(1000);
+ StringWriter rightWriter = new StringWriter(1000);
+
+ this.out = out;
+ this.leftWidth = leftWidth;
+ this.leftBuf = leftWriter.getBuffer();
+ this.rightBuf = rightWriter.getBuffer();
+ this.leftColumn = new IndentingWriter(leftWriter, leftWidth);
+ this.rightColumn = new IndentingWriter(rightWriter, rightWidth, spacer);
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param out {@code non-null;} stream to send final output to
+ * @param leftWidth {@code >= 1;} width of the left column, in characters
+ * @param rightWidth {@code >= 1;} width of the right column, in characters
+ * @param spacer {@code non-null;} spacer string to sit between the two columns
+ */
+ public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth, String spacer) {
+ this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
+ }
+
+ /**
+ * Gets the writer to use to write to the left column.
+ *
+ * @return {@code non-null;} the left column writer
+ */
+ public Writer getLeft() {
+ return leftColumn;
+ }
+
+ /**
+ * Gets the writer to use to write to the right column.
+ *
+ * @return {@code non-null;} the right column writer
+ */
+ public Writer getRight() {
+ return rightColumn;
+ }
+
+ /**
+ * Flushes the output. If there are more lines of pending output in one
+ * column, then the other column will get filled with blank lines.
+ */
+ public void flush() {
+ try {
+ appendNewlineIfNecessary(leftBuf, leftColumn);
+ appendNewlineIfNecessary(rightBuf, rightColumn);
+ outputFullLines();
+ flushLeft();
+ flushRight();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
}
+ }
- /**
- * Outputs to the final destination as many full line pairs as
- * there are in the pending output, removing those lines from
- * their respective buffers. This method terminates when at
- * least one of the two column buffers is empty.
- */
- private void outputFullLines() throws IOException {
- for (;;) {
- int leftLen = leftBuf.indexOf("\n");
- if (leftLen < 0) {
- return;
- }
+ /**
+ * Outputs to the final destination as many full line pairs as
+ * there are in the pending output, removing those lines from
+ * their respective buffers. This method terminates when at
+ * least one of the two column buffers is empty.
+ */
+ private void outputFullLines() throws IOException {
+ for (;;) {
+ int leftLen = leftBuf.indexOf("\n");
+ if (leftLen < 0) {
+ return;
+ }
- int rightLen = rightBuf.indexOf("\n");
- if (rightLen < 0) {
- return;
- }
+ int rightLen = rightBuf.indexOf("\n");
+ if (rightLen < 0) {
+ return;
+ }
- if (leftLen != 0) {
- out.write(leftBuf.substring(0, leftLen));
- }
+ if (leftLen != 0) {
+ out.write(leftBuf.substring(0, leftLen));
+ }
- if (rightLen != 0) {
- writeSpaces(out, leftWidth - leftLen);
- out.write(rightBuf.substring(0, rightLen));
- }
+ if (rightLen != 0) {
+ writeSpaces(out, leftWidth - leftLen);
+ out.write(rightBuf.substring(0, rightLen));
+ }
- out.write('\n');
+ out.write('\n');
- leftBuf.delete(0, leftLen + 1);
- rightBuf.delete(0, rightLen + 1);
- }
+ leftBuf.delete(0, leftLen + 1);
+ rightBuf.delete(0, rightLen + 1);
}
+ }
- /**
- * Flushes the left column buffer, printing it and clearing the buffer.
- * If the buffer is already empty, this does nothing.
- */
- private void flushLeft() throws IOException {
- appendNewlineIfNecessary(leftBuf, leftColumn);
+ /**
+ * Flushes the left column buffer, printing it and clearing the buffer.
+ * If the buffer is already empty, this does nothing.
+ */
+ private void flushLeft() throws IOException {
+ appendNewlineIfNecessary(leftBuf, leftColumn);
- while (leftBuf.length() != 0) {
- rightColumn.write('\n');
- outputFullLines();
- }
+ while (leftBuf.length() != 0) {
+ rightColumn.write('\n');
+ outputFullLines();
}
+ }
- /**
- * Flushes the right column buffer, printing it and clearing the buffer.
- * If the buffer is already empty, this does nothing.
- */
- private void flushRight() throws IOException {
- appendNewlineIfNecessary(rightBuf, rightColumn);
+ /**
+ * Flushes the right column buffer, printing it and clearing the buffer.
+ * If the buffer is already empty, this does nothing.
+ */
+ private void flushRight() throws IOException {
+ appendNewlineIfNecessary(rightBuf, rightColumn);
- while (rightBuf.length() != 0) {
- leftColumn.write('\n');
- outputFullLines();
- }
+ while (rightBuf.length() != 0) {
+ leftColumn.write('\n');
+ outputFullLines();
}
+ }
- /**
- * Appends a newline to the given buffer via the given writer, but
- * only if it isn't empty and doesn't already end with one.
- *
- * @param buf {@code non-null;} the buffer in question
- * @param out {@code non-null;} the writer to use
- */
- private static void appendNewlineIfNecessary(StringBuffer buf,
- Writer out)
- throws IOException {
- int len = buf.length();
+ /**
+ * Appends a newline to the given buffer via the given writer, but
+ * only if it isn't empty and doesn't already end with one.
+ *
+ * @param buf {@code non-null;} the buffer in question
+ * @param out {@code non-null;} the writer to use
+ */
+ private static void appendNewlineIfNecessary(StringBuffer buf, Writer out) throws IOException {
+ int len = buf.length();
- if ((len != 0) && (buf.charAt(len - 1) != '\n')) {
- out.write('\n');
- }
+ if ((len != 0) && (buf.charAt(len - 1) != '\n')) {
+ out.write('\n');
}
+ }
- /**
- * Writes the given number of spaces to the given writer.
- *
- * @param out {@code non-null;} where to write
- * @param amt {@code >= 0;} the number of spaces to write
- */
- private static void writeSpaces(Writer out, int amt) throws IOException {
- while (amt > 0) {
- out.write(' ');
- amt--;
- }
+ /**
+ * Writes the given number of spaces to the given writer.
+ *
+ * @param out {@code non-null;} where to write
+ * @param amt {@code >= 0;} the number of spaces to write
+ */
+ private static void writeSpaces(Writer out, int amt) throws IOException {
+ while (amt > 0) {
+ out.write(' ');
+ amt--;
}
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Uint.java b/dx/src/com/android/jack/dx/util/Uint.java
index f84a988..3bccc92 100644
--- a/dx/src/com/android/jack/dx/util/Uint.java
+++ b/dx/src/com/android/jack/dx/util/Uint.java
@@ -20,13 +20,14 @@
* An unsigned integer.
*/
public final class Uint implements Comparable<Uint> {
- public final int intValue;
+ public final int intValue;
- public Uint(int value) {
- this.intValue = value;
- }
+ public Uint(int value) {
+ this.intValue = value;
+ }
- public int compareTo(Uint uint) {
- return Unsigned.compare(intValue, uint.intValue);
- }
+ @Override
+ public int compareTo(Uint uint) {
+ return Unsigned.compare(intValue, uint.intValue);
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Unsigned.java b/dx/src/com/android/jack/dx/util/Unsigned.java
index 63c8e1d..cd20cde 100644
--- a/dx/src/com/android/jack/dx/util/Unsigned.java
+++ b/dx/src/com/android/jack/dx/util/Unsigned.java
@@ -20,23 +20,23 @@
* Unsigned arithmetic over Java's signed types.
*/
public final class Unsigned {
- private Unsigned() {}
+ private Unsigned() {}
- public static int compare(short ushortA, short ushortB) {
- if (ushortA == ushortB) {
- return 0;
- }
- int a = ushortA & 0xFFFF;
- int b = ushortB & 0xFFFF;
- return a < b ? -1 : 1;
+ public static int compare(short ushortA, short ushortB) {
+ if (ushortA == ushortB) {
+ return 0;
}
+ int a = ushortA & 0xFFFF;
+ int b = ushortB & 0xFFFF;
+ return a < b ? -1 : 1;
+ }
- public static int compare(int uintA, int uintB) {
- if (uintA == uintB) {
- return 0;
- }
- long a = uintA & 0xFFFFFFFFL;
- long b = uintB & 0xFFFFFFFFL;
- return a < b ? -1 : 1;
+ public static int compare(int uintA, int uintB) {
+ if (uintA == uintB) {
+ return 0;
}
+ long a = uintA & 0xFFFFFFFFL;
+ long b = uintB & 0xFFFFFFFFL;
+ return a < b ? -1 : 1;
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Warning.java b/dx/src/com/android/jack/dx/util/Warning.java
index effb49f..b941091 100644
--- a/dx/src/com/android/jack/dx/util/Warning.java
+++ b/dx/src/com/android/jack/dx/util/Warning.java
@@ -20,12 +20,15 @@
* Exception which is meant to indicate a non-fatal warning.
*/
public class Warning extends RuntimeException {
- /**
- * Constructs an instance.
- *
- * @param message human-oriented message
- */
- public Warning(String message) {
- super(message);
- }
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param message human-oriented message
+ */
+ public Warning(String message) {
+ super(message);
+ }
}
diff --git a/dx/src/com/android/jack/dx/util/Writers.java b/dx/src/com/android/jack/dx/util/Writers.java
index 3d5c8d1..e13d7c7 100644
--- a/dx/src/com/android/jack/dx/util/Writers.java
+++ b/dx/src/com/android/jack/dx/util/Writers.java
@@ -23,26 +23,26 @@
* Utilities for dealing with {@code Writer}s.
*/
public final class Writers {
- /**
- * This class is uninstantiable.
- */
- private Writers() {
- // This space intentionally left blank.
+ /**
+ * This class is uninstantiable.
+ */
+ private Writers() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Makes a {@code PrintWriter} for the given {@code Writer},
+ * returning the given writer if it already happens to be the right
+ * class.
+ *
+ * @param writer {@code non-null;} writer to (possibly) wrap
+ * @return {@code non-null;} an appropriate instance
+ */
+ public static PrintWriter printWriterFor(Writer writer) {
+ if (writer instanceof PrintWriter) {
+ return (PrintWriter) writer;
}
- /**
- * Makes a {@code PrintWriter} for the given {@code Writer},
- * returning the given writer if it already happens to be the right
- * class.
- *
- * @param writer {@code non-null;} writer to (possibly) wrap
- * @return {@code non-null;} an appropriate instance
- */
- public static PrintWriter printWriterFor(Writer writer) {
- if (writer instanceof PrintWriter) {
- return (PrintWriter) writer;
- }
-
- return new PrintWriter(writer);
- }
+ return new PrintWriter(writer);
+ }
}
diff --git a/hamcrest-core/Android.mk b/hamcrest-core/Android.mk
index 776522b..023870c 100644
--- a/hamcrest-core/Android.mk
+++ b/hamcrest-core/Android.mk
@@ -38,3 +38,14 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_JAVA_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := hamcrest-core-jack
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/jack-tests/Android.mk b/jack-tests/Android.mk
index 7b358a3..bfefef6 100644
--- a/jack-tests/Android.mk
+++ b/jack-tests/Android.mk
@@ -59,6 +59,7 @@
$(call declare-test-with-name,arithmetic/test001)
$(call declare-test-with-name,arithmetic/test002)
$(call declare-test-with-name,arithmetic/test003)
+$(call declare-test-with-name,arithmetic/test004)
# Array
$(call declare-test-with-name,array/test001)
diff --git a/jack-tests/tests/com/android/jack/arithmetic/test004/dx/Tests.java b/jack-tests/tests/com/android/jack/arithmetic/test004/dx/Tests.java
new file mode 100644
index 0000000..b3b13aa
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/arithmetic/test004/dx/Tests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.arithmetic.test004.dx;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.android.jack.arithmetic.test004.jack.ArithmeticWithoutValue;
+
+/**
+ * Arithmetic with unary operator.
+ */
+public class Tests {
+
+ @Test
+ public void test1() {
+ Assert.assertEquals(2, ArithmeticWithoutValue.add1(1, 1));
+ Assert.assertEquals(2, ArithmeticWithoutValue.add2(1, 1));
+ Assert.assertEquals(0, ArithmeticWithoutValue.add3(1, 1));
+ }
+
+}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/jack-tests/tests/com/android/jack/arithmetic/test004/jack/ArithmeticWithoutValue.java
similarity index 64%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to jack-tests/tests/com/android/jack/arithmetic/test004/jack/ArithmeticWithoutValue.java
index 0c967d9..27d032b 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/jack-tests/tests/com/android/jack/arithmetic/test004/jack/ArithmeticWithoutValue.java
@@ -14,18 +14,22 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
-
-import java.util.Collection;
-
-import javax.annotation.Nonnull;
+package com.android.jack.arithmetic.test004.jack;
/**
- * Virtual directory.
+ * Arithmetic with unary operator.
*/
-public interface VDir extends VElement {
+public class ArithmeticWithoutValue {
- @Nonnull
- Collection<? extends VElement> list();
+ public static int add1(int a, int b) {
+ return a + - + - + b;
+ }
+ public static int add2(int a, int b) {
+ return a + - + - + + b;
+ }
+
+ public static int add3(int a, int b) {
+ return a + - + - - b;
+ }
}
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/jack/A.java b/jack-tests/tests/com/android/jack/frontend/test001/jack/missing/MissingObject.java
similarity index 79%
rename from jack-tests/tests/com/android/jack/shrob/test027/jack/A.java
rename to jack-tests/tests/com/android/jack/frontend/test001/jack/missing/MissingObject.java
index 5a2caba..db9f020 100644
--- a/jack-tests/tests/com/android/jack/shrob/test027/jack/A.java
+++ b/jack-tests/tests/com/android/jack/frontend/test001/jack/missing/MissingObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-package com.android.jack.shrob.test027.jack;
+package com.android.jack.frontend.test001.jack.missing;
-public class A {
+public class MissingObject {
}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/SuperClass.java
similarity index 73%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/SuperClass.java
index 0c967d9..4571d8d 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/SuperClass.java
@@ -14,18 +14,15 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.jack.frontend.test001.jack.sub2;
-import java.util.Collection;
+import com.android.jack.frontend.test001.jack.missing.MissingObject;
-import javax.annotation.Nonnull;
+public class SuperClass extends TopClass {
-/**
- * Virtual directory.
- */
-public interface VDir extends VElement {
-
- @Nonnull
- Collection<? extends VElement> list();
+ @Override
+ MissingObject get() {
+ return null;
+ }
}
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/jack/A.java b/jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/TopClass.java
similarity index 76%
copy from jack-tests/tests/com/android/jack/shrob/test027/jack/A.java
copy to jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/TopClass.java
index 5a2caba..fd3ae6c 100644
--- a/jack-tests/tests/com/android/jack/shrob/test027/jack/A.java
+++ b/jack-tests/tests/com/android/jack/frontend/test001/jack/sub2/TopClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,12 @@
* limitations under the License.
*/
-package com.android.jack.shrob.test027.jack;
+package com.android.jack.frontend.test001.jack.sub2;
-public class A {
+public class TopClass {
+
+ Object get() {
+ return null;
+ }
}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/jack-tests/tests/com/android/jack/frontend/test001/jack/test/SubClass.java
similarity index 73%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to jack-tests/tests/com/android/jack/frontend/test001/jack/test/SubClass.java
index 0c967d9..518837e 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/jack-tests/tests/com/android/jack/frontend/test001/jack/test/SubClass.java
@@ -14,18 +14,10 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.jack.frontend.test001.jack.test;
-import java.util.Collection;
+import com.android.jack.frontend.test001.jack.sub2.SuperClass;
-import javax.annotation.Nonnull;
-
-/**
- * Virtual directory.
- */
-public interface VDir extends VElement {
-
- @Nonnull
- Collection<? extends VElement> list();
+public class SubClass extends SuperClass {
}
diff --git a/jack-tests/tests/com/android/jack/inner/test026/jack/D.java b/jack-tests/tests/com/android/jack/inner/test026/jack/D.java
index 5edfc73..e4178b9 100644
--- a/jack-tests/tests/com/android/jack/inner/test026/jack/D.java
+++ b/jack-tests/tests/com/android/jack/inner/test026/jack/D.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.inner.test026.jack;
import com.android.jack.inner.test026.jack.pkg.C;
diff --git a/jack-tests/tests/com/android/jack/jarjar/test001/jack/DummyAnnot.java b/jack-tests/tests/com/android/jack/jarjar/test001/jack/DummyAnnot.java
index bbf8017..4134bec 100644
--- a/jack-tests/tests/com/android/jack/jarjar/test001/jack/DummyAnnot.java
+++ b/jack-tests/tests/com/android/jack/jarjar/test001/jack/DummyAnnot.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.jarjar.test001.jack;
import java.lang.annotation.Retention;
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/jack-tests/tests/com/android/jack/resource/test001/jack/IrrelevantForTest.java
similarity index 73%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to jack-tests/tests/com/android/jack/resource/test001/jack/IrrelevantForTest.java
index 0c967d9..fc67d00 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/IrrelevantForTest.java
@@ -14,18 +14,15 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
-
-import java.util.Collection;
-
-import javax.annotation.Nonnull;
+package com.android.jack.resource.test001.jack;
/**
- * Virtual directory.
+ * This class is irrelevant for the test, since what we test here is the handling of resources.
*/
-public interface VDir extends VElement {
+public class IrrelevantForTest {
- @Nonnull
- Collection<? extends VElement> list();
+ public int getInt() {
+ return 4;
+ }
}
diff --git a/jack-tests/tests/com/android/jack/resource/test001/jack/Resource1 b/jack-tests/tests/com/android/jack/resource/test001/jack/Resource1
new file mode 100644
index 0000000..b98ccd9
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/Resource1
@@ -0,0 +1 @@
+Res1
diff --git a/jack-tests/tests/com/android/jack/resource/test001/jack/Resource2 b/jack-tests/tests/com/android/jack/resource/test001/jack/Resource2
new file mode 100644
index 0000000..1bcdbc0
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/Resource2
@@ -0,0 +1 @@
+Res2
diff --git a/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource3 b/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource3
new file mode 100644
index 0000000..d0da24e
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource3
@@ -0,0 +1 @@
+Res3
diff --git a/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource4 b/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource4
new file mode 100644
index 0000000..cf38257
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/pack/Resource4
@@ -0,0 +1 @@
+Res4
diff --git a/jack-tests/tests/com/android/jack/resource/test001/jack/proguard.flags b/jack-tests/tests/com/android/jack/resource/test001/jack/proguard.flags
new file mode 100644
index 0000000..a8d845e
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/resource/test001/jack/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.jack.resource.test001.jack.IrrelevantForTest
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags001.mapping
index 21fc0d4..dd71fd9 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags001.mapping
@@ -1,3 +1,2 @@
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
- void m() -> a
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
+ void m() -> renamedM
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags002.mapping
index df84b16..0d80a32 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags002.mapping
@@ -1,4 +1,2 @@
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
- void privateFunc() -> privateFunc
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
- void m() -> a
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
+ void m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags003.mapping
index 535ddb9..dd71fd9 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags003.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags003.mapping
@@ -1,4 +1,2 @@
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
- void m() -> m
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
- void m() -> a
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
+ void m() -> renamedM
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags004.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags004.mapping
index cc3053b..963fef8 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags004.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags004.mapping
@@ -1,3 +1,2 @@
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
- void keep() -> a
- void main2(java.lang.String[]) -> main2
+ void keep() -> renamedKeep
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping
index 5a4f462..a8a6e5f 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping
@@ -1,5 +1,4 @@
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
- void keep() -> a
- void main(java.lang.String[]) -> main
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.a:
- void keep() -> a
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
+ void keep() -> renamedKeep
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping002 b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping002
index 5a4f462..a8a6e5f 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping002
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping002
@@ -1,5 +1,4 @@
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
- void keep() -> a
- void main(java.lang.String[]) -> main
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.a:
- void keep() -> a
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
+ void keep() -> renamedKeep
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping003 b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping003
index 5a4f462..a8a6e5f 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping003
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags005.mapping003
@@ -1,5 +1,4 @@
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
- void keep() -> a
- void main(java.lang.String[]) -> main
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.a:
- void keep() -> a
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
+ void keep() -> renamedKeep
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags006.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags006.mapping
index 9723086..060dffb 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags006.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags006.mapping
@@ -1,6 +1,5 @@
com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.G:
- void m() -> a
- void main(java.lang.String[]) -> main
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.a:
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.b:
- void m() -> a
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.RenamedH:
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags007.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags007.mapping
deleted file mode 100644
index d1fc58b..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags007.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.J:
- int[][][] m3() -> m3
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags008.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags008.mapping
index 52aad70..cafefd5 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags008.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags008.mapping
@@ -1,3 +1 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep() -> keep
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags009.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags009.mapping
index e2fa379..453ed82 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags009.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags009.mapping
@@ -1,5 +1,3 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep2() -> keep2
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
- int fieldPrivate -> b
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
+ int fieldPrivate -> renamedFielPrivate
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags010.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags010.mapping
index 3570842..17428f7 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags010.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags010.mapping
@@ -1,5 +1,3 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep3() -> keep3
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
- int fieldPrivate -> b
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
+ int fieldPrivate -> renamedFielPrivate
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags011.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags011.mapping
index 5d902a5..513bb72 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags011.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags011.mapping
@@ -1,6 +1,4 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep4() -> keep4
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.c:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> renamedM
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags012.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags012.mapping
index b474da0..513bb72 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags012.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags012.mapping
@@ -1,6 +1,4 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep5() -> keep5
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.c:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> renamedM
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags013.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags013.mapping
deleted file mode 100644
index 822a5dd..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags013.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags014.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags014.mapping
index 73c80ea..0de1868 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags014.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags014.mapping
@@ -1,5 +1,3 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep6() -> keep6
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
- long fieldLong -> b
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
+ long fieldLong -> renamedFieldLong
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags015.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags015.mapping
index 33be300..a1c72c9 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags015.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags015.mapping
@@ -1,7 +1,5 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep7() -> keep7
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
- long fieldLong -> b
- long fieldLong3 -> c
- long fieldLong4 -> d
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
+ long fieldLong -> renamedFieldLong
+ long fieldLong3 -> renamedFieldLong3
+ long fieldLong4 -> renamedFieldLong4
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags016.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags016.mapping
index 32dea38..d096156 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags016.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags016.mapping
@@ -1,6 +1,5 @@
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
- void keep8() -> keep8
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> renamedA
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> renamedB
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags017.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags017.mapping
index 84e1c9b..aec0caf 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags017.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags017.mapping
@@ -1,8 +1,7 @@
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> a
- int h -> b
- int i2 -> c
- int j -> d
- java.lang.Object o -> e
- java.lang.String TAG2 -> f
- void keep() -> keep
+ int i -> renamedI
+ int h -> renamedH
+ int i2 -> renamedI2
+ int j -> renamedJ
+ java.lang.Object o -> renamedI
+ java.lang.String TAG2 -> renamedTAG2
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags018.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags018.mapping
deleted file mode 100644
index 52fca62..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags018.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test001.jack.L -> com.android.jack.shrob.test001.jack.L:
- void onReceive() -> onReceive
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags019.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags019.mapping
deleted file mode 100644
index 14d06cd..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags019.mapping
+++ /dev/null
@@ -1,30 +0,0 @@
-com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
- java.lang.String TAG -> TAG
- java.lang.String TAG2 -> TAG2
- void keep() -> keep
-com.android.jack.shrob.test001.jack.L -> com.android.jack.shrob.test001.jack.L:
- java.lang.String TAG -> TAG
- void onReceive() -> onReceive
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
- long fieldLong -> fieldLong
- long fieldLong2 -> fieldLong2
- long fieldLong3 -> fieldLong3
- long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
- void calledMethod() -> calledMethod
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> m
- void privateMethod(com.android.jack.shrob.test001.jack.Reflect2$B) -> privateMethod
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.Reflect2$B:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags020.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags020.mapping
deleted file mode 100644
index 1ba7b92..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags020.mapping
+++ /dev/null
@@ -1,25 +0,0 @@
-com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
- java.lang.String TAG -> TAG
- java.lang.String TAG2 -> TAG2
-com.android.jack.shrob.test001.jack.L -> com.android.jack.shrob.test001.jack.L:
- java.lang.String TAG -> TAG
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
- long fieldLong -> fieldLong
- long fieldLong2 -> fieldLong2
- long fieldLong3 -> fieldLong3
- long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.Reflect2$B:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags021.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags021.mapping
index 48a2db6..ca830b9 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags021.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags021.mapping
@@ -1,67 +1,39 @@
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.a:
- void m() -> a
- void privateFunc() -> b
-com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.c:
- void f() -> a
- void m() -> b
-com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.d:
- void keep() -> a
- void main(java.lang.String[]) -> a
- void main2(java.lang.String[]) -> b
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.e:
- void keep() -> a
-com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.f:
- void keep() -> a
-com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.g:
- void m() -> a
- void main(java.lang.String[]) -> a
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.h:
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.i:
- void m() -> a
-com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.j:
- int[][][] m5(int,boolean,long) -> a
- int[][][] m3() -> a
- int[][] m2() -> b
- int[] m1() -> c
- int m0() -> d
- int[][][] m() -> e
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.RenamedH:
+com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.RenamedJ:
+ int[][][] m() -> renamedM
+ int m0() -> renamedM0
+ int[] m1() -> renamedM1
+ int[][] m2() -> renamedM2
+ int[][][] m3() -> renamedM3
+ int[][][] m5(int,boolean,long) -> renamedM5
+com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.RenamedF:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.RenamedB:
+com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.RenamedD:
+ void keep() -> renamedKeep
+ void main(java.lang.String[]) -> renamedMain
+ void main2(java.lang.String[]) -> renamedMain2
+com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.RenamedG:
+ void m() -> renamedM
+ void main(java.lang.String[]) -> renamedMain
+com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.RenamedReflect:
+ void keep() -> renamedKeep
+ void keep2() -> renamedKeep2
+ void keep3() -> renamedKeep3
+ void keep4() -> renamedKeep4
+ void keep5() -> renamedKeep5
+ void keep6() -> renamedKeep6
+ void keep7() -> renamedKeep7
+ void keep8() -> renamedKeep8
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
+ void f() -> renamedF
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.RenamedA:
+ void m() -> renamedM
+ void privateFunc() -> renamedPrivateFunc
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
- java.lang.String TAG -> TAG
- java.lang.String TAG2 -> TAG2
- void keep() -> a
-com.android.jack.shrob.test001.jack.L -> com.android.jack.shrob.test001.jack.L:
- java.lang.String TAG -> TAG
- void onReceive() -> a
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.k:
- void keep() -> a
- void keep2() -> b
- void keep3() -> c
- void keep4() -> d
- void keep5() -> e
- void keep6() -> f
- void keep7() -> g
- void keep8() -> h
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
- long fieldLong -> fieldLong
- long fieldLong2 -> fieldLong2
- long fieldLong3 -> fieldLong3
- long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
- void calledMethod() -> a
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
- void privateMethod(com.android.jack.shrob.test001.jack.Reflect2$B) -> a
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.Reflect2$B:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
+ void keep() -> renamedKeep
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags022.mapping b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags022.mapping
index 44c10d6..0b8ef10 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags022.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test001/proguard.flags022.mapping
@@ -1,67 +1,37 @@
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.a:
- void m() -> a
- void privateFunc() -> b
-com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.c:
- void f() -> a
- void m() -> b
-com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.d:
- void keep() -> a
- void main(java.lang.String[]) -> a
- void main2(java.lang.String[]) -> b
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.e:
- void keep() -> a
-com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.f:
- void keep() -> a
-com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.g:
- void m() -> a
- void main(java.lang.String[]) -> a
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.h:
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.i:
- void m() -> a
-com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.j:
- int[][][] m5(int,boolean,long) -> a
- int[][][] m3() -> a
- int[][] m2() -> b
- int[] m1() -> c
- int m0() -> d
- int[][][] m() -> e
-com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
- java.lang.String TAG -> TAG
- java.lang.String TAG2 -> TAG2
- void keep() -> keep
-com.android.jack.shrob.test001.jack.L -> com.android.jack.shrob.test001.jack.L:
- java.lang.String TAG -> TAG
- void onReceive() -> onReceive
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.k:
- void keep() -> a
- void keep2() -> b
- void keep3() -> c
- void keep4() -> d
- void keep5() -> e
- void keep6() -> f
- void keep7() -> g
- void keep8() -> h
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
- long fieldLong -> fieldLong
- long fieldLong2 -> fieldLong2
- long fieldLong3 -> fieldLong3
- long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
- void calledMethod() -> calledMethod
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> m
- void privateMethod(com.android.jack.shrob.test001.jack.Reflect2$B) -> privateMethod
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.Reflect2$B:
- com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.renamedH:
+com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.renamedJ:
+ int[][][] m5(int,boolean,long) -> renamedM5
+ int[][][] m3() -> renamedM3
+ int[][] m2() -> renamedM2
+ int[] m1() -> renamedM1
+ int m0() -> renamedM0
+ int[][][] m() -> renamedM
+com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.RenamedF:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.RenamedB:
+com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.RenamedD:
+ void keep() -> renamedKeep
+ void main(java.lang.String[]) -> renamedMain
+ void main2(java.lang.String[]) -> renamedMain2
+com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.RenamedG:
+ void m() -> renamedM
+ void main(java.lang.String[]) -> renamedMain
+com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.RenamedReflect:
+ void keep() -> renamedKeep
+ void keep2() -> renamedKeep2
+ void keep3() -> renamedKeep3
+ void keep4() -> renamedKeep4
+ void keep5() -> renamedKeep5
+ void keep6() -> renamedKeep6
+ void keep7() -> renamedKeep7
+ void keep8() -> renamedKeep8
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
+ void f() -> renamedF
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.RenamedA:
+ void m() -> renamedM
+ void privateFunc() -> renamedPrivateFunc
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-001.txt
index 51f1db2..6463a01 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-001.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
void <init>() -> <init>
- void m() -> a
+ void m() -> renamedM
com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
- void <clinit>() -> <clinit>
void <init>() -> <init>
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-002.txt
index b0049fe..f827dd9 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-002.txt
@@ -1,7 +1,7 @@
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
void <init>() -> <init>
- void m() -> a
+ void m() -> renamedM
com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
- void <clinit>() -> <clinit>
void <init>() -> <init>
void privateFunc() -> privateFunc
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-003.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-003.txt
index acbe6d5..fa2b35a 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-003.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-003.txt
@@ -1,8 +1,8 @@
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
void <init>() -> <init>
- void m() -> a
+ void m() -> renamedM
com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.A:
- void <clinit>() -> <clinit>
void <init>() -> <init>
void <init>(int) -> <init>
void m() -> m
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-004.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-004.txt
index 952f08d..4b9187a 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-004.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-004.txt
@@ -1,4 +1,4 @@
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
void <init>() -> <init>
- void keep() -> a
+ void keep() -> renamedKeep
void main2(java.lang.String[]) -> main2
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-005.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-005.txt
index 9882dfa..d2f22ee 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-005.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-005.txt
@@ -1,7 +1,7 @@
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
void <init>() -> <init>
- void keep() -> a
+ void keep() -> renamedKeep
com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.D:
void <init>() -> <init>
- void keep() -> a
+ void keep() -> renamedKeep
void main(java.lang.String[]) -> main
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-006.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-006.txt
index 8c2943a..5d053cc 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-006.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-006.txt
@@ -1,7 +1,7 @@
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.b:
- void m() -> a
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.RenamedH:
com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.G:
void <init>() -> <init>
- void m() -> a
+ void m() -> renamedM
void main(java.lang.String[]) -> main
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-008.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-008.txt
index 0965567..d3a17fc 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-008.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-008.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep() -> keep
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-009.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-009.txt
index 23e4011..1350955 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-009.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-009.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep2() -> keep2
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-010.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-010.txt
index 28402c5..1c70c36 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-010.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-010.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep3() -> keep3
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-011.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-011.txt
index 0287a94..8dcc0e0 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-011.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-011.txt
@@ -1,8 +1,8 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep4() -> keep4
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
void <init>() -> <init>
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.c:
+ void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> renamedM
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-012.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-012.txt
index c95a035..3810d94 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-012.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-012.txt
@@ -1,8 +1,8 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep5() -> keep5
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
void <init>() -> <init>
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.c:
+ void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> renamedM
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-014.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-014.txt
index 2967038..77808f5 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-014.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-014.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep6() -> keep6
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- int fieldPublic -> a
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ int fieldPublic -> renamedFieldPublic
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-015.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-015.txt
index 154a665..eb6fd7f 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-015.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-015.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep7() -> keep7
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- long fieldLong -> b
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ long fieldLong -> renamedFieldLong
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-016.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-016.txt
index 5ad9d9c..9bd0417 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-016.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-016.txt
@@ -1,9 +1,9 @@
com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.Reflect:
void <init>() -> <init>
void keep8() -> keep8
-com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.a:
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
+com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.RenamedReflect2:
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> renamedA
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> renamedB
void <init>() -> <init>
-com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.b:
-com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.c:
+com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.RenamedReflect2$A:
+com.android.jack.shrob.test001.jack.Reflect2$B -> com.android.jack.shrob.test001.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-017.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-017.txt
index ccfdc41..fd3cb91 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-017.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-017.txt
@@ -1,10 +1,10 @@
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> a
- int h -> b
- int i2 -> c
- int j -> d
- java.lang.Object o -> e
- java.lang.String TAG2 -> f
- void <clinit>() -> <clinit>
+ java.lang.String TAG2 -> renamedTAG2
+ int h -> renamedH
+ int i -> renamedI
+ int i2 -> renamedI2
+ int j -> renamedJ
+ java.lang.Object o -> renamedI
void <init>() -> <init>
void keep() -> keep
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-019.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-019.txt
index 93a7c09..345010d 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-019.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-019.txt
@@ -1,13 +1,13 @@
com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> a
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> b
+ java.lang.Object c -> c
long fieldLong -> fieldLong
long fieldLong2 -> fieldLong2
long fieldLong3 -> fieldLong3
long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
+ int fieldPrivate -> fieldPrivate
+ int fieldPublic -> fieldPublic
void <init>() -> <init>
void calledMethod() -> calledMethod
void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> m
@@ -23,14 +23,14 @@
void <init>() -> <init>
void onReceive() -> onReceive
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
java.lang.String TAG -> TAG
java.lang.String TAG2 -> TAG2
- void <clinit>() -> <clinit>
+ int h -> h
+ int i -> i
+ int i2 -> i2
+ int i3 -> i3
+ int j -> j
+ java.lang.Object o -> o
void <init>() -> <init>
void keep() -> keep
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-020.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-020.txt
index a68d609..3123550 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-020.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-020.txt
@@ -1,13 +1,13 @@
com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> a
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> b
+ java.lang.Object c -> c
long fieldLong -> fieldLong
long fieldLong2 -> fieldLong2
long fieldLong3 -> fieldLong3
long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
+ int fieldPrivate -> fieldPrivate
+ int fieldPublic -> fieldPublic
void <init>() -> <init>
com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
@@ -17,13 +17,13 @@
java.lang.String TAG -> TAG
void <init>() -> <init>
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
java.lang.String TAG -> TAG
java.lang.String TAG2 -> TAG2
- void <clinit>() -> <clinit>
+ int h -> h
+ int i -> i
+ int i2 -> i2
+ int i3 -> i3
+ int j -> j
+ java.lang.Object o -> o
void <init>() -> <init>
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-021.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-021.txt
index 350f38a..58b7103 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-021.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-021.txt
@@ -1,65 +1,65 @@
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.e:
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
void <init>() -> <init>
- void keep() -> a
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.i:
- void m() -> a
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.h:
-com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.j:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.RenamedH:
+com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.RenamedJ:
void <init>() -> <init>
- int[][][] m5(int,boolean,long) -> a
- int[][][] m3() -> a
- int[][] m2() -> b
- int[] m1() -> c
- int m0() -> d
- int[][][] m() -> e
-com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.f:
+ int[][][] m() -> renamedM
+ int m0() -> renamedM0
+ int[] m1() -> renamedM1
+ int[][] m2() -> renamedM2
+ int[][][] m3() -> renamedM3
+ int[][][] m5(int,boolean,long) -> renamedM5
+com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.RenamedF:
void <init>() -> <init>
- void keep() -> a
-com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.b:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.d:
+com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.RenamedD:
void <init>() -> <init>
- void keep() -> a
- void main(java.lang.String[]) -> a
- void main2(java.lang.String[]) -> b
-com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.g:
+ void keep() -> renamedKeep
+ void main(java.lang.String[]) -> renamedMain
+ void main2(java.lang.String[]) -> renamedMain2
+com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.RenamedG:
void <init>() -> <init>
- void m() -> a
- void main(java.lang.String[]) -> a
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.k:
+ void m() -> renamedM
+ void main(java.lang.String[]) -> renamedMain
+com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.RenamedReflect:
void <init>() -> <init>
- void keep() -> a
- void keep2() -> b
- void keep3() -> c
- void keep4() -> d
- void keep5() -> e
- void keep6() -> f
- void keep7() -> g
- void keep8() -> h
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.c:
+ void keep() -> renamedKeep
+ void keep2() -> renamedKeep2
+ void keep3() -> renamedKeep3
+ void keep4() -> renamedKeep4
+ void keep5() -> renamedKeep5
+ void keep6() -> renamedKeep6
+ void keep7() -> renamedKeep7
+ void keep8() -> renamedKeep8
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
void <init>() -> <init>
- void f() -> a
- void m() -> b
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.a:
- void <clinit>() -> <clinit>
+ void f() -> renamedF
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.RenamedA:
void <init>() -> <init>
void <init>(int) -> <init>
- void m() -> a
- void privateFunc() -> b
+ void m() -> renamedM
+ void privateFunc() -> renamedPrivateFunc
+ void <clinit>() -> <clinit>
com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> a
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> b
+ java.lang.Object c -> c
long fieldLong -> fieldLong
long fieldLong2 -> fieldLong2
long fieldLong3 -> fieldLong3
long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
+ int fieldPrivate -> fieldPrivate
+ int fieldPublic -> fieldPublic
void <init>() -> <init>
void calledMethod() -> a
- void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> a
- void privateMethod(com.android.jack.shrob.test001.jack.Reflect2$B) -> a
+ void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> b
+ void privateMethod(com.android.jack.shrob.test001.jack.Reflect2$B) -> c
com.android.jack.shrob.test001.jack.Reflect2$A -> com.android.jack.shrob.test001.jack.Reflect2$A:
com.android.jack.shrob.test001.jack.Reflect2 this$0 -> this$0
void <init>(com.android.jack.shrob.test001.jack.Reflect2) -> <init>
@@ -71,14 +71,14 @@
void <init>() -> <init>
void onReceive() -> a
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
java.lang.String TAG -> TAG
java.lang.String TAG2 -> TAG2
- void <clinit>() -> <clinit>
+ int h -> h
+ int i -> i
+ int i2 -> i2
+ int i3 -> i3
+ int j -> j
+ java.lang.Object o -> o
void <init>() -> <init>
- void keep() -> a
+ void keep() -> renamedKeep
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-022.txt b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-022.txt
index 5f9de20..0e236ab 100644
--- a/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-022.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test001/refsObfuscationWithMapping/expected-022.txt
@@ -1,61 +1,61 @@
-com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.e:
+com.android.jack.shrob.test001.jack.E -> com.android.jack.shrob.test001.jack.RenamedE:
void <init>() -> <init>
- void keep() -> a
-com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.i:
- void m() -> a
-com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.h:
-com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.j:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.I -> com.android.jack.shrob.test001.jack.RenamedI:
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.H -> com.android.jack.shrob.test001.jack.renamedH:
+com.android.jack.shrob.test001.jack.J -> com.android.jack.shrob.test001.jack.renamedJ:
void <init>() -> <init>
- int[][][] m5(int,boolean,long) -> a
- int[][][] m3() -> a
- int[][] m2() -> b
- int[] m1() -> c
- int m0() -> d
- int[][][] m() -> e
-com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.f:
+ int[][][] m() -> renamedM
+ int m0() -> renamedM0
+ int[] m1() -> renamedM1
+ int[][] m2() -> renamedM2
+ int[][][] m3() -> renamedM3
+ int[][][] m5(int,boolean,long) -> renamedM5
+com.android.jack.shrob.test001.jack.F -> com.android.jack.shrob.test001.jack.RenamedF:
void <init>() -> <init>
- void keep() -> a
-com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.b:
+ void keep() -> renamedKeep
+com.android.jack.shrob.test001.jack.B -> com.android.jack.shrob.test001.jack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.d:
+com.android.jack.shrob.test001.jack.D -> com.android.jack.shrob.test001.jack.RenamedD:
void <init>() -> <init>
- void keep() -> a
- void main(java.lang.String[]) -> a
- void main2(java.lang.String[]) -> b
-com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.g:
+ void keep() -> renamedKeep
+ void main(java.lang.String[]) -> renamedMain
+ void main2(java.lang.String[]) -> renamedMain2
+com.android.jack.shrob.test001.jack.G -> com.android.jack.shrob.test001.jack.RenamedG:
void <init>() -> <init>
- void m() -> a
- void main(java.lang.String[]) -> a
-com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.k:
+ void m() -> renamedM
+ void main(java.lang.String[]) -> renamedMain
+com.android.jack.shrob.test001.jack.Reflect -> com.android.jack.shrob.test001.jack.RenamedReflect:
void <init>() -> <init>
- void keep() -> a
- void keep2() -> b
- void keep3() -> c
- void keep4() -> d
- void keep5() -> e
- void keep6() -> f
- void keep7() -> g
- void keep8() -> h
-com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.c:
+ void keep() -> renamedKeep
+ void keep2() -> renamedKeep2
+ void keep3() -> renamedKeep3
+ void keep4() -> renamedKeep4
+ void keep5() -> renamedKeep5
+ void keep6() -> renamedKeep6
+ void keep7() -> renamedKeep7
+ void keep8() -> renamedKeep8
+com.android.jack.shrob.test001.jack.C -> com.android.jack.shrob.test001.jack.RenamedC:
void <init>() -> <init>
- void f() -> a
- void m() -> b
-com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.a:
- void <clinit>() -> <clinit>
+ void f() -> renamedF
+ void m() -> renamedM
+com.android.jack.shrob.test001.jack.A -> com.android.jack.shrob.test001.jack.RenamedA:
void <init>() -> <init>
void <init>(int) -> <init>
- void m() -> a
- void privateFunc() -> b
+ void m() -> renamedM
+ void privateFunc() -> renamedPrivateFunc
+ void <clinit>() -> <clinit>
com.android.jack.shrob.test001.jack.Reflect2 -> com.android.jack.shrob.test001.jack.Reflect2:
- int fieldPublic -> fieldPublic
- int fieldPrivate -> fieldPrivate
+ com.android.jack.shrob.test001.jack.Reflect2$A a -> a
+ com.android.jack.shrob.test001.jack.Reflect2$B b -> b
+ java.lang.Object c -> c
long fieldLong -> fieldLong
long fieldLong2 -> fieldLong2
long fieldLong3 -> fieldLong3
long fieldLong4 -> fieldLong4
- com.android.jack.shrob.test001.jack.Reflect2$A a -> a
- com.android.jack.shrob.test001.jack.Reflect2$B b -> b
- java.lang.Object c -> c
+ int fieldPrivate -> fieldPrivate
+ int fieldPublic -> fieldPublic
void <init>() -> <init>
void calledMethod() -> calledMethod
void m(com.android.jack.shrob.test001.jack.Reflect2$A) -> m
@@ -71,14 +71,14 @@
void <init>() -> <init>
void onReceive() -> onReceive
com.android.jack.shrob.test001.jack.K -> com.android.jack.shrob.test001.jack.K:
- int i -> i
- int h -> h
- int i2 -> i2
- int j -> j
- int i3 -> i3
- java.lang.Object o -> o
java.lang.String TAG -> TAG
java.lang.String TAG2 -> TAG2
- void <clinit>() -> <clinit>
+ int h -> h
+ int i -> i
+ int i2 -> i2
+ int i3 -> i3
+ int j -> j
+ java.lang.Object o -> o
void <init>() -> <init>
void keep() -> keep
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags002.mapping
deleted file mode 100644
index d184e76..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags002.mapping
+++ /dev/null
@@ -1 +0,0 @@
-com.android.jack.shrob.test002.jack.B -> com.android.jack.shrob.test002.jack.B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags003.mapping
deleted file mode 100644
index d184e76..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test002/proguard.flags003.mapping
+++ /dev/null
@@ -1 +0,0 @@
-com.android.jack.shrob.test002.jack.B -> com.android.jack.shrob.test002.jack.B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/info.txt b/jack-tests/tests/com/android/jack/shrob/test003/info.txt
new file mode 100644
index 0000000..ed6fc3d
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test003/info.txt
@@ -0,0 +1,3 @@
+This test was written to show the different behavior between using library jars or injars.
+The class in lib contains a Class.ForName with an existing class that should be kept when the
+lib is used as a injar.
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/lib/Test.class b/jack-tests/tests/com/android/jack/shrob/test003/lib/Test.class
new file mode 100644
index 0000000..bd9a8c9
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test003/lib/Test.class
Binary files differ
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags001.mapping
deleted file mode 100644
index f6b7dd6..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags001.mapping
+++ /dev/null
@@ -1 +0,0 @@
-com.android.jack.shrob.test003.jack.B -> com.android.jack.shrob.test003.jack.B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags002 b/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags002
new file mode 100644
index 0000000..320bdd0
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test003/proguard.flags002
@@ -0,0 +1,3 @@
+-keep class com.android.jack.shrob.test003.lib.Test {
+ void keep();
+}
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsFlattenPackage/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsFlattenPackage/expected-001.txt
deleted file mode 100644
index f231988..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/refsFlattenPackage/expected-001.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test003.jack.B -> com.android.jack.shrob.test003.jack.B:
- void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithMapping/expected-001.txt
deleted file mode 100644
index f231988..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithMapping/expected-001.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test003.jack.B -> com.android.jack.shrob.test003.jack.B:
- void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithoutMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithoutMapping/expected-001.txt
deleted file mode 100644
index f231988..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/refsObfuscationWithoutMapping/expected-001.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test003.jack.B -> com.android.jack.shrob.test003.jack.B:
- void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsRepackageClasses/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsRepackageClasses/expected-001.txt
deleted file mode 100644
index f231988..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/refsRepackageClasses/expected-001.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test003.jack.B -> com.android.jack.shrob.test003.jack.B:
- void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsSeed/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsSeed/expected-001.txt
deleted file mode 100644
index 90b2f3e..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/refsSeed/expected-001.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-com.android.jack.shrob.test003.jack.B
-com.android.jack.shrob.test003.lib.Test
-com.android.jack.shrob.test003.lib.Test: void keep()
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/refsShrinking/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test003/refsShrinking/expected-002.txt
new file mode 100644
index 0000000..d285e15
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test003/refsShrinking/expected-002.txt
@@ -0,0 +1,5 @@
+Lcom/android/jack/shrob/test003/jack/A;:
+<init>()V
+Lcom/android/jack/shrob/test003/lib/Test;:
+<init>()V
+keep()V
diff --git a/jack-tests/tests/com/android/jack/shrob/test003/test.jar b/jack-tests/tests/com/android/jack/shrob/test003/test.jar
deleted file mode 100644
index c05fa6b..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test003/test.jar
+++ /dev/null
Binary files differ
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags001.mapping
index 95418dc..73c2c28 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags001.mapping
@@ -1,2 +1,2 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
- void m() -> a
+ void m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags002.mapping
index 8441b1f..94a7eaf 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags002.mapping
@@ -1,3 +1,3 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
- void m() -> a
- void m2() -> b
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags003.mapping
index 8441b1f..94a7eaf 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags003.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test004/proguard.flags003.mapping
@@ -1,3 +1,3 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
- void m() -> a
- void m2() -> b
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-001.txt
index 3695723..dc8b051 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-001.txt
@@ -1,3 +1,3 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
void <init>() -> <init>
- void m() -> a
+ void m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-002.txt
index 6dd9c9b..e19d8c6 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-002.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
void <init>() -> <init>
void <init>(int) -> <init>
- void m() -> a
- void m2() -> b
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-003.txt b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-003.txt
index 6dd9c9b..e19d8c6 100644
--- a/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-003.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test004/refsObfuscationWithMapping/expected-003.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test004.jack.A -> com.android.jack.shrob.test004.jack.A:
void <init>() -> <init>
void <init>(int) -> <init>
- void m() -> a
- void m2() -> b
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags001.mapping
index d1ece21..5cd97ea 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags001.mapping
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
\ No newline at end of file
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags002.mapping
index ef90650..5cd97ea 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags002.mapping
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags003.mapping
index d1ece21..5cd97ea 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags003.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags003.mapping
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
\ No newline at end of file
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags004.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags004.mapping
deleted file mode 100644
index a01062b..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags004.mapping
+++ /dev/null
@@ -1 +0,0 @@
-com.android.jack.shrob.test005.jack.Annot -> com.android.jack.shrob.test005.jack.Annot:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags005.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags005.mapping
index 83f2fad..86e6525 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags005.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags005.mapping
@@ -1,13 +1,13 @@
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.b:
- int intValue() -> a
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.d:
-com.android.jack.shrob.test005.jack.C -> a.a.a.a.a.a.e:
-com.android.jack.shrob.test005.jack.E -> a.a.a.a.a.a.f:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> d
- com.android.jack.shrob.test005.jack.E valueOf(java.lang.String) -> a
- com.android.jack.shrob.test005.jack.E[] values() -> b
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+ int intValue() -> renamedIntValue
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
+com.android.jack.shrob.test005.jack.C -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedC:
+com.android.jack.shrob.test005.jack.E -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedE:
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
+ com.android.jack.shrob.test005.jack.E valueOf(java.lang.String) -> renamedValueOf
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags006.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags006.mapping
index 2fe0e72..0a24e15 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags006.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags006.mapping
@@ -1,10 +1,6 @@
-com.android.jack.shrob.test005.jack.A -> com.android.jack.shrob.test005.jack.A:
-com.android.jack.shrob.test005.jack.Annot -> com.android.jack.shrob.test005.jack.Annot:
-com.android.jack.shrob.test005.jack.Annot2 -> com.android.jack.shrob.test005.jack.Annot2:
-com.android.jack.shrob.test005.jack.B -> com.android.jack.shrob.test005.jack.B:
-com.android.jack.shrob.test005.jack.C -> com.android.jack.shrob.test005.jack.C:
com.android.jack.shrob.test005.jack.E -> com.android.jack.shrob.test005.jack.E:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> e
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags007.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags007.mapping
deleted file mode 100644
index 8692631..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags007.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test005.jack.Annot -> com.android.jack.shrob.test005.jack.Annot:
-com.android.jack.shrob.test005.jack.Annot2 -> com.android.jack.shrob.test005.jack.Annot2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags008.mapping b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags008.mapping
index 4808055..0a24e15 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags008.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test005/proguard.flags008.mapping
@@ -1,5 +1,6 @@
com.android.jack.shrob.test005.jack.E -> com.android.jack.shrob.test005.jack.E:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> e
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-001.txt
index d31f1cf..a9c9020 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-001.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-002.txt
index d31f1cf..a9c9020 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-002.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-003.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-003.txt
index d31f1cf..a9c9020 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-003.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-003.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.c:
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.b:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.d:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-005.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-005.txt
index 38f0380..fded0e5 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-005.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-005.txt
@@ -1,18 +1,18 @@
-com.android.jack.shrob.test005.jack.Annot -> a.a.a.a.a.a.b:
- int intValue() -> a
-com.android.jack.shrob.test005.jack.E -> a.a.a.a.a.a.f:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> d
- void <clinit>() -> <clinit>
- com.android.jack.shrob.test005.jack.E valueOf(java.lang.String) -> a
- com.android.jack.shrob.test005.jack.E[] values() -> b
+com.android.jack.shrob.test005.jack.Annot -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot:
+ int intValue() -> renamedIntValue
+com.android.jack.shrob.test005.jack.E -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedE:
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
void <init>(java.lang.String,int) -> <init>
-com.android.jack.shrob.test005.jack.A -> a.a.a.a.a.a.a:
+ com.android.jack.shrob.test005.jack.E valueOf(java.lang.String) -> renamedValueOf
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
+ void <clinit>() -> <clinit>
+com.android.jack.shrob.test005.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.B -> a.a.a.a.a.a.d:
+com.android.jack.shrob.test005.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.C -> a.a.a.a.a.a.e:
+com.android.jack.shrob.test005.jack.C -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedC:
void <init>() -> <init>
-com.android.jack.shrob.test005.jack.Annot2 -> a.a.a.a.a.a.c:
+com.android.jack.shrob.test005.jack.Annot2 -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest005.renamedJack.RenamedAnnot2:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-006.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-006.txt
index 35a7a05..b2a5fa4 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-006.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-006.txt
@@ -1,12 +1,12 @@
com.android.jack.shrob.test005.jack.Annot -> com.android.jack.shrob.test005.jack.Annot:
com.android.jack.shrob.test005.jack.E -> com.android.jack.shrob.test005.jack.E:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> e
- com.android.jack.shrob.test005.jack.E[] values() -> a
- void <clinit>() -> <clinit>
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
void <init>(java.lang.String,int) -> <init>
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
+ void <clinit>() -> <clinit>
com.android.jack.shrob.test005.jack.A -> com.android.jack.shrob.test005.jack.A:
void <init>() -> <init>
com.android.jack.shrob.test005.jack.B -> com.android.jack.shrob.test005.jack.B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-008.txt b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-008.txt
index 723de19..99f600a 100644
--- a/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-008.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test005/refsObfuscationWithMapping/expected-008.txt
@@ -1,8 +1,8 @@
com.android.jack.shrob.test005.jack.E -> com.android.jack.shrob.test005.jack.E:
- com.android.jack.shrob.test005.jack.E A -> a
- com.android.jack.shrob.test005.jack.E B -> b
- com.android.jack.shrob.test005.jack.E C -> c
- com.android.jack.shrob.test005.jack.E[] $VALUES -> e
- com.android.jack.shrob.test005.jack.E[] values() -> a
- void <clinit>() -> <clinit>
+ com.android.jack.shrob.test005.jack.E A -> renamedA
+ com.android.jack.shrob.test005.jack.E B -> renamedB
+ com.android.jack.shrob.test005.jack.E C -> renamedC
+ com.android.jack.shrob.test005.jack.E[] $VALUES -> renamed$VALUES
void <init>(java.lang.String,int) -> <init>
+ com.android.jack.shrob.test005.jack.E[] values() -> renamedValues
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags001.mapping
deleted file mode 100644
index 2be876c..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags001.mapping
+++ /dev/null
@@ -1,4 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m1() -> m1
- void m4() -> m4
- void m5(java.lang.String[]) -> m5
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags002.mapping
deleted file mode 100644
index 542bff4..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags002.mapping
+++ /dev/null
@@ -1,4 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m() -> m
- void m2() -> m2
- int m8() -> m8
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags003.mapping
deleted file mode 100644
index 4aff1a6..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags003.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m5(java.lang.String[]) -> m5
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags004.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags004.mapping
deleted file mode 100644
index d7ecf53..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags004.mapping
+++ /dev/null
@@ -1,3 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m6() -> m6
- void m7() -> m7
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags005.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags005.mapping
deleted file mode 100644
index e215817..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags005.mapping
+++ /dev/null
@@ -1,5 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m() -> m
- void m2() -> m2
- void m6() -> m6
- int m8() -> m8
diff --git a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags006.mapping b/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags006.mapping
deleted file mode 100644
index 96b4c9d..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test006/proguard.flags006.mapping
+++ /dev/null
@@ -1,5 +0,0 @@
-com.android.jack.shrob.test006.jack.A -> com.android.jack.shrob.test006.jack.A:
- void m1() -> m1
- void m3() -> m3
- void m4() -> m4
- void m5(java.lang.String[]) -> m5
diff --git a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags001.mapping
deleted file mode 100644
index a420b6c..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags001.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test007.jack.A -> com.android.jack.shrob.test007.jack.A:
- java.lang.Object getObject() -> getObject
diff --git a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags002.mapping
deleted file mode 100644
index d0a31d4..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags002.mapping
+++ /dev/null
@@ -1,4 +0,0 @@
-com.android.jack.shrob.test007.jack.A -> com.android.jack.shrob.test007.jack.A:
- java.lang.Object getObject() -> getObject
- float getFloat() -> getFloat
- java.lang.Object[] getObjects() -> getObjects
diff --git a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags003.mapping
deleted file mode 100644
index b01ae59..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test007/proguard.flags003.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test007.jack.A -> com.android.jack.shrob.test007.jack.A:
- float getFloat() -> getFloat
diff --git a/jack-tests/tests/com/android/jack/shrob/test007/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test007/refsObfuscationWithMapping/expected-002.txt
index 03e309f..12bf267 100644
--- a/jack-tests/tests/com/android/jack/shrob/test007/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test007/refsObfuscationWithMapping/expected-002.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test007.jack.A -> com.android.jack.shrob.test007.jack.A:
void <init>() -> <init>
- java.lang.Object getObject() -> getObject
float getFloat() -> getFloat
+ java.lang.Object getObject() -> getObject
java.lang.Object[] getObjects() -> getObjects
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags001.mapping
index 2b32885..b97a198 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags001.mapping
@@ -1,4 +1,3 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
- void m() -> a
- void keep() -> keep
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags002.mapping
index a10fae7..b97a198 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags002.mapping
@@ -1,4 +1,3 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
- void m() -> a
- void keep2() -> keep2
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags003.mapping
index b8617a4..b97a198 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags003.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags003.mapping
@@ -1,4 +1,3 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
- void m() -> a
- void keep3() -> keep3
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags004.mapping b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags004.mapping
index c2a969a..29a3a97 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags004.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test008/proguard.flags004.mapping
@@ -1,3 +1 @@
-com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
- void keep4() -> keep4
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-001.txt
index d4eae97..3327d44 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-001.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
void <init>() -> <init>
- void m() -> a
void keep() -> keep
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-002.txt
index 6fc69ba..422da79 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-002.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
void <init>() -> <init>
- void m() -> a
void keep2() -> keep2
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-003.txt b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-003.txt
index d9bde3b..bf98e39 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-003.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-003.txt
@@ -1,6 +1,6 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
void <init>() -> <init>
- void m() -> a
void keep3() -> keep3
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+ void m() -> renamedM
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-004.txt b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-004.txt
index 8f3f534..376accb 100644
--- a/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-004.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test008/refsObfuscationWithMapping/expected-004.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test008.jack.A -> com.android.jack.shrob.test008.jack.A:
void <init>() -> <init>
void keep4() -> keep4
-com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.a:
+com.android.jack.shrob.test008.jack.MyException -> com.android.jack.shrob.test008.jack.RenamedMyException:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags001.mapping
deleted file mode 100644
index 900362c..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags001.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test009.jack.A -> com.android.jack.shrob.test009.jack.A:
- void m(int,boolean,float,long) -> m
diff --git a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags002.mapping
deleted file mode 100644
index 900362c..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags002.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test009.jack.A -> com.android.jack.shrob.test009.jack.A:
- void m(int,boolean,float,long) -> m
diff --git a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003.mapping
deleted file mode 100644
index 900362c..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test009.jack.A -> com.android.jack.shrob.test009.jack.A:
- void m(int,boolean,float,long) -> m
diff --git a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags001.mapping
index fb83ecd..40d45af 100644
--- a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags001.mapping
@@ -1,2 +1 @@
-com.android.jack.shrob.test010.jack.B -> com.android.jack.shrob.test010.jack.B:
- void keep() -> keep
+com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.RenamedA:
diff --git a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags002.mapping
deleted file mode 100644
index c66dc7a..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags002.mapping
+++ /dev/null
@@ -1,3 +0,0 @@
-com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.A:
- java.lang.Object get() -> get
- void set(java.lang.Object) -> set
diff --git a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags003.mapping b/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags003.mapping
index 6829e58..e32b485 100644
--- a/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags003.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test010/proguard.flags003.mapping
@@ -1,4 +1 @@
-com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.A:
- java.lang.Object get() -> get
- void set(com.android.jack.shrob.test010.jack.C) -> set
-com.android.jack.shrob.test010.jack.C -> com.android.jack.shrob.test010.jack.a:
+com.android.jack.shrob.test010.jack.C -> com.android.jack.shrob.test010.jack.RenamedC:
diff --git a/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-001.txt
index 370e43e..698145e 100644
--- a/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test010.jack.B -> com.android.jack.shrob.test010.jack.B:
void <init>() -> <init>
void keep() -> keep
-com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.a:
+com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.RenamedA:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-003.txt b/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-003.txt
index 415214d..92c67ea 100644
--- a/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-003.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test010/refsObfuscationWithMapping/expected-003.txt
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test010.jack.C -> com.android.jack.shrob.test010.jack.a:
+com.android.jack.shrob.test010.jack.C -> com.android.jack.shrob.test010.jack.RenamedC:
void <init>() -> <init>
com.android.jack.shrob.test010.jack.A -> com.android.jack.shrob.test010.jack.A:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags001.mapping
index 20cd8cd..cfd70e5 100644
--- a/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags001.mapping
@@ -1,3 +1,2 @@
-com.android.jack.shrob.test011.jack.A -> com.android.jack.shrob.test011.jack.A:
- java.lang.Object keep1() -> keep1
-com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.a:
+com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.RenamedB:
+com.android.jack.shrob.test011.jack.C -> com.android.jack.shrob.test011.jack.RenamedC:
diff --git a/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags002.mapping
index b4d6638..b14d9cd 100644
--- a/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test011/proguard.flags002.mapping
@@ -1,4 +1,2 @@
-com.android.jack.shrob.test011.jack.A -> com.android.jack.shrob.test011.jack.A:
- int keep2() -> keep2
-com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.a:
- int value() -> a
+com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.RenamedB:
+ int value() -> renamedValue
diff --git a/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-001.txt
index 4b930bf..681f4ba 100644
--- a/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-001.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.a:
+com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test011.jack.C -> com.android.jack.shrob.test011.jack.b:
+com.android.jack.shrob.test011.jack.C -> com.android.jack.shrob.test011.jack.RenamedC:
void <init>() -> <init>
com.android.jack.shrob.test011.jack.A -> com.android.jack.shrob.test011.jack.A:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-002.txt
index a1dd7bc..7365948 100644
--- a/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test011/refsObfuscationWithMapping/expected-002.txt
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.a:
+com.android.jack.shrob.test011.jack.B -> com.android.jack.shrob.test011.jack.RenamedB:
void <init>() -> <init>
- int value() -> a
+ int value() -> renamedValue
com.android.jack.shrob.test011.jack.A -> com.android.jack.shrob.test011.jack.A:
void <init>() -> <init>
int keep2() -> keep2
diff --git a/jack-tests/tests/com/android/jack/shrob/test012/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test012/proguard.flags001.mapping
deleted file mode 100644
index 904d812..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test012/proguard.flags001.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test012.jack.A -> com.android.jack.shrob.test012.jack.A:
- void m(com.android.jack.shrob.test012.jack.A) -> m
diff --git a/jack-tests/tests/com/android/jack/shrob/test013/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test013/proguard.flags001.mapping
deleted file mode 100644
index 053e592..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test013/proguard.flags001.mapping
+++ /dev/null
@@ -1,2 +0,0 @@
-com.android.jack.shrob.test013.jack.A -> com.android.jack.shrob.test013.jack.A:
- 26:26:void m(com.android.jack.shrob.test013.jack.A) -> m
diff --git a/jack-tests/tests/com/android/jack/shrob/test014/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test014/proguard.flags001.mapping
index 9cede76..9bd0a54 100644
--- a/jack-tests/tests/com/android/jack/shrob/test014/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test014/proguard.flags001.mapping
@@ -1,18 +1,16 @@
com.android.jack.shrob.test014.jack.A -> com.android.jack.shrob.test014.jack.A:
- int a -> a
- int m -> b
- boolean b -> c
- void m() -> b
- void f() -> c
- void m(int) -> a
- void g() -> d
- void keep() -> keep
+ int a -> renamedA
+ int m -> renamedM
+ boolean b -> renamedB
+ void m() -> renamedM
+ void f() -> renamedF
+ void m(int) -> renamedM
+ void g() -> renamedG
com.android.jack.shrob.test014.jack.B -> com.android.jack.shrob.test014.jack.B:
- char c -> d
- boolean m -> e
- void a() -> a
- void r() -> e
- void m() -> b
- void l() -> f
- void m(int) -> a
- void keep() -> keep
+ char c -> renamedC
+ boolean m -> renamedM
+ void a() -> renamedA
+ void r() -> renamedR
+ void m() -> renamedM
+ void l() -> renamedL
+ void m(int) -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test014/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test014/refsObfuscationWithMapping/expected-001.txt
index 1572c2d..0790e02 100644
--- a/jack-tests/tests/com/android/jack/shrob/test014/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test014/refsObfuscationWithMapping/expected-001.txt
@@ -1,20 +1,20 @@
com.android.jack.shrob.test014.jack.B -> com.android.jack.shrob.test014.jack.B:
- char c -> d
- boolean m -> e
+ char c -> renamedC
+ boolean m -> renamedM
void <init>() -> <init>
- void a() -> a
- void r() -> e
- void m() -> b
- void l() -> f
- void m(int) -> a
+ void a() -> renamedA
void keep() -> keep
+ void l() -> renamedL
+ void m() -> renamedM
+ void m(int) -> renamedM
+ void r() -> renamedR
com.android.jack.shrob.test014.jack.A -> com.android.jack.shrob.test014.jack.A:
- int a -> a
- int m -> b
- boolean b -> c
+ int a -> renamedA
+ boolean b -> renamedB
+ int m -> renamedM
void <init>() -> <init>
- void m() -> b
- void f() -> c
- void m(int) -> a
- void g() -> d
+ void f() -> renamedF
+ void g() -> renamedG
void keep() -> keep
+ void m() -> renamedM
+ void m(int) -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test015/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test015/proguard.flags001.mapping
index 83bfd4a..76594dd 100644
--- a/jack-tests/tests/com/android/jack/shrob/test015/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test015/proguard.flags001.mapping
@@ -1,6 +1,6 @@
-com.android.jack.shrob.test015.jack.A -> a.a.a.a.a.a.a:
- 23:23:com.android.jack.shrob.test015.jack.B m() -> a
- 28:28:void m(com.android.jack.shrob.test015.jack.A) -> a
-com.android.jack.shrob.test015.jack.A$I -> a.a.a.a.a.a.a$a:
-com.android.jack.shrob.test015.jack.A$J -> a.a.a.a.a.a.a$b:
-com.android.jack.shrob.test015.jack.B -> a.a.a.a.a.a.b:
+com.android.jack.shrob.test015.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA:
+ 23:23:com.android.jack.shrob.test015.jack.B m() -> renamedM
+ 28:28:void m(com.android.jack.shrob.test015.jack.A) -> renamedM
+com.android.jack.shrob.test015.jack.A$I -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA$I:
+com.android.jack.shrob.test015.jack.A$J -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA$J:
+com.android.jack.shrob.test015.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedB:
diff --git a/jack-tests/tests/com/android/jack/shrob/test015/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test015/refsObfuscationWithMapping/expected-001.txt
index 41f353e..4f187a6 100644
--- a/jack-tests/tests/com/android/jack/shrob/test015/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test015/refsObfuscationWithMapping/expected-001.txt
@@ -1,8 +1,8 @@
-com.android.jack.shrob.test015.jack.B -> a.a.a.a.a.a.b:
+com.android.jack.shrob.test015.jack.B -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedB:
void <init>() -> <init>
-com.android.jack.shrob.test015.jack.A -> a.a.a.a.a.a.a:
+com.android.jack.shrob.test015.jack.A -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA:
void <init>() -> <init>
- com.android.jack.shrob.test015.jack.B m() -> a
- void m(com.android.jack.shrob.test015.jack.A) -> a
-com.android.jack.shrob.test015.jack.A$I -> a.a.a.a.a.a.a$a:
-com.android.jack.shrob.test015.jack.A$J -> a.a.a.a.a.a.a$b:
+ com.android.jack.shrob.test015.jack.B m() -> renamedM
+ void m(com.android.jack.shrob.test015.jack.A) -> renamedM
+com.android.jack.shrob.test015.jack.A$I -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA$I:
+com.android.jack.shrob.test015.jack.A$J -> renamedCom.renamedAndroid.renamedJack.renamedShrob.renamedTest015.renamedJack.RenamedA$J:
diff --git a/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags001.mapping
index 2a96f6c..74ff488 100644
--- a/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags001.mapping
@@ -1,17 +1,22 @@
-com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.a:
-com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.b:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.c:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.d:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.e:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.f:
- java.lang.String value() -> value
+com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.RenamedAnnot:
+ java.lang.String value() -> renamedValue
com.android.jack.shrob.test016.jack.KeepClass -> com.android.jack.shrob.test016.jack.KeepClass:
- java.lang.String value() -> value
- java.lang.String value2() -> value2
- java.lang.String value3() -> value3
- java.lang.String value4() -> value4
- java.lang.String value5() -> value5
\ No newline at end of file
+ void <init>() -> <init>
+ java.lang.String value() -> renamedValue
+ java.lang.String value2() -> renamedValue2
+ java.lang.String value3() -> renamedValue3
+ java.lang.String value4() -> renamedValue4
+ java.lang.String value5() -> renamedValue5
+ java.lang.String value6() -> renamedValue6
+ java.lang.String value7() -> renamedValue7
+ java.lang.String value8() -> renamedValue8
+ java.lang.String value9() -> renamedValue9
+com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.RenamedAnnot4:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.RenamedAnnot5:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.RenamedA:
+com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.RenamedAnnot2:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.RenamedAnnot3:
+ java.lang.String value() -> renamedValue
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags002.mapping b/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags002.mapping
index 64c97e9..a7ca2bf 100644
--- a/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags002.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test016/proguard.flags002.mapping
@@ -1,21 +1,21 @@
-com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.a:
-com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.b:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.c:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.d:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.e:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.f:
- java.lang.String value() -> a
+com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.RenamedA:
+com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.RenamedAnnot:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.RenamedAnnot2:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.RenamedAnnot3:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.RenamedAnnot4:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.RenamedAnnot5:
+ java.lang.String value() -> renamedValue
com.android.jack.shrob.test016.jack.KeepClass -> com.android.jack.shrob.test016.jack.KeepClass:
- java.lang.String value() -> a
- java.lang.String value2() -> b
- java.lang.String value3() -> c
- java.lang.String value4() -> d
- java.lang.String value5() -> e
- java.lang.String value6() -> f
- java.lang.String value7() -> g
- java.lang.String value8() -> h
- java.lang.String value9() -> i
\ No newline at end of file
+ java.lang.String value() -> renamedValue
+ java.lang.String value2() -> renamedValue2
+ java.lang.String value3() -> renamedValue3
+ java.lang.String value4() -> renamedValue4
+ java.lang.String value5() -> renamedValue5
+ java.lang.String value6() -> renamedValue6
+ java.lang.String value7() -> renamedValue7
+ java.lang.String value8() -> renamedValue8
+ java.lang.String value9() -> renamedValue9
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-001.txt
index 3eb5acf..bc4aa5c 100644
--- a/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-001.txt
@@ -1,23 +1,23 @@
-com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.b:
- java.lang.String value() -> value
+com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.RenamedAnnot:
+ java.lang.String value() -> renamedValue
com.android.jack.shrob.test016.jack.KeepClass -> com.android.jack.shrob.test016.jack.KeepClass:
void <init>() -> <init>
- java.lang.String value() -> value
- java.lang.String value2() -> value2
- java.lang.String value3() -> value3
- java.lang.String value4() -> value4
- java.lang.String value5() -> value5
- java.lang.String value6() -> value6
- java.lang.String value7() -> value7
- java.lang.String value8() -> value8
- java.lang.String value9() -> value9
-com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.e:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.f:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.a:
+ java.lang.String value() -> renamedValue
+ java.lang.String value2() -> renamedValue2
+ java.lang.String value3() -> renamedValue3
+ java.lang.String value4() -> renamedValue4
+ java.lang.String value5() -> renamedValue5
+ java.lang.String value6() -> renamedValue6
+ java.lang.String value7() -> renamedValue7
+ java.lang.String value8() -> renamedValue8
+ java.lang.String value9() -> renamedValue9
+com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.RenamedAnnot4:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.RenamedAnnot5:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.c:
- java.lang.String value() -> value
-com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.d:
- java.lang.String value() -> value
+com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.RenamedAnnot2:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.RenamedAnnot3:
+ java.lang.String value() -> renamedValue
diff --git a/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-002.txt b/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-002.txt
index cb9d1db..bc4aa5c 100644
--- a/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-002.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test016/refsObfuscationWithMapping/expected-002.txt
@@ -1,23 +1,23 @@
-com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.b:
- java.lang.String value() -> a
+com.android.jack.shrob.test016.jack.Annot -> com.android.jack.shrob.test016.jack.RenamedAnnot:
+ java.lang.String value() -> renamedValue
com.android.jack.shrob.test016.jack.KeepClass -> com.android.jack.shrob.test016.jack.KeepClass:
void <init>() -> <init>
- java.lang.String value() -> a
- java.lang.String value2() -> b
- java.lang.String value3() -> c
- java.lang.String value4() -> d
- java.lang.String value5() -> e
- java.lang.String value6() -> f
- java.lang.String value7() -> g
- java.lang.String value8() -> h
- java.lang.String value9() -> i
-com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.e:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.f:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.a:
+ java.lang.String value() -> renamedValue
+ java.lang.String value2() -> renamedValue2
+ java.lang.String value3() -> renamedValue3
+ java.lang.String value4() -> renamedValue4
+ java.lang.String value5() -> renamedValue5
+ java.lang.String value6() -> renamedValue6
+ java.lang.String value7() -> renamedValue7
+ java.lang.String value8() -> renamedValue8
+ java.lang.String value9() -> renamedValue9
+com.android.jack.shrob.test016.jack.Annot4 -> com.android.jack.shrob.test016.jack.RenamedAnnot4:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot5 -> com.android.jack.shrob.test016.jack.RenamedAnnot5:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.A -> com.android.jack.shrob.test016.jack.RenamedA:
void <init>() -> <init>
-com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.c:
- java.lang.String value() -> a
-com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.d:
- java.lang.String value() -> a
+com.android.jack.shrob.test016.jack.Annot2 -> com.android.jack.shrob.test016.jack.RenamedAnnot2:
+ java.lang.String value() -> renamedValue
+com.android.jack.shrob.test016.jack.Annot3 -> com.android.jack.shrob.test016.jack.RenamedAnnot3:
+ java.lang.String value() -> renamedValue
diff --git a/jack-tests/tests/com/android/jack/shrob/test017/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test017/proguard.flags001.mapping
index 602f21a..135648c 100644
--- a/jack-tests/tests/com/android/jack/shrob/test017/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test017/proguard.flags001.mapping
@@ -1,10 +1,10 @@
-com.android.jack.shrob.test017.jack.Reflect2 -> com.android.jack.shrob.test017.jack.a:
-com.android.jack.shrob.test017.jack.Reflect2$A -> com.android.jack.shrob.test017.jack.b:
-com.android.jack.shrob.test017.jack.Reflect2$B -> com.android.jack.shrob.test017.jack.c:
-com.android.jack.shrob.test017.jack.Reflect3 -> com.android.jack.shrob.test017.jack.d:
- int fieldPublic -> a
- long fieldLong -> b
- long fieldLong3 -> c
- long fieldLong4 -> d
- com.android.jack.shrob.test017.jack.Reflect2$A a -> e
- 47:47:void m(com.android.jack.shrob.test017.jack.Reflect2$A) -> a
\ No newline at end of file
+com.android.jack.shrob.test017.jack.Reflect2 -> com.android.jack.shrob.test017.jack.RenamedReflect2:
+com.android.jack.shrob.test017.jack.Reflect2$A -> com.android.jack.shrob.test017.jack.RenamedReflect2$A:
+com.android.jack.shrob.test017.jack.Reflect2$B -> com.android.jack.shrob.test017.jack.RenamedReflect2$B:
+com.android.jack.shrob.test017.jack.Reflect3 -> com.android.jack.shrob.test017.jack.RenamedReflect3:
+ int fieldPublic -> renamedFieldPublic
+ long fieldLong -> renamedFieldLong
+ long fieldLong3 -> renamedFieldLong3
+ long fieldLong4 -> renamedFieldLong4
+ com.android.jack.shrob.test017.jack.Reflect2$A a -> renamedA
+ 47:47:void m(com.android.jack.shrob.test017.jack.Reflect2$A) -> renamedM
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test017/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test017/refsObfuscationWithMapping/expected-001.txt
index b393f13..8e97b63 100644
--- a/jack-tests/tests/com/android/jack/shrob/test017/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test017/refsObfuscationWithMapping/expected-001.txt
@@ -4,11 +4,11 @@
void keep3() -> keep3
void keep4() -> keep4
void keep5() -> keep5
-com.android.jack.shrob.test017.jack.Reflect3 -> com.android.jack.shrob.test017.jack.d:
- int fieldPublic -> a
+com.android.jack.shrob.test017.jack.Reflect3 -> com.android.jack.shrob.test017.jack.RenamedReflect3:
+ int fieldPublic -> renamedFieldPublic
void <init>() -> <init>
- void m(com.android.jack.shrob.test017.jack.Reflect2$A) -> a
-com.android.jack.shrob.test017.jack.Reflect2 -> com.android.jack.shrob.test017.jack.a:
+ void m(com.android.jack.shrob.test017.jack.Reflect2$A) -> renamedM
+com.android.jack.shrob.test017.jack.Reflect2 -> com.android.jack.shrob.test017.jack.RenamedReflect2:
void <init>() -> <init>
-com.android.jack.shrob.test017.jack.Reflect2$A -> com.android.jack.shrob.test017.jack.b:
-com.android.jack.shrob.test017.jack.Reflect2$B -> com.android.jack.shrob.test017.jack.c:
+com.android.jack.shrob.test017.jack.Reflect2$A -> com.android.jack.shrob.test017.jack.RenamedReflect2$A:
+com.android.jack.shrob.test017.jack.Reflect2$B -> com.android.jack.shrob.test017.jack.RenamedReflect2$B:
diff --git a/jack-tests/tests/com/android/jack/shrob/test019/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test019/refsObfuscationWithMapping/expected-001.txt
index b108b6f..3d3e14e 100644
--- a/jack-tests/tests/com/android/jack/shrob/test019/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test019/refsObfuscationWithMapping/expected-001.txt
@@ -4,7 +4,7 @@
void <init>() -> <init>
com.android.jack.shrob.test019.jack.B$C$Inner4 -> com.android.jack.shrob.test019.jack.B$C$Inner4:
void <init>() -> <init>
-com.android.jack.shrob.test019.jack.B$E -> com.android.jack.shrob.test019.jack.a:
+com.android.jack.shrob.test019.jack.B$E -> com.android.jack.shrob.test019.jack.RenamedB$E:
void <init>() -> <init>
com.android.jack.shrob.test019.jack.B$E$1 -> com.android.jack.shrob.test019.jack.B$E$1:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test021/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test021/proguard.flags001.mapping
new file mode 100644
index 0000000..14597dc
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test021/proguard.flags001.mapping
@@ -0,0 +1,2 @@
+com.android.jack.shrob.test021.jack.Shrob021$KeptInterface -> com.android.jack.shrob.test021.jack.RenamedShrob021$KeptInterface:
+ void interfaceMethod() -> renamedInterfaceMethod
diff --git a/jack-tests/tests/com/android/jack/shrob/test021/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test021/refsObfuscationWithMapping/expected-001.txt
index 9e8e7d8..a923f0f 100644
--- a/jack-tests/tests/com/android/jack/shrob/test021/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test021/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test021.jack.Shrob021 -> com.android.jack.shrob.test021.jack.Shrob021:
void <init>() -> <init>
int toKeep() -> toKeep
-com.android.jack.shrob.test021.jack.Shrob021$KeptInterface -> com.android.jack.shrob.test021.jack.a:
- void interfaceMethod() -> a
+com.android.jack.shrob.test021.jack.Shrob021$KeptInterface -> com.android.jack.shrob.test021.jack.RenamedShrob021$KeptInterface:
+ void interfaceMethod() -> renamedInterfaceMethod
diff --git a/jack-tests/tests/com/android/jack/shrob/test022/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test022/proguard.flags001.mapping
new file mode 100644
index 0000000..7ce5a1d
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test022/proguard.flags001.mapping
@@ -0,0 +1 @@
+com.android.jack.shrob.test022.jack.AbstractClass -> com.android.jack.shrob.test022.jack.RenamedAbstractClass:
diff --git a/jack-tests/tests/com/android/jack/shrob/test022/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test022/refsObfuscationWithMapping/expected-001.txt
index c0c3b70..21d2582 100644
--- a/jack-tests/tests/com/android/jack/shrob/test022/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test022/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test022.jack.Shrob022 -> com.android.jack.shrob.test022.jack.Shrob022:
void <init>() -> <init>
void method() -> method
-com.android.jack.shrob.test022.jack.AbstractClass -> com.android.jack.shrob.test022.jack.a:
+com.android.jack.shrob.test022.jack.AbstractClass -> com.android.jack.shrob.test022.jack.RenamedAbstractClass:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test023/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test023/proguard.flags001.mapping
new file mode 100644
index 0000000..b5eb082
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test023/proguard.flags001.mapping
@@ -0,0 +1,3 @@
+com.android.jack.shrob.test023.jack.Outer$Inner -> com.android.jack.shrob.test023.jack.Outer$Inner:
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test023/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test023/refsObfuscationWithMapping/expected-001.txt
index c3debfc..ae96dbb 100644
--- a/jack-tests/tests/com/android/jack/shrob/test023/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test023/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test023.jack.Outer$Inner -> com.android.jack.shrob.test023.jack.Outer$Inner:
void <init>() -> <init>
void <init>(int) -> <init>
- void m() -> a
- void m2() -> b
+ void m() -> renamedM
+ void m2() -> renamedM2
diff --git a/jack-tests/tests/com/android/jack/shrob/test025/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test025/refsObfuscationWithMapping/expected-001.txt
index c297699..0072c41 100644
--- a/jack-tests/tests/com/android/jack/shrob/test025/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test025/refsObfuscationWithMapping/expected-001.txt
@@ -1,7 +1,7 @@
com.android.jack.shrob.test025.jack.Keep -> com.android.jack.shrob.test025.jack.Keep:
void <init>() -> <init>
- java.lang.String m(java.lang.String) -> m
java.lang.String keep() -> keep
+ java.lang.String m(java.lang.String) -> m
com.android.jack.shrob.test025.jack.A$I -> com.android.jack.shrob.test025.jack.A$I:
com.android.jack.shrob.test025.jack.A$I2 -> com.android.jack.shrob.test025.jack.A$I2:
java.lang.String s -> s
diff --git a/jack-tests/tests/com/android/jack/shrob/test026/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test026/proguard.flags001.mapping
new file mode 100644
index 0000000..5a7008f
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test026/proguard.flags001.mapping
@@ -0,0 +1,2 @@
+com.android.jack.shrob.test026.jack.Enum -> com.android.jack.shrob.test026.jack.Enum:
+ com.android.jack.shrob.test026.jack.Enum[] $VALUES -> renamed$VALUES
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test026/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test026/refsObfuscationWithMapping/expected-001.txt
index c64557f..f41d8e6 100644
--- a/jack-tests/tests/com/android/jack/shrob/test026/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test026/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test026.jack.Enum -> com.android.jack.shrob.test026.jack.Enum:
- com.android.jack.shrob.test026.jack.Enum[] $VALUES -> a
- void <clinit>() -> <clinit>
+ com.android.jack.shrob.test026.jack.Enum[] $VALUES -> renamed$VALUES
com.android.jack.shrob.test026.jack.Enum valueOf(java.lang.String) -> valueOf
com.android.jack.shrob.test026.jack.Enum[] values() -> values
+ void <clinit>() -> <clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.class b/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.class
deleted file mode 100644
index be729ee..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.class
+++ /dev/null
Binary files differ
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.java b/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.java
deleted file mode 100644
index 2b797c9..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test027/lib/ForName.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.jack.shrob.test027.lib;
-
-public class ForName {
- public static Class<?> keptMethod() throws ClassNotFoundException {
- return Class.forName("com.android.jack.shrob.test027.jack.A");
- }
-}
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/proguard.flags001 b/jack-tests/tests/com/android/jack/shrob/test027/proguard.flags001
deleted file mode 100644
index 0be8a6a..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test027/proguard.flags001
+++ /dev/null
@@ -1,3 +0,0 @@
--keep class **.ForName {
- *;
-}
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test027/refsShrinking/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test027/refsShrinking/expected-001.txt
deleted file mode 100644
index 8525ee8..0000000
--- a/jack-tests/tests/com/android/jack/shrob/test027/refsShrinking/expected-001.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Lcom/android/jack/shrob/test027/jack/A;:
-<init>()V
-Lcom/android/jack/shrob/test027/lib/ForName;:
-<init>()V
-keptMethod()Ljava/lang/Class;
diff --git a/jack-tests/tests/com/android/jack/shrob/test029/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test029/proguard.flags001.mapping
index 11178a1..4d69ede 100644
--- a/jack-tests/tests/com/android/jack/shrob/test029/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test029/proguard.flags001.mapping
@@ -1,5 +1,5 @@
-com.android.jack.shrob.test029.jack.I -> com.android.jack.shrob.test029.jack.a:
-com.android.jack.shrob.test029.jack.B -> com.android.jack.shrob.test029.jack.b:
- com.android.jack.shrob.test029.jack.B get(com.android.jack.shrob.test029.jack.I) -> a
-com.android.jack.shrob.test029.jack.C -> com.android.jack.shrob.test029.jack.c:
-com.android.jack.shrob.test029.jack.A -> com.android.jack.shrob.test029.jack.d:
+com.android.jack.shrob.test029.jack.I -> com.android.jack.shrob.test029.jack.RenamedI:
+com.android.jack.shrob.test029.jack.B -> com.android.jack.shrob.test029.jack.RenamedB:
+ com.android.jack.shrob.test029.jack.B get(com.android.jack.shrob.test029.jack.I) -> renamedGet
+com.android.jack.shrob.test029.jack.C -> com.android.jack.shrob.test029.jack.RenamedC:
+com.android.jack.shrob.test029.jack.A -> com.android.jack.shrob.test029.jack.RenamedA:
diff --git a/jack-tests/tests/com/android/jack/shrob/test029/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test029/refsObfuscationWithMapping/expected-001.txt
index b3feff8..2b074ac 100644
--- a/jack-tests/tests/com/android/jack/shrob/test029/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test029/refsObfuscationWithMapping/expected-001.txt
@@ -1,12 +1,12 @@
com.android.jack.shrob.test029.jack.Kept -> com.android.jack.shrob.test029.jack.Kept:
void <init>() -> <init>
void kept() -> kept
-com.android.jack.shrob.test029.jack.I -> com.android.jack.shrob.test029.jack.a:
+com.android.jack.shrob.test029.jack.I -> com.android.jack.shrob.test029.jack.RenamedI:
void <init>() -> <init>
-com.android.jack.shrob.test029.jack.B -> com.android.jack.shrob.test029.jack.b:
+com.android.jack.shrob.test029.jack.B -> com.android.jack.shrob.test029.jack.RenamedB:
void <init>() -> <init>
- com.android.jack.shrob.test029.jack.B get(com.android.jack.shrob.test029.jack.I) -> a
-com.android.jack.shrob.test029.jack.C -> com.android.jack.shrob.test029.jack.c:
+ com.android.jack.shrob.test029.jack.B get(com.android.jack.shrob.test029.jack.I) -> renamedGet
+com.android.jack.shrob.test029.jack.C -> com.android.jack.shrob.test029.jack.RenamedC:
void <init>() -> <init>
-com.android.jack.shrob.test029.jack.A -> com.android.jack.shrob.test029.jack.d:
+com.android.jack.shrob.test029.jack.A -> com.android.jack.shrob.test029.jack.RenamedA:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test030/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test030/proguard.flags001.mapping
index a8740da..7f9b50c 100644
--- a/jack-tests/tests/com/android/jack/shrob/test030/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test030/proguard.flags001.mapping
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test030.jack.I -> com.android.jack.shrob.test030.jack.a:
- int m() -> a
-com.android.jack.shrob.test030.jack.A -> com.android.jack.shrob.test030.jack.b:
- int m() -> a
+com.android.jack.shrob.test030.jack.Kept -> com.android.jack.shrob.test030.jack.Kept:
+com.android.jack.shrob.test030.jack.I -> com.android.jack.shrob.test030.jack.RenamedI:
+com.android.jack.shrob.test030.jack.A -> com.android.jack.shrob.test030.jack.RenamedA:
+ int m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test030/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test030/refsObfuscationWithMapping/expected-001.txt
index 5ba496e..2419711 100644
--- a/jack-tests/tests/com/android/jack/shrob/test030/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test030/refsObfuscationWithMapping/expected-001.txt
@@ -1,10 +1,10 @@
com.android.jack.shrob.test030.jack.Kept -> com.android.jack.shrob.test030.jack.Kept:
void <init>() -> <init>
int kept(com.android.jack.shrob.test030.jack.I) -> kept
-com.android.jack.shrob.test030.jack.I -> com.android.jack.shrob.test030.jack.a:
- int m() -> a
+com.android.jack.shrob.test030.jack.I -> com.android.jack.shrob.test030.jack.RenamedI:
+ int m() -> renamedM
com.android.jack.shrob.test030.jack.B -> com.android.jack.shrob.test030.jack.B:
void <init>() -> <init>
-com.android.jack.shrob.test030.jack.A -> com.android.jack.shrob.test030.jack.b:
+com.android.jack.shrob.test030.jack.A -> com.android.jack.shrob.test030.jack.RenamedA:
void <init>() -> <init>
- int m() -> a
+ int m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test031/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test031/proguard.flags001.mapping
index 6a76a4c..09aa9cc 100644
--- a/jack-tests/tests/com/android/jack/shrob/test031/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test031/proguard.flags001.mapping
@@ -1,16 +1,4 @@
-com.android.jack.shrob.test031.jack.E -> com.android.jack.shrob.test031.jack.E:
- void <init>() -> <init>
-com.android.jack.shrob.test031.jack.Kept -> com.android.jack.shrob.test031.jack.Kept:
- void <init>() -> <init>
- int kept(com.android.jack.shrob.test031.jack.I) -> kept
-com.android.jack.shrob.test031.jack.I -> com.android.jack.shrob.test031.jack.a:
- int m() -> a
-com.android.jack.shrob.test031.jack.F -> com.android.jack.shrob.test031.jack.b:
- void <init>() -> <init>
-com.android.jack.shrob.test031.jack.B -> com.android.jack.shrob.test031.jack.B:
- void <init>() -> <init>
-com.android.jack.shrob.test031.jack.D -> com.android.jack.shrob.test031.jack.D:
- void <init>() -> <init>
-com.android.jack.shrob.test031.jack.A -> com.android.jack.shrob.test031.jack.c:
- void <init>() -> <init>
- int m() -> a
+com.android.jack.shrob.test031.jack.I -> com.android.jack.shrob.test031.jack.RenamedI:
+ int m() -> renamedM
+com.android.jack.shrob.test031.jack.F -> com.android.jack.shrob.test031.jack.RenamedF:
+com.android.jack.shrob.test031.jack.A -> com.android.jack.shrob.test031.jack.RenamedA:
diff --git a/jack-tests/tests/com/android/jack/shrob/test031/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test031/refsObfuscationWithMapping/expected-001.txt
index d5d1daf..89eb0ed 100644
--- a/jack-tests/tests/com/android/jack/shrob/test031/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test031/refsObfuscationWithMapping/expected-001.txt
@@ -3,14 +3,14 @@
com.android.jack.shrob.test031.jack.Kept -> com.android.jack.shrob.test031.jack.Kept:
void <init>() -> <init>
int kept(com.android.jack.shrob.test031.jack.I) -> kept
-com.android.jack.shrob.test031.jack.I -> com.android.jack.shrob.test031.jack.a:
- int m() -> a
-com.android.jack.shrob.test031.jack.F -> com.android.jack.shrob.test031.jack.b:
+com.android.jack.shrob.test031.jack.I -> com.android.jack.shrob.test031.jack.RenamedI:
+ int m() -> renamedM
+com.android.jack.shrob.test031.jack.F -> com.android.jack.shrob.test031.jack.RenamedF:
void <init>() -> <init>
com.android.jack.shrob.test031.jack.B -> com.android.jack.shrob.test031.jack.B:
void <init>() -> <init>
com.android.jack.shrob.test031.jack.D -> com.android.jack.shrob.test031.jack.D:
void <init>() -> <init>
-com.android.jack.shrob.test031.jack.A -> com.android.jack.shrob.test031.jack.c:
+com.android.jack.shrob.test031.jack.A -> com.android.jack.shrob.test031.jack.RenamedA:
void <init>() -> <init>
- int m() -> a
+ int m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test032/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test032/proguard.flags001.mapping
index ac19db9..80c9322 100644
--- a/jack-tests/tests/com/android/jack/shrob/test032/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test032/proguard.flags001.mapping
@@ -1,4 +1,4 @@
-com.android.jack.shrob.test032.jack.I -> com.android.jack.shrob.test032.jack.a:
-com.android.jack.shrob.test032.jack.B -> com.android.jack.shrob.test032.jack.b:
-com.android.jack.shrob.test032.jack.A -> com.android.jack.shrob.test032.jack.c:
- int m() -> a
+com.android.jack.shrob.test032.jack.I -> com.android.jack.shrob.test032.jack.RenamedI:
+com.android.jack.shrob.test032.jack.B -> com.android.jack.shrob.test032.jack.RenamedB:
+com.android.jack.shrob.test032.jack.A -> com.android.jack.shrob.test032.jack.RenamedA:
+ int m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test032/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test032/refsObfuscationWithMapping/expected-001.txt
index c9a8f93..1f831ef 100644
--- a/jack-tests/tests/com/android/jack/shrob/test032/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test032/refsObfuscationWithMapping/expected-001.txt
@@ -1,13 +1,13 @@
com.android.jack.shrob.test032.jack.Kept -> com.android.jack.shrob.test032.jack.Kept:
void <init>() -> <init>
int kept(com.android.jack.shrob.test032.jack.I) -> kept
-com.android.jack.shrob.test032.jack.I -> com.android.jack.shrob.test032.jack.a:
- int m() -> a
-com.android.jack.shrob.test032.jack.B -> com.android.jack.shrob.test032.jack.b:
+com.android.jack.shrob.test032.jack.I -> com.android.jack.shrob.test032.jack.RenamedI:
+ int m() -> renamedM
+com.android.jack.shrob.test032.jack.B -> com.android.jack.shrob.test032.jack.RenamedB:
void <init>() -> <init>
com.android.jack.shrob.test032.jack.C -> com.android.jack.shrob.test032.jack.C:
void <init>() -> <init>
- int m() -> a
-com.android.jack.shrob.test032.jack.A -> com.android.jack.shrob.test032.jack.c:
+ int m() -> renamedM
+com.android.jack.shrob.test032.jack.A -> com.android.jack.shrob.test032.jack.RenamedA:
void <init>() -> <init>
- int m() -> a
+ int m() -> renamedM
diff --git a/jack-tests/tests/com/android/jack/shrob/test036/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test036/proguard.flags001.mapping
new file mode 100644
index 0000000..8b692a9
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test036/proguard.flags001.mapping
@@ -0,0 +1,8 @@
+com.android.jack.shrob.test036.jack.E -> com.android.jack.shrob.test036.jack.RenamedE:
+ com.android.jack.shrob.test036.jack.E A -> renamedA
+ com.android.jack.shrob.test036.jack.E B -> renamedB
+ com.android.jack.shrob.test036.jack.E C -> renamedC
+ com.android.jack.shrob.test036.jack.E[] $VALUES -> renamed$VALUES
+ void <init>(java.lang.String,int) -> renamed<init>
+ com.android.jack.shrob.test036.jack.E[] values() -> renamedValues
+ void <clinit>() -> renamed<clinit>
diff --git a/jack-tests/tests/com/android/jack/shrob/test036/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test036/refsObfuscationWithMapping/expected-001.txt
index b024d02..1d7594a 100644
--- a/jack-tests/tests/com/android/jack/shrob/test036/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test036/refsObfuscationWithMapping/expected-001.txt
@@ -1,10 +1,10 @@
-com.android.jack.shrob.test036.jack.E -> com.android.jack.shrob.test036.jack.a:
- com.android.jack.shrob.test036.jack.E A -> a
- com.android.jack.shrob.test036.jack.E B -> b
- com.android.jack.shrob.test036.jack.E C -> c
- com.android.jack.shrob.test036.jack.E[] $VALUES -> d
+com.android.jack.shrob.test036.jack.E -> com.android.jack.shrob.test036.jack.RenamedE:
+ com.android.jack.shrob.test036.jack.E A -> renamedA
+ com.android.jack.shrob.test036.jack.E B -> renamedB
+ com.android.jack.shrob.test036.jack.E C -> renamedC
+ com.android.jack.shrob.test036.jack.E[] $VALUES -> renamed$VALUES
void <init>(java.lang.String,int) -> <init>
- com.android.jack.shrob.test036.jack.E[] values() -> a
+ com.android.jack.shrob.test036.jack.E[] values() -> renamedValues
void <clinit>() -> <clinit>
com.android.jack.shrob.test036.jack.Kept -> com.android.jack.shrob.test036.jack.Kept:
int[] -ESwitchesValues -> -ESwitchesValues
diff --git a/jack-tests/tests/com/android/jack/shrob/test037/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test037/proguard.flags001.mapping
index c6b7a14..34627fe 100644
--- a/jack-tests/tests/com/android/jack/shrob/test037/proguard.flags001.mapping
+++ b/jack-tests/tests/com/android/jack/shrob/test037/proguard.flags001.mapping
@@ -1,3 +1,3 @@
-com.android.jack.shrob.test037.jack.B -> com.android.jack.shrob.test037.jack.a:
- void m() -> a
-com.android.jack.shrob.test037.jack.A -> com.android.jack.shrob.test037.jack.b:
+com.android.jack.shrob.test037.jack.B -> com.android.jack.shrob.test037.jack.RenamedB:
+ void m() -> renamedM
+com.android.jack.shrob.test037.jack.A -> com.android.jack.shrob.test037.jack.RenamedA:
diff --git a/jack-tests/tests/com/android/jack/shrob/test037/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test037/refsObfuscationWithMapping/expected-001.txt
index b4e8d03..e060833 100644
--- a/jack-tests/tests/com/android/jack/shrob/test037/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test037/refsObfuscationWithMapping/expected-001.txt
@@ -1,8 +1,8 @@
com.android.jack.shrob.test037.jack.Kept -> com.android.jack.shrob.test037.jack.Kept:
void <init>() -> <init>
void kept() -> kept
-com.android.jack.shrob.test037.jack.B -> com.android.jack.shrob.test037.jack.a:
+com.android.jack.shrob.test037.jack.B -> com.android.jack.shrob.test037.jack.RenamedB:
void <init>() -> <init>
- void m() -> a
-com.android.jack.shrob.test037.jack.A -> com.android.jack.shrob.test037.jack.b:
+ void m() -> renamedM
+com.android.jack.shrob.test037.jack.A -> com.android.jack.shrob.test037.jack.RenamedA:
void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test038/proguard.flags001.mapping b/jack-tests/tests/com/android/jack/shrob/test038/proguard.flags001.mapping
new file mode 100644
index 0000000..820fbe8
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test038/proguard.flags001.mapping
@@ -0,0 +1,5 @@
+com.android.jack.shrob.test038.jack.Kept -> com.android.jack.shrob.test038.jack.Kept:
+ void <init>() -> <init>
+ void kept() -> kept
+com.android.jack.shrob.test038.jack.Element -> com.android.jack.shrob.test038.jack.RenamedElement:
+ void <init>() -> <init>
diff --git a/jack-tests/tests/com/android/jack/shrob/test038/refsObfuscationWithMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test038/refsObfuscationWithMapping/expected-001.txt
index db5c11e..820fbe8 100644
--- a/jack-tests/tests/com/android/jack/shrob/test038/refsObfuscationWithMapping/expected-001.txt
+++ b/jack-tests/tests/com/android/jack/shrob/test038/refsObfuscationWithMapping/expected-001.txt
@@ -1,5 +1,5 @@
com.android.jack.shrob.test038.jack.Kept -> com.android.jack.shrob.test038.jack.Kept:
void <init>() -> <init>
void kept() -> kept
-com.android.jack.shrob.test038.jack.Element -> com.android.jack.shrob.test038.jack.a:
+com.android.jack.shrob.test038.jack.Element -> com.android.jack.shrob.test038.jack.RenamedElement:
void <init>() -> <init>
diff --git a/jack/.settings/org.eclipse.jdt.core.prefs b/jack/.settings/org.eclipse.jdt.core.prefs
index b474ac4..58cab3f 100644
--- a/jack/.settings/org.eclipse.jdt.core.prefs
+++ b/jack/.settings/org.eclipse.jdt.core.prefs
@@ -185,7 +185,7 @@
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=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
diff --git a/jack/src/com/android/jack/CommandLine.java b/jack/src/com/android/jack/CommandLine.java
index 38abde4..8cead0f 100644
--- a/jack/src/com/android/jack/CommandLine.java
+++ b/jack/src/com/android/jack/CommandLine.java
@@ -18,6 +18,7 @@
import com.android.jack.frontend.FrontendCompilationException;
import com.android.sched.util.TextUtils;
+import com.android.sched.util.UnrecoverableException;
import com.android.sched.util.config.ChainedException;
import com.android.sched.util.config.ConfigurationException;
import com.android.sched.util.config.GatherConfigBuilder;
@@ -77,10 +78,17 @@
} else if (e instanceof StackOverflowError) {
System.err.println("Try increasing stack size with java option '-Xss<size>'");
}
+ System.err.println("Warning: This may have produced partial or corrupted output.");
logger.log(Level.CONFIG, "Virtual machine error:", e);
System.exit(ExitStatus.FAILURE_VM);
+ } catch (UnrecoverableException e) {
+ System.err.println("Unrecoverable error: " + e.getMessage());
+ System.err.println("Warning: This may have produced partial or corrupted output.");
+ logger.log(Level.FINE, "Unrecoverable exception:", e);
+ System.exit(ExitStatus.FAILURE_UNRECOVERABLE);
} catch (Throwable e) {
System.err.println("Internal compiler error (see log)");
+ System.err.println("Warning: This may have produced partial or corrupted output.");
logger.log(Level.SEVERE, "Internal compiler error:", e);
System.exit(ExitStatus.FAILURE_INTERNAL);
diff --git a/jack/src/com/android/jack/ExitStatus.java b/jack/src/com/android/jack/ExitStatus.java
index 8293ed4..3fb67a0 100644
--- a/jack/src/com/android/jack/ExitStatus.java
+++ b/jack/src/com/android/jack/ExitStatus.java
@@ -44,4 +44,8 @@
* Virtual machine error.
*/
public static final int FAILURE_VM = 5;
+ /**
+ * Unrecoverable exception.
+ */
+ public static final int FAILURE_UNRECOVERABLE = 6;
}
diff --git a/jack/src/com/android/jack/Jack.java b/jack/src/com/android/jack/Jack.java
index 8cf25f5..ca07644 100644
--- a/jack/src/com/android/jack/Jack.java
+++ b/jack/src/com/android/jack/Jack.java
@@ -60,7 +60,7 @@
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.formatter.InternalFormatter;
@@ -185,9 +185,6 @@
import com.android.jack.transformations.uselessif.UselessIfChecker;
import com.android.jack.transformations.uselessif.UselessIfRemover;
import com.android.jack.util.collect.UnmodifiableCollections;
-import com.android.jack.vfs.VDir;
-import com.android.jack.vfs.direct.DirectDir;
-import com.android.jack.vfs.zip.ZipArchive;
import com.android.sched.scheduler.FeatureSet;
import com.android.sched.scheduler.IllegalRequestException;
import com.android.sched.scheduler.Plan;
@@ -204,6 +201,7 @@
import com.android.sched.util.config.ConfigPrinterFactory;
import com.android.sched.util.config.ConfigurationException;
import com.android.sched.util.config.HasKeyId;
+import com.android.sched.util.config.ReflectFactory;
import com.android.sched.util.config.ThreadConfig;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.ReflectFactoryPropertyId;
@@ -211,12 +209,16 @@
import com.android.sched.util.log.LoggerFactory;
import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.direct.InputDirectDir;
+import com.android.sched.vfs.zip.InputZipArchive;
import org.antlr.runtime.RecognitionException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
@@ -243,8 +245,8 @@
UserFriendlyFormatter.getFormatter();
@Nonnull
- public static final ObjectId<JProgram> PROGRAM =
- new ObjectId<JProgram>("jack.program", JProgram.class);
+ public static final ObjectId<JSession> SESSION =
+ new ObjectId<JSession>("jack.session", JSession.class);
// Compilation configuration kept in a static field to avoid ThreadConfig overhead
@@ -258,7 +260,7 @@
"jack.internal.jayce.loader.classpath.policy",
"Hint on default load policy for classpath entries",
JaycePackageLoader.class)
- .addArgType(VDir.class).addArgType(JPhantomLookup.class).bypassAccessibility()
+ .addArgType(InputVDir.class).addArgType(JPhantomLookup.class).bypassAccessibility()
.addDefaultValue("structure");
@Nonnull
@@ -267,12 +269,12 @@
"jack.internal.jayce.loader.import.policy",
"Hint on default load policy for import entries",
JaycePackageLoader.class)
- .addArgType(VDir.class).addArgType(JPhantomLookup.class).bypassAccessibility()
+ .addArgType(InputVDir.class).addArgType(JPhantomLookup.class).bypassAccessibility()
.addDefaultValue("full");
@Nonnull
- public static JProgram getProgram() {
- return ThreadConfig.get(Jack.PROGRAM);
+ public static JSession getSession() {
+ return ThreadConfig.get(Jack.SESSION);
}
@Nonnull
@@ -334,7 +336,7 @@
logger.log(Level.INFO, "Jack sanity checks {0}",
(options.hasSanityChecks() ? "enabled" : "disabled"));
- JProgram program = buildProgram(options, hooks);
+ JSession session = buildSession(options, hooks);
Request request = createInitialRequest();
JavaVersion sourceVersion = config.get(Options.JAVA_SOURCE_VERSION);
@@ -405,9 +407,9 @@
ProductionSet targetProduction = request.getTargetProductions();
FeatureSet features = request.getFeatures();
- PlanBuilder<JProgram> planBuilder;
+ PlanBuilder<JSession> planBuilder;
try {
- planBuilder = request.getPlanBuilder(JProgram.class);
+ planBuilder = request.getPlanBuilder(JSession.class);
} catch (IllegalRequestException e) {
throw new AssertionError(e);
}
@@ -444,11 +446,11 @@
}
}
- Plan<JProgram> plan;
+ Plan<JSession> plan;
try {
// Try to build an automatic plan ...
try {
- plan = request.buildPlan(JProgram.class);
+ plan = request.buildPlan(JSession.class);
} catch (PlanNotFoundException e) {
throw new AssertionError(e);
} catch (IllegalRequestException e) {
@@ -466,7 +468,7 @@
PlanPrinterFactory.getPlanPrinter().printPlan(plan);
try {
- plan.getScheduleInstance().process(program);
+ plan.getScheduleInstance().process(session);
} catch (Exception e) {
throw new AssertionError(e);
}
@@ -507,26 +509,22 @@
}
@Nonnull
- static JProgram buildProgram(@Nonnull Options options, @Nonnull RunnableHooks hooks)
+ static JSession buildSession(@Nonnull Options options, @Nonnull RunnableHooks hooks)
throws JackIOException {
Tracer tracer = TracerFactory.getTracer();
List<String> ecjArguments = options.ecjArguments;
- JProgram program = getProgram();
+ JSession session = getSession();
- ComposedPackageLoader rootPackageLoader = program.getTopLevelLoader();
+ ComposedPackageLoader rootPackageLoader = session.getTopLevelLoader();
- JPhantomLookup phantomLookup = program.getPhantomLookup();
- putInJackClasspath(options.jayceImport, rootPackageLoader, phantomLookup, hooks,
- IMPORT_POLICY);
- putInJackClasspath(options.getBootclasspath(), rootPackageLoader, phantomLookup, hooks,
- CLASSPATH_POLICY);
- putInJackClasspath(options.getClasspath(), rootPackageLoader, phantomLookup, hooks,
- CLASSPATH_POLICY);
-
- JayceFileImporter jayceImporter = new JayceFileImporter(options.jayceImport);
+ JPhantomLookup phantomLookup = session.getPhantomLookup();
+ JayceFileImporter jayceImporter =
+ getJayceFileImporter(options.jayceImport, rootPackageLoader, phantomLookup, hooks);
+ putInJackClasspath(options.getBootclasspath(), rootPackageLoader, phantomLookup, hooks);
+ putInJackClasspath(options.getClasspath(), rootPackageLoader, phantomLookup, hooks);
if (ecjArguments != null) {
String bootclasspathOption = "-bootclasspath";
@@ -543,7 +541,7 @@
ecjArguments.add(JackBatchCompiler.JACK_LOGICAL_PATH_ENTRY);
}
- JackBatchCompiler jbc = new JackBatchCompiler(program, jayceImporter);
+ JackBatchCompiler jbc = new JackBatchCompiler(session, jayceImporter);
Event event = tracer.start(JackEventType.ECJ_COMPILATION);
@@ -556,18 +554,18 @@
}
}
- jayceImporter.doImport(program);
+ jayceImporter.doImport(session);
Event eventIdMerger = tracer.start(JackEventType.METHOD_ID_MERGER);
try {
JClass javaLangObject = phantomLookup.getClass(CommonTypes.JAVA_LANG_OBJECT);
MethodIdMerger merger = new MethodIdMerger(javaLangObject);
- for (JType type : program.getTypesToEmit()) {
+ for (JType type : session.getTypesToEmit()) {
merger.accept(type);
}
JVisitor remover = new VirtualMethodsMarker.Remover(javaLangObject);
- for (JType type : program.getTypesToEmit()) {
+ for (JType type : session.getTypesToEmit()) {
remover.accept(type);
}
} finally {
@@ -575,106 +573,135 @@
}
MethodIdDuplicateRemover methodIdDupRemover = new MethodIdDuplicateRemover();
- methodIdDupRemover.accept(program);
+ methodIdDupRemover.accept(session);
- return program;
+ return session;
+ }
+
+ @Nonnull
+ private static JayceFileImporter getJayceFileImporter(@Nonnull List<File> jayceImport,
+ @Nonnull ComposedPackageLoader rootPackageLoader, @Nonnull JPhantomLookup phantomLookup,
+ @Nonnull RunnableHooks hooks) {
+ List<InputVDir> jackFilesToImport = new ArrayList<InputVDir>(jayceImport.size());
+ ReflectFactory<JaycePackageLoader> factory = ThreadConfig.get(IMPORT_POLICY);
+ for (final File jackFile : jayceImport) {
+ try {
+ InputVDir vDir = wrapAsVDir(jackFile, hooks);
+ jackFilesToImport.add(vDir);
+ // add to classpath
+ JaycePackageLoader rootPLoader = factory.create(vDir, phantomLookup);
+ rootPackageLoader.appendLoader(rootPLoader);
+ } catch (IOException ioException) {
+ throw new JackFileException("Error importing jack container: " + jackFile.getAbsolutePath(),
+ ioException);
+ }
+ }
+ return new JayceFileImporter(jackFilesToImport);
}
private static void putInJackClasspath(@Nonnull List<File> jackFiles,
@Nonnull ComposedPackageLoader rootPackageLoader,
@Nonnull JPhantomLookup phantomJNodeLookup,
- @Nonnull RunnableHooks hooks,
- @Nonnull ReflectFactoryPropertyId<JaycePackageLoader> loadPolicy)
- throws JackIOException {
+ @Nonnull RunnableHooks hooks) {
+ ReflectFactory<JaycePackageLoader> factory = ThreadConfig.get(CLASSPATH_POLICY);
for (final File jackFile : jackFiles) {
try {
- VDir dir;
- if (jackFile.isDirectory()) {
- dir = new DirectDir(jackFile);
- } else { // zip
- final ZipArchive zipArchive = new ZipArchive(jackFile);
- dir = zipArchive;
- hooks.addHook(new Runnable() {
- @Override
- public void run() {
- try {
- zipArchive.close();
- } catch (IOException e) {
- logger.log(Level.FINE, "Failed to close zip for '" + jackFile + "'.", e);
- }
- }
- });
- }
- JaycePackageLoader rootPLoader =
- ThreadConfig.get(loadPolicy).create(dir, phantomJNodeLookup);
+ InputVDir vDir = wrapAsVDir(jackFile, hooks);
+ JaycePackageLoader rootPLoader = factory.create(vDir, phantomJNodeLookup);
rootPackageLoader.appendLoader(rootPLoader);
} catch (IOException ioException) {
// Ignore bad entry
- logger.log(Level.WARNING, "Ignore bad entry into classpath: {0}",
+ logger.log(Level.WARNING, "Bad classpath entry ignored: {0}",
jackFile.getAbsolutePath());
}
}
}
+ @Nonnull
+ private static InputVDir wrapAsVDir(@Nonnull final File dirOrZip,
+ @Nonnull RunnableHooks hooks) throws IOException {
+ InputVDir dir;
+ if (dirOrZip.isDirectory()) {
+ dir = new InputDirectDir(dirOrZip);
+ } else { // zip
+ final InputZipArchive zipArchive = new InputZipArchive(dirOrZip);
+ dir = zipArchive;
+ hooks.addHook(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ zipArchive.close();
+ } catch (IOException e) {
+ logger.log(Level.FINE, "Failed to close zip for '" + dirOrZip + "'.", e);
+ }
+ }
+ });
+ }
+ return dir;
+ }
+
private static void fillJayceToJaycePlan(
- @Nonnull Options options, @Nonnull PlanBuilder<JProgram> programPlan) {
+ @Nonnull Options options, @Nonnull PlanBuilder<JSession> planBuilder) {
// Add here transformations we want to apply before writing .jack file
- FeatureSet features = programPlan.getRequest().getFeatures();
- ProductionSet productions = programPlan.getRequest().getTargetProductions();
+ FeatureSet features = planBuilder.getRequest().getFeatures();
+ ProductionSet productions = planBuilder.getRequest().getTargetProductions();
if (features.contains(SanityChecks.class)) {
- programPlan.append(TypeDuplicateRemoverChecker.class);
+ planBuilder.append(TypeDuplicateRemoverChecker.class);
}
// JarJar
if (features.contains(Jarjar.class)) {
- programPlan.append(PackageRenamer.class);
+ planBuilder.append(PackageRenamer.class);
}
// Shrob
- appendStringRefiningPlan(programPlan);
+ if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
+ appendStringRefiningPlan(planBuilder);
+ }
+
if (productions.contains(SeedFile.class)) {
- programPlan.append(SeedPrinter.class);
+ planBuilder.append(SeedPrinter.class);
}
if (features.contains(Shrinking.class)) {
- appendShrinkingPlan(programPlan);
+ appendShrinkingPlan(planBuilder);
}
if (features.contains(Obfuscation.class)) {
- appendObfuscationPlan(programPlan);
+ appendObfuscationPlan(planBuilder);
}
if (productions.contains(Mapping.class)) {
- programPlan.append(MappingPrinter.class);
+ planBuilder.append(MappingPrinter.class);
}
if (productions.contains(TypeAndMemberListing.class)) {
- programPlan.append(TypeAndMemberLister.class);
+ planBuilder.append(TypeAndMemberLister.class);
}
if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
- appendShrobMarkerRemoverPlan(programPlan);
+ appendShrobMarkerRemoverPlan(planBuilder);
}
}
- static void fillDexPlan(@Nonnull Options options, @Nonnull PlanBuilder<JProgram> programPlan) {
- FeatureSet features = programPlan.getRequest().getFeatures();
- ProductionSet productions = programPlan.getRequest().getTargetProductions();
+ static void fillDexPlan(@Nonnull Options options, @Nonnull PlanBuilder<JSession> planBuilder) {
+ FeatureSet features = planBuilder.getRequest().getFeatures();
+ ProductionSet productions = planBuilder.getRequest().getTargetProductions();
boolean hasSanityChecks = features.contains(SanityChecks.class);
// Build the plan
if (hasSanityChecks) {
- programPlan.append(TypeDuplicateRemoverChecker.class);
+ planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(Jarjar.class)) {
- programPlan.append(PackageRenamer.class);
+ planBuilder.append(PackageRenamer.class);
}
if (hasSanityChecks) {
- programPlan.append(ParentSetterChecker.class);
+ planBuilder.append(ParentSetterChecker.class);
}
- programPlan.append(DexFileBuilder.class);
+ planBuilder.append(DexFileBuilder.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
if (features.contains(LineDebugInfo.class)) {
@@ -690,21 +717,24 @@
}
}
- appendStringRefiningPlan(programPlan);
+ if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
+ appendStringRefiningPlan(planBuilder);
+ }
+
if (productions.contains(SeedFile.class)) {
- programPlan.append(SeedPrinter.class);
+ planBuilder.append(SeedPrinter.class);
}
if (features.contains(Shrinking.class)) {
- appendShrinkingPlan(programPlan);
+ appendShrinkingPlan(planBuilder);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(UsedEnumFieldCollector.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan2 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
if (features.contains(DxLegacy.class)) {
typePlan2.append(VisibilityBridgeAdder.class);
@@ -715,10 +745,10 @@
methodPlan.append(AssertionTransformer.class);
}
}
- programPlan.append(AssertionTransformerSchedulingSeparator.class);
+ planBuilder.append(AssertionTransformerSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
{
@@ -746,18 +776,18 @@
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(SwitchEnumSupport.class);
}
- programPlan.append(InnerAccessorSchedulingSeparator.class);
- programPlan.append(TryStatementSchedulingSeparator.class);
- programPlan.append(EnumMappingSchedulingSeparator.class);
+ planBuilder.append(InnerAccessorSchedulingSeparator.class);
+ planBuilder.append(TryStatementSchedulingSeparator.class);
+ planBuilder.append(EnumMappingSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan4.append(InnerAccessorAdder.class);
typePlan4.append(UsedEnumFieldMarkerRemover.class);
{
@@ -786,12 +816,12 @@
}
if (features.contains(JackFileZipOutput.class)) {
- programPlan.append(JayceZipWriter.class);
+ planBuilder.append(JayceZipWriter.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan4.appendSubPlan(JMethodAdaptor.class);
@@ -830,24 +860,24 @@
}
}
if (features.contains(Obfuscation.class)) {
- appendObfuscationPlan(programPlan);
+ appendObfuscationPlan(planBuilder);
}
if (productions.contains(Mapping.class)) {
- programPlan.append(MappingPrinter.class);
+ planBuilder.append(MappingPrinter.class);
}
if (productions.contains(TypeAndMemberListing.class)) {
- programPlan.append(TypeAndMemberLister.class);
+ planBuilder.append(TypeAndMemberLister.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(ClassDefItemBuilder.class);
typePlan.append(ClassAnnotationBuilder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan5 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
SubPlanBuilder<JMethod> methodPlan4 =
typePlan5.appendSubPlan(JMethodAdaptor.class);
@@ -897,49 +927,52 @@
}
if (hasSanityChecks) {
- programPlan.append(ParentSetterChecker.class);
+ planBuilder.append(ParentSetterChecker.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(DeclaredTypePackageChecker.class);
}
{
- SubPlanBuilder<JPackage> packagePlan = programPlan.appendSubPlan(JPackageAdapter.class);
+ SubPlanBuilder<JPackage> packagePlan = planBuilder.appendSubPlan(JPackageAdapter.class);
packagePlan.append(PackageChecker.class);
}
}
}
private static void fillJavaToJaycePlan(
- @Nonnull Options options, @Nonnull PlanBuilder<JProgram> programPlan) {
- Request request = programPlan.getRequest();
+ @Nonnull Options options, @Nonnull PlanBuilder<JSession> planBuilder) {
+ Request request = planBuilder.getRequest();
FeatureSet features = request.getFeatures();
ProductionSet productions = request.getTargetProductions();
boolean hasSanityChecks = features.contains(SanityChecks.class);
// Build the plan
if (hasSanityChecks) {
- programPlan.append(TypeDuplicateRemoverChecker.class);
+ planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(Jarjar.class)) {
- programPlan.append(PackageRenamer.class);
+ planBuilder.append(PackageRenamer.class);
}
- appendStringRefiningPlan(programPlan);
+ if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
+ appendStringRefiningPlan(planBuilder);
+ }
+
if (productions.contains(SeedFile.class)) {
- programPlan.append(SeedPrinter.class);
+ planBuilder.append(SeedPrinter.class);
}
if (features.contains(Shrinking.class)) {
- appendShrinkingPlan(programPlan);
+ appendShrinkingPlan(planBuilder);
}
if (hasSanityChecks) {
- programPlan.append(ParentSetterChecker.class);
+ planBuilder.append(ParentSetterChecker.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan7 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan7.append(UsedEnumFieldCollector.class);
{
@@ -957,7 +990,7 @@
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan2 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
if (features.contains(DxLegacy.class)) {
typePlan2.append(VisibilityBridgeAdder.class);
}
@@ -971,10 +1004,10 @@
}
}
}
- programPlan.append(AssertionTransformerSchedulingSeparator.class);
+ planBuilder.append(AssertionTransformerSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
{
SubPlanBuilder<JField> fieldPlan =
@@ -999,17 +1032,17 @@
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(SwitchEnumSupport.class);
}
- programPlan.append(InnerAccessorSchedulingSeparator.class);
- programPlan.append(EnumMappingSchedulingSeparator.class);
+ planBuilder.append(InnerAccessorSchedulingSeparator.class);
+ planBuilder.append(EnumMappingSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan4.append(InnerAccessorAdder.class);
typePlan4.append(UsedEnumFieldMarkerRemover.class);
{
@@ -1027,29 +1060,29 @@
}
typePlan4.append(FieldInitMethodRemover.class);
}
- programPlan.append(TryStatementSchedulingSeparator.class);
+ planBuilder.append(TryStatementSchedulingSeparator.class);
if (hasSanityChecks) {
- programPlan.append(TypeDuplicateRemoverChecker.class);
+ planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(Obfuscation.class)) {
- appendObfuscationPlan(programPlan);
+ appendObfuscationPlan(planBuilder);
}
if (productions.contains(Mapping.class)) {
- programPlan.append(MappingPrinter.class);
+ planBuilder.append(MappingPrinter.class);
}
if (productions.contains(TypeAndMemberListing.class)) {
- programPlan.append(TypeAndMemberLister.class);
+ planBuilder.append(TypeAndMemberLister.class);
}
if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
- appendShrobMarkerRemoverPlan(programPlan);
+ appendShrobMarkerRemoverPlan(planBuilder);
}
}
- private static void appendStringRefiningPlan(@Nonnull PlanBuilder<JProgram> programPlan) {
+ private static void appendStringRefiningPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(TypeGenericSignatureSplitter.class);
typePlan.append(TypeStringLiteralRefiner.class);
{
@@ -1068,10 +1101,10 @@
}
}
- private static void appendShrobMarkerRemoverPlan(@Nonnull PlanBuilder<JProgram> programPlan) {
+ private static void appendShrobMarkerRemoverPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan4.append(TypeShrinkMarkerRemover.class);
typePlan4.append(TypeKeepNameMarkerRemover.class);
typePlan4.append(TypeOriginalNameMarkerRemover.class);
@@ -1088,20 +1121,20 @@
}
}
- private static void appendShrinkingPlan(@Nonnull PlanBuilder<JProgram> programPlan) {
+ private static void appendShrinkingPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(ExtendingOrImplementingClassFinder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(Keeper.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(TypeShrinker.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
@@ -1114,16 +1147,16 @@
}
}
- private static void appendObfuscationPlan(@Nonnull PlanBuilder<JProgram> programPlan) {
+ private static void appendObfuscationPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
{
SubPlanBuilder<JPackage> packagePlan =
- programPlan.appendSubPlan(JPackageAdapter.class);
+ planBuilder.appendSubPlan(JPackageAdapter.class);
packagePlan.append(NameKeeper.class);
}
- programPlan.append(Renamer.class);
+ planBuilder.append(Renamer.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(TypeAnnotationRemover.class);
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdaptor.class);
@@ -1138,43 +1171,46 @@
}
private static void fillJayceToDexPlan(
- @Nonnull Options options, @Nonnull PlanBuilder<JProgram> programPlan) {
- Request request = programPlan.getRequest();
+ @Nonnull Options options, @Nonnull PlanBuilder<JSession> planBuilder) {
+ Request request = planBuilder.getRequest();
FeatureSet features = request.getFeatures();
ProductionSet productions = request.getTargetProductions();
boolean hasSanityChecks = features.contains(SanityChecks.class);
// Build the plan
if (hasSanityChecks) {
- programPlan.append(TypeDuplicateRemoverChecker.class);
+ planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(Jarjar.class)) {
- programPlan.append(PackageRenamer.class);
+ planBuilder.append(PackageRenamer.class);
}
- appendStringRefiningPlan(programPlan);
+ if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)) {
+ appendStringRefiningPlan(planBuilder);
+ }
+
if (productions.contains(SeedFile.class)) {
- programPlan.append(SeedPrinter.class);
+ planBuilder.append(SeedPrinter.class);
}
if (features.contains(Shrinking.class)) {
- appendShrinkingPlan(programPlan);
+ appendShrinkingPlan(planBuilder);
}
if (hasSanityChecks) {
- programPlan.append(ParentSetterChecker.class);
+ planBuilder.append(ParentSetterChecker.class);
}
- programPlan.append(DexFileBuilder.class);
+ planBuilder.append(DexFileBuilder.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan.append(ReflectAnnotationsAdder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
{
SubPlanBuilder<JMethod> methodPlan2 =
@@ -1191,7 +1227,7 @@
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
typePlan4.append(ClassDefItemBuilder.class);
typePlan4.append(ClassAnnotationBuilder.class);
{
@@ -1231,18 +1267,18 @@
}
if (features.contains(Obfuscation.class)) {
- appendObfuscationPlan(programPlan);
+ appendObfuscationPlan(planBuilder);
}
if (productions.contains(Mapping.class)) {
- programPlan.append(MappingPrinter.class);
+ planBuilder.append(MappingPrinter.class);
}
if (productions.contains(TypeAndMemberListing.class)) {
- programPlan.append(TypeAndMemberLister.class);
+ planBuilder.append(TypeAndMemberLister.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan5 =
- programPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
{
SubPlanBuilder<JMethod> methodPlan4 =
typePlan5.appendSubPlan(JMethodAdaptor.class);
@@ -1292,7 +1328,7 @@
}
if (hasSanityChecks) {
- programPlan.append(ParentSetterChecker.class);
+ planBuilder.append(ParentSetterChecker.class);
}
}
diff --git a/jack/src/com/android/jack/JackEventType.java b/jack/src/com/android/jack/JackEventType.java
index c447058..50227d5 100644
--- a/jack/src/com/android/jack/JackEventType.java
+++ b/jack/src/com/android/jack/JackEventType.java
@@ -25,37 +25,28 @@
*/
public enum JackEventType implements EventType {
- NNODE_READING_FOR_IMPORT("NNode reading for import", "Blue"),
- NNODE_READING_FOR_CLASSPATH("NNode reading for classpath", "Teal"),
- NNODE_TO_JNODE_CONVERSION_FOR_IMPORT("NNode to JNode conversion for import", "Purple"),
- NNODE_TO_JNODE_CONVERSION_FOR_CLASSPATH("NNode to JNode conversion for classpath", "Green"),
- JNODE_TO_NNODE_CONVERSION("JNode to NNode conversion", "Red"),
- NNODE_WRITING("NNode writing", "Orange"),
- LOOKUP_TRANSFER("Lookup transfer", "Yellow"),
- METHOD_ID_MERGER("Method id merger", "Beige"),
- PRELOOKUP("Pre-lookup", "Pink"),
- ECJ_COMPILATION("ECJ compilation", "Black"),
- GWT_AST_BUILDER("GwtAstBuilder", "LightSkyBlue"),
- J_AST_BUILDER("JAstBuilder", "LightSeaGreen"),
- DX_OPTIMIZATION("Dx optimizations on RopMethod", "Brown"),
- REMOVE_DEAD_CODE("Remove dead code", "Chocolate"),
- DOP_CREATION("Dop creation", "Cyan"),
- JACK_RUN("Jack run", "BlueBerry");
+ NNODE_READING_FOR_IMPORT("NNode reading for import"),
+ NNODE_READING_FOR_CLASSPATH("NNode reading for classpath"),
+ NNODE_TO_JNODE_CONVERSION_FOR_IMPORT("NNode to JNode conversion for import"),
+ NNODE_TO_JNODE_CONVERSION_FOR_CLASSPATH("NNode to JNode conversion for classpath"),
+ JNODE_TO_NNODE_CONVERSION("JNode to NNode conversion"),
+ NNODE_WRITING("NNode writing"),
+ LOOKUP_TRANSFER("Lookup transfer"),
+ METHOD_ID_MERGER("Method id merger"),
+ PRELOOKUP("Pre-lookup"),
+ ECJ_COMPILATION("ECJ compilation"),
+ GWT_AST_BUILDER("GwtAstBuilder"),
+ J_AST_BUILDER("JAstBuilder"),
+ DX_OPTIMIZATION("Dx optimizations on RopMethod"),
+ REMOVE_DEAD_CODE("Remove dead code"),
+ DOP_CREATION("Dop creation"),
+ JACK_RUN("Jack run");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- JackEventType(@Nonnull String name, @Nonnull String cssColor) {
+ JackEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/jack/src/com/android/jack/Options.java b/jack/src/com/android/jack/Options.java
index f974515..448656f 100644
--- a/jack/src/com/android/jack/Options.java
+++ b/jack/src/com/android/jack/Options.java
@@ -45,6 +45,7 @@
import com.android.sched.util.config.StringLocation;
import com.android.sched.util.config.id.BooleanPropertyId;
import com.android.sched.util.config.id.EnumPropertyId;
+import com.android.sched.util.config.id.ImplementationPropertyId;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import com.android.sched.util.file.Directory;
@@ -99,11 +100,11 @@
@Nonnull
public static final BooleanPropertyId GENERATE_DEX_FILE = BooleanPropertyId.create(
- "jack.dex.generate", "Generate dex file").addDefaultValue("false");
+ "jack.dex.generate", "Generate dex file").addDefaultValue(Boolean.FALSE);
@Nonnull
public static final BooleanPropertyId GENERATE_JACK_FILE = BooleanPropertyId.create(
- "jack.jackfile.generate", "Generate jack files").addDefaultValue("false");
+ "jack.jackfile.generate", "Generate jack files").addDefaultValue(Boolean.FALSE);
@Nonnull
public static final EnumPropertyId<Container> DEX_OUTPUT_CONTAINER_TYPE = EnumPropertyId.create(
@@ -215,7 +216,7 @@
@Nonnull
public static final BooleanPropertyId SANITY_CHECKS = BooleanPropertyId.create(
"jack.sanitychecks", "enable/disable compiler sanity checks")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Option(name = "--tracer-dir", usage = "enable tracer and output into this dir (.html)",
metaVar = "DIRECTORY")
@@ -244,24 +245,24 @@
@Nonnull
public static final BooleanPropertyId EMIT_LOCAL_DEBUG_INFO = BooleanPropertyId.create(
"jack.dex.debug.vars", "Emit local variable debug info into generated dex")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final BooleanPropertyId EMIT_JACK_FLAG = BooleanPropertyId.create(
"jack.internal.jackflag", "Emit jack flag into generated dex")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
protected boolean emitSyntheticDebugInfo = false;
@Nonnull
public static final BooleanPropertyId EMIT_LINE_NUMBER_DEBUG_INFO = BooleanPropertyId.create(
"jack.dex.debug.lines", "Emit line number debug info into generated dex")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId EMIT_SOURCE_FILE_DEBUG_INFO = BooleanPropertyId.create(
"jack.dex.debug.source", "Emit source file debug info into generated dex")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
protected boolean keepMethodBody = false;
@@ -275,7 +276,7 @@
@Nonnull
public static final BooleanPropertyId USE_MIXED_CASE_CLASSNAME = BooleanPropertyId.create(
"jack.obfuscation.mixedcaseclassname",
- "Use mixed case class name when obfuscating").addDefaultValue("false");
+ "Use mixed case class name when obfuscating").addDefaultValue(Boolean.FALSE);
protected File typeAndMemberListing;
@@ -285,10 +286,12 @@
@Nonnull
protected Filter<JMethod> filter = new AllMethods();
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings("unchecked")
@Nonnull
- public static final ObjectId<Filter<JMethod>> METHOD_FILTER =
- new ObjectId("jack.methodfilter", Filter.class);
+ public static final ImplementationPropertyId<Filter<JMethod>> METHOD_FILTER =
+ (ImplementationPropertyId<Filter<JMethod>>) (Object) ImplementationPropertyId.create(
+ "jack.internal.filter.method", "Define which filter will be used for methods",
+ Filter.class).addDefaultValue("all-methods");
//
// Getter
@@ -426,158 +429,158 @@
}
for (Entry<String, String> entry : properties.entrySet()) {
- configBuilder.set(entry.getKey(), entry.getValue(), new StringLocation("-D option"));
+ configBuilder.setString(entry.getKey(), entry.getValue(), new StringLocation("-D option"));
}
configBuilder.pushDefaultLocation(new StringLocation("Options"));
if (jarjarRulesFile != null) {
- configBuilder.set(PackageRenamer.JARJAR_FILE, jarjarRulesFile.getAbsolutePath());
+ configBuilder.set(PackageRenamer.JARJAR_FILE, jarjarRulesFile);
}
configBuilder.pushDefaultLocation(new StringLocation("proguard flags"));
if (flags != null) {
configBuilder.set(ReflectAnnotationsAdder.EMIT_ANNOTATION_SIG,
- Boolean.toString(flags.keepAttribute("Signatures")));
+ flags.keepAttribute("Signatures"));
configBuilder.set(ReflectAnnotationsAdder.EMIT_ANNOTATION_THROWS,
- Boolean.toString(flags.keepAttribute("Exceptions")));
+ flags.keepAttribute("Exceptions"));
configBuilder.set(ReflectAnnotationsAdder.EMIT_ANNOTATION_MEMBER_CLASSES,
- Boolean.toString(flags.keepAttribute("InnerClasses")));
+ flags.keepAttribute("InnerClasses"));
configBuilder.set(ReflectAnnotationsAdder.EMIT_ANNOTATION_ENCLOSING_METHOD,
- Boolean.toString(flags.keepAttribute("EnclosingMethod")));
+ flags.keepAttribute("EnclosingMethod"));
configBuilder.set(DefaultValueAnnotationAdder.EMIT_ANNOTATION_DEFAULT,
- Boolean.toString(flags.keepAttribute("AnnotationDefault")));
+ flags.keepAttribute("AnnotationDefault"));
configBuilder.set(AnnotationRemover.EMIT_RUNTIME_INVISIBLE_ANNOTATION,
- Boolean.toString(flags.keepAttribute("RuntimeInvisibleAnnotations")));
+ flags.keepAttribute("RuntimeInvisibleAnnotations"));
configBuilder.set(AnnotationRemover.EMIT_RUNTIME_VISIBLE_ANNOTATION,
- Boolean.toString(flags.keepAttribute("RuntimeVisibleAnnotations")));
+ flags.keepAttribute("RuntimeVisibleAnnotations"));
configBuilder.set(ParameterAnnotationRemover.EMIT_RUNTIME_VISIBLE_PARAMETER_ANNOTATION,
- Boolean.toString(flags.keepAttribute("RuntimeVisibleParameterAnnotations")));
+ flags.keepAttribute("RuntimeVisibleParameterAnnotations"));
configBuilder.set(ParameterAnnotationRemover.EMIT_RUNTIME_INVISIBLE_PARAMETER_ANNOTATION,
- Boolean.toString(flags.keepAttribute("RuntimeInvisibleParameterAnnotations")));
+ flags.keepAttribute("RuntimeInvisibleParameterAnnotations"));
configBuilder.set(EMIT_LINE_NUMBER_DEBUG_INFO,
- Boolean.toString(flags.keepAttribute("LineNumberTable")));
+ flags.keepAttribute("LineNumberTable"));
configBuilder.set(Options.FLAGS, flags);
configBuilder.set(
- Options.USE_MIXED_CASE_CLASSNAME, String.valueOf(flags.getUseMixedCaseClassName()));
+ Options.USE_MIXED_CASE_CLASSNAME, flags.getUseMixedCaseClassName());
configBuilder.set(Renamer.USE_UNIQUE_CLASSMEMBERNAMES,
- String.valueOf(flags.getUseUniqueClassMemberNames()));
+ flags.getUseUniqueClassMemberNames());
File mapping = flags.getObfuscationMapping();
if (mapping != null) {
- configBuilder.set(Renamer.USE_MAPPING, "true");
- configBuilder.set(Renamer.MAPPING_FILE, mapping.getAbsolutePath());
+ configBuilder.set(Renamer.USE_MAPPING, true);
+ configBuilder.setString(Renamer.MAPPING_FILE, mapping.getAbsolutePath());
} else {
- configBuilder.set(Renamer.USE_MAPPING, "false");
+ configBuilder.set(Renamer.USE_MAPPING, false);
}
File seeds = flags.getSeedsFile();
if (seeds != null) {
- configBuilder.set(SeedPrinter.SEEDS_OUTPUT_FILE, seeds.getAbsolutePath());
+ configBuilder.setString(SeedPrinter.SEEDS_OUTPUT_FILE, seeds.getAbsolutePath());
}
File dictionary = flags.getObfuscationDictionary();
if (dictionary != null) {
- configBuilder.set(Renamer.USE_OBFUSCATION_DICTIONARY, "true");
- configBuilder.set(Renamer.OBFUSCATION_DICTIONARY, dictionary.getAbsolutePath());
+ configBuilder.set(Renamer.USE_OBFUSCATION_DICTIONARY, true);
+ configBuilder.setString(Renamer.OBFUSCATION_DICTIONARY, dictionary.getAbsolutePath());
} else {
- configBuilder.set(Renamer.USE_OBFUSCATION_DICTIONARY, "false");
+ configBuilder.set(Renamer.USE_OBFUSCATION_DICTIONARY, false);
}
File classDictionary = flags.getClassObfuscationDictionary();
if (classDictionary != null) {
- configBuilder.set(Renamer.USE_CLASS_OBFUSCATION_DICTIONARY, "true");
- configBuilder.set(Renamer.CLASS_OBFUSCATION_DICTIONARY, classDictionary.getAbsolutePath());
+ configBuilder.set(Renamer.USE_CLASS_OBFUSCATION_DICTIONARY, true);
+ configBuilder.setString(Renamer.CLASS_OBFUSCATION_DICTIONARY,
+ classDictionary.getAbsolutePath());
} else {
- configBuilder.set(Renamer.USE_CLASS_OBFUSCATION_DICTIONARY, "false");
+ configBuilder.set(Renamer.USE_CLASS_OBFUSCATION_DICTIONARY, false);
}
File packageDictionary = flags.getPackageObfuscationDictionary();
if (packageDictionary != null) {
- configBuilder.set(Renamer.USE_PACKAGE_OBFUSCATION_DICTIONARY, "true");
- configBuilder.set(
+ configBuilder.set(Renamer.USE_PACKAGE_OBFUSCATION_DICTIONARY, true);
+ configBuilder.setString(
Renamer.PACKAGE_OBFUSCATION_DICTIONARY, packageDictionary.getAbsolutePath());
} else {
- configBuilder.set(Renamer.USE_PACKAGE_OBFUSCATION_DICTIONARY, "false");
+ configBuilder.set(Renamer.USE_PACKAGE_OBFUSCATION_DICTIONARY, false);
}
File outputmapping = flags.getOutputMapping();
if (outputmapping != null) {
- configBuilder.set(MappingPrinter.MAPPING_OUTPUT_FILE, outputmapping.getAbsolutePath());
+ configBuilder.setString(MappingPrinter.MAPPING_OUTPUT_FILE,
+ outputmapping.getAbsolutePath());
}
if (nameProvider != null) {
- configBuilder.set(NameProviderFactory.NAMEPROVIDER, nameProvider);
+ configBuilder.setString(NameProviderFactory.NAMEPROVIDER, nameProvider);
} else {
if (flags.getUseMixedCaseClassName()) {
- configBuilder.set(NameProviderFactory.NAMEPROVIDER, "mixed-case");
+ configBuilder.setString(NameProviderFactory.NAMEPROVIDER, "mixed-case");
}
}
String packageForRenamedClasses = flags.getPackageForRenamedClasses();
if (packageForRenamedClasses != null) {
- configBuilder.set(Renamer.REPACKAGE_CLASSES, "true");
+ configBuilder.set(Renamer.REPACKAGE_CLASSES, true);
configBuilder.set(Renamer.PACKAGE_FOR_RENAMED_CLASSES, packageForRenamedClasses);
if (flags.getPackageForFlatHierarchy() != null) {
throw new IllegalOptionsException("Flatten package and repackage classes cannot be used"
+ " simultaneously");
}
} else {
- configBuilder.set(Renamer.REPACKAGE_CLASSES, "false");
+ configBuilder.set(Renamer.REPACKAGE_CLASSES, false);
}
String packageForRenamedPackages = flags.getPackageForFlatHierarchy();
if (packageForRenamedPackages != null) {
- configBuilder.set(Renamer.FLATTEN_PACKAGE, "true");
+ configBuilder.set(Renamer.FLATTEN_PACKAGE, true);
configBuilder.set(Renamer.PACKAGE_FOR_RENAMED_PACKAGES, packageForRenamedPackages);
} else {
- configBuilder.set(Renamer.FLATTEN_PACKAGE, "false");
+ configBuilder.set(Renamer.FLATTEN_PACKAGE, false);
}
}
configBuilder.popDefaultLocation();
- configBuilder.set(EMIT_LOCAL_DEBUG_INFO, Boolean.toString(emitLocalDebugInfo));
+ configBuilder.set(EMIT_LOCAL_DEBUG_INFO, emitLocalDebugInfo);
configBuilder.set(
- CodeItemBuilder.EMIT_SYNTHETIC_LOCAL_DEBUG_INFO, Boolean.toString(emitSyntheticDebugInfo));
+ CodeItemBuilder.EMIT_SYNTHETIC_LOCAL_DEBUG_INFO, emitSyntheticDebugInfo);
if (typeAndMemberListing != null) {
- configBuilder.set(TypeAndMemberLister.TYPE_AND_MEMBER_LISTING, "true");
- configBuilder.set(
+ configBuilder.set(TypeAndMemberLister.TYPE_AND_MEMBER_LISTING, true);
+ configBuilder.setString(
TypeAndMemberLister.TYPE_AND_MEMBER_LISTING_FILE, typeAndMemberListing.getAbsolutePath());
}
if (jayceOutZip != null) {
- configBuilder.set(JACK_FILE_OUTPUT_ZIP, jayceOutZip.getAbsolutePath());
- configBuilder.set(JACK_OUTPUT_CONTAINER_TYPE, Container.ZIP.toString());
- configBuilder.set(GENERATE_JACK_FILE, "true");
+ configBuilder.setString(JACK_FILE_OUTPUT_ZIP, jayceOutZip.getAbsolutePath());
+ configBuilder.set(JACK_OUTPUT_CONTAINER_TYPE, Container.ZIP);
+ configBuilder.set(GENERATE_JACK_FILE, true);
} else if (jayceOutDir != null) {
- configBuilder.set(JACK_FILE_OUTPUT_DIR, jayceOutDir.getAbsolutePath());
- configBuilder.set(JACK_OUTPUT_CONTAINER_TYPE, Container.DIR.toString());
- configBuilder.set(GENERATE_JACK_FILE, "true");
+ configBuilder.setString(JACK_FILE_OUTPUT_DIR, jayceOutDir.getAbsolutePath());
+ configBuilder.set(JACK_OUTPUT_CONTAINER_TYPE, Container.DIR);
+ configBuilder.set(GENERATE_JACK_FILE, true);
} else if (outZip != null) {
- configBuilder.set(DEX_FILE_OUTPUT, outZip.getAbsolutePath());
- configBuilder.set(DEX_OUTPUT_CONTAINER_TYPE, Container.ZIP.toString());
- configBuilder.set(GENERATE_DEX_FILE, "true");
+ configBuilder.setString(DEX_FILE_OUTPUT, outZip.getAbsolutePath());
+ configBuilder.set(DEX_OUTPUT_CONTAINER_TYPE, Container.ZIP);
+ configBuilder.set(GENERATE_DEX_FILE, true);
} else {
- configBuilder.set(DEX_FILE_OUTPUT, out.getAbsolutePath());
- configBuilder.set(DEX_OUTPUT_CONTAINER_TYPE, Container.FILE.toString());
- configBuilder.set(GENERATE_DEX_FILE, "true");
+ configBuilder.setString(DEX_FILE_OUTPUT, out.getAbsolutePath());
+ configBuilder.set(DEX_OUTPUT_CONTAINER_TYPE, Container.FILE);
+ configBuilder.set(GENERATE_DEX_FILE, true);
}
- configBuilder.set(FieldInitializerRemover.CLASS_AS_INITIALVALUE, Boolean.toString(!dxLegacy));
+ configBuilder.set(FieldInitializerRemover.CLASS_AS_INITIALVALUE, !dxLegacy);
configBuilder.set(
- FieldInitializerRemover.STRING_AS_INITIALVALUE_OF_OBJECT, Boolean.toString(!runtimeLegacy));
-
- configBuilder.set(METHOD_FILTER, filter);
+ FieldInitializerRemover.STRING_AS_INITIALVALUE_OF_OBJECT, !runtimeLegacy);
if (tracerDir != null) {
- configBuilder.set(TracerFactory.TRACER, "html");
- configBuilder.set(StatsTracerFtl.TRACER_DIR, tracerDir.getAbsolutePath());
+ configBuilder.setString(TracerFactory.TRACER, "html");
+ configBuilder.setString(StatsTracerFtl.TRACER_DIR, tracerDir.getAbsolutePath());
}
- configBuilder.set(SANITY_CHECKS, Boolean.toString(sanityChecks));
+ configBuilder.set(SANITY_CHECKS, sanityChecks);
if (dumpProperties) {
- configBuilder.set(ConfigPrinterFactory.CONFIG_PRINTER, "properties-file");
+ configBuilder.setString(ConfigPrinterFactory.CONFIG_PRINTER, "properties-file");
}
configBuilder.popDefaultLocation();
@@ -702,10 +705,6 @@
jayceImport.add(importFile);
}
- public void setFilter(@Nonnull Filter<JMethod> filter) {
- this.filter = filter;
- }
-
public void addProperty(@Nonnull String propertyName, @Nonnull String propertyValue) {
properties.put(propertyName, propertyValue);
}
diff --git a/jack/src/com/android/jack/backend/dex/ClassDefItemBuilder.java b/jack/src/com/android/jack/backend/dex/ClassDefItemBuilder.java
index b6b43a6..eb873cc 100644
--- a/jack/src/com/android/jack/backend/dex/ClassDefItemBuilder.java
+++ b/jack/src/com/android/jack/backend/dex/ClassDefItemBuilder.java
@@ -95,7 +95,7 @@
return;
}
- DexFileMarker dexFileMarker = declaredType.getJProgram().getMarker(DexFileMarker.class);
+ DexFileMarker dexFileMarker = declaredType.getSession().getMarker(DexFileMarker.class);
assert dexFileMarker != null;
DexFile dexFile = dexFileMarker.getDexFile();
@@ -127,10 +127,10 @@
if (superClass == null) {
if (type instanceof JDefinedInterface) {
return RopHelper.getCstType(
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT));
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT));
} else {
- assert type == Jack.getProgram().getPhantomLookup().getType(CommonTypes.JAVA_LANG_OBJECT)
- || type == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ assert type == Jack.getSession().getPhantomLookup().getType(CommonTypes.JAVA_LANG_OBJECT)
+ || type == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
return null;
}
}
diff --git a/jack/src/com/android/jack/backend/dex/DexFileBuilder.java b/jack/src/com/android/jack/backend/dex/DexFileBuilder.java
index b6b4100..910f6c0 100644
--- a/jack/src/com/android/jack/backend/dex/DexFileBuilder.java
+++ b/jack/src/com/android/jack/backend/dex/DexFileBuilder.java
@@ -18,7 +18,7 @@
import com.android.jack.dx.dex.DexOptions;
import com.android.jack.dx.dex.file.DexFile;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.marker.DexFileMarker;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
@@ -28,27 +28,27 @@
import javax.annotation.Nonnull;
/**
- * Builds a {@code DexFile} instance from a {@code JProgram}.
+ * Builds a {@code DexFile} instance from a {@code Session}.
*
* <p>This builder only creates an empty {@code DexFile} instance. This instance
* is then filled with {@code ClassDefItem}s by the {@code ClassDefItemBuilder}.
*
* @see ClassDefItemBuilder
*/
-@Description("Builds a DexFile instance from a JProgram.")
+@Description("Builds a DexFile instance from a Session.")
@Name("DexFileBuilder")
@Transform(add = DexFileMarker.class)
-public class DexFileBuilder implements RunnableSchedulable<JProgram> {
+public class DexFileBuilder implements RunnableSchedulable<JSession> {
private final DexFile dexFile = new DexFile(new DexOptions());
/**
- * Attaches the {@code DexFile} instance to build to the given {@code program}
+ * Attaches the {@code DexFile} instance to build to the given {@code session}
* in a {@code DexFileMarker}. This {@code DexFile} instance is then accessible
* in {@code ClassDefItemBuilder} schedulable.
*/
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
DexFileMarker dexFileMarker = new DexFileMarker(dexFile);
- program.addMarker(dexFileMarker);
+ session.addMarker(dexFileMarker);
}
}
diff --git a/jack/src/com/android/jack/backend/dex/DexFileWriter.java b/jack/src/com/android/jack/backend/dex/DexFileWriter.java
index c92f27c..d158a34 100644
--- a/jack/src/com/android/jack/backend/dex/DexFileWriter.java
+++ b/jack/src/com/android/jack/backend/dex/DexFileWriter.java
@@ -19,7 +19,7 @@
import com.android.jack.JackFileException;
import com.android.jack.Options;
import com.android.jack.dx.dex.file.DexFile;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.feature.DexNonZipOutput;
import com.android.jack.scheduling.marker.DexFileMarker;
import com.android.jack.scheduling.tags.DexFileProduct;
@@ -45,14 +45,14 @@
@Constraint(need = {DexFileMarker.Complete.class})
@Produce(DexFileProduct.class)
@Support(DexNonZipOutput.class)
-public class DexFileWriter implements RunnableSchedulable<JProgram> {
+public class DexFileWriter implements RunnableSchedulable<JSession> {
@Nonnull
protected File outputFile = ThreadConfig.get(Options.DEX_FILE_OUTPUT);
@Override
- public void run(@Nonnull JProgram program) throws Exception {
- DexFile dexFile = getDexFile(program);
+ public void run(@Nonnull JSession session) throws Exception {
+ DexFile dexFile = getDexFile(session);
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
try {
@@ -66,8 +66,8 @@
}
@Nonnull
- protected DexFile getDexFile(@Nonnull JProgram program) {
- DexFileMarker dexFileMarker = program.getMarker(DexFileMarker.class);
+ protected DexFile getDexFile(@Nonnull JSession session) {
+ DexFileMarker dexFileMarker = session.getMarker(DexFileMarker.class);
assert dexFileMarker != null;
DexFile dexFile = dexFileMarker.getDexFile();
assert dexFile != null;
diff --git a/jack/src/com/android/jack/backend/dex/DexZipWriter.java b/jack/src/com/android/jack/backend/dex/DexZipWriter.java
index 2c14498..f966a5e 100644
--- a/jack/src/com/android/jack/backend/dex/DexZipWriter.java
+++ b/jack/src/com/android/jack/backend/dex/DexZipWriter.java
@@ -19,7 +19,7 @@
import com.android.jack.JackFileException;
import com.android.jack.backend.jayce.ResourceContainerMarker;
import com.android.jack.dx.dex.file.DexFile;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.feature.DexZipOutput;
import com.android.jack.scheduling.marker.DexFileMarker;
import com.android.jack.scheduling.tags.DexFileProduct;
@@ -29,11 +29,13 @@
import com.android.sched.schedulable.Constraint;
import com.android.sched.schedulable.Produce;
import com.android.sched.schedulable.Support;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.InputVFile;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.annotation.Nonnull;
@@ -52,8 +54,8 @@
private static final String DEX_NAME = "classes.dex";
@Override
- public void run(@Nonnull JProgram program) throws Exception {
- DexFile dexFile = getDexFile(program);
+ public void run(@Nonnull JSession session) throws Exception {
+ DexFile dexFile = getDexFile(session);
ZipOutputStream zos = null;
try {
@@ -63,16 +65,22 @@
dexFile.writeTo(zos, null, false);
zos.closeEntry();
- ResourceContainerMarker resourceContainer = program.getMarker(ResourceContainerMarker.class);
+ ResourceContainerMarker resourceContainer = session.getMarker(ResourceContainerMarker.class);
if (resourceContainer != null) {
- ZipFile zipFile = resourceContainer.getZipFile();
- for (ZipEntry resourceEntry : resourceContainer.getZipEntries()) {
+ for (InputVFile resource : resourceContainer.getResources()) {
+ Location location = resource.getLocation();
+ String entryName;
+ if (location instanceof ZipLocation) {
+ ZipLocation zipLocation = (ZipLocation) location;
+ entryName = zipLocation.getEntryName();
+ } else {
+ entryName = resource.getName();
+ }
+ ZipEntry resourceEntry = new ZipEntry(entryName);
zos.putNextEntry(resourceEntry);
- BytesStreamSucker sucker =
- new BytesStreamSucker(zipFile.getInputStream(resourceEntry), zos);
+ BytesStreamSucker sucker = new BytesStreamSucker(resource.openRead(), zos);
sucker.run();
}
- zipFile.close();
}
} catch (IOException e) {
throw new JackFileException(
diff --git a/jack/src/com/android/jack/backend/dex/FieldInitializerRemover.java b/jack/src/com/android/jack/backend/dex/FieldInitializerRemover.java
index 4485055..4739569 100644
--- a/jack/src/com/android/jack/backend/dex/FieldInitializerRemover.java
+++ b/jack/src/com/android/jack/backend/dex/FieldInitializerRemover.java
@@ -61,12 +61,12 @@
@Nonnull
public static final BooleanPropertyId CLASS_AS_INITIALVALUE = BooleanPropertyId.create(
"jack.legacy.dx.initialvalue.class",
- "Emit class literal as initial value of field").addDefaultValue("true");
+ "Emit class literal as initial value of field").addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId STRING_AS_INITIALVALUE_OF_OBJECT = BooleanPropertyId.create(
"jack.legacy.runtime.initialvalue.string",
- "Emit string literal as initial value of field").addDefaultValue("true");
+ "Emit string literal as initial value of field").addDefaultValue(Boolean.TRUE);
private final boolean allowClassInInitialValue =
ThreadConfig.get(CLASS_AS_INITIALVALUE).booleanValue();
@@ -84,7 +84,7 @@
/* Object field initialized by a String literal: don't remove unless allowed */
&& (allowStringAsObjectInit
|| !((field.getType() !=
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING))
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING))
&& (initialValue instanceof JAbstractStringLiteral)))
/* Field initialized by a class literal: don't remove unless allowed */
&& (allowClassInInitialValue || !(initialValue instanceof JClassLiteral))
diff --git a/jack/src/com/android/jack/backend/dex/annotations/DefaultValueAnnotationAdder.java b/jack/src/com/android/jack/backend/dex/annotations/DefaultValueAnnotationAdder.java
index 35543ac..7275e6c 100644
--- a/jack/src/com/android/jack/backend/dex/annotations/DefaultValueAnnotationAdder.java
+++ b/jack/src/com/android/jack/backend/dex/annotations/DefaultValueAnnotationAdder.java
@@ -87,7 +87,7 @@
@Nonnull
public static final BooleanPropertyId EMIT_ANNOTATION_DEFAULT = BooleanPropertyId.create(
"jack.annotation.annotationdefault", "Emit annotation default")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER);
@@ -150,7 +150,7 @@
@Nonnull
private JAnnotation getDefaultAnnotationType(@Nonnull JDefinedClassOrInterface type) {
if (defaultAnnotation == null) {
- defaultAnnotation = type.getJProgram()
+ defaultAnnotation = type.getSession()
.getPhantomLookup().getAnnotation(DexAnnotations.ANNOTATION_ANNOTATION_DEFAULT);
}
assert defaultAnnotation != null;
diff --git a/jack/src/com/android/jack/backend/dex/annotations/ReflectAnnotationsAdder.java b/jack/src/com/android/jack/backend/dex/annotations/ReflectAnnotationsAdder.java
index 2fc3e60..540a343 100644
--- a/jack/src/com/android/jack/backend/dex/annotations/ReflectAnnotationsAdder.java
+++ b/jack/src/com/android/jack/backend/dex/annotations/ReflectAnnotationsAdder.java
@@ -129,6 +129,11 @@
}
@Override
+ public boolean visit(@Nonnull JMethod x) {
+ return false;
+ }
+
+ @Override
public void endVisit(@Nonnull JDefinedClassOrInterface x) {
JClassOrInterface enclosingType = x.getEnclosingType();
if (enclosingType != null) {
@@ -380,21 +385,21 @@
@Nonnull
public static final BooleanPropertyId EMIT_ANNOTATION_SIG = BooleanPropertyId.create(
"jack.annotation.signature", "Emit annotation signature")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId EMIT_ANNOTATION_ENCLOSING_METHOD = BooleanPropertyId.create(
"jack.annotation.enclosingmethod", "Emit annotation enclosing method")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId EMIT_ANNOTATION_THROWS = BooleanPropertyId.create(
- "jack.annotation.throws", "Emit annotation throws").addDefaultValue("true");
+ "jack.annotation.throws", "Emit annotation throws").addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId EMIT_ANNOTATION_MEMBER_CLASSES = BooleanPropertyId.create(
"jack.annotation.memberclasses", "Emit annotation member classes")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
private final boolean addAnnotationThrows =
ThreadConfig.get(EMIT_ANNOTATION_THROWS).booleanValue();
@@ -411,7 +416,7 @@
@Override
public synchronized void run(@Nonnull JDefinedClassOrInterface declaredType) throws Exception {
TransformationRequest tr = new TransformationRequest(declaredType);
- Visitor visitor = new Visitor(tr, declaredType.getJProgram().getPhantomLookup());
+ Visitor visitor = new Visitor(tr, declaredType.getSession().getPhantomLookup());
visitor.accept(declaredType);
tr.commit();
}
diff --git a/jack/src/com/android/jack/backend/dex/rop/CodeItemBuilder.java b/jack/src/com/android/jack/backend/dex/rop/CodeItemBuilder.java
index 66d7350b..97031e8 100644
--- a/jack/src/com/android/jack/backend/dex/rop/CodeItemBuilder.java
+++ b/jack/src/com/android/jack/backend/dex/rop/CodeItemBuilder.java
@@ -144,17 +144,17 @@
@Nonnull
public static final BooleanPropertyId EMIT_SYNTHETIC_LOCAL_DEBUG_INFO = BooleanPropertyId.create(
"jack.dex.debug.vars.synthetic",
- "Emit synthetic local variable debug info into generated dex").addDefaultValue("false");
+ "Emit synthetic local variable debug info into generated dex").addDefaultValue(Boolean.FALSE);
@Nonnull
public static final BooleanPropertyId DEX_OPTIMIZE = BooleanPropertyId.create(
"jack.dex.optimize", "Define if Dex optimizations are activated")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId FORCE_JUMBO = BooleanPropertyId.create(
"jack.dex.forcejumbo", "Force string opcodes to be emitted as jumbo in dex")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER);
@@ -487,7 +487,7 @@
@Nonnull
private DalvCode createCode(@Nonnull JMethod method, @Nonnull RopMethod ropMethod) {
DexFileMarker dexFileMarker =
- method.getEnclosingType().getJProgram().getMarker(DexFileMarker.class);
+ method.getEnclosingType().getSession().getMarker(DexFileMarker.class);
assert dexFileMarker != null;
DexOptions options = dexFileMarker.getDexFile().getDexOptions();
diff --git a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
index ec07c79..ed50bc5 100644
--- a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
+++ b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
@@ -20,30 +20,26 @@
import com.android.jack.JackEventType;
import com.android.jack.JackFileException;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JPackage;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.jayce.JayceFormatException;
import com.android.jack.jayce.JayceVersionException;
-import com.android.jack.lookup.JLookup;
import com.android.sched.util.codec.EnumCodec;
-import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.Location;
import com.android.sched.util.config.ThreadConfig;
-import com.android.sched.util.config.ZipLocation;
import com.android.sched.util.config.id.PropertyId;
import com.android.sched.util.log.Event;
import com.android.sched.util.log.LoggerFactory;
import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.InputVFile;
+import com.android.sched.vfs.VElement;
-import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import javax.annotation.Nonnull;
@@ -56,6 +52,8 @@
@Nonnull
public static final String JAYCE_FILE_EXTENSION = ".jack";
+ public static final int JACK_EXTENSION_LENGTH = JAYCE_FILE_EXTENSION.length();
+
@Nonnull
private final Tracer tracer = TracerFactory.getTracer();
@@ -63,7 +61,7 @@
private final java.util.logging.Logger logger = LoggerFactory.getLogger();
@Nonnull
- private final List<File> jayceContainers;
+ private final List<InputVDir> jayceContainers;
private enum CollisionPolicy {
KEEP_FIRST,
@@ -75,100 +73,86 @@
"jack.jackimport.policy",
"Defines the policy to follow concerning type collision in imported jack files",
new EnumCodec<CollisionPolicy>(CollisionPolicy.values()).ignoreCase())
- .addDefaultValue("fail");
+ .addDefaultValue(CollisionPolicy.FAIL);
@Nonnull
private final CollisionPolicy collisionPolicy = ThreadConfig.get(COLLISION_POLICY);
- public JayceFileImporter(@Nonnull List<File> jayceContainers) {
+ public JayceFileImporter(@Nonnull List<InputVDir> jayceContainers) {
this.jayceContainers = jayceContainers;
}
- public void doImport(@Nonnull JProgram program)
- throws JayceFormatException, JayceVersionException, JackFileException {
+ public void doImport(@Nonnull JSession session) throws JayceFormatException,
+ JayceVersionException, JackFileException {
- JLookup lookup = program.getPhantomLookup();
- for (File jayceContainer : jayceContainers) {
- String rootDirPath = jayceContainer.getAbsolutePath();
+ ResourceContainerMarker resourceMarker = session.getMarker(ResourceContainerMarker.class);
+ if (resourceMarker == null) {
+ resourceMarker = new ResourceContainerMarker();
+ session.addMarker(resourceMarker);
+ }
+ for (InputVDir jayceContainer : jayceContainers) {
try {
- if (jayceContainer.isDirectory()) {
- logger.log(Level.FINE, "Importing jack directory ''{0}''",
- jayceContainer.getAbsolutePath());
- for (File subFile : jayceContainer.listFiles()) {
- importJayceFile(subFile, program, lookup, rootDirPath);
- }
- } else {
- // try zip
- ZipFile zipFile = new ZipFile(jayceContainer);
- logger.log(Level.FINE, "Importing jack archive ''{0}''",
- jayceContainer.getAbsolutePath());
- List<ZipEntry> resources = new ArrayList<ZipEntry>();
- Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
- while (zipFileEntries.hasMoreElements()) {
- ZipEntry zipEntry = zipFileEntries.nextElement();
- if (zipEntry.getName().endsWith(JAYCE_FILE_EXTENSION)) {
- addImportedTypesToProgram(
- program,
- lookup,
- zipEntry.getName(),
- rootDirPath,
- new ZipLocation(new FileLocation(jayceContainer), zipEntry));
- } else {
- resources.add(zipEntry);
- }
- }
- program.addMarker(new ResourceContainerMarker(zipFile, resources));
+ logger.log(Level.FINE, "Importing {0}", jayceContainer.getLocation().getDescription());
+ JPackage topLevelPackage = session.getTopLevelPackage();
+ for (VElement subFile : jayceContainer.list()) {
+ importJayceFile(subFile, session, topLevelPackage, resourceMarker);
}
} catch (IOException e) {
- throw new JackFileException("Error reading jack archive " + rootDirPath, e);
+ throw new JackFileException(
+ "Error importing " + jayceContainer.getLocation().getDescription(), e);
}
}
}
- private void importJayceFile(@Nonnull File file, @Nonnull JProgram program,
- @Nonnull JLookup lookup,
- @Nonnull String rootDirPath) throws IOException, JayceFormatException, JayceVersionException {
- if (file.isDirectory()) {
- for (File subFile : file.listFiles()) {
- importJayceFile(subFile, program, lookup, rootDirPath);
+ private void importJayceFile(@Nonnull VElement element, @Nonnull JSession session,
+ @Nonnull JPackage pack, @Nonnull ResourceContainerMarker resourceMarker) throws IOException,
+ JayceFormatException, JayceVersionException {
+ if (element instanceof InputVDir) {
+ for (VElement subFile : ((InputVDir) element).list()) {
+ importJayceFile(subFile, session, pack.getSubPackage(element.getName()), resourceMarker);
+ }
+ } else if (element instanceof InputVFile) {
+ InputVFile file = (InputVFile) element;
+ if (isJackFileName(file.getName())) {
+ addImportedTypes(session, file.getName(), pack, file.getLocation());
+ } else {
+ resourceMarker.addResource(file);
}
} else {
- if (file.getName().endsWith(JAYCE_FILE_EXTENSION)) {
- String fullName = file.getAbsolutePath().substring(rootDirPath.length() + 1);
- addImportedTypesToProgram(program, lookup, fullName, rootDirPath, new FileLocation(file));
- }
+ throw new AssertionError();
}
}
- private void addImportedTypesToProgram(
- @Nonnull JProgram program,
- @Nonnull JLookup lookup,
- @Nonnull String path,
- @Nonnull String rootDirPath,
- @Nonnull Location expectedLoadSource) throws JayceFormatException, JayceVersionException {
-
+ private void addImportedTypes(@Nonnull JSession session, @Nonnull String path,
+ @Nonnull JPackage pack, @Nonnull Location expectedLoadSource) throws JayceFormatException,
+ JayceVersionException {
Event readEvent = tracer.start(JackEventType.NNODE_READING_FOR_IMPORT);
try {
- logger.log(Level.FINEST, "Importing jack file ''{0}'' - from ''{1}''",
- new Object[] {path, rootDirPath});
- String typeBinaryName = path.substring(0, path.length() - JAYCE_FILE_EXTENSION.length());
- JDefinedClassOrInterface declaredType =
- (JDefinedClassOrInterface) lookup.getType('L' + typeBinaryName + ';');
+ logger.log(Level.FINEST, "Importing jack file ''{0}'' in package ''{1}''",
+ new Object[] {path, Jack.getUserFriendlyFormatter().getName(pack)});
+ String simpleName = path.substring(0, path.length() - JAYCE_FILE_EXTENSION.length());
+ JDefinedClassOrInterface declaredType = pack.getType(simpleName);
Location existingSource = declaredType.getLocation();
if (!expectedLoadSource.equals(existingSource)) {
if (collisionPolicy == CollisionPolicy.FAIL) {
throw new ImportConflictException(declaredType, expectedLoadSource);
} else {
- logger.log(Level.INFO, "Type '{0}' from '{1}' has already been imported from {2}: "
+ logger.log(Level.INFO,
+ "Type ''{0}'' has already been imported from {1}: "
+ "ignoring import", new Object[] {
- Jack.getUserFriendlyFormatter().getName(declaredType), rootDirPath,
- "'" + existingSource.getDescription() + "'"});
+ Jack.getUserFriendlyFormatter().getName(declaredType),
+ existingSource.getDescription()});
}
} else {
- program.addTypeToEmit(declaredType);
+ session.addTypeToEmit(declaredType);
}
} finally {
readEvent.end();
}
}
+
+ public static boolean isJackFileName(@Nonnull String name) {
+ return (name.length() > JACK_EXTENSION_LENGTH) && (name.substring(
+ name.length() - JACK_EXTENSION_LENGTH).equalsIgnoreCase(JAYCE_FILE_EXTENSION));
+ }
}
diff --git a/jack/src/com/android/jack/backend/jayce/JayceSingleTypeWriter.java b/jack/src/com/android/jack/backend/jayce/JayceSingleTypeWriter.java
index de300c9..fef2d32 100644
--- a/jack/src/com/android/jack/backend/jayce/JayceSingleTypeWriter.java
+++ b/jack/src/com/android/jack/backend/jayce/JayceSingleTypeWriter.java
@@ -28,15 +28,19 @@
import com.android.jack.scheduling.feature.JackFileNonZipOutput;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
+import com.android.sched.item.Synchronized;
import com.android.sched.schedulable.Constraint;
import com.android.sched.schedulable.Produce;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Support;
import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.file.Directory;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+import com.android.sched.vfs.direct.OutputDirectDir;
import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -50,26 +54,22 @@
@Constraint(need = {JackFormatIr.class}, no = {NonJackFormatIr.class})
@Produce(JackFormatProduct.class)
@Support(JackFileNonZipOutput.class)
+@Synchronized
public class JayceSingleTypeWriter implements RunnableSchedulable<JDefinedClassOrInterface> {
@Nonnull
private static final TypeFormatter formatter = new FilePathFormatter();
@Nonnull
- private final File outputDir = ThreadConfig.get(Options.JACK_FILE_OUTPUT_DIR).getFile();
+ private final Directory outputDir = ThreadConfig.get(Options.JACK_FILE_OUTPUT_DIR);
@Override
- public void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
- String filePath = getFilePath(type);
- File typeFile = new File(outputDir, filePath);
+ public synchronized void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
+ OutputVDir vDir = new OutputDirectDir(outputDir);
+ OutputVFile vFile = vDir.createOutputVFile(getFilePath(type));
try {
- if (!typeFile.getParentFile().mkdirs() && !typeFile.getParentFile().isDirectory()) {
- throw new IOException(
- "Could not create directory: " + typeFile.getParentFile().getAbsolutePath());
- }
-
- OutputStream out = new BufferedOutputStream(new FileOutputStream(typeFile));
+ OutputStream out = new BufferedOutputStream(vFile.openWrite());
try {
// Write to file
JayceWriter writer = new JayceWriter(out);
@@ -78,8 +78,7 @@
out.close();
}
} catch (IOException e) {
- throw new JackFileException(
- "Could not write Jack file to output '" + typeFile.getAbsolutePath() + "'", e);
+ throw new JackFileException("Could not write Jack file to output '" + vFile + "'", e);
}
}
diff --git a/jack/src/com/android/jack/backend/jayce/JayceZipWriter.java b/jack/src/com/android/jack/backend/jayce/JayceZipWriter.java
index dec5124..221b38c 100644
--- a/jack/src/com/android/jack/backend/jayce/JayceZipWriter.java
+++ b/jack/src/com/android/jack/backend/jayce/JayceZipWriter.java
@@ -21,7 +21,7 @@
import com.android.jack.ir.JackFormatIr;
import com.android.jack.ir.NonJackFormatIr;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.jayce.JayceWriter;
import com.android.jack.scheduling.feature.JackFileZipOutput;
import com.android.jack.util.BytesStreamSucker;
@@ -31,14 +31,16 @@
import com.android.sched.schedulable.Produce;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Support;
+import com.android.sched.util.config.Location;
import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.InputVFile;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.annotation.Nonnull;
@@ -51,19 +53,19 @@
@Constraint(need = {JackFormatIr.class}, no = {NonJackFormatIr.class})
@Produce(JackFormatProduct.class)
@Support(JackFileZipOutput.class)
-public class JayceZipWriter implements RunnableSchedulable<JProgram> {
+public class JayceZipWriter implements RunnableSchedulable<JSession> {
@Nonnull
private final File outputZip = ThreadConfig.get(Options.JACK_FILE_OUTPUT_ZIP);
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
try {
ZipOutputStream zos =
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outputZip)));
try {
- for (JDefinedClassOrInterface type : program.getTypesToEmit()) {
+ for (JDefinedClassOrInterface type : session.getTypesToEmit()) {
String filePath = JayceSingleTypeWriter.getFilePath(type);
ZipEntry zipEntry = new ZipEntry(filePath);
zos.putNextEntry(zipEntry);
@@ -72,16 +74,23 @@
}
ResourceContainerMarker resourceContainer =
- program.getMarker(ResourceContainerMarker.class);
+ session.getMarker(ResourceContainerMarker.class);
if (resourceContainer != null) {
- ZipFile zipFile = resourceContainer.getZipFile();
- for (ZipEntry resourceEntry : resourceContainer.getZipEntries()) {
+ for (InputVFile resource : resourceContainer.getResources()) {
+ Location location = resource.getLocation();
+ String entryName;
+ if (location instanceof ZipLocation) {
+ ZipLocation zipLocation = (ZipLocation) location;
+ entryName = zipLocation.getEntryName();
+ } else {
+ entryName = resource.getName();
+ }
+ ZipEntry resourceEntry = new ZipEntry(entryName);
zos.putNextEntry(resourceEntry);
BytesStreamSucker sucker =
- new BytesStreamSucker(zipFile.getInputStream(resourceEntry), zos);
+ new BytesStreamSucker(resource.openRead(), zos);
sucker.run();
}
- zipFile.close();
}
} finally {
zos.close();
diff --git a/jack/src/com/android/jack/backend/jayce/ResourceContainerMarker.java b/jack/src/com/android/jack/backend/jayce/ResourceContainerMarker.java
index b4acc21..d128015 100644
--- a/jack/src/com/android/jack/backend/jayce/ResourceContainerMarker.java
+++ b/jack/src/com/android/jack/backend/jayce/ResourceContainerMarker.java
@@ -16,14 +16,14 @@
package com.android.jack.backend.jayce;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.marker.Marker;
import com.android.sched.marker.ValidOn;
+import com.android.sched.vfs.InputVFile;
+import java.util.ArrayList;
import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import javax.annotation.Nonnull;
@@ -31,27 +31,18 @@
* A marker that contains resources.
*/
@Description("A marker that contains resources.")
-@ValidOn(JProgram.class)
+@ValidOn(JSession.class)
public final class ResourceContainerMarker implements Marker {
@Nonnull
- private final ZipFile zipFile;
- @Nonnull
- private final List<ZipEntry> zipEntries;
+ private final List<InputVFile> resourceFiles = new ArrayList<InputVFile>();
- public ResourceContainerMarker(@Nonnull ZipFile zipFile, @Nonnull List<ZipEntry> zipEntries) {
- this.zipFile = zipFile;
- this.zipEntries = zipEntries;
+ public ResourceContainerMarker() {
}
@Nonnull
- public List<ZipEntry> getZipEntries() {
- return zipEntries;
- }
-
- @Nonnull
- public ZipFile getZipFile() {
- return zipFile;
+ public List<InputVFile> getResources() {
+ return resourceFiles;
}
@Override
@@ -60,4 +51,11 @@
return this;
}
+ public void addResource(@Nonnull InputVFile file) {
+ boolean res = resourceFiles.add(file);
+ if (!res) {
+ throw new AssertionError();
+ }
+ }
+
}
diff --git a/jack/src/com/android/jack/cfg/CfgMarkerRemover.java b/jack/src/com/android/jack/cfg/CfgMarkerRemover.java
index 7e5bab2..cf1f6a4 100644
--- a/jack/src/com/android/jack/cfg/CfgMarkerRemover.java
+++ b/jack/src/com/android/jack/cfg/CfgMarkerRemover.java
@@ -16,14 +16,17 @@
package com.android.jack.cfg;
+import com.android.jack.Options;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JVisitor;
+import com.android.jack.util.filter.Filter;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
import com.android.sched.schedulable.Constraint;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Transform;
+import com.android.sched.util.config.ThreadConfig;
import javax.annotation.Nonnull;
@@ -36,6 +39,9 @@
@Transform(remove = {ControlFlowGraph.class, BasicBlockMarker.class})
public class CfgMarkerRemover implements RunnableSchedulable<JMethod> {
+ @Nonnull
+ private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER);
+
private static class Visitor extends JVisitor {
@Override
public boolean visit(@Nonnull JStatement stmt) {
@@ -46,6 +52,11 @@
@Override
public void run(@Nonnull JMethod method) throws Exception {
+ if (method.getEnclosingType().isExternal() || method.isNative() || method.isAbstract()
+ || !filter.accept(this.getClass(), method)) {
+ return;
+ }
+
method.removeMarker(ControlFlowGraph.class);
Visitor v = new Visitor();
v.accept(method);
diff --git a/jack/src/com/android/jack/config/id/JavaVersionPropertyId.java b/jack/src/com/android/jack/config/id/JavaVersionPropertyId.java
index fe62ff9..e35e0a2 100644
--- a/jack/src/com/android/jack/config/id/JavaVersionPropertyId.java
+++ b/jack/src/com/android/jack/config/id/JavaVersionPropertyId.java
@@ -100,6 +100,14 @@
@Override
@Nonnull
+ public JavaVersionPropertyId addDefaultValue (@Nonnull JavaVersion defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public JavaVersionPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/jack/src/com/android/jack/frontend/TypeDuplicateRemoverChecker.java b/jack/src/com/android/jack/frontend/TypeDuplicateRemoverChecker.java
index c320770..eb3eb9f 100644
--- a/jack/src/com/android/jack/frontend/TypeDuplicateRemoverChecker.java
+++ b/jack/src/com/android/jack/frontend/TypeDuplicateRemoverChecker.java
@@ -26,7 +26,7 @@
import com.android.jack.ir.ast.JFieldId;
import com.android.jack.ir.ast.JInterface;
import com.android.jack.ir.ast.JNode;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.lookup.JLookup;
@@ -49,37 +49,37 @@
"counterparts in IR.")
@Name("TypeDuplicatesRemoverChecker")
@Support(SanityChecks.class)
-public class TypeDuplicateRemoverChecker implements RunnableSchedulable<JProgram> {
+public class TypeDuplicateRemoverChecker implements RunnableSchedulable<JSession> {
private static class Visitor extends JVisitor {
@Nonnull
- private final JProgram program;
+ private final JSession session;
- public Visitor(@Nonnull JProgram program) {
- this.program = program;
+ public Visitor(@Nonnull JSession session) {
+ this.session = session;
}
@Override
public void endVisit(@Nonnull JNode x) {
- checkFieldsOf(x.getClass(), x, program);
+ checkFieldsOf(x.getClass(), x, session);
}
}
@Override
- public void run(@Nonnull JProgram program) throws Exception {
- TypeDuplicateRemoverChecker.checkFieldsOf(Jack.getProgram().getPhantomLookup().getClass(),
- Jack.getProgram().getPhantomLookup(), program);
+ public void run(@Nonnull JSession session) throws Exception {
+ TypeDuplicateRemoverChecker.checkFieldsOf(Jack.getSession().getPhantomLookup().getClass(),
+ Jack.getSession().getPhantomLookup(), session);
- Visitor visitor = new Visitor(program);
- for (JDefinedClassOrInterface declaredType : program.getTypesToEmit()) {
+ Visitor visitor = new Visitor(session);
+ for (JDefinedClassOrInterface declaredType : session.getTypesToEmit()) {
visitor.accept(declaredType);
}
}
@SuppressWarnings("rawtypes")
- public static void checkFieldsOf(@Nonnull Class<?> type, @Nonnull Object node, JProgram program) {
- JLookup lookup = program.getPhantomLookup();
+ public static void checkFieldsOf(@Nonnull Class<?> type, @Nonnull Object node, JSession session) {
+ JLookup lookup = session.getPhantomLookup();
for (Field f : type.getDeclaredFields()) {
boolean fieldAccess = f.isAccessible();
try {
@@ -93,7 +93,7 @@
if (typeField instanceof JArrayType) {
// break the stack overflow (JArrayType.array <=> JArrayType.elementType)
if (((JArrayType) typeField).getElementType() != node) {
- checkFieldsOf(typeField.getClass(), typeField, program);
+ checkFieldsOf(typeField.getClass(), typeField, session);
}
}
}
@@ -113,7 +113,7 @@
checkType(node, lookup, f, t);
}
} else if (fieldObject instanceof JFieldId) {
- checkFieldsOf(fieldObject.getClass(), fieldObject, program);
+ checkFieldsOf(fieldObject.getClass(), fieldObject, session);
}
} catch (IllegalArgumentException e) {
throw new AssertionError("Error during duplicate types checking.");
@@ -126,10 +126,10 @@
}
}
if (type.getSuperclass() != null && type.getSuperclass() != JNode.class) {
- checkFieldsOf(type.getSuperclass(), node, program);
+ checkFieldsOf(type.getSuperclass(), node, session);
}
for (Class<?> interf : type.getInterfaces()) {
- checkFieldsOf(interf, node, program);
+ checkFieldsOf(interf, node, session);
}
}
diff --git a/jack/src/com/android/jack/frontend/java/JAstBuilder.java b/jack/src/com/android/jack/frontend/java/JAstBuilder.java
index 72a8b2e..c3f3ed9 100644
--- a/jack/src/com/android/jack/frontend/java/JAstBuilder.java
+++ b/jack/src/com/android/jack/frontend/java/JAstBuilder.java
@@ -21,10 +21,11 @@
import com.android.jack.backend.jayce.JayceFileImporter;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.impl.EcjSourceTypeLoader;
import com.android.jack.ir.impl.GwtAstBuilder;
import com.android.jack.ir.impl.ReferenceMapper;
+import com.android.sched.util.config.FileLocation;
import com.android.sched.util.log.Event;
import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
@@ -40,6 +41,7 @@
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
+import java.io.File;
import java.io.PrintWriter;
import java.util.List;
@@ -55,7 +57,7 @@
private static final Tracer tracer = TracerFactory.getTracer();
@Nonnull
- private final JProgram jprogram;
+ private final JSession session;
@Nonnull
private final GwtAstBuilder astBuilder;
@@ -78,7 +80,7 @@
@CheckForNull PrintWriter out,
@CheckForNull CompilationProgress progress,
@Nonnull JayceFileImporter jayceImporter,
- @Nonnull JProgram program) {
+ @Nonnull JSession session) {
super(environment,
policy,
options,
@@ -86,15 +88,15 @@
problemFactory,
out,
progress);
- jprogram = program;
- astBuilder = new GwtAstBuilder(lookupEnvironment, program);
+ this.session = session;
+ astBuilder = new GwtAstBuilder(lookupEnvironment, session);
this.jayceImporter = jayceImporter;
}
@Nonnull
private JPackage getOrCreatePackage(@Nonnull char[][] compoundName, int compoundNameLength) {
assert compoundNameLength <= compoundName.length && compoundNameLength >= 0;
- JPackage currentPackage = jprogram.getTopLevelPackage();
+ JPackage currentPackage = session.getTopLevelPackage();
for (int i = 0; i < compoundNameLength; i++) {
String name = String.valueOf(compoundName[i]);
currentPackage = currentPackage.getOrCreateSubPackage(name);
@@ -133,7 +135,7 @@
}
for (JDefinedClassOrInterface type : types) {
- jprogram.addTypeToEmit(type);
+ session.addTypeToEmit(type);
}
} finally {
jastEvent.end();
@@ -154,7 +156,7 @@
char[][] packageNames = parsedUnit.currentPackage.tokens;
enclosingPackage = getOrCreatePackage(packageNames, packageNames.length);
} else {
- enclosingPackage = jprogram.getTopLevelPackage();
+ enclosingPackage = session.getTopLevelPackage();
}
ReferenceMapper refMap = astBuilder.getTypeMap();
@@ -171,14 +173,15 @@
char[][] packageNames = unit.currentPackage.tokens;
enclosingPackage = getOrCreatePackage(packageNames, packageNames.length);
} else {
- enclosingPackage = jprogram.getTopLevelPackage();
+ enclosingPackage = session.getTopLevelPackage();
}
ReferenceMapper refMap = astBuilder.getTypeMap();
for (LocalTypeBinding binding : unit.localTypes) {
/* binding.constantPoolName() == null means that ecj detected the local type to be dead
* code and didn't completed processing */
if (binding != null && binding.constantPoolName() != null) {
- EcjSourceTypeLoader.createType(refMap, enclosingPackage, binding, null);
+ EcjSourceTypeLoader.createType(refMap, enclosingPackage, binding, null,
+ new FileLocation(new File(new String(unit.getFileName()))));
}
}
}
@@ -187,7 +190,8 @@
private void createTypes(@Nonnull JPackage enclosingPackage, @Nonnull ReferenceMapper refMap,
@Nonnull TypeDeclaration typeDeclaration) {
EcjSourceTypeLoader.createType(refMap, enclosingPackage, typeDeclaration.binding,
- typeDeclaration);
+ typeDeclaration,
+ new FileLocation(new File(new String(typeDeclaration.compilationResult.fileName))));
if (typeDeclaration.memberTypes != null) {
for (TypeDeclaration memberType : typeDeclaration.memberTypes) {
createTypes(enclosingPackage, refMap, memberType);
diff --git a/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java b/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
index d7d9810..c2657b5 100644
--- a/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
+++ b/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
@@ -18,7 +18,7 @@
import com.android.jack.backend.jayce.JayceFileImporter;
import com.android.jack.ecj.loader.jast.JAstClasspath;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.util.log.LoggerFactory;
import org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory;
@@ -55,12 +55,12 @@
LoggerFactory.getLogger();
@Nonnull
- private final JProgram program;
+ private final JSession session;
- public JackBatchCompiler(@Nonnull JProgram program,
+ public JackBatchCompiler(@Nonnull JSession session,
@Nonnull JayceFileImporter jayceFileImporter) {
super(new PrintWriter(System.out), new PrintWriter(System.err), true, null, null);
- this.program = program;
+ this.session = session;
jayceImporter = jayceFileImporter;
}
@@ -84,7 +84,7 @@
isSourceOnly,
rejectDestinationPathOnJars);
} else if (JACK_LOGICAL_PATH_ENTRY.equals(currentClasspathName)) {
- paths.add(new JAstClasspath(currentClasspathName, program.getLookup(), null));
+ paths.add(new JAstClasspath(currentClasspathName, session.getLookup(), null));
} else {
/* Call super so that it make the required checks and prepare ClasspathDex
@@ -151,7 +151,7 @@
out,
progress,
jayceImporter,
- program);
+ session);
batchCompiler.remainingIterations = maxRepetition - currentRepetition;
batchCompiler.useSingleThread = Boolean.getBoolean(USE_SINGLE_THREAD_SYSPROP);
diff --git a/jack/src/com/android/jack/ir/JackFormatIr.java b/jack/src/com/android/jack/ir/JackFormatIr.java
index 548e861..f925c2a 100644
--- a/jack/src/com/android/jack/ir/JackFormatIr.java
+++ b/jack/src/com/android/jack/ir/JackFormatIr.java
@@ -96,8 +96,8 @@
import com.android.jack.ir.ast.JPrimitiveType.JLongType;
import com.android.jack.ir.ast.JPrimitiveType.JShortType;
import com.android.jack.ir.ast.JPrimitiveType.JVoidType;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReturnStatement;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShlOperation;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JShrOperation;
@@ -216,7 +216,7 @@
JPrefixNegOperation.class,
JPrefixNotOperation.class,
JPrimitiveClassLiteral.class,
- JProgram.class,
+ JSession.class,
JReturnStatement.class,
JShlOperation.class,
JShortLiteral.class,
diff --git a/jack/src/com/android/jack/ir/JavaSourceIr.java b/jack/src/com/android/jack/ir/JavaSourceIr.java
index 27b67b3..33bd98c 100644
--- a/jack/src/com/android/jack/ir/JavaSourceIr.java
+++ b/jack/src/com/android/jack/ir/JavaSourceIr.java
@@ -117,8 +117,8 @@
import com.android.jack.ir.ast.JPrimitiveType.JLongType;
import com.android.jack.ir.ast.JPrimitiveType.JShortType;
import com.android.jack.ir.ast.JPrimitiveType.JVoidType;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReturnStatement;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShlOperation;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JShrOperation;
@@ -261,7 +261,7 @@
JPrefixNegOperation.class,
JPrefixNotOperation.class,
JPrimitiveClassLiteral.class,
- JProgram.class,
+ JSession.class,
JReturnStatement.class,
JShlOperation.class,
JShortLiteral.class,
diff --git a/jack/src/com/android/jack/ir/ast/Annotable.java b/jack/src/com/android/jack/ir/ast/Annotable.java
index 3d3ac71..c6c68c5 100644
--- a/jack/src/com/android/jack/ir/ast/Annotable.java
+++ b/jack/src/com/android/jack/ir/ast/Annotable.java
@@ -33,6 +33,4 @@
@Nonnull
Collection<JAnnotationLiteral> getAnnotations();
-
- void updateAnnotations();
}
diff --git a/jack/src/com/android/jack/ir/ast/AnnotationSet.java b/jack/src/com/android/jack/ir/ast/AnnotationSet.java
index 4384786..af611df 100644
--- a/jack/src/com/android/jack/ir/ast/AnnotationSet.java
+++ b/jack/src/com/android/jack/ir/ast/AnnotationSet.java
@@ -24,9 +24,7 @@
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -103,21 +101,4 @@
annotation.traverse(schedule);
}
}
-
- void updateAnnotationSet() {
- Map<JAnnotation, JAnnotationLiteral> updatedAnnotations =
- new HashMap<JAnnotation, JAnnotationLiteral>();
-
- Iterator<Entry<JAnnotation, JAnnotationLiteral>> it = annotations.entrySet().iterator();
- while (it.hasNext()) {
- Entry<JAnnotation, JAnnotationLiteral> entry = it.next();
- JAnnotation valueType = entry.getValue().getType();
- if (entry.getKey() != valueType) {
- updatedAnnotations.put(valueType, entry.getValue());
- it.remove();
- }
- }
-
- annotations.putAll(updatedAnnotations);
- }
}
diff --git a/jack/src/com/android/jack/ir/ast/JAbstractStringLiteral.java b/jack/src/com/android/jack/ir/ast/JAbstractStringLiteral.java
index e741075..ccf8737 100644
--- a/jack/src/com/android/jack/ir/ast/JAbstractStringLiteral.java
+++ b/jack/src/com/android/jack/ir/ast/JAbstractStringLiteral.java
@@ -37,7 +37,7 @@
@Override
@Nonnull
public JClass getType() {
- return Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
+ return Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
}
@Nonnull
diff --git a/jack/src/com/android/jack/ir/ast/JArrayType.java b/jack/src/com/android/jack/ir/ast/JArrayType.java
index 97f6d9b..3ca3812 100644
--- a/jack/src/com/android/jack/ir/ast/JArrayType.java
+++ b/jack/src/com/android/jack/ir/ast/JArrayType.java
@@ -126,7 +126,7 @@
public List<JInterface> getImplements() {
// TODO(mikaelpeltier): Move init of superInterfaces into constructor (Bug:9652410)
if (superInterfaces.isEmpty()) {
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
superInterfaces.add(lookup.getInterface(CommonTypes.JAVA_IO_SERIALIZABLE));
superInterfaces.add(lookup.getInterface(CommonTypes.JAVA_LANG_CLONEABLE));
}
diff --git a/jack/src/com/android/jack/ir/ast/JCastOperation.java b/jack/src/com/android/jack/ir/ast/JCastOperation.java
index d4dc73b..65bcb8d 100644
--- a/jack/src/com/android/jack/ir/ast/JCastOperation.java
+++ b/jack/src/com/android/jack/ir/ast/JCastOperation.java
@@ -62,13 +62,6 @@
this.castType = type;
}
- /**
- * Resolve an external reference during AST stitching.
- */
- public void resolve(@Nonnull JType newType) {
- castType = newType;
- }
-
@Override
protected void replaceImpl(@Nonnull JNode existingNode, @Nonnull JNode newNode)
throws UnsupportedOperationException {
diff --git a/jack/src/com/android/jack/ir/ast/JClassLiteral.java b/jack/src/com/android/jack/ir/ast/JClassLiteral.java
index f2f409b..a4edff2 100644
--- a/jack/src/com/android/jack/ir/ast/JClassLiteral.java
+++ b/jack/src/com/android/jack/ir/ast/JClassLiteral.java
@@ -37,7 +37,7 @@
private JClass javaLangClass;
- private JType refType;
+ private final JType refType;
public JClassLiteral(SourceInfo sourceInfo, JType type, JClass javaLangClass) {
super(sourceInfo);
@@ -63,13 +63,6 @@
return true;
}
- /**
- * Resolve an external reference during AST stitching.
- */
- public void resolve(JType newType) {
- refType = newType;
- }
-
@Override
public void traverse(@Nonnull JVisitor visitor) {
if (visitor.visit(this)) {
diff --git a/jack/src/com/android/jack/ir/ast/JConditionalExpression.java b/jack/src/com/android/jack/ir/ast/JConditionalExpression.java
index 037a509..0d8441b 100644
--- a/jack/src/com/android/jack/ir/ast/JConditionalExpression.java
+++ b/jack/src/com/android/jack/ir/ast/JConditionalExpression.java
@@ -104,7 +104,7 @@
}
// JLS-7 15.25 fourth bullet
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
if (isNumber(thenType) && isNumber(elseType)) {
// first sub-bullet
if ((JPrimitiveTypeEnum.BYTE.getType().isEquivalent(thenType)
diff --git a/jack/src/com/android/jack/ir/ast/JConstructor.java b/jack/src/com/android/jack/ir/ast/JConstructor.java
index c8a915f..392f3c4 100644
--- a/jack/src/com/android/jack/ir/ast/JConstructor.java
+++ b/jack/src/com/android/jack/ir/ast/JConstructor.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.SourceInfo;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
import com.android.jack.load.MethodLoader;
+import com.android.jack.util.NamingTools;
import com.android.sched.item.Component;
import com.android.sched.item.Description;
import com.android.sched.scheduler.ScheduleInstance;
@@ -35,7 +36,7 @@
public JConstructor(@Nonnull SourceInfo info, @Nonnull JDefinedClass enclosingType,
int modifier) {
- super(info, new JMethodId(JProgram.INIT_NAME, MethodKind.INSTANCE_NON_VIRTUAL),
+ super(info, new JMethodId(NamingTools.INIT_NAME, MethodKind.INSTANCE_NON_VIRTUAL),
enclosingType, JPrimitiveTypeEnum.VOID.getType(), modifier);
assert JModifier.isMethodModifier(modifier);
assert JModifier.isValidMethodModifier(modifier);
@@ -49,7 +50,7 @@
public JConstructor(@Nonnull SourceInfo info, @Nonnull JDefinedClass enclosingType, int modifier,
@Nonnull MethodLoader loader) {
- super(info, new JMethodId(JProgram.INIT_NAME, MethodKind.INSTANCE_NON_VIRTUAL),
+ super(info, new JMethodId(NamingTools.INIT_NAME, MethodKind.INSTANCE_NON_VIRTUAL),
enclosingType, JPrimitiveTypeEnum.VOID.getType(), modifier, loader);
assert JModifier.isMethodModifier(modifier);
assert JModifier.isValidMethodModifier(modifier);
diff --git a/jack/src/com/android/jack/ir/ast/JDefinedClassOrInterface.java b/jack/src/com/android/jack/ir/ast/JDefinedClassOrInterface.java
index 9a76555..2ab63d1 100644
--- a/jack/src/com/android/jack/ir/ast/JDefinedClassOrInterface.java
+++ b/jack/src/com/android/jack/ir/ast/JDefinedClassOrInterface.java
@@ -87,6 +87,9 @@
@Nonnull
protected final ClassOrInterfaceLoader loader;
+ @Nonnull
+ private final Location location;
+
public JDefinedClassOrInterface(@Nonnull SourceInfo info, @Nonnull String name, int modifier,
@Nonnull JPackage enclosingPackage) {
this(info, name, modifier, enclosingPackage, NopClassOrInterfaceLoader.INSTANCE);
@@ -104,6 +107,7 @@
this.enclosingPackage = enclosingPackage;
this.enclosingPackage.addType(this);
this.loader = loader;
+ location = loader.getLocation(this);
}
public void setModifier(int modifier) {
@@ -193,8 +197,8 @@
return enclosingType;
}
- public JProgram getJProgram() {
- return enclosingPackage.getProgram();
+ public JSession getSession() {
+ return enclosingPackage.getSession();
}
/**
@@ -404,11 +408,6 @@
}
}
- @Override
- public void updateAnnotations() {
- annotations.updateAnnotationSet();
- }
-
@Nonnull
@Override
public JMethodId getMethodId(@Nonnull String name, @Nonnull List<? extends JType> argsType,
@@ -550,7 +549,7 @@
@Nonnull
public Location getLocation() {
- return loader.getLocation(this);
+ return location;
}
}
diff --git a/jack/src/com/android/jack/ir/ast/JEnumLiteral.java b/jack/src/com/android/jack/ir/ast/JEnumLiteral.java
index 12d593f..cd075bc 100644
--- a/jack/src/com/android/jack/ir/ast/JEnumLiteral.java
+++ b/jack/src/com/android/jack/ir/ast/JEnumLiteral.java
@@ -33,7 +33,7 @@
private static final long serialVersionUID = 1L;
@Nonnull
- private JFieldId value;
+ private final JFieldId value;
public JEnumLiteral(@Nonnull SourceInfo sourceInfo, @Nonnull JFieldId value) {
super(sourceInfo);
@@ -69,13 +69,6 @@
return value;
}
- /**
- * Resolve an external reference during AST stitching.
- */
- public void resolve(@Nonnull JFieldId newField) {
- value = newField;
- }
-
@Override
public void visit(@Nonnull JVisitor visitor, @Nonnull TransformRequest transformRequest)
throws Exception {
diff --git a/jack/src/com/android/jack/ir/ast/JField.java b/jack/src/com/android/jack/ir/ast/JField.java
index 9d95317..31bd627 100644
--- a/jack/src/com/android/jack/ir/ast/JField.java
+++ b/jack/src/com/android/jack/ir/ast/JField.java
@@ -258,10 +258,4 @@
super.transform(existingNode, newNode, transformation);
}
}
-
- @Override
- public void updateAnnotations() {
- annotations.updateAnnotationSet();
- }
-
}
diff --git a/jack/src/com/android/jack/ir/ast/JFieldRef.java b/jack/src/com/android/jack/ir/ast/JFieldRef.java
index 0c43e05..c0396e6 100644
--- a/jack/src/com/android/jack/ir/ast/JFieldRef.java
+++ b/jack/src/com/android/jack/ir/ast/JFieldRef.java
@@ -39,7 +39,7 @@
private JClassOrInterface receiverType;
@Nonnull
- private JFieldId fieldId;
+ private final JFieldId fieldId;
/**
* This can only be null if the referenced field is static.
@@ -86,13 +86,6 @@
return true;
}
- /**
- * Resolve an external reference during AST stitching.
- */
- public void resolve(@Nonnull JFieldId fieldId) {
- this.fieldId = fieldId;
- }
-
@Override
public void traverse(@Nonnull JVisitor visitor) {
if (visitor.visit(this)) {
diff --git a/jack/src/com/android/jack/ir/ast/JInstanceOf.java b/jack/src/com/android/jack/ir/ast/JInstanceOf.java
index a4682ee..6ec1931 100644
--- a/jack/src/com/android/jack/ir/ast/JInstanceOf.java
+++ b/jack/src/com/android/jack/ir/ast/JInstanceOf.java
@@ -33,7 +33,7 @@
private static final long serialVersionUID = 1L;
private JExpression expr;
- private JReferenceType testType;
+ private final JReferenceType testType;
public JInstanceOf(SourceInfo info, JReferenceType testType, JExpression expression) {
super(info);
@@ -59,13 +59,6 @@
return true;
}
- /**
- * Resolve an external reference during AST stitching.
- */
- public void resolve(JReferenceType newType) {
- testType = newType;
- }
-
@Override
public void traverse(@Nonnull JVisitor visitor) {
if (visitor.visit(this)) {
diff --git a/jack/src/com/android/jack/ir/ast/JMethod.java b/jack/src/com/android/jack/ir/ast/JMethod.java
index f29a99a..42185f8 100644
--- a/jack/src/com/android/jack/ir/ast/JMethod.java
+++ b/jack/src/com/android/jack/ir/ast/JMethod.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.SourceInfo;
import com.android.jack.load.MethodLoader;
+import com.android.jack.util.NamingTools;
import com.android.sched.item.Component;
import com.android.sched.item.Description;
import com.android.sched.marker.Marker;
@@ -391,11 +392,6 @@
visitor.visit(this, transformRequest);
}
- @Override
- public void updateAnnotations() {
- annotations.updateAnnotationSet();
- }
-
@Nonnull
public JMethodId getMethodId() {
return methodId;
@@ -423,4 +419,8 @@
public JThis getThis() {
return jThis;
}
+
+ public static boolean isClinit(@Nonnull JMethod method) {
+ return method.getName().equals(NamingTools.STATIC_INIT_NAME);
+ }
}
diff --git a/jack/src/com/android/jack/ir/ast/JMethodCall.java b/jack/src/com/android/jack/ir/ast/JMethodCall.java
index 99e2692..7c92419 100644
--- a/jack/src/com/android/jack/ir/ast/JMethodCall.java
+++ b/jack/src/com/android/jack/ir/ast/JMethodCall.java
@@ -56,7 +56,7 @@
@Nonnull
private JMethodId methodId;
@Nonnull
- private JType returnType;
+ private final JType returnType;
@Nonnull
private final DispatchKind dispatchKind;
@@ -189,10 +189,6 @@
return returnType;
}
- public void resolveType(@Nonnull JType returnType) {
- this.returnType = returnType;
- }
-
public void resolveMethodId(@Nonnull JMethodId methodId) {
this.methodId = methodId;
}
@@ -239,11 +235,6 @@
return methodId.getName();
}
- public void resolve(@Nonnull JClassOrInterface receiverType, @Nonnull JType returnType) {
- setReceiverType(receiverType);
- this.returnType = returnType;
- }
-
@Nonnull
public DispatchKind getDispatchKind() {
return dispatchKind;
diff --git a/jack/src/com/android/jack/ir/ast/JMethodId.java b/jack/src/com/android/jack/ir/ast/JMethodId.java
index a379cc4..3bead39 100644
--- a/jack/src/com/android/jack/ir/ast/JMethodId.java
+++ b/jack/src/com/android/jack/ir/ast/JMethodId.java
@@ -17,6 +17,7 @@
package com.android.jack.ir.ast;
import com.android.jack.Jack;
+import com.android.jack.util.NamingTools;
import com.android.sched.marker.LocalMarkerManager;
import java.io.Serializable;
@@ -48,16 +49,16 @@
@Nonnull
private String name;
@Nonnull
- private List<JType> paramTypes = new ArrayList<JType>();
+ private final List<JType> paramTypes = new ArrayList<JType>();
@Nonnull
- private List<JMethod> methods = new ArrayList<JMethod>();
+ private final List<JMethod> methods = new ArrayList<JMethod>();
@Nonnull
private final MethodKind methodKind;
public JMethodId(@Nonnull String name, @Nonnull MethodKind kind) {
assert !(name.contains("(") || name.contains(")"));
- assert (!("<init>".equals(name) || "<clinit>".equals(name)))
+ assert (!(NamingTools.INIT_NAME.equals(name) || NamingTools.STATIC_INIT_NAME.equals(name)))
|| (kind != MethodKind.INSTANCE_VIRTUAL);
this.name = name;
this.methodKind = kind;
@@ -144,14 +145,6 @@
return paramTypes;
}
- public void resolve(@Nonnull List<JType> paramTypes, @Nonnull Collection<JMethod> methods) {
- this.paramTypes = paramTypes;
- this.methods = new ArrayList<JMethod>();
- for (JMethod jMethod : methods) {
- addMethod(jMethod);
- }
- }
-
@Override
public void setName(@Nonnull String newName) {
assert !(name.contains("(") || name.contains(")"));
diff --git a/jack/src/com/android/jack/ir/ast/JPackage.java b/jack/src/com/android/jack/ir/ast/JPackage.java
index 5af0b69..a09b06f 100644
--- a/jack/src/com/android/jack/ir/ast/JPackage.java
+++ b/jack/src/com/android/jack/ir/ast/JPackage.java
@@ -23,6 +23,9 @@
import com.android.sched.item.Description;
import com.android.sched.scheduler.ScheduleInstance;
import com.android.sched.transform.TransformRequest;
+import com.android.sched.util.log.stats.Counter;
+import com.android.sched.util.log.stats.CounterImpl;
+import com.android.sched.util.log.stats.StatisticId;
import java.util.ArrayList;
import java.util.Collection;
@@ -39,6 +42,16 @@
private static final long serialVersionUID = 1L;
+ @Nonnull
+ public static final StatisticId<Counter> PACKAGE_CREATION = new StatisticId<Counter>(
+ "jack.package.create", "Created JPackage",
+ CounterImpl.class, Counter.class);
+
+ @Nonnull
+ public static final StatisticId<Counter> PHANTOM_CREATION = new StatisticId<Counter>(
+ "jack.phantom.create", "Created phantom class or interface",
+ CounterImpl.class, Counter.class);
+
@CheckForNull
private JPackage enclosingPackage;
@@ -69,7 +82,7 @@
private String name;
@Nonnull
- private final JProgram program;
+ private final JSession session;
@Nonnull
private final transient ComposedPackageLoader loader;
@@ -77,14 +90,14 @@
private boolean isOnPath;
public JPackage(
- @Nonnull String name, @Nonnull JProgram program, @CheckForNull JPackage enclosingPackage) {
- this(name, program, enclosingPackage, new ComposedPackageLoader());
+ @Nonnull String name, @Nonnull JSession session, @CheckForNull JPackage enclosingPackage) {
+ this(name, session, enclosingPackage, new ComposedPackageLoader());
}
- public JPackage(@Nonnull String name, @Nonnull JProgram program,
+ public JPackage(@Nonnull String name, @Nonnull JSession session,
@CheckForNull JPackage enclosingPackage, @Nonnull ComposedPackageLoader loader) {
super(SourceOrigin.UNKNOWN);
- this.program = program;
+ this.session = session;
this.name = name;
this.loader = loader;
if (enclosingPackage != null) {
@@ -93,7 +106,8 @@
this.enclosingPackage.addPackage(this);
}
isOnPath = loader.isOnPath(this);
- }
+ session.getTracer().getStatistic(PACKAGE_CREATION).incValue();
+ }
public void addType(@Nonnull JDefinedClassOrInterface type) {
declaredTypes.add(type);
@@ -158,7 +172,7 @@
return getSubPackage(packageName);
} catch (JPackageLookupException e) {
assert !packageName.isEmpty();
- JPackage newPackage = new JPackage(packageName, program, this);
+ JPackage newPackage = new JPackage(packageName, session, this);
newPackage.updateParents(this);
return newPackage;
}
@@ -198,6 +212,7 @@
}
JPhantomClassOrInterface phantom = new JPhantomClassOrInterface(typeName, this);
phantomTypes.add(phantom);
+ session.getTracer().getStatistic(PHANTOM_CREATION).incValue();
return phantom;
}
}
@@ -219,6 +234,7 @@
}
JPhantomClass phantom = new JPhantomClass(typeName, this);
phantomClasses.add(phantom);
+ session.getTracer().getStatistic(PHANTOM_CREATION).incValue();
return phantom;
}
@@ -239,6 +255,7 @@
}
JPhantomEnum phantom = new JPhantomEnum(typeName, this);
phantomEnums.add(phantom);
+ session.getTracer().getStatistic(PHANTOM_CREATION).incValue();
return phantom;
}
@@ -259,6 +276,7 @@
}
JPhantomInterface phantom = new JPhantomInterface(typeName, this);
phantomInterfaces.add(phantom);
+ session.getTracer().getStatistic(PHANTOM_CREATION).incValue();
return phantom;
}
@@ -279,6 +297,7 @@
}
JPhantomAnnotation phantom = new JPhantomAnnotation(typeName, this);
phantomAnnotations.add(phantom);
+ session.getTracer().getStatistic(PHANTOM_CREATION).incValue();
return phantom;
}
@@ -292,8 +311,8 @@
}
@Nonnull
- public JProgram getProgram() {
- return program;
+ public JSession getSession() {
+ return session;
}
@Override
diff --git a/jack/src/com/android/jack/ir/ast/JPrimitiveType.java b/jack/src/com/android/jack/ir/ast/JPrimitiveType.java
index 69fec7e..93a522e 100644
--- a/jack/src/com/android/jack/ir/ast/JPrimitiveType.java
+++ b/jack/src/com/android/jack/ir/ast/JPrimitiveType.java
@@ -30,7 +30,6 @@
import com.android.sched.scheduler.ScheduleInstance;
import com.android.sched.transform.TransformRequest;
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -71,9 +70,6 @@
@Nonnull
protected final String name;
- @CheckForNull
- private JArrayType array;
-
private JPrimitiveType(@Nonnull String name, @Nonnull String signatureName) {
super(SourceOrigin.UNKNOWN);
this.name = name;
@@ -156,11 +152,11 @@
@Nonnull
public final JClass getWrapperType() {
- return Jack.getProgram().getPhantomLookup().getClass(getWrapperCommonType());
+ return Jack.getSession().getPhantomLookup().getClass(getWrapperCommonType());
}
public boolean isWrapperType(@Nonnull JType candidate) {
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
return lookup.getClass(getWrapperCommonType()) == candidate
|| lookup.getType(getWrapperCommonType()) == candidate;
}
@@ -187,11 +183,7 @@
@Override
@Nonnull
public JArrayType getArray() {
- if (array == null) {
- array = new JArrayType(this);
- }
- assert array != null;
- return array;
+ return Jack.getSession().getArrayOf(getPrimitiveTypeEnum());
}
@Nonnull
@@ -540,11 +532,12 @@
CommonType getWrapperCommonType() {
return CommonTypes.JAVA_LANG_VOID;
}
- }
- static void reset() {
- for (JPrimitiveTypeEnum typeEnum : JPrimitiveTypeEnum.values()) {
- typeEnum.type.array = null;
+ @Override
+ @Nonnull
+ public JArrayType getArray() {
+ // Array of void does not exist.
+ throw new AssertionError();
}
}
}
diff --git a/jack/src/com/android/jack/ir/ast/JReferenceTypeCommon.java b/jack/src/com/android/jack/ir/ast/JReferenceTypeCommon.java
index 3b7890d..0eaf0b7 100644
--- a/jack/src/com/android/jack/ir/ast/JReferenceTypeCommon.java
+++ b/jack/src/com/android/jack/ir/ast/JReferenceTypeCommon.java
@@ -68,8 +68,8 @@
protected boolean isTrivialCast(@Nonnull JReferenceType castTo) {
if (this == castTo
- || castTo == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT)
- || castTo == Jack.getProgram().getPhantomLookup().getType(CommonTypes.JAVA_LANG_OBJECT)) {
+ || castTo == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT)
+ || castTo == Jack.getSession().getPhantomLookup().getType(CommonTypes.JAVA_LANG_OBJECT)) {
return true;
}
diff --git a/jack/src/com/android/jack/ir/ast/JProgram.java b/jack/src/com/android/jack/ir/ast/JSession.java
similarity index 75%
rename from jack/src/com/android/jack/ir/ast/JProgram.java
rename to jack/src/com/android/jack/ir/ast/JSession.java
index 83f455e..61801ed 100644
--- a/jack/src/com/android/jack/ir/ast/JProgram.java
+++ b/jack/src/com/android/jack/ir/ast/JSession.java
@@ -16,17 +16,17 @@
package com.android.jack.ir.ast;
-import com.android.jack.Jack;
-import com.android.jack.ir.SourceInfo;
import com.android.jack.ir.SourceOrigin;
+import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
import com.android.jack.load.ComposedPackageLoader;
-import com.android.jack.lookup.CommonTypes;
import com.android.jack.lookup.JNodeLookup;
import com.android.jack.lookup.JPhantomLookup;
import com.android.sched.item.Component;
import com.android.sched.item.Description;
import com.android.sched.scheduler.ScheduleInstance;
import com.android.sched.transform.TransformRequest;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
import java.util.ArrayList;
import java.util.List;
@@ -35,23 +35,13 @@
import javax.annotation.Nonnull;
/**
- * Root for the AST representing an entire Java program.
+ * Storage for information concerning one compilation.
*/
-@Description("Representing an entire Java program")
-public class JProgram extends JNode {
+@Description("Representing a compilation")
+public class JSession extends JNode {
private static final long serialVersionUID = 1L;
- public static final String STATIC_INIT_NAME = "<clinit>";
-
- public static final String INIT_NAME = "<init>";
-
- public static boolean isClinit(JMethod method) {
- return method.getName().equals(STATIC_INIT_NAME);
- }
-
- public final List<JDefinedClass> codeGenTypes = new ArrayList<JDefinedClass>();
-
@Nonnull
private final List<JDefinedClassOrInterface> typesToEmit =
new ArrayList<JDefinedClassOrInterface>();
@@ -65,9 +55,14 @@
@Nonnull
private final transient JPhantomLookup phantomLookup;
- public JProgram() {
- super(SourceOrigin.create(0, 0, JProgram.class.getName()));
- JPrimitiveType.reset();
+ @Nonnull
+ private final JArrayType[] primitiveArrays = new JArrayType[JPrimitiveTypeEnum.values().length];
+
+ @Nonnull
+ private final transient Tracer tracer = TracerFactory.getTracer();
+
+ public JSession() {
+ super(SourceOrigin.create(0, 0, JSession.class.getName()));
topLevelPackage = new JPackage("", this, null);
topLevelPackage.updateParents(this);
lookup = new JNodeLookup(topLevelPackage);
@@ -87,6 +82,11 @@
return lookup;
}
+ @Nonnull
+ public Tracer getTracer() {
+ return tracer;
+ }
+
/**
* @return the phantom lookup
*/
@@ -111,19 +111,6 @@
return topLevelPackage;
}
- public JStringLiteral getLiteralString(SourceInfo sourceInfo, char[] s) {
- return getLiteralString(sourceInfo, String.valueOf(s));
- }
-
- public JStringLiteral getLiteralString(SourceInfo sourceInfo, String s) {
- return new JStringLiteral(sourceInfo, s);
- }
-
- public boolean isJavaLangString(JType type) {
- JClass jls = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
- return type == jls;
- }
-
@Override
public void traverse(@Nonnull JVisitor visitor) {
if (visitor.visit(this)) {
@@ -156,4 +143,13 @@
throws Exception {
visitor.visit(this, transformRequest);
}
+
+ @Nonnull
+ synchronized JArrayType getArrayOf(JPrimitiveTypeEnum primitive) {
+ assert primitive != JPrimitiveTypeEnum.VOID;
+ if (primitiveArrays[primitive.ordinal()] == null) {
+ primitiveArrays[primitive.ordinal()] = new JArrayType(primitive.getType());
+ }
+ return primitiveArrays[primitive.ordinal()];
+ }
}
diff --git a/jack/src/com/android/jack/ir/ast/JVariable.java b/jack/src/com/android/jack/ir/ast/JVariable.java
index caa78ba..572a977 100644
--- a/jack/src/com/android/jack/ir/ast/JVariable.java
+++ b/jack/src/com/android/jack/ir/ast/JVariable.java
@@ -121,9 +121,4 @@
super.transform(existingNode, newNode, transformation);
}
}
-
- @Override
- public void updateAnnotations() {
- annotations.updateAnnotationSet();
- }
}
diff --git a/jack/src/com/android/jack/ir/ast/JVisitor.java b/jack/src/com/android/jack/ir/ast/JVisitor.java
index 5514b91..8534e21 100644
--- a/jack/src/com/android/jack/ir/ast/JVisitor.java
+++ b/jack/src/com/android/jack/ir/ast/JVisitor.java
@@ -374,7 +374,7 @@
endVisit((JType) x);
}
- public void endVisit(@Nonnull JProgram x) {
+ public void endVisit(@Nonnull JSession x) {
endVisit((JNode) x);
}
@@ -750,7 +750,7 @@
return visit((JType) x);
}
- public boolean visit(@Nonnull JProgram x) {
+ public boolean visit(@Nonnull JSession x) {
return visit((JNode) x);
}
@@ -1194,7 +1194,7 @@
visit((JType) x, transformRequest);
}
- public void visit(@Nonnull JProgram x, @Nonnull TransformRequest transformRequest)
+ public void visit(@Nonnull JSession x, @Nonnull TransformRequest transformRequest)
throws Exception {
visit((JNode) x, transformRequest);
}
diff --git a/jack/src/com/android/jack/ir/impl/EcjSourceTypeLoader.java b/jack/src/com/android/jack/ir/impl/EcjSourceTypeLoader.java
index 172e9b6..b944f6c 100644
--- a/jack/src/com/android/jack/ir/impl/EcjSourceTypeLoader.java
+++ b/jack/src/com/android/jack/ir/impl/EcjSourceTypeLoader.java
@@ -34,7 +34,6 @@
import com.android.jack.lookup.JLookup;
import com.android.jack.util.NamingTools;
import com.android.sched.marker.Marker;
-import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.Location;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -46,7 +45,6 @@
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
-import java.io.File;
import java.lang.ref.WeakReference;
import java.util.List;
@@ -82,7 +80,7 @@
@Nonnull
private final WeakReference<SourceTypeBinding> bindingRef;
- @Nonnull
+ @CheckForNull
private final WeakReference<TypeDeclaration> declarationRef;
@Nonnull
@@ -91,10 +89,14 @@
private int loadStatus = 0;
@Nonnull
+ private final Location location;
+
+ @Nonnull
public static JDefinedClassOrInterface createType(@Nonnull ReferenceMapper refMap,
@Nonnull JPackage enclosingPackage, @Nonnull SourceTypeBinding binding,
- @CheckForNull TypeDeclaration typeDeclaration) {
- EcjSourceTypeLoader loader = new EcjSourceTypeLoader(refMap, binding, typeDeclaration);
+ @CheckForNull TypeDeclaration typeDeclaration, Location location) {
+ EcjSourceTypeLoader loader = new EcjSourceTypeLoader(refMap, binding, typeDeclaration,
+ location);
CudInfo cuInfo = new CudInfo(binding.scope.referenceCompilationUnit());
SourceInfo info = ReferenceMapper.makeSourceInfo(cuInfo, binding.scope.referenceContext);
String name;
@@ -134,24 +136,27 @@
} else {
throw new AssertionError("ReferenceBinding is not a class, interface, or enum.");
}
- type.updateParents(enclosingPackage.getProgram());
+ type.updateParents(enclosingPackage.getSession());
return type;
}
EcjSourceTypeLoader(@Nonnull ReferenceMapper refMap, @Nonnull SourceTypeBinding binding,
- @CheckForNull TypeDeclaration typeDeclaration) {
+ @CheckForNull TypeDeclaration typeDeclaration, @Nonnull Location location) {
this.refMap = new WeakReference<ReferenceMapper>(refMap);
this.bindingRef = new WeakReference<SourceTypeBinding>(binding);
- this.declarationRef = new WeakReference<TypeDeclaration>(typeDeclaration);
+ if (typeDeclaration != null) {
+ this.declarationRef = new WeakReference<TypeDeclaration>(typeDeclaration);
+ } else {
+ this.declarationRef = null;
+ }
+ this.location = location;
}
@Override
@Nonnull
public Location getLocation(@Nonnull JDefinedClassOrInterface loaded) {
- TypeDeclaration decl = declarationRef.get();
- assert decl != null;
- return new FileLocation(new File(new String(decl.compilationResult.fileName)));
+ return location;
}
@@ -196,7 +201,7 @@
return;
}
SourceTypeBinding binding = getBinding(loaded);
- JLookup lookup = loaded.getEnclosingPackage().getProgram().getPhantomLookup();
+ JLookup lookup = loaded.getEnclosingPackage().getSession().getPhantomLookup();
if (loaded instanceof JDefinedClass) {
ReferenceBinding superclass = binding.superclass();
if (superclass != null) {
@@ -278,11 +283,14 @@
if (isLoaded(Scope.INNERS)) {
return;
}
- TypeDeclaration declaration = declarationRef.get();
- if (declaration != null && declaration.memberTypes != null) {
- ReferenceMapper referenceMapper = refMap.get();
- for (TypeDeclaration memberType : declaration.memberTypes) {
- ((JDefinedClassOrInterface) referenceMapper.get(memberType.binding)).getEnclosingType();
+ if (declarationRef != null) {
+ TypeDeclaration declaration = declarationRef.get();
+ assert declaration != null;
+ if (declaration.memberTypes != null) {
+ ReferenceMapper referenceMapper = refMap.get();
+ for (TypeDeclaration memberType : declaration.memberTypes) {
+ ((JDefinedClassOrInterface) referenceMapper.get(memberType.binding)).getEnclosingType();
+ }
}
}
markLoaded(Scope.INNERS);
@@ -310,7 +318,7 @@
return;
}
SourceTypeBinding binding = getBinding(loaded);
- JLookup lookup = loaded.getEnclosingPackage().getProgram().getPhantomLookup();
+ JLookup lookup = loaded.getEnclosingPackage().getSession().getPhantomLookup();
for (MethodBinding methodBinding : binding.methods()) {
load(lookup, loaded, methodBinding);
}
@@ -331,7 +339,7 @@
return;
}
SourceTypeBinding binding = getBinding(loaded);
- JLookup lookup = loaded.getEnclosingPackage().getProgram().getPhantomLookup();
+ JLookup lookup = loaded.getEnclosingPackage().getSession().getPhantomLookup();
for (FieldBinding fieldBinding : binding.fields()) {
load(lookup, loaded, fieldBinding);
}
diff --git a/jack/src/com/android/jack/ir/impl/GwtAstBuilder.java b/jack/src/com/android/jack/ir/impl/GwtAstBuilder.java
index 351b7c8..a54416c 100644
--- a/jack/src/com/android/jack/ir/impl/GwtAstBuilder.java
+++ b/jack/src/com/android/jack/ir/impl/GwtAstBuilder.java
@@ -98,9 +98,9 @@
import com.android.jack.ir.ast.JPrefixOperation;
import com.android.jack.ir.ast.JPrimitiveType;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReferenceType;
import com.android.jack.ir.ast.JReturnStatement;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JStringLiteral;
@@ -119,6 +119,7 @@
import com.android.jack.ir.ast.marker.OriginalTypeInfo;
import com.android.jack.ir.ast.marker.ThisRefTypeInfo;
import com.android.jack.lookup.CommonTypes;
+import com.android.jack.util.NamingTools;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -239,7 +240,7 @@
/**
* Constructs a GWT Java AST from a single isolated compilation unit. The AST is
- * not associated with any {@link com.android.jack.ir.ast.JProgram} and will
+ * not associated with any {@link com.android.jack.ir.ast.JSession} and will
* contain unresolved references.
*/
public class GwtAstBuilder {
@@ -2248,7 +2249,8 @@
JNewArray newExpr = JNewArray.createWithInits(info, enumArrayType, initializers);
JFieldRef valuesRef = new JFieldRef(info, null, valuesField.getId(), type);
JAsgOperation assignValues = new JAsgOperation(info, valuesRef, newExpr);
- JMethod clinit = type.getMethod(JProgram.STATIC_INIT_NAME, JPrimitiveTypeEnum.VOID.getType());
+ JMethod clinit = type.getMethod(NamingTools.STATIC_INIT_NAME,
+ JPrimitiveTypeEnum.VOID.getType());
JAbstractMethodBody body = clinit.getBody();
assert body instanceof JMethodBody;
JBlock clinitBlock = ((JMethodBody) body).getBlock();
@@ -2585,7 +2587,8 @@
JMethod initMeth;
if (x.isStatic()) {
initMeth =
- curClass.type.getMethod(JProgram.STATIC_INIT_NAME, JPrimitiveTypeEnum.VOID.getType());
+ curClass.type.getMethod(NamingTools.STATIC_INIT_NAME,
+ JPrimitiveTypeEnum.VOID.getType());
} else {
initMeth = curClass.type.getMethod(INIT_METHOD_NAME, JPrimitiveTypeEnum.VOID.getType());
}
@@ -3185,9 +3188,9 @@
private final LookupEnvironment lookupEnvironment;
public GwtAstBuilder(@Nonnull LookupEnvironment lookupEnvironment,
- @Nonnull JProgram program) {
+ @Nonnull JSession session) {
this.lookupEnvironment = lookupEnvironment;
- typeMap = new ReferenceMapper(program.getLookup(), lookupEnvironment);
+ typeMap = new ReferenceMapper(session.getLookup(), lookupEnvironment);
}
/**
@@ -3457,7 +3460,7 @@
int modifier = JModifier.STATIC | JModifier.STATIC_INIT;
JMethod method =
new JMethod(info,
- new JMethodId(JProgram.STATIC_INIT_NAME, MethodKind.STATIC),
+ new JMethodId(NamingTools.STATIC_INIT_NAME, MethodKind.STATIC),
enclosingType,
JPrimitiveTypeEnum.VOID.getType(),
modifier);
diff --git a/jack/src/com/android/jack/ir/impl/SourceGenerationVisitor.java b/jack/src/com/android/jack/ir/impl/SourceGenerationVisitor.java
index 4e19899..e9c4cf5 100644
--- a/jack/src/com/android/jack/ir/impl/SourceGenerationVisitor.java
+++ b/jack/src/com/android/jack/ir/impl/SourceGenerationVisitor.java
@@ -22,7 +22,7 @@
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.util.TextOutput;
import javax.annotation.Nonnull;
@@ -61,7 +61,7 @@
newline();
}
for (JMethod it : x.getMethods()) {
- if (JProgram.isClinit(it)) {
+ if (JMethod.isClinit(it)) {
// Suppress empty clinit.
JMethodBody body = (JMethodBody) it.getBody();
assert body != null;
@@ -100,7 +100,7 @@
}
@Override
- public boolean visit(@Nonnull JProgram x) {
+ public boolean visit(@Nonnull JSession x) {
for (int i = 0; i < x.getTypesToEmit().size(); ++i) {
JDefinedClassOrInterface type = x.getTypesToEmit().get(i);
if (!type.isExternal()) {
diff --git a/jack/src/com/android/jack/ir/impl/ToStringGenerationVisitor.java b/jack/src/com/android/jack/ir/impl/ToStringGenerationVisitor.java
index 8c23276..307c81b 100644
--- a/jack/src/com/android/jack/ir/impl/ToStringGenerationVisitor.java
+++ b/jack/src/com/android/jack/ir/impl/ToStringGenerationVisitor.java
@@ -92,10 +92,10 @@
import com.android.jack.ir.ast.JPostfixOperation;
import com.android.jack.ir.ast.JPrefixOperation;
import com.android.jack.ir.ast.JPrimitiveType;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReferenceType;
import com.android.jack.ir.ast.JReinterpretCastOperation;
import com.android.jack.ir.ast.JReturnStatement;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JSwitchStatement;
@@ -305,7 +305,7 @@
@Override
public boolean visit(@Nonnull JCatchBlock x) {
JLocal catchVar = x.getCatchVar();
- if (catchVar.getType() == Jack.getProgram().getPhantomLookup()
+ if (catchVar.getType() == Jack.getSession().getPhantomLookup()
.getClass(CommonTypes.JAVA_LANG_OBJECT)) {
print(CHARS_FINALLY);
} else {
@@ -954,8 +954,8 @@
}
@Override
- public boolean visit(@Nonnull JProgram x) {
- print("<JProgram>");
+ public boolean visit(@Nonnull JSession x) {
+ print("<JSession>");
return false;
}
diff --git a/jack/src/com/android/jack/jayce/FullPackageLoader.java b/jack/src/com/android/jack/jayce/FullPackageLoader.java
index 0e121f2..00ffec0 100644
--- a/jack/src/com/android/jack/jayce/FullPackageLoader.java
+++ b/jack/src/com/android/jack/jayce/FullPackageLoader.java
@@ -17,15 +17,15 @@
package com.android.jack.jayce;
import com.android.jack.lookup.JPhantomLookup;
-import com.android.jack.vfs.VDir;
import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.vfs.InputVDir;
import javax.annotation.Nonnull;
@ImplementationName(iface = JaycePackageLoader.class, name = "full")
class FullPackageLoader extends JaycePackageLoader {
- public FullPackageLoader(@Nonnull VDir dir, @Nonnull JPhantomLookup lookup) {
+ public FullPackageLoader(@Nonnull InputVDir dir, @Nonnull JPhantomLookup lookup) {
super(dir, lookup, NodeLevel.FULL);
}
}
diff --git a/jack/src/com/android/jack/jayce/JayceClassOrInterfaceLoader.java b/jack/src/com/android/jack/jayce/JayceClassOrInterfaceLoader.java
index abb21bf..af6d6d6 100644
--- a/jack/src/com/android/jack/jayce/JayceClassOrInterfaceLoader.java
+++ b/jack/src/com/android/jack/jayce/JayceClassOrInterfaceLoader.java
@@ -22,20 +22,30 @@
import com.android.jack.ir.ast.JDefinedAnnotation;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.load.AbtractClassOrInterfaceLoader;
import com.android.jack.lookup.JPhantomLookup;
import com.android.jack.util.NamingTools;
-import com.android.jack.vfs.VFile;
import com.android.sched.util.config.Location;
import com.android.sched.util.log.LoggerFactory;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.Counter;
+import com.android.sched.util.log.stats.CounterImpl;
+import com.android.sched.util.log.stats.Percent;
+import com.android.sched.util.log.stats.PercentImpl;
+import com.android.sched.util.log.stats.StatisticId;
+import com.android.sched.vfs.InputVFile;
+import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
/**
@@ -43,13 +53,22 @@
*/
public class JayceClassOrInterfaceLoader extends AbtractClassOrInterfaceLoader {
@Nonnull
+ private static final StatisticId<Percent> NNODE_RELOAD = new StatisticId<
+ Percent>("jayce.reload", "Jayce file reload versus total jayce file load",
+ PercentImpl.class, Percent.class);
+ @Nonnull
+ private static final StatisticId<Counter> STRUCTURE_LOAD = new StatisticId<Counter>(
+ "jayce.structure.load", "NDeclaredType structure loaded in a JNode",
+ CounterImpl.class, Counter.class);
+
+ @Nonnull
private final Logger logger = LoggerFactory.getLogger();
@Nonnull
- private final VFile source;
+ private final InputVFile source;
@Nonnull
- private SoftReference<DeclaredTypeNode> nnode;
+ private Reference<DeclaredTypeNode> nnode;
private boolean structureLoaded = false;
@@ -59,15 +78,21 @@
@Nonnull
private final NodeLevel defaultLoadLevel;
+ @Nonnegative
+ private int loadCount = 0;
+
@Nonnull
- public static JDefinedClassOrInterface load(@Nonnull VFile source, @Nonnull JProgram program,
+ final Tracer tracer = TracerFactory.getTracer();
+
+ @Nonnull
+ public static JDefinedClassOrInterface load(@Nonnull InputVFile source, @Nonnull JSession session,
@Nonnull NodeLevel maxLevel)
throws JayceFormatException, IOException {
- return new JayceClassOrInterfaceLoader(source, program.getPhantomLookup(),
- maxLevel).create(program);
+ return new JayceClassOrInterfaceLoader(source, session.getPhantomLookup(),
+ maxLevel).create(session);
}
- JayceClassOrInterfaceLoader(@Nonnull VFile source, @Nonnull JPhantomLookup lookup,
+ JayceClassOrInterfaceLoader(@Nonnull InputVFile source, @Nonnull JPhantomLookup lookup,
@Nonnull NodeLevel defaultLoadLevel) {
this.source = source;
this.lookup = lookup;
@@ -113,20 +138,20 @@
+ type.getSignature() + "' while expecting '" + expectedSignature + "'");
}
JDefinedClassOrInterface jType = type.create(enclosingPackage, this);
- jType.updateParents(enclosingPackage.getProgram());
+ jType.updateParents(enclosingPackage.getSession());
return jType;
}
@Nonnull
- private JDefinedClassOrInterface create(@Nonnull JProgram program)
+ private JDefinedClassOrInterface create(@Nonnull JSession session)
throws JayceFormatException, IOException {
DeclaredTypeNode type = getNNode(NodeLevel.TYPES);
String packageQualifiedName = NamingTools.getPackageNameFromBinaryName(
NamingTools.getClassBinaryNameFromDescriptor(type.getSignature()));
- JPackage pack = program.getLookup().getOrCreatePackage(packageQualifiedName);
+ JPackage pack = session.getLookup().getOrCreatePackage(packageQualifiedName);
JDefinedClassOrInterface jType = type.create(pack, this);
- jType.updateParents(program);
+ jType.updateParents(session);
return jType;
}
@@ -134,7 +159,7 @@
DeclaredTypeNode getNNode(@Nonnull NodeLevel minimumLevel) throws IOException {
DeclaredTypeNode type = nnode.get();
if (type == null || !type.getLevel().keep(minimumLevel)) {
- InputStream in = source.openRead();
+ InputStream in = new BufferedInputStream(source.openRead());
try {
JayceReader reader = new JayceReader(in);
NodeLevel loadLevel = defaultLoadLevel;
@@ -150,6 +175,8 @@
logger.log(Level.WARNING, "Failed to close input stream on '" + source + "'", e);
}
}
+ tracer.getStatistic(NNODE_RELOAD).add(loadCount > 0);
+ loadCount++;
}
return type;
}
@@ -169,7 +196,7 @@
type.updateToStructure(loaded, this);
ParentSetter parentSetter = new ParentSetter();
parentSetter.accept(loaded);
- structureLoaded = true;
+ tracer.getStatistic(STRUCTURE_LOAD).incValue();
}
}
}
diff --git a/jack/src/com/android/jack/jayce/JayceMethodLoader.java b/jack/src/com/android/jack/jayce/JayceMethodLoader.java
index 0cb7119..8c617a8 100644
--- a/jack/src/com/android/jack/jayce/JayceMethodLoader.java
+++ b/jack/src/com/android/jack/jayce/JayceMethodLoader.java
@@ -22,6 +22,9 @@
import com.android.jack.ir.ast.JNode;
import com.android.jack.load.AbstractMethodLoader;
import com.android.sched.util.config.Location;
+import com.android.sched.util.log.stats.Counter;
+import com.android.sched.util.log.stats.CounterImpl;
+import com.android.sched.util.log.stats.StatisticId;
import java.io.IOException;
import java.lang.ref.SoftReference;
@@ -32,6 +35,10 @@
* A loader for method loaded from a jack file.
*/
public class JayceMethodLoader extends AbstractMethodLoader {
+ @Nonnull
+ private static final StatisticId<Counter> BODY_LOAD_COUNT = new StatisticId<Counter>(
+ "jayce.body.load", "Body loaded from a NNode in a JNode",
+ CounterImpl.class, Counter.class);
@Nonnull
private final JayceClassOrInterfaceLoader enclosingClassLoader;
@@ -59,6 +66,7 @@
body.updateParents(loaded);
}
isLoaded = true;
+ enclosingClassLoader.tracer.getStatistic(BODY_LOAD_COUNT).incValue();
}
}
diff --git a/jack/src/com/android/jack/jayce/JaycePackageLoader.java b/jack/src/com/android/jack/jayce/JaycePackageLoader.java
index 6b7e00b..8d88afd 100644
--- a/jack/src/com/android/jack/jayce/JaycePackageLoader.java
+++ b/jack/src/com/android/jack/jayce/JaycePackageLoader.java
@@ -26,10 +26,10 @@
import com.android.jack.load.ComposablePackageLoader;
import com.android.jack.lookup.JLookupException;
import com.android.jack.lookup.JPhantomLookup;
-import com.android.jack.vfs.VDir;
-import com.android.jack.vfs.VElement;
-import com.android.jack.vfs.VFile;
import com.android.sched.util.config.Location;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.InputVFile;
+import com.android.sched.vfs.VElement;
import java.io.IOException;
import java.util.ArrayList;
@@ -43,16 +43,14 @@
*/
public class JaycePackageLoader implements ComposablePackageLoader {
- private static final int JACK_EXTENSION_LENGTH = JayceFileImporter.JAYCE_FILE_EXTENSION.length();
-
@Nonnull
- private final VDir dir;
+ private final InputVDir dir;
private final JPhantomLookup lookup;
@Nonnull
private final NodeLevel defaultLoadLevel;
- JaycePackageLoader(@Nonnull VDir dir, @Nonnull JPhantomLookup lookup,
+ JaycePackageLoader(@Nonnull InputVDir dir, @Nonnull JPhantomLookup lookup,
@Nonnull NodeLevel defaultLoadLevel) {
this.dir = dir;
this.lookup = lookup;
@@ -64,9 +62,9 @@
public JDefinedClassOrInterface loadClassOrInterface(
@Nonnull JPackage loading, @Nonnull String simpleName) throws JLookupException {
for (VElement sub : dir.list()) {
- if (sub instanceof VFile && isJackFileNameOf(sub.getName(), simpleName)) {
+ if (sub instanceof InputVFile && isJackFileNameOf(sub.getName(), simpleName)) {
try {
- return new JayceClassOrInterfaceLoader((VFile) sub, lookup, defaultLoadLevel)
+ return new JayceClassOrInterfaceLoader((InputVFile) sub, lookup, defaultLoadLevel)
.loadClassOrInterface(loading, simpleName);
} catch (IOException e) {
throw new JackIOException("Failed to load class '" + simpleName + "' in package '"
@@ -83,7 +81,7 @@
List<String> subs = new ArrayList<String>();
for (VElement sub : dir.list()) {
String fileName = sub.getName();
- if (sub instanceof VFile && isJackFileName(fileName)) {
+ if (sub instanceof InputVFile && JayceFileImporter.isJackFileName(fileName)) {
subs.add(fileName.substring(0, fileName.length() - 5));
}
}
@@ -94,11 +92,11 @@
@Override
public ComposablePackageLoader getLoaderForSubPackage(@Nonnull JPackage loading,
@Nonnull String simpleName) {
- for (VElement sub : dir.list()) {
- if (sub instanceof VDir && sub.getName().equals(simpleName)) {
- return new JaycePackageLoader((VDir) sub, lookup, defaultLoadLevel);
+ for (VElement sub : dir.list()) {
+ if (sub instanceof InputVDir && sub.getName().equals(simpleName)) {
+ return new JaycePackageLoader((InputVDir) sub, lookup, defaultLoadLevel);
+ }
}
- }
throw new JPackageLookupException(simpleName, loading);
}
@@ -107,7 +105,7 @@
public Collection<String> getSubPackageNames(@Nonnull JPackage loading) {
List<String> subs = new ArrayList<String>();
for (VElement sub : dir.list()) {
- if (sub instanceof VDir) {
+ if (sub instanceof InputVDir) {
subs.add(sub.getName());
}
}
@@ -121,21 +119,14 @@
}
private boolean isJackFileNameOf(@Nonnull String fileName, @Nonnull String typeName) {
- return (fileName.length() > JACK_EXTENSION_LENGTH)
- && (fileName.substring(0, fileName.length() - JACK_EXTENSION_LENGTH).equals(typeName))
- && (fileName.substring(fileName.length() - JACK_EXTENSION_LENGTH).equalsIgnoreCase(
- JayceFileImporter.JAYCE_FILE_EXTENSION));
- }
-
- private boolean isJackFileName(@Nonnull String name) {
- return (name.length() > JACK_EXTENSION_LENGTH)
- && (name.substring(name.length() - JACK_EXTENSION_LENGTH).equalsIgnoreCase(
- JayceFileImporter.JAYCE_FILE_EXTENSION));
+ return (fileName.length() > JayceFileImporter.JACK_EXTENSION_LENGTH) && (fileName.substring(0,
+ fileName.length() - JayceFileImporter.JACK_EXTENSION_LENGTH).equals(typeName)) && (fileName
+ .substring(fileName.length() - JayceFileImporter.JACK_EXTENSION_LENGTH).equalsIgnoreCase(
+ JayceFileImporter.JAYCE_FILE_EXTENSION));
}
@Override
public boolean isOnPath(@Nonnull JPackage loaded) {
return true;
}
-
}
diff --git a/jack/src/com/android/jack/jayce/LoadIOException.java b/jack/src/com/android/jack/jayce/LoadIOException.java
index 4e1acee..53ac61a 100644
--- a/jack/src/com/android/jack/jayce/LoadIOException.java
+++ b/jack/src/com/android/jack/jayce/LoadIOException.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.jayce;
import com.android.jack.Jack;
diff --git a/jack/src/com/android/jack/jayce/StructurePackageLoader.java b/jack/src/com/android/jack/jayce/StructurePackageLoader.java
index ecb7fb0..83a2b87 100644
--- a/jack/src/com/android/jack/jayce/StructurePackageLoader.java
+++ b/jack/src/com/android/jack/jayce/StructurePackageLoader.java
@@ -17,15 +17,15 @@
package com.android.jack.jayce;
import com.android.jack.lookup.JPhantomLookup;
-import com.android.jack.vfs.VDir;
import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.vfs.InputVDir;
import javax.annotation.Nonnull;
@ImplementationName(iface = JaycePackageLoader.class, name = "structure")
class StructurePackageLoader extends JaycePackageLoader {
- public StructurePackageLoader(@Nonnull VDir dir, @Nonnull JPhantomLookup lookup) {
+ public StructurePackageLoader(@Nonnull InputVDir dir, @Nonnull JPhantomLookup lookup) {
super(dir, lookup, NodeLevel.STRUCTURE);
}
}
diff --git a/jack/src/com/android/jack/jayce/v0002/NodeFactory.java b/jack/src/com/android/jack/jayce/v0002/NodeFactory.java
index 6740092..d340c54 100644
--- a/jack/src/com/android/jack/jayce/v0002/NodeFactory.java
+++ b/jack/src/com/android/jack/jayce/v0002/NodeFactory.java
@@ -112,9 +112,9 @@
import com.android.jack.ir.ast.JPrefixIncOperation;
import com.android.jack.ir.ast.JPrefixNegOperation;
import com.android.jack.ir.ast.JPrefixNotOperation;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReinterpretCastOperation;
import com.android.jack.ir.ast.JReturnStatement;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShlOperation;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JShrOperation;
@@ -671,7 +671,7 @@
}
@Override
- public boolean visit(@Nonnull JProgram x) {
+ public boolean visit(@Nonnull JSession x) {
newNode = new NProgram();
return false;
}
diff --git a/jack/src/com/android/jack/jayce/v0002/io/ExportSession.java b/jack/src/com/android/jack/jayce/v0002/io/ExportSession.java
index 93ae5ca..b37bfda 100644
--- a/jack/src/com/android/jack/jayce/v0002/io/ExportSession.java
+++ b/jack/src/com/android/jack/jayce/v0002/io/ExportSession.java
@@ -31,7 +31,7 @@
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JParameter;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.MethodKind;
import com.android.jack.ir.formatter.TypeFormatter;
@@ -93,11 +93,11 @@
private JMethod currentMethod;
@Nonnull
- private final JProgram program;
+ private final JSession session;
public ExportSession(
- @Nonnull JLookup lookup, @Nonnull JProgram program, @Nonnull NodeLevel nodeLevel) {
- this.program = program;
+ @Nonnull JLookup lookup, @Nonnull JSession session, @Nonnull NodeLevel nodeLevel) {
+ this.session = session;
this.lookup = lookup;
this.nodeLevel = nodeLevel;
}
@@ -133,8 +133,8 @@
}
@Nonnull
- public JProgram getProgram() {
- return program;
+ public JSession getSession() {
+ return session;
}
@Nonnull
diff --git a/jack/src/com/android/jack/jayce/v0002/io/JayceInternalReaderImpl.java b/jack/src/com/android/jack/jayce/v0002/io/JayceInternalReaderImpl.java
index 3132bf9..3bc42aa 100644
--- a/jack/src/com/android/jack/jayce/v0002/io/JayceInternalReaderImpl.java
+++ b/jack/src/com/android/jack/jayce/v0002/io/JayceInternalReaderImpl.java
@@ -31,6 +31,11 @@
import com.android.jack.jayce.v0002.util.MethodKindIdHelper;
import com.android.jack.jayce.v0002.util.ReceiverKindIdHelper;
import com.android.jack.jayce.v0002.util.RetentionPolicyIdHelper;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.Percent;
+import com.android.sched.util.log.stats.PercentImpl;
+import com.android.sched.util.log.stats.StatisticId;
import java.io.IOException;
import java.io.InputStream;
@@ -46,6 +51,14 @@
* Jayce internal reader implementation.
*/
public class JayceInternalReaderImpl implements JayceInternalReader {
+ @Nonnull
+ public static final StatisticId<Percent> SKIPED_NDECLARED_TYPE = new StatisticId<Percent>(
+ "jayce.ndeclaredtype.skiped", "NDeclaredType loading that skiped by the reader",
+ PercentImpl.class, Percent.class);
+ @Nonnull
+ public static final StatisticId<Percent> SKIPED_BODY = new StatisticId<Percent>(
+ "jayce.body.skiped", "Body loading skiped by the reader",
+ PercentImpl.class, Percent.class);
@Nonnull
private final Tokenizer tokenizer;
@@ -65,6 +78,9 @@
@Nonnull
private final List<String> currentCatchBlockList = new ArrayList<String>();
+ @Nonnull
+ private final Tracer tracer = TracerFactory.getTracer();
+
public JayceInternalReaderImpl(@Nonnull InputStream in, @Nonnull Charset encoding) {
this.tokenizer = new Tokenizer(in);
}
@@ -179,6 +195,8 @@
return null;
}
+
+
tokenizer.readOpen();
NNode node;
try {
@@ -186,6 +204,12 @@
} catch (InvalidTokenException e) {
throw new ParseException("Unexpected token " + token + " while expecting node.", e);
}
+ Percent statistic = null;
+ if (token == Token.METHOD_BODY) {
+ statistic = tracer.getStatistic(SKIPED_BODY);
+ } else if (node instanceof NDeclaredType) {
+ statistic = tracer.getStatistic(SKIPED_NDECLARED_TYPE);
+ }
assert nodeClass.isAssignableFrom(node.getClass());
@@ -204,8 +228,14 @@
tokenizer.readClose();
if (nodeLevel.keep(token.getNodeLevel())) {
+ if (statistic != null) {
+ statistic.addFalse();
+ }
return (T) node;
} else {
+ if (statistic != null) {
+ statistic.addTrue();
+ }
return null;
}
}
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NAnnotationType.java b/jack/src/com/android/jack/jayce/v0002/nodes/NAnnotationType.java
index 5a8462b..0f611b2 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NAnnotationType.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NAnnotationType.java
@@ -82,7 +82,7 @@
String binaryName = NamingTools.getClassBinaryNameFromDescriptor(signature);
String simpleName = NamingTools.getSimpleClassNameFromBinaryName(binaryName);
SourceInfo jSourceInfo = sourceInfo.exportAsJast(
- new ExportSession(loader.getLookup(), enclosingPackage.getProgram(), NodeLevel.TYPES));
+ new ExportSession(loader.getLookup(), enclosingPackage.getSession(), NodeLevel.TYPES));
JDefinedAnnotation jInterfaceType =
new JDefinedAnnotation(jSourceInfo, simpleName, modifiers, enclosingPackage, loader);
jInterfaceType.setRetentionPolicy(retentionPolicy);
@@ -95,7 +95,7 @@
assert sourceInfo != null;
assert signature != null;
JDefinedAnnotation jInterfaceType = (JDefinedAnnotation) loading;
- ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getJProgram(),
+ ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getSession(),
NodeLevel.STRUCTURE);
exportSession.setCurrentType(jInterfaceType);
exportSession.setCurrentType(jInterfaceType);
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NClassType.java b/jack/src/com/android/jack/jayce/v0002/nodes/NClassType.java
index 8193817..6744a25 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NClassType.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NClassType.java
@@ -117,7 +117,7 @@
String binaryName = NamingTools.getClassBinaryNameFromDescriptor(signature);
String simpleName = NamingTools.getSimpleClassNameFromBinaryName(binaryName);
SourceInfo jSourceInfo = sourceInfo.exportAsJast(
- new ExportSession(loader.getLookup(), enclosingPackage.getProgram(), NodeLevel.TYPES));
+ new ExportSession(loader.getLookup(), enclosingPackage.getSession(), NodeLevel.TYPES));
JDefinedClass jClassType =
new JDefinedClass(jSourceInfo, simpleName, modifiers, enclosingPackage, loader);
return jClassType;
@@ -129,7 +129,7 @@
assert sourceInfo != null;
assert signature != null;
JDefinedClass jClassType = (JDefinedClass) loading;
- ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getJProgram(),
+ ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getSession(),
NodeLevel.STRUCTURE);
exportSession.setCurrentType(jClassType);
if (superClass != null) {
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NEnumType.java b/jack/src/com/android/jack/jayce/v0002/nodes/NEnumType.java
index 2232b30..e0ff8d0 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NEnumType.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NEnumType.java
@@ -80,7 +80,7 @@
String binaryName = NamingTools.getClassBinaryNameFromDescriptor(signature);
String simpleName = NamingTools.getSimpleClassNameFromBinaryName(binaryName);
SourceInfo jSourceInfo = sourceInfo.exportAsJast(
- new ExportSession(loader.getLookup(), enclosingPackage.getProgram(), NodeLevel.TYPES));
+ new ExportSession(loader.getLookup(), enclosingPackage.getSession(), NodeLevel.TYPES));
JDefinedEnum jEnumType =
new JDefinedEnum(jSourceInfo, simpleName, modifiers, enclosingPackage, loader);
return jEnumType;
@@ -91,7 +91,7 @@
assert sourceInfo != null;
assert signature != null;
JDefinedEnum jEnumType = (JDefinedEnum) loading;
- ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getJProgram(),
+ ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getSession(),
NodeLevel.STRUCTURE);
exportSession.setCurrentType(jEnumType);
try {
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NInterfaceType.java b/jack/src/com/android/jack/jayce/v0002/nodes/NInterfaceType.java
index b6257bb..70f5c4e 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NInterfaceType.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NInterfaceType.java
@@ -103,7 +103,7 @@
String binaryName = NamingTools.getClassBinaryNameFromDescriptor(signature);
String simpleName = NamingTools.getSimpleClassNameFromBinaryName(binaryName);
SourceInfo jSourceInfo = sourceInfo.exportAsJast(
- new ExportSession(loader.getLookup(), enclosingPackage.getProgram(), NodeLevel.TYPES));
+ new ExportSession(loader.getLookup(), enclosingPackage.getSession(), NodeLevel.TYPES));
JDefinedInterface jInterfaceType =
new JDefinedInterface(jSourceInfo, simpleName, modifiers, enclosingPackage, loader);
return jInterfaceType;
@@ -115,7 +115,7 @@
assert sourceInfo != null;
assert signature != null;
JDefinedInterface jInterfaceType = (JDefinedInterface) loading;
- ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getJProgram(),
+ ExportSession exportSession = new ExportSession(loader.getLookup(), loading.getSession(),
NodeLevel.STRUCTURE);
exportSession.setCurrentType(jInterfaceType);
for (String superInterface : superInterfaces) {
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java b/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
index 64fa4ad..39da324 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
@@ -22,7 +22,7 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JParameter;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.MethodKind;
import com.android.jack.jayce.JayceClassOrInterfaceLoader;
import com.android.jack.jayce.JayceMethodLoader;
@@ -144,8 +144,8 @@
@Override
public JAbstractMethodBody loadBody(@Nonnull JMethod method) {
if (body != null) {
- JProgram program = method.getParent(JProgram.class);
- ExportSession exportSession = new ExportSession(program.getPhantomLookup(), program,
+ JSession session = method.getParent(JSession.class);
+ ExportSession exportSession = new ExportSession(session.getPhantomLookup(), session,
NodeLevel.FULL);
exportSession.setCurrentMethod(method);
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NProgram.java b/jack/src/com/android/jack/jayce/v0002/nodes/NProgram.java
index 57f9223..ce4ad19 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NProgram.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NProgram.java
@@ -17,7 +17,7 @@
package com.android.jack.jayce.v0002.nodes;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.jayce.v0002.NNode;
import com.android.jack.jayce.v0002.io.ExportSession;
import com.android.jack.jayce.v0002.io.ImportHelper;
@@ -44,20 +44,19 @@
@Override
public void importFromJast(@Nonnull ImportHelper loader, @Nonnull Object node) {
- JProgram jProgram = (JProgram) node;
- assert jProgram.codeGenTypes.isEmpty();
- allTypes = loader.load(NDeclaredType.class, jProgram.getTypesToEmit());
+ JSession session = (JSession) node;
+ allTypes = loader.load(NDeclaredType.class, session.getTypesToEmit());
}
@Override
@Nonnull
- public JProgram exportAsJast(@Nonnull ExportSession exportSession) {
- JProgram jProgram = new JProgram();
+ public JSession exportAsJast(@Nonnull ExportSession exportSession) {
+ JSession session = new JSession();
for (NDeclaredType declaredType : allTypes) {
JDefinedClassOrInterface jDeclaredType = declaredType.exportAsJast(exportSession);
- jProgram.addTypeToEmit(jDeclaredType);
+ session.addTypeToEmit(jDeclaredType);
}
- return jProgram;
+ return session;
}
@Override
diff --git a/jack/src/com/android/jack/load/ComposedPackageLoader.java b/jack/src/com/android/jack/load/ComposedPackageLoader.java
index 52a53e4..4de2ea7 100644
--- a/jack/src/com/android/jack/load/ComposedPackageLoader.java
+++ b/jack/src/com/android/jack/load/ComposedPackageLoader.java
@@ -72,7 +72,7 @@
}
}
if (loader != null) {
- JPackage subPackage = new JPackage(simpleName, loading.getProgram(), loading, loader);
+ JPackage subPackage = new JPackage(simpleName, loading.getSession(), loading, loader);
subPackage.updateParents(loading);
return subPackage;
} else {
diff --git a/jack/src/com/android/jack/lookup/JNodeLookup.java b/jack/src/com/android/jack/lookup/JNodeLookup.java
index fab3a80..c83d447 100644
--- a/jack/src/com/android/jack/lookup/JNodeLookup.java
+++ b/jack/src/com/android/jack/lookup/JNodeLookup.java
@@ -29,6 +29,11 @@
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JTypeLookupException;
import com.android.jack.util.NamingTools;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.Percent;
+import com.android.sched.util.log.stats.PercentImpl;
+import com.android.sched.util.log.stats.StatisticId;
import java.util.Iterator;
import java.util.Map;
@@ -40,10 +45,17 @@
* Jack lookup.
*/
public class JNodeLookup extends JLookup {
+ @Nonnull
+ public static final StatisticId<Percent> SUCCESS_LOOKUP = new StatisticId<Percent>(
+ "jack.lookup.success", "Lookup requests returning a JDefinedClassOrInterface",
+ PercentImpl.class, Percent.class);
@Nonnull
private final Map<String, JType> types = new ConcurrentHashMap<String, JType>();
+ @Nonnull
+ private final Tracer tracer = TracerFactory.getTracer();
+
/**
* Initialize lookup.
*/
@@ -73,13 +85,15 @@
@Override
@Nonnull
public JType getType(@Nonnull String typeName) throws JTypeLookupException {
+ Percent statistic = tracer.getStatistic(SUCCESS_LOOKUP);
+ statistic.addFalse();
synchronized (types) {
JType result = types.get(typeName);
if (result == null) {
int typeNameLength = typeName.length();
assert typeNameLength > 1 : "Invalid signature or missing primitive type '" + typeName
- + "'";
+ + "'";
if (typeName.charAt(0) == '[') {
JArrayType arrayType = getArrayType(typeName);
types.put(typeName, arrayType);
@@ -105,7 +119,8 @@
result = currentPackage.getType(simpleName);
types.put(typeName, result);
}
-
+ statistic.removeFalse();
+ statistic.addTrue();
return result;
}
}
diff --git a/jack/src/com/android/jack/optimizations/NotSimplifier.java b/jack/src/com/android/jack/optimizations/NotSimplifier.java
index 087e626..530ef3f 100644
--- a/jack/src/com/android/jack/optimizations/NotSimplifier.java
+++ b/jack/src/com/android/jack/optimizations/NotSimplifier.java
@@ -78,7 +78,7 @@
@Override
public boolean visit(@Nonnull JExpression expr) {
assert expr.getType() instanceof JBooleanType || expr.getType()
- == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
opAfterTransformation++;
return false;
}
@@ -86,7 +86,7 @@
@Override
public boolean visit(@Nonnull JBinaryOperation binaryOp) {
assert binaryOp.getType() instanceof JBooleanType || binaryOp.getType()
- == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
opBeforeTransformation++;
JBinaryOperator op = binaryOp.getOp();
@@ -131,7 +131,7 @@
@Override
public boolean visit(@Nonnull JExpression expr) {
assert expr.getType() instanceof JBooleanType || expr.getType()
- == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
tr.append(new Replace(expr, new JPrefixNotOperation(expr.getSourceInfo(), expr)));
return false;
}
@@ -139,7 +139,7 @@
@Override
public boolean visit(@Nonnull JBinaryOperation binaryOp) {
assert binaryOp.getType() instanceof JBooleanType || binaryOp.getType()
- == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ == Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
JBinaryOperator op = binaryOp.getOp();
if (op.isComparison() || op.isConditionalOperation()
diff --git a/jack/src/com/android/jack/scheduling/adapter/JDefinedClassOrInterfaceAdaptor.java b/jack/src/com/android/jack/scheduling/adapter/JDefinedClassOrInterfaceAdaptor.java
index ef9a3f6..529d2aa 100644
--- a/jack/src/com/android/jack/scheduling/adapter/JDefinedClassOrInterfaceAdaptor.java
+++ b/jack/src/com/android/jack/scheduling/adapter/JDefinedClassOrInterfaceAdaptor.java
@@ -15,7 +15,7 @@
package com.android.jack.scheduling.adapter;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.schedulable.AdapterSchedulable;
@@ -25,22 +25,22 @@
import javax.annotation.Nonnull;
/**
- * Adapts a process on {@code JProgram} onto one or several processes on each
- * {@code JDefinedClassOrInterface} declared by this program.
+ * Adapts a process on {@code JSession} onto one or several processes on each
+ * {@code JDefinedClassOrInterface} to emit during this session.
*/
-@Description("Adapts process on JProgram to one or several processes on each of its " +
+@Description("Adapts process on JSession to one or several processes on each of its " +
"JDefinedClassOrInterface")
public class JDefinedClassOrInterfaceAdaptor
- implements AdapterSchedulable<JProgram, JDefinedClassOrInterface> {
+ implements AdapterSchedulable<JSession, JDefinedClassOrInterface> {
/**
- * Return every {@code JDefinedClassOrInterface} declared in the given {@code JProgram}.
+ * Return every {@code JDefinedClassOrInterface} to emit during the given {@code JSession}.
*/
@Override
@Nonnull
- public Iterator<JDefinedClassOrInterface> adapt(@Nonnull JProgram program)
+ public Iterator<JDefinedClassOrInterface> adapt(@Nonnull JSession session)
throws Exception {
// Use a copy to scan types in order to support concurrent modification.
- return new ArrayList<JDefinedClassOrInterface>(program.getTypesToEmit()).iterator();
+ return new ArrayList<JDefinedClassOrInterface>(session.getTypesToEmit()).iterator();
}
}
diff --git a/jack/src/com/android/jack/scheduling/adapter/JPackageAdapter.java b/jack/src/com/android/jack/scheduling/adapter/JPackageAdapter.java
index 69ce38a..2f6a8ba 100644
--- a/jack/src/com/android/jack/scheduling/adapter/JPackageAdapter.java
+++ b/jack/src/com/android/jack/scheduling/adapter/JPackageAdapter.java
@@ -19,7 +19,7 @@
import com.google.common.collect.Iterators;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
import com.android.sched.schedulable.AdapterSchedulable;
@@ -31,12 +31,12 @@
import javax.annotation.Nonnull;
/**
- * Adapts a process on {@code JProgram} onto one or several processes on
- * each {@code JPackage} declared by this program.
+ * Adapts a process on {@code JSession} onto one or several processes on
+ * each {@code JPackage} known by this session.
*/
-@Description("Adapts process on JProgram to one or several processes on each of its JPackage")
+@Description("Adapts process on JSession to one or several processes on each of its JPackage")
@Name("JPackageAdapter")
-public class JPackageAdapter implements AdapterSchedulable<JProgram, JPackage> {
+public class JPackageAdapter implements AdapterSchedulable<JSession, JPackage> {
@Nonnull
private Iterator<JPackage> process(@Nonnull JPackage pack)
throws Exception {
@@ -53,14 +53,14 @@
}
/**
- * Returns every {@code JPackage} declared in the given {@code JProgram}.
+ * Returns every {@code JPackage} known by the given {@code JSession}.
*/
@Override
@Nonnull
- public Iterator<JPackage> adapt(@Nonnull JProgram program)
+ public Iterator<JPackage> adapt(@Nonnull JSession session)
throws Exception {
- return Iterators.concat(Iterators.singletonIterator(program.getTopLevelPackage()),
- process(program.getTopLevelPackage()));
+ return Iterators.concat(Iterators.singletonIterator(session.getTopLevelPackage()),
+ process(session.getTopLevelPackage()));
}
}
diff --git a/jack/src/com/android/jack/scheduling/feature/DexNonZipOutput.java b/jack/src/com/android/jack/scheduling/feature/DexNonZipOutput.java
index cd28688..0827957 100644
--- a/jack/src/com/android/jack/scheduling/feature/DexNonZipOutput.java
+++ b/jack/src/com/android/jack/scheduling/feature/DexNonZipOutput.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/feature/DexZipOutput.java b/jack/src/com/android/jack/scheduling/feature/DexZipOutput.java
index 8695cde..65ee1b8 100644
--- a/jack/src/com/android/jack/scheduling/feature/DexZipOutput.java
+++ b/jack/src/com/android/jack/scheduling/feature/DexZipOutput.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/feature/DxLegacy.java b/jack/src/com/android/jack/scheduling/feature/DxLegacy.java
index 66372cd..8822eb8 100644
--- a/jack/src/com/android/jack/scheduling/feature/DxLegacy.java
+++ b/jack/src/com/android/jack/scheduling/feature/DxLegacy.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/feature/JackFileNonZipOutput.java b/jack/src/com/android/jack/scheduling/feature/JackFileNonZipOutput.java
index 8643256..71ca439 100644
--- a/jack/src/com/android/jack/scheduling/feature/JackFileNonZipOutput.java
+++ b/jack/src/com/android/jack/scheduling/feature/JackFileNonZipOutput.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/feature/JackFileZipOutput.java b/jack/src/com/android/jack/scheduling/feature/JackFileZipOutput.java
index a206c96..7428a7b 100644
--- a/jack/src/com/android/jack/scheduling/feature/JackFileZipOutput.java
+++ b/jack/src/com/android/jack/scheduling/feature/JackFileZipOutput.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/feature/SourceVersion7.java b/jack/src/com/android/jack/scheduling/feature/SourceVersion7.java
index ddd19b0..1ba59e9 100644
--- a/jack/src/com/android/jack/scheduling/feature/SourceVersion7.java
+++ b/jack/src/com/android/jack/scheduling/feature/SourceVersion7.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.scheduling.feature;
import com.android.sched.item.Description;
diff --git a/jack/src/com/android/jack/scheduling/marker/DexFileMarker.java b/jack/src/com/android/jack/scheduling/marker/DexFileMarker.java
index 972a727..5a621b9 100644
--- a/jack/src/com/android/jack/scheduling/marker/DexFileMarker.java
+++ b/jack/src/com/android/jack/scheduling/marker/DexFileMarker.java
@@ -17,7 +17,7 @@
package com.android.jack.scheduling.marker;
import com.android.jack.dx.dex.file.DexFile;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.ComposedOf;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
@@ -31,7 +31,7 @@
* A marker which contains a {@code DexFile} instance.
*/
@Description("A marker which contains a DexFile instance.")
-@ValidOn(JProgram.class)
+@ValidOn(JSession.class)
public final class DexFileMarker implements Marker {
@Nonnull
private final DexFile dexFile;
diff --git a/jack/src/com/android/jack/shrob/SeedPrinter.java b/jack/src/com/android/jack/shrob/SeedPrinter.java
index c612c6d..d303109 100644
--- a/jack/src/com/android/jack/shrob/SeedPrinter.java
+++ b/jack/src/com/android/jack/shrob/SeedPrinter.java
@@ -23,7 +23,7 @@
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JParameter;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.shrob.obfuscation.OriginalNames;
import com.android.jack.shrob.proguard.GrammarActions;
@@ -59,7 +59,7 @@
@Description("Visitor that prints the seeds")
@Produce(SeedFile.class)
@Constraint(need = OriginalNames.class)
-public class SeedPrinter implements RunnableSchedulable<JProgram> {
+public class SeedPrinter implements RunnableSchedulable<JSession> {
@Nonnull
public static final PropertyId<StreamFile> SEEDS_OUTPUT_FILE = PropertyId.create(
@@ -91,9 +91,9 @@
}
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
- for (JDefinedClassOrInterface type : program.getTypesToEmit()) {
+ for (JDefinedClassOrInterface type : session.getTypesToEmit()) {
boolean matched = false;
List<FieldSpecification> matchedFieldSpecs = new ArrayList<FieldSpecification>();
List<MethodSpecification> matchedMethodSpecs = new ArrayList<MethodSpecification>();
diff --git a/jack/src/com/android/jack/shrob/obfuscation/MappingApplier.java b/jack/src/com/android/jack/shrob/obfuscation/MappingApplier.java
index a44fb3c..941bd0a 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/MappingApplier.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/MappingApplier.java
@@ -27,7 +27,7 @@
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JTypeLookupException;
import com.android.jack.lookup.JLookupException;
@@ -64,9 +64,6 @@
private static final char[] EMPTY_STOP_CHARS = new char[] {};
@Nonnull
- private static final char[] OLD_NAME_STOP_CHARS = new char[] {'-'};
-
- @Nonnull
private static final char[] CLASSINFO_STOP_CHARS = new char[] {':'};
@Nonnull
@@ -102,14 +99,14 @@
@CheckForNull
private JDefinedClassOrInterface createMappingForType(@Nonnull String oldName,
- @Nonnull String newName, @Nonnull JProgram program, @Nonnull File mappingFile,
+ @Nonnull String newName, @Nonnull JSession session, @Nonnull File mappingFile,
int lineNumber) {
JClassOrInterface type = null;
- JNodeLookup lookup = program.getLookup();
+ JNodeLookup lookup = session.getLookup();
try {
String typeSignature = NamingTools.getTypeSignatureName(oldName);
type = (JClassOrInterface) lookup.getType(typeSignature);
- if (!program.getTypesToEmit().contains(type)) {
+ if (!session.getTypesToEmit().contains(type)) {
logger.log(Level.WARNING, "{0}:{1}: Type {2} has a mapping but was removed",
new Object[] {mappingFile.getAbsolutePath(), Integer.valueOf(lineNumber), oldName});
return null;
@@ -167,6 +164,31 @@
return index;
}
+ /**
+ * Reads this string until a whitespace or the '->' separator is read
+ * or until the end of the string, starting the search at the specified index.
+ * @param line the line to read from.
+ * @param index the index to start the reading from.
+ * @return the index of the first occurrence of a whitespace, the '->' separator
+ * or the end of the string.
+ */
+ private int readNameUntilSeparatorOrWhitespace(@Nonnull String line, int index) {
+ int length = line.length();
+ char c = line.charAt(index);
+ while (!Character.isWhitespace(c)) {
+ if (c == '-' && line.charAt(index + 1) == '>') {
+ // We check the second char to avoid bad parsing of names containing '-'
+ break;
+ }
+ if (++index < length) {
+ c = line.charAt(index);
+ } else {
+ break;
+ }
+ }
+ return index;
+ }
+
private int readWhiteSpaces(@Nonnull String line, int index) {
char c = line.charAt(index);
while (Character.isWhitespace(c)) {
@@ -187,11 +209,11 @@
@CheckForNull
private JDefinedClassOrInterface readClassInfo(
- @Nonnull String line, @Nonnull JProgram program, @Nonnull File mappingFile, int lineNumber) {
+ @Nonnull String line, @Nonnull JSession session, @Nonnull File mappingFile, int lineNumber) {
// qualifiedOldClassName -> newClassName:
try {
int startIndex = readWhiteSpaces(line, 0);
- int endIndex = readName(line, startIndex, OLD_NAME_STOP_CHARS);
+ int endIndex = readNameUntilSeparatorOrWhitespace(line, startIndex);
String qualifiedOldClassName = line.substring(startIndex, endIndex);
startIndex = readWhiteSpaces(line, endIndex);
startIndex = readSeparator(line, startIndex, mappingFile, lineNumber);
@@ -199,7 +221,7 @@
endIndex = readName(line, startIndex, CLASSINFO_STOP_CHARS);
String newClassName = line.substring(startIndex, endIndex);
return createMappingForType(
- qualifiedOldClassName, newClassName, program, mappingFile, lineNumber);
+ qualifiedOldClassName, newClassName, session, mappingFile, lineNumber);
} catch (ArrayIndexOutOfBoundsException e) {
throwException(
mappingFile, lineNumber, "The mapping file is badly formatted (class mapping expected)");
@@ -227,7 +249,7 @@
int endIndex = readName(line, startIndex, EMPTY_STOP_CHARS);
String typeSignature = GrammarActions.getSignature(line.substring(startIndex, endIndex));
startIndex = readWhiteSpaces(line, endIndex);
- endIndex = readName(line, startIndex, OLD_NAME_STOP_CHARS);
+ endIndex = readNameUntilSeparatorOrWhitespace(line, startIndex);
String oldName = line.substring(startIndex, endIndex);
int index = readWhiteSpaces(line, endIndex);
index = readSeparator(line, index, mappingFile, lineNumber);
@@ -324,7 +346,16 @@
protected void renameMethod(
@Nonnull JMethod method, @Nonnull File mappingFile, int lineNumber, @Nonnull String newName) {
- rename(method.getMethodId(), mappingFile, lineNumber, newName);
+ String oldName = method.getName();
+ if (oldName.equals(NamingTools.INIT_NAME)) {
+ logger.log(Level.WARNING, "{0}:{1}: Constructors cannot be renamed",
+ new Object[] {mappingFile.getAbsolutePath(), Integer.valueOf(lineNumber)});
+ } else if (oldName.equals(NamingTools.STATIC_INIT_NAME)) {
+ logger.log(Level.WARNING, "{0}:{1}: Static initializers cannot be renamed",
+ new Object[] {mappingFile.getAbsolutePath(), Integer.valueOf(lineNumber)});
+ } else {
+ rename(method.getMethodId(), mappingFile, lineNumber, newName);
+ }
}
/**
@@ -335,10 +366,10 @@
* type must be in the java form (e.g. java.lang.String, boolean).
*
* @param mappingFile
- * @param program
+ * @param session
* @throws JackIOException
*/
- public void applyMapping(@Nonnull File mappingFile, @Nonnull JProgram program)
+ public void applyMapping(@Nonnull File mappingFile, @Nonnull JSession session)
throws JackIOException {
LineNumberReader reader = null;
try {
@@ -348,12 +379,12 @@
while (line != null) {
if (isClassInfo(line)) {
- currentType = readClassInfo(line, program, mappingFile, reader.getLineNumber());
+ currentType = readClassInfo(line, session, mappingFile, reader.getLineNumber());
} else {
if (currentType != null) {
if (isMethodInfo(line)) {
readMethodInfo(line, currentType, mappingFile, reader.getLineNumber(),
- program.getLookup());
+ session.getLookup());
} else {
readFieldInfo(line, currentType, mappingFile, reader.getLineNumber());
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/MappingPrinter.java b/jack/src/com/android/jack/shrob/obfuscation/MappingPrinter.java
index 35a1904..3df9dcb 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/MappingPrinter.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/MappingPrinter.java
@@ -28,7 +28,7 @@
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JPackage;
import com.android.jack.ir.ast.JParameter;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.shrob.proguard.GrammarActions;
@@ -61,7 +61,7 @@
@Produce(Mapping.class)
@Optional(@ToSupport(
feature = Obfuscation.class, add = @Constraint(need = OriginalNameMarker.class)))
-public class MappingPrinter implements RunnableSchedulable<JProgram> {
+public class MappingPrinter implements RunnableSchedulable<JSession> {
@Nonnull
public static final PropertyId<StreamFile> MAPPING_OUTPUT_FILE = PropertyId.create(
@@ -195,7 +195,7 @@
}
@Override
- public void run(@Nonnull JProgram t) throws Exception {
+ public void run(@Nonnull JSession t) throws Exception {
Visitor visitor = new Visitor();
visitor.accept(t);
stream.close();
diff --git a/jack/src/com/android/jack/shrob/obfuscation/NameKeeper.java b/jack/src/com/android/jack/shrob/obfuscation/NameKeeper.java
index a64cbe6..67e9674 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/NameKeeper.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/NameKeeper.java
@@ -24,7 +24,6 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.shrob.proguard.GrammarActions;
import com.android.jack.shrob.shrink.NodeFinder;
@@ -91,7 +90,7 @@
@Override
public boolean visit(@Nonnull JMethod m) {
- if (JProgram.isClinit(m) || m instanceof JConstructor) {
+ if (JMethod.isClinit(m) || m instanceof JConstructor) {
keepName(m);
}
return false;
diff --git a/jack/src/com/android/jack/shrob/obfuscation/ObfuscationEventType.java b/jack/src/com/android/jack/shrob/obfuscation/ObfuscationEventType.java
index b72000f..9b9a27d 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/ObfuscationEventType.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/ObfuscationEventType.java
@@ -25,22 +25,13 @@
*/
public enum ObfuscationEventType implements EventType {
- FINDING_OBFUSCATION_SEEDS("Finding seeds", "black");
+ FINDING_OBFUSCATION_SEEDS("Finding seeds");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- ObfuscationEventType(@Nonnull String name, @Nonnull String cssColor) {
+ ObfuscationEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/jack/src/com/android/jack/shrob/obfuscation/Renamer.java b/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
index ec76e31..5807e60 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
@@ -27,7 +27,7 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.shrob.obfuscation.nameprovider.NameProvider;
import com.android.jack.shrob.proguard.GrammarActions;
@@ -67,13 +67,13 @@
@Transform(add = {OriginalNameMarker.class, OriginalPackageMarker.class},
remove = OriginalNames.class)
@Use(MappingApplier.class)
-public class Renamer implements RunnableSchedulable<JProgram> {
+public class Renamer implements RunnableSchedulable<JSession> {
@Nonnull
public static final
BooleanPropertyId USE_PACKAGE_OBFUSCATION_DICTIONARY = BooleanPropertyId.create(
"jack.obfuscation.packagedictionary",
- "Use obfuscation dictionary for packages").addDefaultValue("false");
+ "Use obfuscation dictionary for packages").addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<File> PACKAGE_OBFUSCATION_DICTIONARY = PropertyId.create(
@@ -83,7 +83,7 @@
@Nonnull
public static final BooleanPropertyId USE_CLASS_OBFUSCATION_DICTIONARY = BooleanPropertyId.create(
"jack.obfuscation.classdictionary", "Use obfuscation dictionary for classes")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<File> CLASS_OBFUSCATION_DICTIONARY = PropertyId.create(
@@ -93,7 +93,7 @@
@Nonnull
public static final BooleanPropertyId USE_OBFUSCATION_DICTIONARY = BooleanPropertyId.create(
"jack.obfuscation.dictionary", "Use obfuscation dictionary for members")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<File> OBFUSCATION_DICTIONARY = PropertyId.create(
@@ -103,7 +103,7 @@
@Nonnull
public static final BooleanPropertyId USE_MAPPING = BooleanPropertyId.create(
"jack.obfuscation.mapping", "Use mapping for types and members")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<File> MAPPING_FILE = PropertyId.create(
@@ -115,7 +115,7 @@
public static final BooleanPropertyId REPACKAGE_CLASSES = BooleanPropertyId.create(
"jack.obfuscation.repackageclasses",
"Change package for all renamed classes")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<String> PACKAGE_FOR_RENAMED_CLASSES = PropertyId.create(
@@ -127,7 +127,7 @@
public static final BooleanPropertyId FLATTEN_PACKAGE = BooleanPropertyId.create(
"jack.obfuscation.flattenpackage",
"Change package for all renamed packages")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<String> PACKAGE_FOR_RENAMED_PACKAGES = PropertyId.create(
@@ -139,7 +139,7 @@
public static final BooleanPropertyId USE_UNIQUE_CLASSMEMBERNAMES = BooleanPropertyId.create(
"jack.obfuscation.uniqueclassmembernames",
"All members with the same name must have the same obfuscated name")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
public static boolean mustBeRenamed(@Nonnull AbstractMarkerManager node) {
return !node.containsMarker(KeepNameMarker.class)
@@ -253,7 +253,7 @@
@Nonnull
private final JPackage packageForRenamedClasses
- = Jack.getProgram().getLookup().getOrCreatePackage(packageNameForRenamedClasses);
+ = Jack.getSession().getLookup().getOrCreatePackage(packageNameForRenamedClasses);
private RepackagerVisitor(@Nonnull TransformationRequest request) {
this.request = request;
@@ -290,7 +290,7 @@
@Nonnull
private final JPackage packageForRenamedPackages
- = Jack.getProgram().getLookup().getOrCreatePackage(packageNameForRenamedPackages);
+ = Jack.getSession().getLookup().getOrCreatePackage(packageNameForRenamedPackages);
@Nonnull
private final NameProvider packageNameProvider =
@@ -350,14 +350,14 @@
}
@Override
- public void run(@Nonnull JProgram program) throws Exception {
- allTypes = program.getTypesToEmit();
+ public void run(@Nonnull JSession session) throws Exception {
+ allTypes = session.getTypesToEmit();
Map<String, String> fieldNames = new HashMap<String, String>();
Map<String, String> methodNames = new HashMap<String, String>();
boolean useUniqueClassMemberNames =
ThreadConfig.get(USE_UNIQUE_CLASSMEMBERNAMES).booleanValue();
if (ThreadConfig.get(USE_MAPPING).booleanValue()) {
- TransformationRequest request = new TransformationRequest(program);
+ TransformationRequest request = new TransformationRequest(session);
MappingApplier mappingApplier;
if (useUniqueClassMemberNames) {
mappingApplier = new CollectingMappingApplier(request);
@@ -366,7 +366,7 @@
} else {
mappingApplier = new MappingApplier(request);
}
- mappingApplier.applyMapping(ThreadConfig.get(MAPPING_FILE), program);
+ mappingApplier.applyMapping(ThreadConfig.get(MAPPING_FILE), session);
request.commit();
}
@@ -386,18 +386,18 @@
}
if (ThreadConfig.get(REPACKAGE_CLASSES).booleanValue()) {
- TransformationRequest request = new TransformationRequest(program);
+ TransformationRequest request = new TransformationRequest(session);
Visitor visitor = new RepackagerVisitor(request);
- visitor.accept(program);
+ visitor.accept(session);
request.commit();
} else if (ThreadConfig.get(FLATTEN_PACKAGE).booleanValue()) {
- TransformationRequest request = new TransformationRequest(program);
+ TransformationRequest request = new TransformationRequest(session);
Visitor visitor = new FlattenerVisitor(request);
- visitor.accept(program);
+ visitor.accept(session);
request.commit();
} else {
Visitor visitor = new Visitor();
- visitor.accept(program);
+ visitor.accept(session);
}
}
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/annotation/AnnotationRemover.java b/jack/src/com/android/jack/shrob/obfuscation/annotation/AnnotationRemover.java
index 6ab2ed6..bebf64e 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/annotation/AnnotationRemover.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/annotation/AnnotationRemover.java
@@ -35,12 +35,12 @@
public static final
BooleanPropertyId EMIT_RUNTIME_INVISIBLE_ANNOTATION = BooleanPropertyId.create(
"jack.annotation.runtimeinvisible", "Emit annotations that are runtime invisible")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final BooleanPropertyId EMIT_RUNTIME_VISIBLE_ANNOTATION = BooleanPropertyId.create(
"jack.annotation.runtimevisible", "Emit annotations that are runtime visible")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
private final Logger logger = LoggerFactory.getLogger();
diff --git a/jack/src/com/android/jack/shrob/obfuscation/annotation/ParameterAnnotationRemover.java b/jack/src/com/android/jack/shrob/obfuscation/annotation/ParameterAnnotationRemover.java
index 195a7d0..a63a00c 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/annotation/ParameterAnnotationRemover.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/annotation/ParameterAnnotationRemover.java
@@ -52,13 +52,13 @@
public static final
BooleanPropertyId EMIT_RUNTIME_VISIBLE_PARAMETER_ANNOTATION = BooleanPropertyId.create(
"jack.annotation.runtimevisible.parameter",
- "Emit parameters annotations that are runtime visible").addDefaultValue("true");
+ "Emit parameters annotations that are runtime visible").addDefaultValue(Boolean.TRUE);
@Nonnull
public static final
BooleanPropertyId EMIT_RUNTIME_INVISIBLE_PARAMETER_ANNOTATION = BooleanPropertyId.create(
"jack.annotation.runtimeinvisible.parameter",
- "Emit parameters annotations that are runtime invisible").addDefaultValue("true");
+ "Emit parameters annotations that are runtime invisible").addDefaultValue(Boolean.TRUE);
@Nonnull
private final Logger logger = LoggerFactory.getLogger();
diff --git a/jack/src/com/android/jack/shrob/shrink/KeepMarker.java b/jack/src/com/android/jack/shrob/shrink/KeepMarker.java
index fadba68..469c7d4 100644
--- a/jack/src/com/android/jack/shrob/shrink/KeepMarker.java
+++ b/jack/src/com/android/jack/shrob/shrink/KeepMarker.java
@@ -31,6 +31,16 @@
@Description("Indicates that this class or member should not be removed when shrinking.")
public class KeepMarker implements Marker {
+ private boolean mustTraceOverridingMethods = false;
+
+ public void setMustTraceOverridingMethods(boolean mustTraceOverridingMethods) {
+ this.mustTraceOverridingMethods = mustTraceOverridingMethods;
+ }
+
+ public boolean mustTraceOverridingMethods() {
+ return mustTraceOverridingMethods;
+ }
+
@Override
public Marker cloneIfNeeded() {
return this;
diff --git a/jack/src/com/android/jack/shrob/shrink/Keeper.java b/jack/src/com/android/jack/shrob/shrink/Keeper.java
index 174f0b4..1df2405 100644
--- a/jack/src/com/android/jack/shrob/shrink/Keeper.java
+++ b/jack/src/com/android/jack/shrob/shrink/Keeper.java
@@ -141,11 +141,38 @@
}
}
}
+
+ @Override
+ protected boolean mustTraceOverridingMethod(@Nonnull JMethod method) {
+ if (method.getEnclosingType().isExternal()) {
+ return true;
+ } else {
+ synchronized (method) {
+ KeepMarker marker = method.getMarker(KeepMarker.class);
+ if (marker != null) {
+ return marker.mustTraceOverridingMethods();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void setMustTraceOverridingMethods(@Nonnull JMethod method) {
+ synchronized (method) {
+ KeepMarker marker = method.getMarker(KeepMarker.class);
+ if (marker != null) {
+ marker.setMustTraceOverridingMethods(true);
+ } else {
+ assert method.getEnclosingType().isExternal();
+ }
+ }
+ }
}
public static final BooleanPropertyId KEEP_ENCLOSING_METHOD = BooleanPropertyId.create(
"jack.shrink.keep.enclosing.method",
- "Keep the enclosing method of annonymous classes").addDefaultValue("false");
+ "Keep the enclosing method of annonymous classes").addDefaultValue(Boolean.FALSE);
@Nonnull
private final Flags flags = ThreadConfig.get(Options.FLAGS);
diff --git a/jack/src/com/android/jack/shrob/shrink/ShrinkEventType.java b/jack/src/com/android/jack/shrob/shrink/ShrinkEventType.java
index 9a645f2..302bd80 100644
--- a/jack/src/com/android/jack/shrob/shrink/ShrinkEventType.java
+++ b/jack/src/com/android/jack/shrob/shrink/ShrinkEventType.java
@@ -25,23 +25,14 @@
*/
public enum ShrinkEventType implements EventType {
- FINDING_SEEDS("Finding seeds", "Blue"),
- OVERRIDING_METHODS("Searching for overridding methods", "Red");
+ FINDING_SEEDS("Finding seeds"),
+ OVERRIDING_METHODS("Searching for overridding methods");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- ShrinkEventType(@Nonnull String name, @Nonnull String cssColor) {
+ ShrinkEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/jack/src/com/android/jack/shrob/shrink/Tracer.java b/jack/src/com/android/jack/shrob/shrink/Tracer.java
index 882a10c..d523bb6 100644
--- a/jack/src/com/android/jack/shrob/shrink/Tracer.java
+++ b/jack/src/com/android/jack/shrob/shrink/Tracer.java
@@ -52,7 +52,6 @@
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JParameter;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JTypeStringLiteral;
import com.android.jack.ir.ast.JVariable;
@@ -113,13 +112,14 @@
if (superClOrI instanceof JDefinedClassOrInterface) {
JDefinedClassOrInterface definedSuperClOrI = (JDefinedClassOrInterface) superClOrI;
for (JMethod method : definedSuperClOrI.getMethods()) {
- if (isMarked(method)) {
+ if (isMarked(method) && mustTraceOverridingMethod(method)) {
JMethodId methodId = method.getMethodId();
JType returnType = method.getType();
JMethod implementation =
findImplementation(methodId, returnType, extendingOrImplementingClass);
if (implementation != null) {
- trace(methodId, implementation.getEnclosingType(), returnType);
+ trace(methodId, implementation.getEnclosingType(), returnType,
+ true /* mustTraceOverridingMethods */);
}
}
}
@@ -134,11 +134,15 @@
}
}
+ protected abstract boolean mustTraceOverridingMethod(@Nonnull JMethod method);
+
+ protected abstract void setMustTraceOverridingMethods(@Nonnull JMethod method);
+
protected void trace(@Nonnull JDefinedClassOrInterface t) {
if (markIfNecessary(t)) {
traceAnnotations(t);
for (JMethod m : t.getMethods()) {
- if (!isMarked(m) && (JProgram.isClinit(m) || isNullaryConstructor(m))) {
+ if (!isMarked(m) && (JMethod.isClinit(m) || isNullaryConstructor(m))) {
trace(m);
}
}
@@ -205,11 +209,14 @@
/**
* Traces the methods corresponding to a method id whose enclosing type is a subclass of
* receiverType
- * @param mid
- * @param receiverType
+ * @param mid the methodId of the searched method
+ * @param receiverType the type with which the methodId was used
+ * @param returnType the return type of the searched method
+ * @param mustTraceOverridingMethods indicates if the overriding methods of the traced method
+ * should be traced as well
*/
- protected void trace(
- @Nonnull JMethodId mid, @Nonnull JClassOrInterface receiverType, @Nonnull JType returnType) {
+ protected void trace(@Nonnull JMethodId mid, @Nonnull JClassOrInterface receiverType,
+ @Nonnull JType returnType, boolean mustTraceOverridingMethods) {
for (JType paramType : mid.getParamTypes()) {
trace(paramType);
}
@@ -217,9 +224,12 @@
JMethod foundMethod = findMethod(mid, receiverType, returnType);
if (foundMethod != null) {
trace(foundMethod);
+ if (mustTraceOverridingMethods) {
+ setMustTraceOverridingMethods(foundMethod);
+ }
}
- if (receiverType instanceof JDefinedClassOrInterface) {
+ if (receiverType instanceof JDefinedClassOrInterface && mustTraceOverridingMethods) {
ExtendingOrImplementingClassMarker marker =
((LocalMarkerManager) receiverType).getMarker(ExtendingOrImplementingClassMarker.class);
if (marker != null) {
@@ -228,12 +238,12 @@
JMethod implementation = findImplementation(mid, returnType, subClass);
if (implementation != null) {
trace(implementation);
+ setMustTraceOverridingMethods(implementation);
}
}
}
}
}
-
}
protected void trace(@Nonnull JMethod m) {
@@ -313,7 +323,7 @@
tracingStartingPoint = receiverType;
}
trace(tracingStartingPoint);
- trace(methodId, tracingStartingPoint, returnType);
+ trace(methodId, tracingStartingPoint, returnType, true /* mustTraceOverridingMethods */);
}
@Override
@@ -321,7 +331,8 @@
JClass returnType = newInstance.getType();
trace(returnType);
JMethodId methodId = newInstance.getMethodId();
- trace(methodId, returnType, JPrimitiveTypeEnum.VOID.getType());
+ trace(methodId, returnType, JPrimitiveTypeEnum.VOID.getType(),
+ false /* mustTraceOverridingMethods */);
}
/**
diff --git a/jack/src/com/android/jack/shrob/shrink/TypeAndMemberLister.java b/jack/src/com/android/jack/shrob/shrink/TypeAndMemberLister.java
index 71fdd39..fa1d6d0 100644
--- a/jack/src/com/android/jack/shrob/shrink/TypeAndMemberLister.java
+++ b/jack/src/com/android/jack/shrob/shrink/TypeAndMemberLister.java
@@ -20,7 +20,7 @@
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.formatter.BinarySignatureFormatter;
import com.android.jack.ir.formatter.TypeAndMethodFormatter;
@@ -48,13 +48,13 @@
@HasKeyId
@Description("lists all members and types")
@Produce(TypeAndMemberListing.class)
-public class TypeAndMemberLister implements RunnableSchedulable<JProgram> {
+public class TypeAndMemberLister implements RunnableSchedulable<JSession> {
@Nonnull
public static final BooleanPropertyId TYPE_AND_MEMBER_LISTING = BooleanPropertyId.create(
"jack.listing",
"List all types and members")
- .addDefaultValue("false");
+ .addDefaultValue(Boolean.FALSE);
@Nonnull
public static final PropertyId<StreamFile> TYPE_AND_MEMBER_LISTING_FILE = PropertyId.create(
@@ -122,7 +122,7 @@
}
@Override
- public void run(@Nonnull JProgram t) throws Exception {
+ public void run(@Nonnull JSession t) throws Exception {
try {
Visitor visitor = new Visitor();
visitor.accept(t);
diff --git a/jack/src/com/android/jack/shrob/spec/MethodSpecification.java b/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
index 71714c3..2ffffba 100644
--- a/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
+++ b/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
@@ -19,6 +19,7 @@
import com.android.jack.ir.ast.JConstructor;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.shrob.proguard.GrammarActions;
+import com.android.jack.util.NamingTools;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -57,12 +58,12 @@
String signature = GrammarActions.getSignatureFormatter().getName(t);
if (t instanceof JConstructor) {
- String methodName = signature.replace("<init>", t.getEnclosingType().getName());
+ String methodName = signature.replace(NamingTools.INIT_NAME, t.getEnclosingType().getName());
if (sigPattern.matches(methodName)) {
return true;
}
- methodName = signature.replace(
- "<init>", GrammarActions.getBinaryNameFormatter().getName(t.getEnclosingType()));
+ methodName = signature.replace(NamingTools.INIT_NAME,
+ GrammarActions.getBinaryNameFormatter().getName(t.getEnclosingType()));
if (sigPattern.matches(methodName)) {
return true;
}
diff --git a/jack/src/com/android/jack/signature/GenericSignatureAction.java b/jack/src/com/android/jack/signature/GenericSignatureAction.java
index 6c276a6..8786f1d 100644
--- a/jack/src/com/android/jack/signature/GenericSignatureAction.java
+++ b/jack/src/com/android/jack/signature/GenericSignatureAction.java
@@ -16,20 +16,23 @@
package com.android.jack.signature;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Actions triggered by the generic signature parser.
*/
-public interface GenericSignatureAction {
+public interface GenericSignatureAction<T> {
public void parsedSymbol(char symbol);
public void parsedIdentifier(@Nonnull String identifier);
- public void parsedTypeName(@Nonnull String name);
+ @CheckForNull
+ public T parsedTypeName(@Nonnull String name);
- public void parsedInnerTypeName(@Nonnull String name);
+ @CheckForNull
+ public T parsedInnerTypeName(@CheckForNull T enclosingType, @Nonnull String name);
public void start();
diff --git a/jack/src/com/android/jack/signature/GenericSignatureParser.java b/jack/src/com/android/jack/signature/GenericSignatureParser.java
index 539a90c..07154f1 100644
--- a/jack/src/com/android/jack/signature/GenericSignatureParser.java
+++ b/jack/src/com/android/jack/signature/GenericSignatureParser.java
@@ -63,10 +63,10 @@
* VoidDescriptor ::= "V".
* </pre>
*/
-public class GenericSignatureParser {
+public class GenericSignatureParser<T> {
@Nonnull
- private final GenericSignatureAction actions;
+ private final GenericSignatureAction<T> actions;
/*
* Parser:
@@ -89,7 +89,7 @@
@Nonnegative
private int pos;
- public GenericSignatureParser(@Nonnull GenericSignatureAction actions) {
+ public GenericSignatureParser(@Nonnull GenericSignatureAction<T> actions) {
this.actions = actions;
}
@@ -219,7 +219,7 @@
String packageName;
qualIdent.append(this.identifier);
- actions.parsedTypeName(qualIdent.toString());
+ T parsedEnclosingType = actions.parsedTypeName(qualIdent.toString());
updateOptTypeArguments();
@@ -229,7 +229,7 @@
scanSymbol();
scanIdentifier();
assert identifier != null;
- actions.parsedInnerTypeName(identifier);
+ parsedEnclosingType = actions.parsedInnerTypeName(parsedEnclosingType, identifier);
updateOptTypeArguments();
}
diff --git a/jack/src/com/android/jack/statistics/BlockCountMarker.java b/jack/src/com/android/jack/statistics/BlockCountMarker.java
index badcbc1..51ce558 100644
--- a/jack/src/com/android/jack/statistics/BlockCountMarker.java
+++ b/jack/src/com/android/jack/statistics/BlockCountMarker.java
@@ -16,7 +16,7 @@
package com.android.jack.statistics;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.marker.Marker;
import com.android.sched.marker.ValidOn;
@@ -28,7 +28,7 @@
* Statistics about block and extra created block.
*/
@Description("Statistics about block and extra created block.")
-@ValidOn(JProgram.class)
+@ValidOn(JSession.class)
public class BlockCountMarker implements Marker {
@Nonnegative
diff --git a/jack/src/com/android/jack/statistics/BlockStatistics.java b/jack/src/com/android/jack/statistics/BlockStatistics.java
index 3d320cd..1d9ea42 100644
--- a/jack/src/com/android/jack/statistics/BlockStatistics.java
+++ b/jack/src/com/android/jack/statistics/BlockStatistics.java
@@ -23,7 +23,7 @@
import com.android.jack.ir.ast.JLabeledStatement;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JNode;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.ast.JWhileStatement;
import com.android.sched.item.Description;
@@ -114,11 +114,11 @@
return;
}
- JProgram jProgram = method.getEnclosingType().getJProgram();
- BlockCountMarker bcm = jProgram.getMarker(BlockCountMarker.class);
+ JSession session = method.getEnclosingType().getSession();
+ BlockCountMarker bcm = session.getMarker(BlockCountMarker.class);
if (bcm == null) {
bcm = new BlockCountMarker();
- jProgram.addMarker(bcm);
+ session.addMarker(bcm);
}
BlockStatisticsVisitor statistics = new BlockStatisticsVisitor(bcm);
diff --git a/jack/src/com/android/jack/transformations/AssertionTransformer.java b/jack/src/com/android/jack/transformations/AssertionTransformer.java
index a7b362a..c80233a 100644
--- a/jack/src/com/android/jack/transformations/AssertionTransformer.java
+++ b/jack/src/com/android/jack/transformations/AssertionTransformer.java
@@ -39,7 +39,6 @@
import com.android.jack.ir.ast.JNewInstance;
import com.android.jack.ir.ast.JPrefixNotOperation;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JThrowStatement;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
@@ -139,7 +138,7 @@
// A.$assertionsDisabled = !A.class.desiredAssertionStatus();
JClass javaLangClass =
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS);
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS);
JClassLiteral thisClass = new JClassLiteral(sourceInfo, type, javaLangClass);
JFieldRef lhs = new JFieldRef(sourceInfo, null, assertionStatusId, type);
JExpression rhs = new JPrefixNotOperation(sourceInfo,
@@ -175,15 +174,15 @@
List<JType> ctorDescriptor = new ArrayList<JType>();
if (assertSt.getArg() != null) {
ctorDescriptor.add(
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT));
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT));
}
JClass assertionError =
- Jack.getProgram().getPhantomLookup()
+ Jack.getSession().getPhantomLookup()
.getClass(CommonTypes.JAVA_LANG_ASSERTION_ERROR);
JNewInstance newAssertionError = new JNewInstance(assertSt.getSourceInfo(),
assertionError,
- assertionError.getOrCreateMethodId(JProgram.INIT_NAME, ctorDescriptor,
+ assertionError.getOrCreateMethodId(NamingTools.INIT_NAME, ctorDescriptor,
MethodKind.INSTANCE_NON_VIRTUAL));
if (assertSt.getArg() != null) {
diff --git a/jack/src/com/android/jack/transformations/AssertionTransformerSchedulingSeparator.java b/jack/src/com/android/jack/transformations/AssertionTransformerSchedulingSeparator.java
index f782c67..e8fbe32 100644
--- a/jack/src/com/android/jack/transformations/AssertionTransformerSchedulingSeparator.java
+++ b/jack/src/com/android/jack/transformations/AssertionTransformerSchedulingSeparator.java
@@ -16,7 +16,7 @@
package com.android.jack.transformations;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.item.Tag;
import com.android.sched.schedulable.Constraint;
@@ -32,10 +32,10 @@
@Description("A separation between AssertionTransformer and FieldInitializer")
@Transform(remove = AssertionTransformerSchedulingSeparator.SeparatorTag.class)
@Constraint(need = AssertionTransformerSchedulingSeparator.SeparatorTag.class)
-public class AssertionTransformerSchedulingSeparator implements RunnableSchedulable<JProgram> {
+public class AssertionTransformerSchedulingSeparator implements RunnableSchedulable<JSession> {
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
// do nothing
}
diff --git a/jack/src/com/android/jack/transformations/EmptyClinitRemover.java b/jack/src/com/android/jack/transformations/EmptyClinitRemover.java
index b8969a2..9f1ab65 100644
--- a/jack/src/com/android/jack/transformations/EmptyClinitRemover.java
+++ b/jack/src/com/android/jack/transformations/EmptyClinitRemover.java
@@ -19,7 +19,6 @@
import com.android.jack.Options;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JReturnStatement;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.transformations.request.Remove;
@@ -47,7 +46,7 @@
@Override
public void run(@Nonnull JMethod method) throws Exception {
- if (JProgram.isClinit(method) && filter.accept(this.getClass(), method)) {
+ if (JMethod.isClinit(method) && filter.accept(this.getClass(), method)) {
JMethodBody body = (JMethodBody) method.getBody();
assert body != null;
List<JStatement> stmts = body.getStatements();
diff --git a/jack/src/com/android/jack/transformations/FieldInitializer.java b/jack/src/com/android/jack/transformations/FieldInitializer.java
index 7cc840a..2089b6a 100644
--- a/jack/src/com/android/jack/transformations/FieldInitializer.java
+++ b/jack/src/com/android/jack/transformations/FieldInitializer.java
@@ -21,12 +21,12 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.shrob.obfuscation.OriginalNames;
import com.android.jack.transformations.request.PrependStatement;
import com.android.jack.transformations.request.TransformationRequest;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeForm;
+import com.android.jack.util.NamingTools;
import com.android.sched.item.Description;
import com.android.sched.schedulable.Constraint;
import com.android.sched.schedulable.RunnableSchedulable;
@@ -58,7 +58,7 @@
TransformationRequest request = new TransformationRequest(field);
// Lookup for clinit
- JMethod clinit = field.getEnclosingType().getMethod(JProgram.STATIC_INIT_NAME,
+ JMethod clinit = field.getEnclosingType().getMethod(NamingTools.STATIC_INIT_NAME,
JPrimitiveTypeEnum.VOID.getType());
JMethodBody body = (JMethodBody) clinit.getBody();
assert body != null;
diff --git a/jack/src/com/android/jack/transformations/ast/CompoundAssignmentRemover.java b/jack/src/com/android/jack/transformations/ast/CompoundAssignmentRemover.java
index 5488d36..27d5c12 100644
--- a/jack/src/com/android/jack/transformations/ast/CompoundAssignmentRemover.java
+++ b/jack/src/com/android/jack/transformations/ast/CompoundAssignmentRemover.java
@@ -184,7 +184,7 @@
}
JClass javaLangString = method.getEnclosingType()
- .getJProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
+ .getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
TransformationRequest tr = new TransformationRequest(method);
RemoveComplexAssignVisitor rca = new RemoveComplexAssignVisitor(tr, javaLangString);
rca.accept(method);
diff --git a/jack/src/com/android/jack/transformations/ast/ConcatRemover.java b/jack/src/com/android/jack/transformations/ast/ConcatRemover.java
index 1ddbfa9..fe3ea56 100644
--- a/jack/src/com/android/jack/transformations/ast/ConcatRemover.java
+++ b/jack/src/com/android/jack/transformations/ast/ConcatRemover.java
@@ -16,7 +16,6 @@
package com.android.jack.transformations.ast;
-import com.android.jack.Jack;
import com.android.jack.Options;
import com.android.jack.ir.SourceInfo;
import com.android.jack.ir.ast.JAsgConcatOperation;
@@ -33,7 +32,7 @@
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JPrimitiveType;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.ast.MethodKind;
@@ -42,6 +41,7 @@
import com.android.jack.transformations.request.Replace;
import com.android.jack.transformations.request.TransformationRequest;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeForm;
+import com.android.jack.util.NamingTools;
import com.android.jack.util.filter.Filter;
import com.android.sched.item.Description;
import com.android.sched.schedulable.Constraint;
@@ -76,7 +76,7 @@
private static final String CHAR_SEQUENCE_SIGNATURE = "Ljava/lang/CharSequence;";
@Nonnull
- private static final String STRING_BUILDER_CONSTRUCTOR_NAME = "<init>";
+ private static final String STRING_BUILDER_CONSTRUCTOR_NAME = NamingTools.INIT_NAME;
@Nonnull
private static final String TO_STRING = "toString";
@@ -84,7 +84,7 @@
@Nonnull
private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER);
@CheckForNull
- private JProgram program;
+ private JSession session;
@CheckForNull
private JClassOrInterface stringBuilder;
@CheckForNull
@@ -130,11 +130,12 @@
JMethodId stringBuilderToString =
stringBuilder.getOrCreateMethodId(TO_STRING, Lists.<JType>create(),
MethodKind.INSTANCE_VIRTUAL);
+ assert session != null;
JMethodCall toString = new JMethodCall(sourceInfo,
appendRhs,
stringBuilder,
stringBuilderToString,
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING),
+ session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING),
stringBuilderToString.canBeVirtual());
tr.append(new Replace(binary, toString));
@@ -164,7 +165,7 @@
return;
}
- program = enclosingType.getJProgram();
+ session = enclosingType.getSession();
Visitor visitor = new Visitor(method);
visitor.accept(method);
@@ -173,9 +174,9 @@
@Nonnull
private JClassOrInterface getStringBuilder() {
if (stringBuilder == null) {
- assert program != null;
+ assert session != null;
stringBuilder =
- (JClassOrInterface) program.getPhantomLookup().getType(STRING_BUILDER_SIGNATURE);
+ (JClassOrInterface) session.getPhantomLookup().getType(STRING_BUILDER_SIGNATURE);
}
assert stringBuilder != null;
@@ -185,9 +186,9 @@
@Nonnull
private JClassOrInterface getCharSequence() {
if (charSequence == null) {
- assert program != null;
+ assert session != null;
charSequence =
- (JClassOrInterface) program.getPhantomLookup().getType(CHAR_SEQUENCE_SIGNATURE);
+ (JClassOrInterface) session.getPhantomLookup().getType(CHAR_SEQUENCE_SIGNATURE);
}
assert charSequence != null;
@@ -202,6 +203,7 @@
JType appendArgType = elementType;
+ assert session != null;
if (elementType instanceof JPrimitiveType) {
JPrimitiveTypeEnum primitiveType = ((JPrimitiveType) elementType).getPrimitiveTypeEnum();
switch (primitiveType) {
@@ -224,14 +226,15 @@
throw new AssertionError();
}
} else if (elementType
- == Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING)) {
- appendArgType = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
+ == session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING)) {
+ appendArgType = session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING);
} else {
JType charSequence = getCharSequence();
+ assert session != null; // FINDBUGS
if (elementType == charSequence){
appendArgType = charSequence;
} else {
- appendArgType = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ appendArgType = session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
}
}
diff --git a/jack/src/com/android/jack/transformations/ast/MultiDimensionNewArrayRemover.java b/jack/src/com/android/jack/transformations/ast/MultiDimensionNewArrayRemover.java
index e3dde54..237cabb 100644
--- a/jack/src/com/android/jack/transformations/ast/MultiDimensionNewArrayRemover.java
+++ b/jack/src/com/android/jack/transformations/ast/MultiDimensionNewArrayRemover.java
@@ -16,7 +16,6 @@
package com.android.jack.transformations.ast;
-import com.android.jack.Jack;
import com.android.jack.Options;
import com.android.jack.ir.SourceInfo;
import com.android.jack.ir.ast.JAbsentArrayDimension;
@@ -30,7 +29,7 @@
import com.android.jack.ir.ast.JMethodCall;
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JNewArray;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.ast.MethodKind;
@@ -78,13 +77,13 @@
@CheckForNull
private JClassOrInterface reflectArray;
@Nonnull
- private final JProgram program;
+ private final JSession session;
@CheckForNull
private JMethodId newInstance;
- public Visitor(@Nonnull TransformationRequest tr, @Nonnull JProgram program) {
+ public Visitor(@Nonnull TransformationRequest tr, @Nonnull JSession session) {
this.tr = tr;
- this.program = program;
+ this.session = session;
}
@Override
@@ -99,11 +98,11 @@
JClassOrInterface reflectArrayType = getReflectArrayType();
JMethodId newInstanceId = getNewInstanceId(reflectArrayType);
JMethodCall call = new JMethodCall(sourceInfo, null, reflectArrayType, newInstanceId,
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT),
+ session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT),
newInstanceId.canBeVirtual());
call.addArg(new JClassLiteral(
sourceInfo, getComponentTypeForNewInstance(newArray, nbPresentDimensions),
- program.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS)));
+ session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS)));
call.addArg(JNewArray.createWithInits(sourceInfo, getIntArrayType(), presentDimensions));
tr.append(new Replace(newArray, new JDynamicCastOperation(sourceInfo, newArray
.getArrayType(), call)));
@@ -116,7 +115,7 @@
private JMethodId getNewInstanceId(JClassOrInterface reflectArrayType) {
if (newInstance == null) {
List<JType> argsType = new ArrayList<JType>(2);
- argsType.add(Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS));
+ argsType.add(session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS));
argsType.add(getIntArrayType());
newInstance = reflectArrayType.getOrCreateMethodId("newInstance", argsType,
MethodKind.STATIC);
@@ -163,7 +162,7 @@
private JClassOrInterface getReflectArrayType() {
if (reflectArray == null) {
reflectArray =
- (JClassOrInterface) program.getPhantomLookup().getType("Ljava/lang/reflect/Array;");
+ (JClassOrInterface) session.getPhantomLookup().getType("Ljava/lang/reflect/Array;");
}
assert reflectArray != null;
@@ -176,7 +175,7 @@
@Nonnull
private JArrayType getIntArrayType() {
if (intArrayType == null) {
- intArrayType = (JArrayType) program.getLookup().getType("[I");
+ intArrayType = (JArrayType) session.getLookup().getType("[I");
}
assert intArrayType != null;
@@ -194,7 +193,7 @@
}
TransformationRequest tr = new TransformationRequest(method);
- Visitor visitor = new Visitor(tr, enclosingType.getJProgram());
+ Visitor visitor = new Visitor(tr, enclosingType.getSession());
visitor.accept(method);
tr.commit();
}
diff --git a/jack/src/com/android/jack/transformations/ast/PrimitiveClassTransformer.java b/jack/src/com/android/jack/transformations/ast/PrimitiveClassTransformer.java
index 3dc01ac..78df2ac 100644
--- a/jack/src/com/android/jack/transformations/ast/PrimitiveClassTransformer.java
+++ b/jack/src/com/android/jack/transformations/ast/PrimitiveClassTransformer.java
@@ -75,7 +75,7 @@
JClass receiverType = getType((JPrimitiveType) classLiteral.getRefType());
JFieldRef fieldAccess = new JFieldRef(classLiteral.getSourceInfo(),
null, receiverType.getFieldId(FIELD_TYPE_NAME,
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS),
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS),
FieldKind.STATIC), receiverType);
tr.append(new Replace(classLiteral, fieldAccess));
}
@@ -86,7 +86,7 @@
// available.
@Nonnull
private JClass getType(@Nonnull JPrimitiveType primType) {
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
switch (primType.getPrimitiveTypeEnum()) {
case BOOLEAN:
return lookup.getClass(CommonTypes.JAVA_LANG_BOOLEAN);
diff --git a/jack/src/com/android/jack/transformations/ast/SynchronizeTransformer.java b/jack/src/com/android/jack/transformations/ast/SynchronizeTransformer.java
index d70020e..854aedb 100644
--- a/jack/src/com/android/jack/transformations/ast/SynchronizeTransformer.java
+++ b/jack/src/com/android/jack/transformations/ast/SynchronizeTransformer.java
@@ -33,7 +33,7 @@
import com.android.jack.ir.ast.JLock;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JSynchronizedBlock;
import com.android.jack.ir.ast.JThisRef;
@@ -91,7 +91,7 @@
public static final BooleanPropertyId REUSE_SYNC_VARIABLE = BooleanPropertyId.create(
"jack.transformation.reusesyncvariable",
"Reduce the 'get class' usage in static synchronized methods by reusing a local variable")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
private final boolean reuseSyncVariable = ThreadConfig.get(REUSE_SYNC_VARIABLE).booleanValue();
@@ -100,15 +100,15 @@
@Nonnull
private final TransformationRequest tr;
@Nonnull
- private final JProgram program;
+ private final JSession session;
@Nonnull
private final LocalVarCreator lvCreator;
- public Visitor(@Nonnull TransformationRequest tr, @Nonnull JProgram program,
+ public Visitor(@Nonnull TransformationRequest tr, @Nonnull JSession session,
@Nonnull LocalVarCreator lvCreator) {
this.tr = tr;
this.lvCreator = lvCreator;
- this.program = program;
+ this.session = session;
}
@Override
@@ -202,7 +202,7 @@
@Nonnull
private JClass getJLClass() {
- return program.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS);
+ return session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CLASS);
}
}
@@ -216,7 +216,7 @@
TransformationRequest tr = new TransformationRequest(method);
LocalVarCreator lvCreator = new LocalVarCreator(method, "sync");
- Visitor visitor = new Visitor(tr, enclosingType.getJProgram(), lvCreator);
+ Visitor visitor = new Visitor(tr, enclosingType.getSession(), lvCreator);
visitor.accept(method);
tr.commit();
}
diff --git a/jack/src/com/android/jack/transformations/ast/TryWithResourcesTransformer.java b/jack/src/com/android/jack/transformations/ast/TryWithResourcesTransformer.java
index f40594c..c5a9104 100644
--- a/jack/src/com/android/jack/transformations/ast/TryWithResourcesTransformer.java
+++ b/jack/src/com/android/jack/transformations/ast/TryWithResourcesTransformer.java
@@ -138,7 +138,7 @@
JBlock finalTryBlock = new JBlock(x.getSourceInfo());
// Declare exception to throw in the end, if any, and initialize it to null;
- JClass throwableClass = Jack.getProgram().getPhantomLookup().getClass(THROWABLE_SIGNATURE);
+ JClass throwableClass = Jack.getSession().getPhantomLookup().getClass(THROWABLE_SIGNATURE);
JLocal exceptionToThrow =
localVarCreator.createTempLocal(throwableClass, firstLineSourceInfos, request);
JAsgOperation assign = new JAsgOperation(
@@ -184,7 +184,7 @@
// Lookup AutoCloseable.close() method
JInterface autoCloseableInterface =
- Jack.getProgram().getPhantomLookup().getInterface(AUTO_CLOSEABLE_SIGNATURE);
+ Jack.getSession().getPhantomLookup().getInterface(AUTO_CLOSEABLE_SIGNATURE);
JMethodId closeMethodId = autoCloseableInterface.getMethodId(
CLOSE_METHOD_NAME, Collections.<JType>emptyList(), MethodKind.INSTANCE_VIRTUAL);
diff --git a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
index 3bfe0a3..5a7a069 100644
--- a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
+++ b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
@@ -353,7 +353,7 @@
String methodName;
JType returnType;
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
if (isBoxingType(lookup, typeToUnbox, CommonTypes.JAVA_LANG_BOOLEAN)) {
methodName = "booleanValue";
@@ -408,7 +408,7 @@
@Nonnull JPrimitiveType pType) {
JClassOrInterface wrapperType = type;
JType argType;
- JPhantomLookup lookup = Jack.getProgram().getPhantomLookup();
+ JPhantomLookup lookup = Jack.getSession().getPhantomLookup();
if (isBoxingType(lookup, wrapperType, CommonTypes.JAVA_LANG_BOOLEAN)) {
argType = JPrimitiveTypeEnum.BOOLEAN.getType();
} else if (isBoxingType(lookup, wrapperType, CommonTypes.JAVA_LANG_BYTE)) {
diff --git a/jack/src/com/android/jack/transformations/ast/inner/InnerAccessorSchedulingSeparator.java b/jack/src/com/android/jack/transformations/ast/inner/InnerAccessorSchedulingSeparator.java
index 86e7d3d..08d7b00 100644
--- a/jack/src/com/android/jack/transformations/ast/inner/InnerAccessorSchedulingSeparator.java
+++ b/jack/src/com/android/jack/transformations/ast/inner/InnerAccessorSchedulingSeparator.java
@@ -16,7 +16,7 @@
package com.android.jack.transformations.ast.inner;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.item.Tag;
import com.android.sched.schedulable.Constraint;
@@ -32,10 +32,10 @@
@Description("A separation between InnerAccessorGenerator and InnerAccessorAdder")
@Transform(remove = InnerAccessorSchedulingSeparator.SeparatorTag.class)
@Constraint(need = InnerAccessorSchedulingSeparator.SeparatorTag.class)
-public class InnerAccessorSchedulingSeparator implements RunnableSchedulable<JProgram> {
+public class InnerAccessorSchedulingSeparator implements RunnableSchedulable<JSession> {
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
// do nothing
}
diff --git a/jack/src/com/android/jack/transformations/ast/string/FieldGenericSignatureSplitter.java b/jack/src/com/android/jack/transformations/ast/string/FieldGenericSignatureSplitter.java
index a7a2dba..9178b5f 100644
--- a/jack/src/com/android/jack/transformations/ast/string/FieldGenericSignatureSplitter.java
+++ b/jack/src/com/android/jack/transformations/ast/string/FieldGenericSignatureSplitter.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.ast.JAbstractStringLiteral;
import com.android.jack.ir.ast.JField;
+import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.marker.OriginalTypeInfo;
import com.android.jack.signature.GenericSignatureParser;
import com.android.sched.item.Description;
@@ -44,7 +45,7 @@
JAbstractStringLiteral oldSignature = marker.getGenericSignature();
if (oldSignature != null) {
GenericSignatureRefiner parserActions = new GenericSignatureRefiner();
- GenericSignatureParser parser = new GenericSignatureParser(parserActions);
+ GenericSignatureParser<JType> parser = new GenericSignatureParser<JType>(parserActions);
String strOldSignature = oldSignature.getValue();
parser.parseFieldSignature(strOldSignature);
assert parserActions.getNewSignature().getValue().equals(strOldSignature);
diff --git a/jack/src/com/android/jack/transformations/ast/string/GenericSignatureRefiner.java b/jack/src/com/android/jack/transformations/ast/string/GenericSignatureRefiner.java
index 9290304..b833d7c 100644
--- a/jack/src/com/android/jack/transformations/ast/string/GenericSignatureRefiner.java
+++ b/jack/src/com/android/jack/transformations/ast/string/GenericSignatureRefiner.java
@@ -21,8 +21,11 @@
import com.android.jack.ir.ast.JAbstractStringLiteral;
import com.android.jack.ir.ast.JCompositeStringLiteral;
import com.android.jack.ir.ast.JStringLiteral;
+import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JTypeStringLiteral;
import com.android.jack.ir.ast.JTypeStringLiteral.Kind;
+import com.android.jack.ir.formatter.BinaryQualifiedNameFormatter;
+import com.android.jack.ir.formatter.TypeFormatter;
import com.android.jack.lookup.JLookup;
import com.android.jack.lookup.JLookupException;
import com.android.jack.shrob.obfuscation.OriginalNames;
@@ -39,7 +42,7 @@
*/
@Constraint(need = OriginalNames.class)
@Transform(add = {JTypeStringLiteral.class, JCompositeStringLiteral.class, JStringLiteral.class})
-public class GenericSignatureRefiner implements GenericSignatureAction {
+public class GenericSignatureRefiner implements GenericSignatureAction<JType> {
@CheckForNull
private JAbstractStringLiteral jstringLiteral = null;
@@ -50,8 +53,11 @@
@Nonnull
private final JLookup jlookup;
+ @Nonnull
+ private final TypeFormatter formatter = BinaryQualifiedNameFormatter.getFormatter();
+
public GenericSignatureRefiner() {
- jlookup = Jack.getProgram().getLookup();
+ jlookup = Jack.getSession().getLookup();
}
@Override
@@ -65,27 +71,36 @@
}
@Override
- public void parsedTypeName(@Nonnull String name) {
+ @CheckForNull
+ public JType parsedTypeName(@Nonnull String name) {
updateJStringLiteral(getJStringLiteralFromBuffer());
try {
- updateJStringLiteral(new JTypeStringLiteral(SourceOrigin.UNKNOWN, Kind.BINARY_QN, jlookup
- .getType(NamingTools.getTypeSignatureName(name))));
+ JType type = jlookup.getType(NamingTools.getTypeSignatureName(name));
+ updateJStringLiteral(new JTypeStringLiteral(SourceOrigin.UNKNOWN, Kind.BINARY_QN, type));
+ return type;
} catch (JLookupException e) {
- // Type not found, kept it as a JStringLiteral
+ // Type not found, keep it as a JStringLiteral
updateJStringLiteral(new JStringLiteral(SourceOrigin.UNKNOWN, name));
+ return null;
}
}
@Override
- public void parsedInnerTypeName(@Nonnull String name) {
+ @CheckForNull
+ public JType parsedInnerTypeName(@CheckForNull JType enclosingType, @Nonnull String name) {
updateJStringLiteral(getJStringLiteralFromBuffer());
- try {
- updateJStringLiteral(new JTypeStringLiteral(SourceOrigin.UNKNOWN, Kind.SIMPLE_NAME,
- jlookup.getType(NamingTools.getTypeSignatureName(name))));
- } catch (JLookupException e) {
- // Type not found, kept it as a JStringLiteral
- updateJStringLiteral(new JStringLiteral(SourceOrigin.UNKNOWN, name));
+ if (enclosingType != null) {
+ try {
+ JType type = jlookup.getType(NamingTools.getTypeSignatureName(
+ formatter.getName(enclosingType) + '$' + name));
+ updateJStringLiteral(new JTypeStringLiteral(SourceOrigin.UNKNOWN, Kind.SIMPLE_NAME, type));
+ return type;
+ } catch (JLookupException e) {
+ // Type not found, keep it as a JStringLiteral
+ }
}
+ updateJStringLiteral(new JStringLiteral(SourceOrigin.UNKNOWN, name));
+ return null;
}
@Override
diff --git a/jack/src/com/android/jack/transformations/ast/string/MethodGenericSignatureSplitter.java b/jack/src/com/android/jack/transformations/ast/string/MethodGenericSignatureSplitter.java
index d37aa5b..d5ecc79 100644
--- a/jack/src/com/android/jack/transformations/ast/string/MethodGenericSignatureSplitter.java
+++ b/jack/src/com/android/jack/transformations/ast/string/MethodGenericSignatureSplitter.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.ast.JAbstractStringLiteral;
import com.android.jack.ir.ast.JMethod;
+import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.marker.OriginalTypeInfo;
import com.android.jack.signature.GenericSignatureParser;
import com.android.sched.item.Description;
@@ -44,7 +45,7 @@
JAbstractStringLiteral oldSignature = marker.getGenericSignature();
if (oldSignature != null) {
GenericSignatureRefiner parserActions = new GenericSignatureRefiner();
- GenericSignatureParser parser = new GenericSignatureParser(parserActions);
+ GenericSignatureParser<JType> parser = new GenericSignatureParser<JType>(parserActions);
String strOldSignature = oldSignature.getValue();
parser.parseMethodSignature(strOldSignature);
assert parserActions.getNewSignature().getValue().equals(strOldSignature);
diff --git a/jack/src/com/android/jack/transformations/ast/string/StringLiteralRefinerVisitor.java b/jack/src/com/android/jack/transformations/ast/string/StringLiteralRefinerVisitor.java
index 849d541..5935b38 100644
--- a/jack/src/com/android/jack/transformations/ast/string/StringLiteralRefinerVisitor.java
+++ b/jack/src/com/android/jack/transformations/ast/string/StringLiteralRefinerVisitor.java
@@ -52,7 +52,7 @@
public StringLiteralRefinerVisitor(@Nonnull TransformationRequest tr) {
this.tr = tr;
- lookup = Jack.getProgram().getLookup();
+ lookup = Jack.getSession().getLookup();
}
@Override
diff --git a/jack/src/com/android/jack/transformations/ast/string/TypeGenericSignatureSplitter.java b/jack/src/com/android/jack/transformations/ast/string/TypeGenericSignatureSplitter.java
index dd61df6..0ddb569 100644
--- a/jack/src/com/android/jack/transformations/ast/string/TypeGenericSignatureSplitter.java
+++ b/jack/src/com/android/jack/transformations/ast/string/TypeGenericSignatureSplitter.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.ast.JAbstractStringLiteral;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
+import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.marker.OriginalTypeInfo;
import com.android.jack.ir.ast.marker.ThisRefTypeInfo;
import com.android.jack.signature.GenericSignatureParser;
@@ -71,7 +72,7 @@
}
GenericSignatureRefiner parserActions = new GenericSignatureRefiner();
- GenericSignatureParser parser = new GenericSignatureParser(parserActions);
+ GenericSignatureParser<JType> parser = new GenericSignatureParser<JType>(parserActions);
String strOldSignature = oldSignature.getValue();
parser.parseClassSignature(strOldSignature);
assert parserActions.getNewSignature().getValue().equals(strOldSignature);
diff --git a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicLongIntUpdaterParameterRefiner.java b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicLongIntUpdaterParameterRefiner.java
index 8fb4919..6f0a84a 100644
--- a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicLongIntUpdaterParameterRefiner.java
+++ b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicLongIntUpdaterParameterRefiner.java
@@ -45,12 +45,12 @@
@Nonnull
private final JClassOrInterface atomicIntegerFieldUpdater =
- (JClassOrInterface) Jack.getProgram().getPhantomLookup()
+ (JClassOrInterface) Jack.getSession().getPhantomLookup()
.getType(CommonTypes.JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICINTEGERFIELDUPDATER);
@Nonnull
private final JClassOrInterface atomicLongFieldUpdater =
- (JClassOrInterface) Jack.getProgram().getPhantomLookup()
+ (JClassOrInterface) Jack.getSession().getPhantomLookup()
.getType(CommonTypes.JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICLONGFIELDUPDATER);
@Override
diff --git a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicReferenceUpdaterParameterRefiner.java b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicReferenceUpdaterParameterRefiner.java
index b77e853..8ff706f 100644
--- a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicReferenceUpdaterParameterRefiner.java
+++ b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/AtomicReferenceUpdaterParameterRefiner.java
@@ -35,7 +35,7 @@
@Nonnull
private final JClassOrInterface atomicFieldUpdater =
- (JClassOrInterface) Jack.getProgram().getPhantomLookup()
+ (JClassOrInterface) Jack.getSession().getPhantomLookup()
.getType(CommonTypes.JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICREFERENCEFIELDUPDATER);
@Override
diff --git a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/CommonStringParameterRefiner.java b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/CommonStringParameterRefiner.java
index 5fd7483..e141bee 100644
--- a/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/CommonStringParameterRefiner.java
+++ b/jack/src/com/android/jack/transformations/ast/string/parameterrefiners/CommonStringParameterRefiner.java
@@ -66,8 +66,8 @@
protected static final TypeFormatter formatter = BinarySignatureFormatter.getFormatter();
CommonStringParameterRefiner() {
- lookup = Jack.getProgram().getLookup();
- JPhantomLookup phantomLookup = Jack.getProgram().getPhantomLookup();
+ lookup = Jack.getSession().getLookup();
+ JPhantomLookup phantomLookup = Jack.getSession().getPhantomLookup();
javaLangClass = phantomLookup.getClass(CommonTypes.JAVA_LANG_CLASS);
javaLangString = phantomLookup.getClass(CommonTypes.JAVA_LANG_STRING);
javaLangClassArray = javaLangClass.getArray();
diff --git a/jack/src/com/android/jack/transformations/ast/switches/SwitchStringSupport.java b/jack/src/com/android/jack/transformations/ast/switches/SwitchStringSupport.java
index 35479ea..68d6aa3 100644
--- a/jack/src/com/android/jack/transformations/ast/switches/SwitchStringSupport.java
+++ b/jack/src/com/android/jack/transformations/ast/switches/SwitchStringSupport.java
@@ -37,7 +37,7 @@
import com.android.jack.ir.ast.JMethodCall;
import com.android.jack.ir.ast.JMethodId;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JSwitchStatement;
import com.android.jack.ir.ast.JType;
@@ -96,8 +96,8 @@
public Visitor(@Nonnull TransformationRequest tr, @Nonnull JMethod method) {
this.tr = tr;
- JProgram program = method.getEnclosingType().getJProgram();
- JPhantomLookup lookup = program.getPhantomLookup();
+ JSession session = method.getEnclosingType().getSession();
+ JPhantomLookup lookup = session.getPhantomLookup();
JClass jlo = lookup.getClass(CommonTypes.JAVA_LANG_OBJECT);
JClass jls = lookup.getClass(CommonTypes.JAVA_LANG_STRING);
equalsMethodId =
diff --git a/jack/src/com/android/jack/transformations/enums/EnumMappingSchedulingSeparator.java b/jack/src/com/android/jack/transformations/enums/EnumMappingSchedulingSeparator.java
index 87724bc..b2041cd 100644
--- a/jack/src/com/android/jack/transformations/enums/EnumMappingSchedulingSeparator.java
+++ b/jack/src/com/android/jack/transformations/enums/EnumMappingSchedulingSeparator.java
@@ -16,7 +16,7 @@
package com.android.jack.transformations.enums;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.item.Tag;
import com.android.sched.schedulable.Constraint;
@@ -32,10 +32,10 @@
@Description("A separation between SwitchEnumSupport and EnumMappingMarkerRemover")
@Transform(remove = EnumMappingSchedulingSeparator.SeparatorTag.class)
@Constraint(need = EnumMappingSchedulingSeparator.SeparatorTag.class)
-public class EnumMappingSchedulingSeparator implements RunnableSchedulable<JProgram> {
+public class EnumMappingSchedulingSeparator implements RunnableSchedulable<JSession> {
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
// do nothing
}
diff --git a/jack/src/com/android/jack/transformations/enums/SwitchEnumSupport.java b/jack/src/com/android/jack/transformations/enums/SwitchEnumSupport.java
index 13b564a..35c3383 100644
--- a/jack/src/com/android/jack/transformations/enums/SwitchEnumSupport.java
+++ b/jack/src/com/android/jack/transformations/enums/SwitchEnumSupport.java
@@ -159,7 +159,7 @@
@Nonnull JDefinedClassOrInterface currentClass) {
this.tr = tr;
this.currentClass = currentClass;
- this.lookup = Jack.getProgram().getPhantomLookup();
+ this.lookup = Jack.getSession().getPhantomLookup();
}
@Override
diff --git a/jack/src/com/android/jack/transformations/exceptions/TryCatchRemover.java b/jack/src/com/android/jack/transformations/exceptions/TryCatchRemover.java
index 3776b79..19edd3f 100644
--- a/jack/src/com/android/jack/transformations/exceptions/TryCatchRemover.java
+++ b/jack/src/com/android/jack/transformations/exceptions/TryCatchRemover.java
@@ -209,7 +209,7 @@
int catchTypesCount = catchTypes.size();
for (JClass catchedType : bb.getCatchTypes()) {
- if (catchedType == Jack.getProgram().getPhantomLookup()
+ if (catchedType == Jack.getSession().getPhantomLookup()
.getClass(CommonTypes.JAVA_LANG_OBJECT)) {
assert bb.getCatchTypes().size() == 1;
stmt.appendCatchBlock(bb);
diff --git a/jack/src/com/android/jack/transformations/exceptions/TryStatementSchedulingSeparator.java b/jack/src/com/android/jack/transformations/exceptions/TryStatementSchedulingSeparator.java
index 3439b18..a6b42f2 100644
--- a/jack/src/com/android/jack/transformations/exceptions/TryStatementSchedulingSeparator.java
+++ b/jack/src/com/android/jack/transformations/exceptions/TryStatementSchedulingSeparator.java
@@ -16,7 +16,7 @@
package com.android.jack.transformations.exceptions;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.item.Description;
import com.android.sched.item.Tag;
import com.android.sched.schedulable.Constraint;
@@ -33,10 +33,10 @@
@Description("A separation between a Schedulable and TryCatchRemover")
@Transform(remove = TryStatementSchedulingSeparator.SeparatorTag.class)
@Constraint(need = TryStatementSchedulingSeparator.SeparatorTag.class)
-public class TryStatementSchedulingSeparator implements RunnableSchedulable<JProgram> {
+public class TryStatementSchedulingSeparator implements RunnableSchedulable<JSession> {
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
// do nothing
}
diff --git a/jack/src/com/android/jack/transformations/finallyblock/FinallyRemover.java b/jack/src/com/android/jack/transformations/finallyblock/FinallyRemover.java
index 70c72e1..1605145 100644
--- a/jack/src/com/android/jack/transformations/finallyblock/FinallyRemover.java
+++ b/jack/src/com/android/jack/transformations/finallyblock/FinallyRemover.java
@@ -410,7 +410,7 @@
JDefinedClassOrInterface enclosingType = method.getEnclosingType();
assert enclosingType != null;
- JClass throwableType = enclosingType.getJProgram().getPhantomLookup().getClass(
+ JClass throwableType = enclosingType.getSession().getPhantomLookup().getClass(
CommonTypes.JAVA_LANG_OBJECT);
TransformationRequest trRequest = new TransformationRequest(method);
diff --git a/jack/src/com/android/jack/transformations/flow/FlowNormalizerSchedulingSeparator.java b/jack/src/com/android/jack/transformations/flow/FlowNormalizerSchedulingSeparator.java
index a6408fe..2a7bc3c 100644
--- a/jack/src/com/android/jack/transformations/flow/FlowNormalizerSchedulingSeparator.java
+++ b/jack/src/com/android/jack/transformations/flow/FlowNormalizerSchedulingSeparator.java
@@ -40,7 +40,7 @@
implements RunnableSchedulable<JDefinedClassOrInterface> {
@Override
- public void run(@Nonnull JDefinedClassOrInterface program) throws Exception {
+ public void run(@Nonnull JDefinedClassOrInterface coi) throws Exception {
// do nothing
}
/**
diff --git a/jack/src/com/android/jack/transformations/parent/PackageChecker.java b/jack/src/com/android/jack/transformations/parent/PackageChecker.java
index f6a22b7..5026149 100644
--- a/jack/src/com/android/jack/transformations/parent/PackageChecker.java
+++ b/jack/src/com/android/jack/transformations/parent/PackageChecker.java
@@ -19,7 +19,7 @@
import com.android.jack.ir.ast.JClassOrInterface;
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.transformations.SanityChecks;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
@@ -49,7 +49,7 @@
}
JNode parent = pack.getParent();
- if (parent instanceof JProgram) {
+ if (parent instanceof JSession) {
if (pack.getEnclosingPackage() != null) {
throw new AssertionError("Wrong enclosing package");
}
diff --git a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java b/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java
index e48119c..53bd662 100644
--- a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java
+++ b/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java
@@ -17,7 +17,7 @@
package com.android.jack.transformations.parent;
import com.android.jack.ir.ast.JNode;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.transformations.SanityChecks;
import com.android.sched.item.Description;
@@ -35,7 +35,7 @@
@Description("Check that parent of JNode are correctly set.")
@Name("ParentSetterChecker")
@Support(SanityChecks.class)
-public class ParentSetterChecker implements RunnableSchedulable<JProgram> {
+public class ParentSetterChecker implements RunnableSchedulable<JSession> {
private static class ParentSetterCheckerVisitor extends JVisitor {
@Nonnull
@@ -47,9 +47,9 @@
@Override
public boolean visit(@Nonnull JNode node) {
- if (node instanceof JProgram) {
+ if (node instanceof JSession) {
if (node.getParent() != null) {
- throw new AssertionError("Parent of JProgram must be null.");
+ throw new AssertionError("Parent of JSession must be null.");
}
} else {
if (node.getParent() != nodes.peek()) {
@@ -71,8 +71,8 @@
}
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
ParentSetterCheckerVisitor checker = new ParentSetterCheckerVisitor();
- checker.accept(program);
+ checker.accept(session);
}
}
\ No newline at end of file
diff --git a/jack/src/com/android/jack/transformations/renamepackage/PackageRenamer.java b/jack/src/com/android/jack/transformations/renamepackage/PackageRenamer.java
index 3cdcf81..7aa2ac5 100644
--- a/jack/src/com/android/jack/transformations/renamepackage/PackageRenamer.java
+++ b/jack/src/com/android/jack/transformations/renamepackage/PackageRenamer.java
@@ -23,7 +23,7 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JStringLiteral;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.formatter.BinaryQualifiedNameFormatter;
@@ -61,7 +61,7 @@
@Name("PackageRenamer")
@Support(Jarjar.class)
@Transform(add = {JStringLiteral.class, JPackage.class}, modify = JDefinedClassOrInterface.class)
-public class PackageRenamer implements RunnableSchedulable<JProgram>{
+public class PackageRenamer implements RunnableSchedulable<JSession>{
@Nonnull
public static final PropertyId<File> JARJAR_FILE = PropertyId.create(
@@ -79,7 +79,7 @@
private final Stack<JNode> transformationRequestRoot = new Stack<JNode>();
@Nonnull
- private final JLookup lookup = Jack.getProgram().getLookup();
+ private final JLookup lookup = Jack.getSession().getLookup();
@Nonnull
private final TypeFormatter formatter = BinaryQualifiedNameFormatter.getFormatter();
@@ -139,11 +139,11 @@
}
@Override
- public void run(@Nonnull JProgram program) throws Exception {
+ public void run(@Nonnull JSession session) throws Exception {
List<PatternElement> result = RulesFileParser.parse(jarjarRulesFile);
List<Wildcard> wildcards = PatternElement.createWildcards(result);
- new Visitor(wildcards).accept(program);
- program.getLookup().clear();
- program.getPhantomLookup().clear();
+ new Visitor(wildcards).accept(session);
+ session.getLookup().clear();
+ session.getPhantomLookup().clear();
}
}
diff --git a/jack/src/com/android/jack/transformations/request/ChangeEnclosingPackage.java b/jack/src/com/android/jack/transformations/request/ChangeEnclosingPackage.java
index bf1e762..af93961 100644
--- a/jack/src/com/android/jack/transformations/request/ChangeEnclosingPackage.java
+++ b/jack/src/com/android/jack/transformations/request/ChangeEnclosingPackage.java
@@ -20,7 +20,7 @@
import com.android.jack.ir.ast.HasEnclosingPackage;
import com.android.jack.ir.ast.JNode;
import com.android.jack.ir.ast.JPackage;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.sched.transform.TransformStep;
import javax.annotation.Nonnull;
@@ -37,11 +37,11 @@
private final HasEnclosingPackage existingNode;
@Nonnull
- private final JProgram program = Jack.getProgram();
+ private final JSession session = Jack.getSession();
public ChangeEnclosingPackage(
@Nonnull HasEnclosingPackage existingNode, @Nonnull JPackage newEnclosingPackage) {
- assert existingNode != program.getTopLevelPackage()
+ assert existingNode != session.getTopLevelPackage()
: "The default package can't change its enclosing package";
this.newEnclosingPackage = newEnclosingPackage;
this.existingNode = existingNode;
diff --git a/jack/src/com/android/jack/util/NamingTools.java b/jack/src/com/android/jack/util/NamingTools.java
index 4f175ed..cd3ca90 100644
--- a/jack/src/com/android/jack/util/NamingTools.java
+++ b/jack/src/com/android/jack/util/NamingTools.java
@@ -35,6 +35,10 @@
public static final char SIGNATURE_SEPARATOR = JLookup.PACKAGE_SEPARATOR;
+ public static final String STATIC_INIT_NAME = "<clinit>";
+
+ public static final String INIT_NAME = "<init>";
+
/**
* Return a string representing a valid name for generated files and which does not conflict with
* name coming from Java source files.
diff --git a/jack/src/com/android/jack/util/filter/AllMethods.java b/jack/src/com/android/jack/util/filter/AllMethods.java
index 83532d0..e316133 100644
--- a/jack/src/com/android/jack/util/filter/AllMethods.java
+++ b/jack/src/com/android/jack/util/filter/AllMethods.java
@@ -18,12 +18,14 @@
import com.android.jack.ir.ast.JMethod;
import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.util.codec.ImplementationName;
import javax.annotation.Nonnull;
/**
* {@link AllMethods} accepts all methods.
*/
+@ImplementationName(iface = Filter.class, name = "all-methods")
public class AllMethods implements Filter<JMethod> {
@Override
diff --git a/jack/src/com/android/jack/util/filter/RejectAllMethods.java b/jack/src/com/android/jack/util/filter/RejectAllMethods.java
index 3cbc65a..f91de31 100644
--- a/jack/src/com/android/jack/util/filter/RejectAllMethods.java
+++ b/jack/src/com/android/jack/util/filter/RejectAllMethods.java
@@ -18,12 +18,14 @@
import com.android.jack.ir.ast.JMethod;
import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.util.codec.ImplementationName;
import javax.annotation.Nonnull;
/**
* {@code RejectAllMethods} allows to reject all methods, such as no body will be generated.
*/
+@ImplementationName(iface = Filter.class, name = "reject-all-methods")
public class RejectAllMethods implements Filter<JMethod> {
@Override
diff --git a/jack/src/com/android/jack/util/filter/SignatureCodec.java b/jack/src/com/android/jack/util/filter/SignatureCodec.java
new file mode 100644
index 0000000..69776bc
--- /dev/null
+++ b/jack/src/com/android/jack/util/filter/SignatureCodec.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.util.filter;
+
+import com.android.sched.util.codec.CodecContext;
+import com.android.sched.util.codec.StringCodec;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+
+/**
+ * This {@link SignatureCodec} is used to check that the string is a valid signature
+ */
+public class SignatureCodec implements StringCodec<String>{
+
+ @Override
+ @Nonnull
+ public String getUsage() {
+ return "a method signature (for instance \"methodname(ILpackage1/package2/Classname;)B\")";
+ }
+
+ @Override
+ @Nonnull
+ public String parseString(@Nonnull CodecContext context, @Nonnull String string) {
+ return string;
+ }
+
+ @Override
+ @CheckForNull
+ public String checkString(@Nonnull CodecContext context, @Nonnull String string) {
+ return string;
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull String data) {
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull String name) {
+ return name;
+ }
+}
diff --git a/jack/src/com/android/jack/util/filter/SignatureMethodFilter.java b/jack/src/com/android/jack/util/filter/SignatureMethodFilter.java
new file mode 100644
index 0000000..abdcb04
--- /dev/null
+++ b/jack/src/com/android/jack/util/filter/SignatureMethodFilter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.util.filter;
+
+import com.android.jack.Jack;
+import com.android.jack.Options;
+import com.android.jack.ir.ast.JMethod;
+import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.util.config.HasKeyId;
+import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.config.id.ImplementationPropertyId;
+import com.android.sched.util.config.id.PropertyId;
+
+import javax.annotation.Nonnull;
+
+@HasKeyId
+@ImplementationName(iface = Filter.class, name = "method-with-signature")
+public class SignatureMethodFilter implements Filter<JMethod> {
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Nonnull
+ public static final PropertyId<String> METHOD_SIGNATURE_FILTER = PropertyId.create(
+ "jack.internal.filter.method.signature",
+ "Method signature that will be accepted by the filter",
+ new SignatureCodec()).requiredIf(
+ ((ImplementationPropertyId<Filter>) (Object) Options.METHOD_FILTER).getClazz()
+ .isImplementedBy(SignatureMethodFilter.class));
+
+ @Nonnull
+ private final String methodSignature;
+
+ public SignatureMethodFilter() {
+ this.methodSignature = ThreadConfig.get(METHOD_SIGNATURE_FILTER);
+ }
+
+ @Override
+ public boolean accept(
+ @Nonnull Class<? extends RunnableSchedulable<?>> runnableSchedulable,
+ @Nonnull JMethod method) {
+ return (Jack.getLookupFormatter().getName(method).equals(methodSignature));
+ }
+}
\ No newline at end of file
diff --git a/jack/src/com/android/jack/util/filter/SupportedMethods.java b/jack/src/com/android/jack/util/filter/SupportedMethods.java
index e5d5957..772fb5d 100644
--- a/jack/src/com/android/jack/util/filter/SupportedMethods.java
+++ b/jack/src/com/android/jack/util/filter/SupportedMethods.java
@@ -18,6 +18,7 @@
import com.android.jack.ir.ast.JMethod;
import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.util.codec.ImplementationName;
import javax.annotation.Nonnull;
@@ -26,6 +27,7 @@
* exists. Otherwise methods are accepted only for a specific set of {@link RunnableSchedulable}
* specify by {@link RunnableSchedulableFilter}.
*/
+@ImplementationName(iface = Filter.class, name = "supported-methods")
public class SupportedMethods implements Filter<JMethod> {
@Override
diff --git a/jack/tests/com/android/jack/AllTests.java b/jack/tests/com/android/jack/AllTests.java
index be9072f..33de0e6 100644
--- a/jack/tests/com/android/jack/AllTests.java
+++ b/jack/tests/com/android/jack/AllTests.java
@@ -38,8 +38,7 @@
@RunWith(Suite.class)
@SuiteClasses(value = {
AnnotationTest.class,
- Arithmetic001Test.class,
- Arithmetic002Test.class,
+ ArithmeticTest.class,
ArrayTest.class,
AssertionTest.class,
AssignmentTest.class,
@@ -83,6 +82,7 @@
OpcodesTest.class,
OrderTest.class,
ReachingDefsTest.class,
+ ResourceTest.class,
ReturnTest.class,
RopRegisterManagerTest.class,
StaticValuesTest.class,
diff --git a/jack/tests/com/android/jack/Arithmetic001Test.java b/jack/tests/com/android/jack/Arithmetic001Test.java
deleted file mode 100644
index 94582d6..0000000
--- a/jack/tests/com/android/jack/Arithmetic001Test.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.jack;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.File;
-
-/**
- * JUnit test for compilation of arithmetic tests.
- */
-public class Arithmetic001Test {
- private static final File PATH = TestTools.getJackTestsWithJackFolder("arithmetic/test001");
-
- private static final File[] JAVA_SOURCES = {
- new File(PATH, "Add.java"),
- new File(PATH, "And.java"),
- new File(PATH, "Div.java"),
- new File(PATH, "Mod.java"),
- new File(PATH, "Mul.java"),
- new File(PATH, "Or.java"),
- new File(PATH, "Shl.java"),
- new File(PATH, "Shr.java"),
- new File(PATH, "Sub.java"),
- new File(PATH, "Ushr.java"),
- new File(PATH, "Xor.java")
- };
-
- @BeforeClass
- public static void setUpClass() {
- Main.class.getClassLoader().setDefaultAssertionStatus(true);
- }
-
- /**
- * Verifies that the test source can compiled from source to dex file.
- */
- @Test
- public void testCompile() throws Exception {
- TestTools.runCompilation(TestTools.buildCommandLineArgs(JAVA_SOURCES));
- }
-}
diff --git a/jack/tests/com/android/jack/Arithmetic002Test.java b/jack/tests/com/android/jack/Arithmetic002Test.java
deleted file mode 100644
index 0b3adc9..0000000
--- a/jack/tests/com/android/jack/Arithmetic002Test.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.jack;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.File;
-
-/**
- * JUnit test for compilation of arithmetic tests.
- */
-public class Arithmetic002Test {
- private static final File PATH = TestTools.getJackTestsWithJackFolder("arithmetic/test002");
-
- private static final File[] JAVA_SOURCES = {
- new File(PATH, "Add.java"),
- new File(PATH, "And.java"),
- new File(PATH, "Div.java"),
- new File(PATH, "Mod.java"),
- new File(PATH, "Mul.java"),
- new File(PATH, "Or.java"),
- new File(PATH, "Shl.java"),
- new File(PATH, "Shr.java"),
- new File(PATH, "Sub.java"),
- new File(PATH, "Ushr.java"),
- new File(PATH, "Xor.java")
- };
-
- @BeforeClass
- public static void setUpClass() {
- Main.class.getClassLoader().setDefaultAssertionStatus(true);
- }
-
- /**
- * Verifies that the test source can compiled from source to dex file.
- */
- @Test
- public void testCompile() throws Exception {
- TestTools.runCompilation(TestTools.buildCommandLineArgs(JAVA_SOURCES));
- }
-}
diff --git a/jack/tests/com/android/jack/ArithmeticTest.java b/jack/tests/com/android/jack/ArithmeticTest.java
new file mode 100644
index 0000000..5f64099
--- /dev/null
+++ b/jack/tests/com/android/jack/ArithmeticTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * JUnit test for compilation of arithmetic.
+ */
+public class ArithmeticTest {
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void testNew001() throws Exception {
+ TestTools.runCompilation(TestTools.buildCommandLineArgs(TestTools
+ .getJackTestsWithJackFolder("arithmetic/test001")));
+ }
+
+ @Test
+ public void testNew002() throws Exception {
+ TestTools.runCompilation(TestTools.buildCommandLineArgs(TestTools
+ .getJackTestsWithJackFolder("arithmetic/test002")));
+ }
+
+ @Test
+ public void testNew003() throws Exception {
+ TestTools.runCompilation(TestTools.buildCommandLineArgs(TestTools
+ .getJackTestsWithJackFolder("arithmetic/test003")));
+ }
+
+ @Test
+ public void testNew004() throws Exception {
+ TestTools.runCompilation(TestTools.buildCommandLineArgs(TestTools
+ .getJackTestsWithJackFolder("arithmetic/test004")));
+ }
+}
diff --git a/jack/tests/com/android/jack/ConditionalTest.java b/jack/tests/com/android/jack/ConditionalTest.java
index ab7d91f..1e13a45 100644
--- a/jack/tests/com/android/jack/ConditionalTest.java
+++ b/jack/tests/com/android/jack/ConditionalTest.java
@@ -24,7 +24,7 @@
import com.android.jack.ir.ast.JParameter;
import com.android.jack.ir.ast.JParameterRef;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.lookup.CommonTypes;
import com.android.jack.lookup.JPhantomLookup;
import com.android.sched.util.RunnableHooks;
@@ -92,8 +92,8 @@
Options options = new Options();
options.checkValidity(new RunnableHooks());
ThreadConfig.setConfig(options.getConfig());
- JProgram prog = Jack.getProgram();
- JPhantomLookup lookup = prog.getPhantomLookup();
+ JSession session = Jack.getSession();
+ JPhantomLookup lookup = session.getPhantomLookup();
JArrayType arrayInt = lookup.getArrayType(JPrimitiveTypeEnum.INT.getType(), 1);
JArrayType arrayByte = lookup.getArrayType(JPrimitiveTypeEnum.BYTE.getType(), 1);
@@ -111,7 +111,7 @@
new JParameter(SourceOrigin.UNKNOWN, "pArrayIntIntInt", arrayIntIntInt, 0, null);
JParameter pArrayByte = new JParameter(SourceOrigin.UNKNOWN, "pArrayByte", arrayByte, 0, null);
JClass javaLangObject =
- Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JParameter pObject =
new JParameter(SourceOrigin.UNKNOWN, "pArrayByte", javaLangObject, 0,
null);
diff --git a/jack/tests/com/android/jack/FibonacciThreeAddressTest.java b/jack/tests/com/android/jack/FibonacciThreeAddressTest.java
index e872697..fc39b4c 100644
--- a/jack/tests/com/android/jack/FibonacciThreeAddressTest.java
+++ b/jack/tests/com/android/jack/FibonacciThreeAddressTest.java
@@ -19,10 +19,9 @@
import com.android.jack.dx.dex.file.ClassDefItem;
import com.android.jack.dx.dex.file.DexFile;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.marker.DexFileMarker;
import com.android.jack.util.FileUtils;
-import com.android.jack.util.filter.RejectAllMethods;
import junit.framework.Assert;
@@ -54,10 +53,10 @@
*/
@Test
public void testLoadFiboInJAst() throws Exception {
- JProgram program = TestTools.buildJAst(TestTools.buildCommandLineArgs(JAVA_FILEPATH));
- Assert.assertNotNull(program);
+ JSession session = TestTools.buildJAst(TestTools.buildCommandLineArgs(JAVA_FILEPATH));
+ Assert.assertNotNull(session);
- JDefinedClassOrInterface fibo = (JDefinedClassOrInterface) program.getLookup().getType(CLASS_SIGNATURE);
+ JDefinedClassOrInterface fibo = (JDefinedClassOrInterface) session.getLookup().getType(CLASS_SIGNATURE);
Assert.assertNotNull(fibo);
}
@@ -68,13 +67,13 @@
@Test
public void testBuildFiboDexFile() throws Exception {
Options fiboArgs = TestTools.buildCommandLineArgs(JAVA_FILEPATH);
- fiboArgs.setFilter(new RejectAllMethods());
- JProgram program = TestTools.buildProgram(fiboArgs);
+ fiboArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
+ JSession session = TestTools.buildSession(fiboArgs);
- JDefinedClassOrInterface fibo = (JDefinedClassOrInterface) program.getLookup().getType(CLASS_SIGNATURE);
+ JDefinedClassOrInterface fibo = (JDefinedClassOrInterface) session.getLookup().getType(CLASS_SIGNATURE);
Assert.assertNotNull(fibo);
- DexFileMarker marker = program.getMarker(DexFileMarker.class);
+ DexFileMarker marker = session.getMarker(DexFileMarker.class);
Assert.assertNotNull(marker);
assert marker != null;
diff --git a/jack/tests/com/android/jack/FinallyTest.java b/jack/tests/com/android/jack/FinallyTest.java
index b886bd4..900a90b 100644
--- a/jack/tests/com/android/jack/FinallyTest.java
+++ b/jack/tests/com/android/jack/FinallyTest.java
@@ -95,8 +95,8 @@
String methodSignature = "get()V";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new checkUselessIf().accept(m);
diff --git a/jack/tests/com/android/jack/MainTest.java b/jack/tests/com/android/jack/MainTest.java
index d4b7676..625aea3 100644
--- a/jack/tests/com/android/jack/MainTest.java
+++ b/jack/tests/com/android/jack/MainTest.java
@@ -17,7 +17,7 @@
package com.android.jack;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import junit.framework.Assert;
@@ -53,10 +53,10 @@
*/
@Test
public void testLoadFiboInJAst() throws Exception {
- JProgram program = TestTools.buildJAst(
+ JSession session = TestTools.buildJAst(
TestTools.buildCommandLineArgs(TestTools.getJackTestFromBinaryName(CLASS_BINARY_NAME)));
JDefinedClassOrInterface fibo =
- (JDefinedClassOrInterface) program.getLookup().getType(CLASS_SIGNATURE);
+ (JDefinedClassOrInterface) session.getLookup().getType(CLASS_SIGNATURE);
Assert.assertNotNull(fibo);
// TODO(yroussel): make further checks
}
diff --git a/jack/tests/com/android/jack/ResourceTest.java b/jack/tests/com/android/jack/ResourceTest.java
new file mode 100644
index 0000000..5f67828
--- /dev/null
+++ b/jack/tests/com/android/jack/ResourceTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack;
+
+import com.android.jack.category.KnownBugs;
+import com.android.jack.util.BytesStreamSucker;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collections;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * JUnit tests for resource support.
+ */
+public class ResourceTest {
+
+ @Nonnull
+ private static final String COMMON_PATH = "com/android/jack/resource/test001/jack/";
+ @Nonnull
+ private static final String JACK_FILE_PATH = COMMON_PATH + "IrrelevantForTest.jack";
+ @Nonnull
+ private static final String RESOURCE1_SHORTPATH = "Resource1";
+ @Nonnull
+ private static final String RESOURCE2_SHORTPATH = "Resource2";
+ @Nonnull
+ private static final String RESOURCE3_SHORTPATH = "pack/Resource3";
+ @Nonnull
+ private static final String RESOURCE4_SHORTPATH = "pack/Resource4";
+ @Nonnull
+ private static final String RESOURCE1_LONGPATH = COMMON_PATH + RESOURCE1_SHORTPATH;
+ @Nonnull
+ private static final String RESOURCE2_LONGPATH = COMMON_PATH + RESOURCE2_SHORTPATH;
+ @Nonnull
+ private static final String RESOURCE3_LONGPATH = COMMON_PATH + RESOURCE3_SHORTPATH;
+ @Nonnull
+ private static final String RESOURCE4_LONGPATH = COMMON_PATH + RESOURCE4_SHORTPATH;
+
+ @Nonnull
+ private static final File FILE =
+ TestTools.getJackTestsWithJackFolder("resource/test001");
+
+ @BeforeClass
+ public static void setUpClass() {
+ Main.class.getClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ @Test
+ public void testJackArchiveToDexArchive() throws Exception {
+ // compile source file to a Jack archive and add resources
+ File jackAr = createJackArchiveWithResources();
+
+ // compile Jack archive to dex archive
+ File dexAr = TestTools.createTempFile("resourcetestdex", ".zip");
+ TestTools.compileJackToDex(new Options(), jackAr, dexAr, true /* zipped */);
+
+ // check that resources are contained in dex archive
+ ZipFile zipFile = new ZipFile(dexAr);
+ checkResourceContent(zipFile, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(zipFile, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(zipFile, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(zipFile, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Test
+ @Category(KnownBugs.class)
+ public void testJackDirToDexArchive() throws Exception {
+ // compile source file to a Jack dir
+ File jackFolder = TestTools.createTempDir("tempjack", "dir");
+ TestTools.compileSourceToJack(new Options(), FILE, TestTools.getDefaultBootclasspathString(),
+ jackFolder, false /* non-zipped */);
+
+ // add resources to Jack dir
+ copyFileToDir(new File(FILE, RESOURCE1_SHORTPATH), RESOURCE1_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE2_SHORTPATH), RESOURCE2_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE3_SHORTPATH), RESOURCE3_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE4_SHORTPATH), RESOURCE4_LONGPATH, jackFolder);
+
+ // compile Jack dir to dex archive
+ File dexAr = TestTools.createTempFile("resourcetestdex", ".zip");
+ TestTools.compileJackToDex(new Options(), jackFolder, dexAr, true /* zipped */);
+
+ // check that resources are contained in dex archive
+ ZipFile zipFile = new ZipFile(dexAr);
+ checkResourceContent(zipFile, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(zipFile, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(zipFile, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(zipFile, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Test
+ public void testJackArchiveToJackArchive() throws Exception {
+ // compile source file to a Jack archive and add resources
+ File jackAr = createJackArchiveWithResources();
+
+ // run shrobbing from Jack archive to Jack archive
+ File shrobbedJackAr = TestTools.createTempFile("shrobbedJackAr", ".zip");
+ ProguardFlags flags = new ProguardFlags(new File(FILE, "proguard.flags"));
+ TestTools.shrobJackToJack(new Options(),
+ jackAr,
+ null /* classpath */,
+ shrobbedJackAr,
+ Collections.singletonList(flags),
+ true /* zipped */);
+
+ // check that resources are contained in dex archive
+ ZipFile zipFile = new ZipFile(shrobbedJackAr);
+ checkResourceContent(zipFile, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(zipFile, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(zipFile, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(zipFile, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Test
+ @Category(KnownBugs.class)
+ public void testJackDirToJackArchive() throws Exception {
+ // compile source file to a Jack dir
+ File jackFolder = TestTools.createTempDir("tempjack", "dir");
+ TestTools.compileSourceToJack(new Options(), FILE, TestTools.getDefaultBootclasspathString(),
+ jackFolder, false /* non-zipped */);
+
+ // add resources to Jack dir
+ copyFileToDir(new File(FILE, RESOURCE1_SHORTPATH), RESOURCE1_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE2_SHORTPATH), RESOURCE2_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE3_SHORTPATH), RESOURCE3_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE4_SHORTPATH), RESOURCE4_LONGPATH, jackFolder);
+
+ // run shrobbing from Jack dir to Jack archive
+ File shrobbedJackAr = TestTools.createTempFile("shrobbedJackAr", ".zip");
+ ProguardFlags flags = new ProguardFlags(new File(FILE, "proguard.flags"));
+ TestTools.shrobJackToJack(new Options(),
+ jackFolder,
+ null /* classpath */,
+ shrobbedJackAr,
+ Collections.singletonList(flags),
+ true /* zipped */);
+
+ // check that resources are contained in Jack archive
+ ZipFile zipFile = new ZipFile(shrobbedJackAr);
+ checkResourceContent(zipFile, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(zipFile, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(zipFile, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(zipFile, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Test
+ @Category(KnownBugs.class)
+ public void testJackArchiveToJackDir() throws Exception {
+ // compile source file to a Jack archive and add resources
+ File jackAr = createJackArchiveWithResources();
+
+ // run shrobbing from Jack archive to Jack dir
+ File shrobbedJackDir = TestTools.createTempDir("shrobbedJack", "dir");
+ ProguardFlags flags = new ProguardFlags(new File(FILE, "proguard.flags"));
+ TestTools.shrobJackToJack(new Options(),
+ jackAr,
+ null /* classpath */,
+ shrobbedJackDir,
+ Collections.singletonList(flags),
+ false /* non-zipped */);
+
+ // check that resources are contained in Jack dir
+ checkResourceContent(shrobbedJackDir, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(shrobbedJackDir, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(shrobbedJackDir, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(shrobbedJackDir, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Test
+ @Category(KnownBugs.class)
+ public void testJackDirToJackDir() throws Exception {
+ /// compile source file to a Jack dir
+ File jackFolder = TestTools.createTempDir("tempjack", "dir");
+ TestTools.compileSourceToJack(new Options(), FILE, TestTools.getDefaultBootclasspathString(),
+ jackFolder, false /* non-zipped */);
+
+ // add resources to Jack dir
+ copyFileToDir(new File(FILE, RESOURCE1_SHORTPATH), RESOURCE1_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE2_SHORTPATH), RESOURCE2_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE3_SHORTPATH), RESOURCE3_LONGPATH, jackFolder);
+ copyFileToDir(new File(FILE, RESOURCE4_SHORTPATH), RESOURCE4_LONGPATH, jackFolder);
+
+ // run shrobbing from Jack dir to Jack dir
+ File shrobbedJackDir = TestTools.createTempDir("shrobbedJack", "dir");
+ ProguardFlags flags = new ProguardFlags(new File(FILE, "proguard.flags"));
+ TestTools.shrobJackToJack(new Options(),
+ jackFolder,
+ null /* classpath */,
+ shrobbedJackDir,
+ Collections.singletonList(flags),
+ false /* non-zipped */);
+
+ // check that resources are contained in Jack dir
+ checkResourceContent(shrobbedJackDir, RESOURCE1_LONGPATH, "Res1");
+ checkResourceContent(shrobbedJackDir, RESOURCE2_LONGPATH, "Res2");
+ checkResourceContent(shrobbedJackDir, RESOURCE3_LONGPATH, "Res3");
+ checkResourceContent(shrobbedJackDir, RESOURCE4_LONGPATH, "Res4");
+ }
+
+ @Nonnull
+ private File createJackArchiveWithResources() throws Exception {
+ // compile source file to a Jack file
+ File tempJackFolder = TestTools.createTempDir("jack", "dir");
+ TestTools.compileSourceToJack(new Options(), FILE, TestTools.getDefaultBootclasspathString(),
+ tempJackFolder, false /* non-zipped */);
+
+ // create Jack archive with resources
+ File singleJackFile = new File(tempJackFolder, JACK_FILE_PATH);
+ File jackAr = TestTools.createTempFile("resourcetestjack", ".zip");
+ ZipOutputStream zos = null;
+ try {
+ zos = new ZipOutputStream(new FileOutputStream(jackAr));
+
+ copyFileToZip(singleJackFile, JACK_FILE_PATH, zos);
+ copyFileToZip(new File(FILE, RESOURCE1_SHORTPATH), RESOURCE1_LONGPATH, zos);
+ copyFileToZip(new File(FILE, RESOURCE2_SHORTPATH), RESOURCE2_LONGPATH, zos);
+ copyFileToZip(new File(FILE, RESOURCE3_SHORTPATH), RESOURCE3_LONGPATH, zos);
+ copyFileToZip(new File(FILE, RESOURCE4_SHORTPATH), RESOURCE4_LONGPATH, zos);
+ } finally {
+ if (zos != null) {
+ zos.close();
+ }
+ }
+ return jackAr;
+ }
+
+ private void checkResourceContent(@Nonnull ZipFile zipFile, @Nonnull String entryName,
+ @Nonnull String expectedContent) throws IOException {
+ ZipEntry entry = zipFile.getEntry(entryName);
+ Assert.assertNotNull(entry);
+ BufferedReader reader = null;
+ try {
+ InputStream in = zipFile.getInputStream(entry);
+ reader = new BufferedReader(new InputStreamReader(in));
+ String line = reader.readLine();
+ Assert.assertEquals(expectedContent, line);
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ private void checkResourceContent(@Nonnull File dir, @Nonnull String path,
+ @Nonnull String expectedContent) throws IOException {
+ assert dir.isDirectory();
+ File file = new File(dir, path);
+ Assert.assertTrue(file.exists());
+ BufferedReader reader = null;
+ try {
+ InputStream in = new FileInputStream(file);
+ reader = new BufferedReader(new InputStreamReader(in));
+ String line = reader.readLine();
+ Assert.assertEquals(expectedContent, line);
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ private void copyFileToDir(@Nonnull File fileToCopy, @Nonnull String relativePath,
+ @Nonnull File dir) throws IOException {
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(fileToCopy);
+ File copiedFile = new File(dir, relativePath);
+ File parentDir = copiedFile.getParentFile();
+ if (!parentDir.exists()) {
+ boolean res = parentDir.mkdirs();
+ if (!res) {
+ throw new AssertionError();
+ }
+ }
+ try {
+ fos = new FileOutputStream(copiedFile);
+ BytesStreamSucker sucker = new BytesStreamSucker(fis, fos);
+ sucker.run();
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ }
+
+ private void copyFileToZip(@Nonnull File fileToCopy, @Nonnull String entryName,
+ @Nonnull ZipOutputStream zos)
+ throws IOException {
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(fileToCopy);
+ ZipEntry sourceEntry = new ZipEntry(entryName);
+ zos.putNextEntry(sourceEntry);
+ BytesStreamSucker sucker = new BytesStreamSucker(fis, zos);
+ sucker.run();
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ }
+}
diff --git a/jack/tests/com/android/jack/SignatureMethodFilter.java b/jack/tests/com/android/jack/SignatureMethodFilter.java
deleted file mode 100644
index ff51d6f..0000000
--- a/jack/tests/com/android/jack/SignatureMethodFilter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.jack;
-
-import com.android.jack.ir.ast.JMethod;
-import com.android.jack.util.filter.Filter;
-import com.android.sched.schedulable.RunnableSchedulable;
-
-import javax.annotation.Nonnull;
-
-public class SignatureMethodFilter implements Filter<JMethod> {
-
- final String methodSignature;
-
- public SignatureMethodFilter(String methodSignature) {
- this.methodSignature = methodSignature;
- }
-
- @Override
- public boolean accept(
- @Nonnull Class<? extends RunnableSchedulable<?>> runnableSchedulable,
- @Nonnull JMethod method) {
- return (Jack.getLookupFormatter().getName(method).equals(methodSignature));
- }
-}
\ No newline at end of file
diff --git a/jack/tests/com/android/jack/StaticValuesTest.java b/jack/tests/com/android/jack/StaticValuesTest.java
index 87b1903..2cd87e6 100644
--- a/jack/tests/com/android/jack/StaticValuesTest.java
+++ b/jack/tests/com/android/jack/StaticValuesTest.java
@@ -23,10 +23,9 @@
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
import com.android.jack.scheduling.adapter.JFieldAdaptor;
-import com.android.jack.util.filter.SupportedMethods;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.Scheduler;
@@ -104,10 +103,10 @@
public static JMethod compileAndGetClinit(String classBinaryName, Options options)
throws Exception {
- options.setFilter(new SupportedMethods());
+ options.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
- JProgram jprogram = TestTools.buildJAst(options);
- Assert.assertNotNull(jprogram);
+ JSession session = TestTools.buildJAst(options);
+ Assert.assertNotNull(session);
Scheduler scheduler = Scheduler.getScheduler();
@@ -119,16 +118,16 @@
set.add(JFieldInitializer.class);
sr.addInitialTagsOrMarkers(set);
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdaptor.class);
fieldPlan.append(FieldInitializerRemover.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
JDefinedClassOrInterface declaredType =
- (JDefinedClassOrInterface) jprogram.getLookup().getType("L" + classBinaryName + ";");
+ (JDefinedClassOrInterface) session.getLookup().getType("L" + classBinaryName + ";");
return declaredType.getMethod(CLINIT, JPrimitiveTypeEnum.VOID.getType());
}
diff --git a/jack/tests/com/android/jack/TestTools.java b/jack/tests/com/android/jack/TestTools.java
index 89f1410..7a968a4 100644
--- a/jack/tests/com/android/jack/TestTools.java
+++ b/jack/tests/com/android/jack/TestTools.java
@@ -22,7 +22,7 @@
import com.android.jack.dx.dex.file.DexFile;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.formatter.MethodFormatter;
import com.android.jack.lookup.JMethodSignatureLookupException;
import com.android.jack.scheduling.marker.DexFileMarker;
@@ -31,8 +31,7 @@
import com.android.jack.shrob.spec.Flags;
import com.android.jack.util.ExecuteFile;
import com.android.jack.util.TextUtils;
-import com.android.jack.util.filter.Filter;
-import com.android.jack.util.filter.SupportedMethods;
+import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.util.RunnableHooks;
@@ -512,28 +511,28 @@
}
@Nonnull
- public static JProgram buildJAst(@Nonnull Options options) throws Exception {
+ public static JSession buildJAst(@Nonnull Options options) throws Exception {
RunnableHooks hooks = new RunnableHooks();
try {
options.checkValidity(hooks);
ThreadConfig.setConfig(options.getConfig());
- JProgram jprogram = Jack.buildProgram(options, hooks);
+ JSession session = Jack.buildSession(options, hooks);
- return (jprogram);
+ return (session);
} finally {
hooks.runHooks();
}
}
/**
- * Build a {@code JProgram} by using the monolithic plan.
+ * Build a {@code JSession} by using the monolithic plan.
*/
@Nonnull
- public static JProgram buildProgram(@Nonnull Options options) throws Exception {
+ public static JSession buildSession(@Nonnull Options options) throws Exception {
RunnableHooks hooks = new RunnableHooks();
try {
- return buildProgram(options, hooks);
+ return buildSession(options, hooks);
} finally {
hooks.runHooks();
}
@@ -541,10 +540,10 @@
}
/**
- * Build a {@code JProgram} by using the monolithic plan.
+ * Build a {@code JSession} by using the monolithic plan.
*/
@Nonnull
- public static JProgram buildProgram(@Nonnull Options options, @Nonnull RunnableHooks hooks) throws Exception {
+ public static JSession buildSession(@Nonnull Options options, @Nonnull RunnableHooks hooks) throws Exception {
if (options.proguardFlagsFiles != null && !options.proguardFlagsFiles.isEmpty()) {
if (options.flags == null) {
options.flags = new Flags();
@@ -558,7 +557,7 @@
options.checkValidity(hooks);
ThreadConfig.setConfig(options.getConfig());
- JProgram jprogram = Jack.buildProgram(options, hooks);
+ JSession session = Jack.buildSession(options, hooks);
Request request = Jack.createInitialRequest();
request.addInitialTagsOrMarkers(Jack.getJavaSourceInitialTagSet());
@@ -567,13 +566,13 @@
request.addProduction(JackFormatProduct.class);
}
- PlanBuilder<JProgram> planBuilder = request.getPlanBuilder(JProgram.class);
+ PlanBuilder<JSession> planBuilder = request.getPlanBuilder(JSession.class);
Jack.fillDexPlan(options, planBuilder);
request.addTargetIncludeTagOrMarker(DexFileMarker.Complete.class);
- planBuilder.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
- return (jprogram);
+ return (session);
}
public static void checkStructure(@CheckForNull File[] bootclasspath,
@@ -677,7 +676,7 @@
if (flags != null) {
jackOptions.applyShrobFlags();
}
- jackOptions.setFilter(new SupportedMethods());
+ jackOptions.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
File out = TestTools.createTempFile("checklisting", ".dex");
TestTools.compileSourceToDex(jackOptions,
@@ -695,7 +694,7 @@
Options jackOptions = new Options();
File candidateNodeListing = TestTools.createTempFile("nodeListing", ".txt");
jackOptions.typeAndMemberListing = candidateNodeListing;
- jackOptions.setFilter(new SupportedMethods());
+ jackOptions.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
jackOptions.disableDxOptimizations();
File out = TestTools.createTempFile("checklisting", ".dex");
@@ -721,15 +720,39 @@
}
@Nonnull
- public static JMethod getJMethod(@Nonnull File fileName, @Nonnull String className,
- @Nonnull String methodSignature, @Nonnull Filter<JMethod> filter) throws Exception {
+ public static JMethod getJMethodWithRejectAllFilter(@Nonnull File fileName,
+ @Nonnull String className, @Nonnull String methodSignature) throws Exception {
Options commandLineArgs = TestTools.buildCommandLineArgs(fileName);
- commandLineArgs.setFilter(filter);
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
commandLineArgs.keepMethodBody = true;
- JProgram program = TestTools.buildProgram(commandLineArgs);
- Assert.assertNotNull(program);
+ JSession session = TestTools.buildSession(commandLineArgs);
+ Assert.assertNotNull(session);
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(className);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(className);
+ Assert.assertNotNull(type);
+
+ JMethod foundMethod = null;
+ foundMethod = getMethod(type, methodSignature);
+
+ Assert.assertNotNull(foundMethod);
+
+ return foundMethod;
+ }
+
+ @Nonnull
+ public static JMethod getJMethodWithSignatureFilter(@Nonnull File fileName,
+ @Nonnull String className, @Nonnull String methodSignature) throws Exception {
+ Options commandLineArgs = TestTools.buildCommandLineArgs(fileName);
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
+ commandLineArgs.keepMethodBody = true;
+ JSession session = TestTools.buildSession(commandLineArgs);
+ Assert.assertNotNull(session);
+
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(className);
Assert.assertNotNull(type);
JMethod foundMethod = null;
diff --git a/jack/tests/com/android/jack/Types.java b/jack/tests/com/android/jack/Types.java
index 8f00850..75f2e2e 100644
--- a/jack/tests/com/android/jack/Types.java
+++ b/jack/tests/com/android/jack/Types.java
@@ -36,7 +36,7 @@
import com.android.jack.ir.ast.JPrefixBitNotOperation;
import com.android.jack.ir.ast.JPrefixNotOperation;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShlOperation;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JType;
@@ -61,8 +61,8 @@
options.getConfigBuilder().setDebug();
ThreadConfig.setConfig(options.getConfig());
- JProgram program = Jack.getProgram();
- program.getLookup().getOrCreatePackage("java/lang");
+ JSession session = Jack.getSession();
+ session.getLookup().getOrCreatePackage("java/lang");
}
@BeforeClass
@@ -97,7 +97,7 @@
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JPrefixNotOperation(
SourceOrigin.UNKNOWN, new JBooleanLiteral(SourceOrigin.UNKNOWN, true)).getType());
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JPrefixNotOperation(
SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l)).getType());
@@ -139,7 +139,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JPrefixBitNotOperation(SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l))
.getType();
@@ -158,7 +158,7 @@
Assert.assertEquals(JPrimitiveTypeEnum.LONG.getType(), new JPrefixBitNotOperation(
SourceOrigin.UNKNOWN, new JLongLiteral(SourceOrigin.UNKNOWN, 1l)).getType());
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CHAR);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_CHAR);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.INT.getType(), new JPrefixBitNotOperation(
SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l)).getType());
@@ -180,7 +180,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JPostfixDecOperation(SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l))
.getType();
@@ -202,7 +202,7 @@
Assert.assertEquals(JPrimitiveTypeEnum.LONG.getType(), new JPostfixDecOperation(
SourceOrigin.UNKNOWN, new JLongLiteral(SourceOrigin.UNKNOWN, 1l)).getType());
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.INT.getType(), new JPostfixDecOperation(
SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l)).getType());
@@ -234,7 +234,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JShlOperation(SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l),
new JIntLiteral(SourceOrigin.UNKNOWN, 1)).getType();
@@ -246,7 +246,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JShlOperation(SourceOrigin.UNKNOWN, new JIntLiteral(SourceOrigin.UNKNOWN, 1),
new JLocalRef(SourceOrigin.UNKNOWN, l)).getType();
@@ -273,8 +273,8 @@
new JShortLiteral(SourceOrigin.UNKNOWN, (short) 1)).getType());
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
- JType t1 = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
+ JType t1 = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
JLocal l1 = new JLocal(SourceOrigin.UNKNOWN, "test2", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.INT.getType(), new JShlOperation(SourceOrigin.UNKNOWN,
@@ -283,7 +283,7 @@
}
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_LONG);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_LONG);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
JLocal l1 = new JLocal(SourceOrigin.UNKNOWN, "test2", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.LONG.getType(), new JShlOperation(SourceOrigin.UNKNOWN,
@@ -307,7 +307,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JLteOperation(SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l),
new JFloatLiteral(SourceOrigin.UNKNOWN, 1)).getType();
@@ -318,7 +318,7 @@
Assert.assertTrue(catched);
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_DOUBLE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JLteOperation(SourceOrigin.UNKNOWN,
new JLocalRef(SourceOrigin.UNKNOWN, l), new JIntLiteral(SourceOrigin.UNKNOWN, 1))
@@ -334,7 +334,7 @@
.getType());
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BYTE);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
JLocal l1 = new JLocal(SourceOrigin.UNKNOWN, "test2", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JLteOperation(SourceOrigin.UNKNOWN,
@@ -361,7 +361,7 @@
new JBooleanLiteral(SourceOrigin.UNKNOWN, true)).getType());
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JBitAndOperation(SourceOrigin.UNKNOWN,
new JLocalRef(SourceOrigin.UNKNOWN, l), new JLocalRef(SourceOrigin.UNKNOWN, l))
@@ -369,7 +369,7 @@
}
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.INT.getType(), new JBitAndOperation(SourceOrigin.UNKNOWN,
new JLocalRef(SourceOrigin.UNKNOWN, l), new JLocalRef(SourceOrigin.UNKNOWN, l))
@@ -377,9 +377,9 @@
}
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_INTEGER);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
- JType t1 = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ JType t1 = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JLocal l1 = new JLocal(SourceOrigin.UNKNOWN, "test", t1, JModifier.DEFAULT, null);
try {
catched = false;
@@ -393,7 +393,7 @@
}
{
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_FLOAT);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_FLOAT);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
try {
catched = false;
@@ -445,7 +445,7 @@
try {
catched = false;
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
new JEqOperation(SourceOrigin.UNKNOWN, new JLocalRef(SourceOrigin.UNKNOWN, l),
new JIntLiteral(SourceOrigin.UNKNOWN, 1)).getType();
@@ -455,7 +455,7 @@
}
Assert.assertTrue(catched);
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JEqOperation(SourceOrigin.UNKNOWN,
new JLocalRef(SourceOrigin.UNKNOWN, l), new JLocalRef(SourceOrigin.UNKNOWN, l)).getType());
@@ -479,7 +479,7 @@
}
Assert.assertTrue(catched);
- JType t = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
+ JType t = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_BOOLEAN);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", t, JModifier.DEFAULT, null);
Assert.assertEquals(JPrimitiveTypeEnum.BOOLEAN.getType(), new JAndOperation(SourceOrigin.UNKNOWN,
new JLocalRef(SourceOrigin.UNKNOWN, l), new JLocalRef(SourceOrigin.UNKNOWN, l)).getType());
@@ -488,7 +488,7 @@
@Test
public void arithmeticGetType() throws Exception {
boolean catched;
- JType objectType = Jack.getProgram().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+ JType objectType = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
JLocal l = new JLocal(SourceOrigin.UNKNOWN, "test", objectType, JModifier.DEFAULT, null);
try {
diff --git a/jack/tests/com/android/jack/UnaryTest.java b/jack/tests/com/android/jack/UnaryTest.java
index cf5d1d1..2b04da4 100644
--- a/jack/tests/com/android/jack/UnaryTest.java
+++ b/jack/tests/com/android/jack/UnaryTest.java
@@ -78,8 +78,8 @@
String classBinaryName = "com/android/jack/unary/test005/jack/UnaryNot";
String methodSignature = "getValue1(II)I";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
CountIfStatement cis = new CountIfStatement();
@@ -88,8 +88,8 @@
methodSignature = "getValue2(IIII)I";
m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
cis = new CountIfStatement();
diff --git a/jack/tests/com/android/jack/analysis/dfa/reachingdefs/ReachingDefsTest.java b/jack/tests/com/android/jack/analysis/dfa/reachingdefs/ReachingDefsTest.java
index d6fdaca..b1765dd 100644
--- a/jack/tests/com/android/jack/analysis/dfa/reachingdefs/ReachingDefsTest.java
+++ b/jack/tests/com/android/jack/analysis/dfa/reachingdefs/ReachingDefsTest.java
@@ -18,7 +18,6 @@
import com.android.jack.Main;
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.analysis.DefinitionMarker;
import com.android.jack.cfg.BasicBlock;
@@ -28,6 +27,7 @@
import com.android.jack.ir.ast.JIntLiteral;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JVariableRef;
+import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.util.codec.ImplementationName;
import junit.framework.Assert;
@@ -83,7 +83,9 @@
public void testDfa001() throws Exception {
Options options = TestTools.buildCommandLineArgs(TestTools
.getJackTestsWithJackFolder("analysis/dfa/reachingdefs/test001"));
- options.setFilter(new SignatureMethodFilter("dfaWithSwitch(I)I"));
+ options.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ options.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ "dfaWithSwitch(I)I");
options.addProperty(ReachingDefinitions.REACHING_DEFS_CHECKER.getName(), "test001Checker");
TestTools.runCompilation(options);
}
diff --git a/jack/tests/com/android/jack/cfg/BuildCfgErrorTest.java b/jack/tests/com/android/jack/cfg/BuildCfgErrorTest.java
index c25a31d..110602f 100644
--- a/jack/tests/com/android/jack/cfg/BuildCfgErrorTest.java
+++ b/jack/tests/com/android/jack/cfg/BuildCfgErrorTest.java
@@ -20,7 +20,6 @@
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.util.filter.RejectAllMethods;
import com.android.jack.util.graph.GraphException;
import org.junit.Before;
@@ -41,9 +40,10 @@
*/
@Test
public void cfgError001() throws Exception {
- JMethod method = TestTools.getJMethod(
- TestTools.getJackTestFromBinaryName(CLASS_BINARY_NAME), "L" + CLASS_BINARY_NAME + ";",
- "fibonacci(I)I", new RejectAllMethods());
+ JMethod method =
+ TestTools.getJMethodWithRejectAllFilter(
+ TestTools.getJackTestFromBinaryName(CLASS_BINARY_NAME), "L" + CLASS_BINARY_NAME + ";",
+ "fibonacci(I)I");
ControlFlowGraph cfg = new ControlFlowGraph(method);
NormalBasicBlock b0 = new NormalBasicBlock(cfg, BasicBlock.EMPTY_STATEMENT_LIST);
NormalBasicBlock b1 = new NormalBasicBlock(cfg, BasicBlock.EMPTY_STATEMENT_LIST);
diff --git a/jack/tests/com/android/jack/cfg/BuildCfgTest.java b/jack/tests/com/android/jack/cfg/BuildCfgTest.java
index c55d10d..4640658 100644
--- a/jack/tests/com/android/jack/cfg/BuildCfgTest.java
+++ b/jack/tests/com/android/jack/cfg/BuildCfgTest.java
@@ -18,13 +18,13 @@
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JAsgOperation;
import com.android.jack.ir.ast.JExpressionStatement;
import com.android.jack.ir.ast.JIfStatement;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JStatement;
+import com.android.jack.util.filter.SignatureMethodFilter;
import junit.framework.Assert;
@@ -47,7 +47,9 @@
File fileName = TestTools.getJackTestFromBinaryName(CLASS_BINARY_NAME);
final String methodSignature = "fibonacci(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(fileName);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method = CfgTools.buildCfg(classSignature, methodSignature, commandLineArgs);
diff --git a/jack/tests/com/android/jack/cfg/CfgTools.java b/jack/tests/com/android/jack/cfg/CfgTools.java
index 8520ac6..d81af75 100644
--- a/jack/tests/com/android/jack/cfg/CfgTools.java
+++ b/jack/tests/com/android/jack/cfg/CfgTools.java
@@ -26,7 +26,7 @@
import com.android.jack.ir.ast.JFieldInitializer;
import com.android.jack.ir.ast.JLoop;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JSynchronizedBlock;
import com.android.jack.ir.ast.JTryStatement;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
@@ -50,8 +50,8 @@
public static JMethod buildCfg(
String classSignature, String methodSignature, Options options) throws Exception {
- JProgram jprogram = TestTools.buildJAst(options);
- Assert.assertNotNull(jprogram);
+ JSession session = TestTools.buildJAst(options);
+ Assert.assertNotNull(session);
Scheduler scheduler = Scheduler.getScheduler();
@@ -74,8 +74,8 @@
set.remove(JFieldInitializer.class);
sr.addInitialTagsOrMarkers(set);
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
- SubPlanBuilder<JDefinedClassOrInterface> typePlan = progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
+ SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(ImplicitBlocks.class);
methodPlan.append(ImplicitBlocksChecker.class);
@@ -83,10 +83,10 @@
methodPlan.append(TryCatchRemover.class);
methodPlan.append(CfgBuilder.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
JDefinedClassOrInterface type = (JDefinedClassOrInterface)
- jprogram.getLookup().getType(classSignature);
+ session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod foundMethod = TestTools.getMethod(type, methodSignature);
diff --git a/jack/tests/com/android/jack/frontend/AllTests.java b/jack/tests/com/android/jack/frontend/AllTests.java
index 7e3ee65..c3041fa 100644
--- a/jack/tests/com/android/jack/frontend/AllTests.java
+++ b/jack/tests/com/android/jack/frontend/AllTests.java
@@ -25,6 +25,7 @@
TypeModifierTest.class,
FieldModifierTest.class,
MethodModifierTest.class,
+ MissingClassTest.class,
ClinitTest.class,
InitTest.class,
InstanceTest.class,
diff --git a/jack/tests/com/android/jack/frontend/ArrayTest.java b/jack/tests/com/android/jack/frontend/ArrayTest.java
index 94c3cce..fe722a1 100644
--- a/jack/tests/com/android/jack/frontend/ArrayTest.java
+++ b/jack/tests/com/android/jack/frontend/ArrayTest.java
@@ -18,7 +18,6 @@
import com.android.jack.TestTools;
-import com.android.jack.util.filter.RejectAllMethods;
import org.junit.Before;
import org.junit.Test;
@@ -33,7 +32,7 @@
@Test
public void arrayReuse() throws Exception {
String binaryName = "com/android/jack/newarray/test003/jack/ArrayReuse";
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(binaryName),
- "L" + binaryName + ";", "arrayDimReuse()V", new RejectAllMethods());
+ TestTools.getJMethodWithRejectAllFilter(TestTools.getJackTestFromBinaryName(binaryName), "L"
+ + binaryName + ";", "arrayDimReuse()V");
}
}
diff --git a/jack/tests/com/android/jack/frontend/ClinitTest.java b/jack/tests/com/android/jack/frontend/ClinitTest.java
index 799316b..e438566 100644
--- a/jack/tests/com/android/jack/frontend/ClinitTest.java
+++ b/jack/tests/com/android/jack/frontend/ClinitTest.java
@@ -24,9 +24,8 @@
import com.android.jack.ir.ast.JExpressionStatement;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
import com.android.jack.ir.ast.JStatement;
-import com.android.jack.util.filter.RejectAllMethods;
+import com.android.jack.util.NamingTools;
import junit.framework.Assert;
@@ -49,10 +48,10 @@
@Test
public void searchStaticInit() throws Exception {
- JMethod clinit = TestTools.getJMethod(
+ JMethod clinit = TestTools.getJMethodWithRejectAllFilter(
TestTools.getJackTestFromBinaryName(CLASS_WITH_VARIABLE_INIT_BINARY_NAME),
"L" + CLASS_WITH_VARIABLE_INIT_BINARY_NAME + ";",
- JProgram.STATIC_INIT_NAME + "()V", new RejectAllMethods());
+ NamingTools.STATIC_INIT_NAME + "()V");
JMethodBody body = (JMethodBody) clinit.getBody();
assert body != null;
@@ -75,9 +74,9 @@
@Test
public void searchEmptyStaticInit() throws Exception {
- JMethod clinit = TestTools.getJMethod(
+ JMethod clinit = TestTools.getJMethodWithRejectAllFilter(
TestTools.getJackTestFromBinaryName(CLASS_BINARY_NAME),
- "L" + CLASS_BINARY_NAME + ";", JProgram.STATIC_INIT_NAME + "()V",new RejectAllMethods());
+ "L" + CLASS_BINARY_NAME + ";", NamingTools.STATIC_INIT_NAME + "()V");
Assert.assertEquals(0, ((JMethodBody)clinit.getBody()).getStatements().size());
}
diff --git a/jack/tests/com/android/jack/frontend/ConstantReuseTest.java b/jack/tests/com/android/jack/frontend/ConstantReuseTest.java
index 971beec..3253449 100644
--- a/jack/tests/com/android/jack/frontend/ConstantReuseTest.java
+++ b/jack/tests/com/android/jack/frontend/ConstantReuseTest.java
@@ -18,7 +18,6 @@
import com.android.jack.TestTools;
-import com.android.jack.util.filter.RejectAllMethods;
import org.junit.Before;
import org.junit.Test;
@@ -38,73 +37,73 @@
@Test
public void intConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "intConstantReuse()V", new RejectAllMethods());
+ "intConstantReuse()V");
}
@Test
public void byteConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "byteConstantReuse()V", new RejectAllMethods());
+ "byteConstantReuse()V");
}
@Test
public void shortConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "shortConstantReuse()V", new RejectAllMethods());
+ "shortConstantReuse()V");
}
@Test
public void charConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "charConstantReuse()V", new RejectAllMethods());
+ "charConstantReuse()V");
}
@Test
public void floatConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "floatConstantReuse()V", new RejectAllMethods());
+ "floatConstantReuse()V");
}
@Test
public void longConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "longConstantReuse()V",new RejectAllMethods());
+ "longConstantReuse()V");
}
@Test
public void doubleConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "doubleConstantReuse()V",new RejectAllMethods());
+ "doubleConstantReuse()V");
}
@Test
public void booleanConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "booleanConstantReuse()V", new RejectAllMethods());
+ "booleanConstantReuse()V");
}
@Test
public void nullConstantReuse() throws Exception {
- TestTools.getJMethod(
+ TestTools.getJMethodWithRejectAllFilter(
TEST_FILE,
CLASS_SIGNATURE,
- "nullConstantReuse()V", new RejectAllMethods());
+ "nullConstantReuse()V");
}
}
diff --git a/jack/tests/com/android/jack/frontend/FieldModifierTest.java b/jack/tests/com/android/jack/frontend/FieldModifierTest.java
index b4ed809..e8d4427 100644
--- a/jack/tests/com/android/jack/frontend/FieldModifierTest.java
+++ b/jack/tests/com/android/jack/frontend/FieldModifierTest.java
@@ -21,8 +21,7 @@
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JField;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.util.filter.RejectAllMethods;
+import com.android.jack.ir.ast.JSession;
import junit.framework.Assert;
@@ -31,27 +30,31 @@
public class FieldModifierTest {
- private JProgram program;
+ private JSession session;
- private final static String FIELD_MODIFIER_BINARY_NAME = "com/android/jack/modifier/jack/FieldModifier";
+ private final static String FIELD_MODIFIER_BINARY_NAME =
+ "com/android/jack/modifier/jack/FieldModifier";
private final static String FIELD_MODIFIER_SIGNATURE = "L" + FIELD_MODIFIER_BINARY_NAME + ";";
- private final static String FIELD_ENUM_BINARY_NAME = "com/android/jack/modifier/jack/FieldEnumModifier";
+ private final static String FIELD_ENUM_BINARY_NAME =
+ "com/android/jack/modifier/jack/FieldEnumModifier";
@Before
public void setUp() throws Exception {
FieldModifierTest.class.getClassLoader().setDefaultAssertionStatus(true);
- Options jackArgs = TestTools.buildCommandLineArgs(
- TestTools.getJackTestFromBinaryName(FIELD_MODIFIER_BINARY_NAME));
- jackArgs.setFilter(new RejectAllMethods());
+ Options jackArgs =
+ TestTools.buildCommandLineArgs(TestTools
+ .getJackTestFromBinaryName(FIELD_MODIFIER_BINARY_NAME));
+ jackArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
- program = TestTools.buildProgram(jackArgs);
- Assert.assertNotNull(program);
+ session = TestTools.buildSession(jackArgs);
+ Assert.assertNotNull(session);
}
@Test
public void fieldPublicModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldPublic");
@@ -62,7 +65,8 @@
@Test
public void fieldProtectedModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldProtected");
@@ -73,7 +77,8 @@
@Test
public void fieldPrivateModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldPrivate");
@@ -84,7 +89,8 @@
@Test
public void fieldStaticModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldStatic");
@@ -95,7 +101,8 @@
@Test
public void fieldVolatileModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldVolatile");
@@ -106,7 +113,8 @@
@Test
public void fieldFinalModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldFinal");
@@ -117,7 +125,8 @@
@Test
public void fieldTransientModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldTransient");
@@ -128,7 +137,8 @@
@Test
public void fieldPublicFinalModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldPublicFinal");
@@ -139,7 +149,8 @@
@Test
public void fieldMultipleFinalModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(FIELD_MODIFIER_SIGNATURE);
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "fieldProtectedStaticVolatileTransient");
@@ -153,12 +164,14 @@
public void fieldEnumModifier() throws Exception {
Options args = TestTools.buildCommandLineArgs(
TestTools.getJackTestFromBinaryName(FIELD_ENUM_BINARY_NAME));
- args.setFilter(new RejectAllMethods());
+ args.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
- JProgram program = TestTools.buildProgram(args);
- Assert.assertNotNull(program);
+ JSession session = TestTools.buildSession(args);
+ Assert.assertNotNull(session);
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType("L" + FIELD_ENUM_BINARY_NAME + "$Select;");
+ JDefinedClassOrInterface type =
+ (JDefinedClassOrInterface) session.getLookup().getType(
+ "L" + FIELD_ENUM_BINARY_NAME + "$Select;");
Assert.assertNotNull(type);
JField field = getFieldFromName(type, "ONE");
diff --git a/jack/tests/com/android/jack/frontend/FrontendTools.java b/jack/tests/com/android/jack/frontend/FrontendTools.java
index 64f0983..6a3bbbf 100644
--- a/jack/tests/com/android/jack/frontend/FrontendTools.java
+++ b/jack/tests/com/android/jack/frontend/FrontendTools.java
@@ -20,7 +20,7 @@
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import junit.framework.Assert;
@@ -29,10 +29,10 @@
public static JMethod parseMethod(
String classSignature, String methodSignature, Options options)
throws Exception {
- JProgram jprogram = TestTools.buildJAst(options);
- Assert.assertNotNull(jprogram);
+ JSession session = TestTools.buildJAst(options);
+ Assert.assertNotNull(session);
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) jprogram.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod foundMethod = TestTools.getMethod(type, methodSignature);
diff --git a/jack/tests/com/android/jack/frontend/GotoTest.java b/jack/tests/com/android/jack/frontend/GotoTest.java
index 6da6520..570b08a 100644
--- a/jack/tests/com/android/jack/frontend/GotoTest.java
+++ b/jack/tests/com/android/jack/frontend/GotoTest.java
@@ -27,7 +27,6 @@
import com.android.jack.ir.ast.JMethodBody;
import com.android.jack.ir.ast.JReturnStatement;
import com.android.jack.ir.ast.JStatement;
-import com.android.jack.util.filter.RejectAllMethods;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
@@ -47,9 +46,9 @@
@Test
public void dumpGoto() throws Exception {
- JMethod dumpGoto = TestTools.getJMethod(
+ JMethod dumpGoto = TestTools.getJMethodWithRejectAllFilter(
TestTools.getJackUnitTestFromBinaryName(TEST_CLASS_BINARY_NAME),
- "L" + TEST_CLASS_BINARY_NAME + ";", "synthetizeCode()V", new RejectAllMethods());
+ "L" + TEST_CLASS_BINARY_NAME + ";", "synthetizeCode()V");
JMethodBody body = (JMethodBody) dumpGoto.getBody();
assert body != null;
diff --git a/jack/tests/com/android/jack/frontend/InitTest.java b/jack/tests/com/android/jack/frontend/InitTest.java
index 156ff48..b32790d 100644
--- a/jack/tests/com/android/jack/frontend/InitTest.java
+++ b/jack/tests/com/android/jack/frontend/InitTest.java
@@ -19,8 +19,7 @@
import com.android.jack.Options;
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.util.filter.RejectAllMethods;
+import com.android.jack.util.NamingTools;
import junit.framework.Assert;
@@ -37,10 +36,10 @@
@Test
public void searchInit() throws Exception {
String binaryName = "com/android/jack/fibonacci/jack/Fibo";
- JMethod init = TestTools.getJMethod(
+ JMethod init = TestTools.getJMethodWithRejectAllFilter(
TestTools.getJackTestFromBinaryName(binaryName),
"L" + binaryName + ";",
- JProgram.INIT_NAME+"()V", new RejectAllMethods());
+ NamingTools.INIT_NAME+"()V");
Assert.assertNotNull(init);
}
diff --git a/jack/tests/com/android/jack/frontend/MethodModifierTest.java b/jack/tests/com/android/jack/frontend/MethodModifierTest.java
index d82d639..c0e1d22 100644
--- a/jack/tests/com/android/jack/frontend/MethodModifierTest.java
+++ b/jack/tests/com/android/jack/frontend/MethodModifierTest.java
@@ -22,8 +22,7 @@
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.util.filter.RejectAllMethods;
+import com.android.jack.ir.ast.JSession;
import junit.framework.Assert;
@@ -33,7 +32,7 @@
public class MethodModifierTest {
- private JProgram program;
+ private JSession session;
private final String classBinaryName = "com/android/jack/modifier/jack/MethodModifier";
private final String classSignature = "L" + classBinaryName + ";";
@@ -43,15 +42,15 @@
Options jackArgs = TestTools.buildCommandLineArgs(
TestTools.getJackTestFromBinaryName(classBinaryName));
- jackArgs.setFilter(new RejectAllMethods());
+ jackArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
- program = TestTools.buildProgram(jackArgs);
- Assert.assertNotNull(program);
+ session = TestTools.buildSession(jackArgs);
+ Assert.assertNotNull(session);
}
@Test
public void methodPublicModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodPublic()V");
@@ -62,7 +61,7 @@
@Test
public void methodProtectedModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodProtected()V");
@@ -73,7 +72,7 @@
@Test
public void methodPrivateModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodPrivate()V");
@@ -84,7 +83,7 @@
@Test
public void methodStaticModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodStatic()V");
@@ -95,7 +94,7 @@
@Test
public void methodFinalModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodFinal()V");
@@ -106,7 +105,7 @@
@Test
public void methodPublicFinalModifier() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodPublicFinal()V");
@@ -117,7 +116,7 @@
@Test
public void methodSynchronized() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodSynchronized()V");
@@ -128,7 +127,7 @@
@Test
public void methodNative() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodNative()V");
@@ -140,7 +139,7 @@
@Test
@Ignore
public void methodVarags() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodVarags([I)V");
@@ -151,7 +150,7 @@
@Test
public void constructorPrivate() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "<init>()V");
@@ -162,7 +161,7 @@
@Test
public void constructorPublic() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "<init>(I)V");
@@ -173,7 +172,7 @@
@Test
public void methodAbstract() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodAbstract()V");
@@ -184,7 +183,7 @@
@Test
public void clinit() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = type.getMethod("<clinit>", JPrimitiveTypeEnum.VOID.getType());
@@ -195,7 +194,7 @@
@Test
public void methodStrictfp() throws Exception {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup().getType(classSignature);
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup().getType(classSignature);
Assert.assertNotNull(type);
JMethod method = TestTools.getMethod(type, "methodStrictfp()V");
diff --git a/jack/tests/com/android/jack/frontend/MissingClassTest.java b/jack/tests/com/android/jack/frontend/MissingClassTest.java
new file mode 100644
index 0000000..8aacd6b
--- /dev/null
+++ b/jack/tests/com/android/jack/frontend/MissingClassTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.frontend;
+
+import com.android.jack.Options;
+import com.android.jack.TestTools;
+import com.android.jack.category.KnownBugs;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+
+public class MissingClassTest {
+
+ @Test
+ @Category(KnownBugs.class)
+ public void test001() throws Exception {
+ File outJackTmpMissing = TestTools.createTempDir("MissingClassTest001-missing", ".jack");
+ File outJackTmpSuper = TestTools.createTempDir("MissingClassTest001-super", ".jack");
+ File outJackTmpTest = TestTools.createTempDir("MissingClassTest001-test", ".jack");
+
+ TestTools.compileSourceToJack(new Options(),
+ new File(TestTools.getJackTestsWithJackFolder("frontend/test001"), "missing"),
+ TestTools.getDefaultBootclasspathString(), outJackTmpMissing, false /* zip */);
+
+ TestTools.compileSourceToJack(new Options(),
+ new File(TestTools.getJackTestsWithJackFolder("frontend/test001"), "sub2"),
+ TestTools.getDefaultBootclasspathString() + File.pathSeparator
+ + outJackTmpMissing.getPath(), outJackTmpSuper, false /* zip */);
+
+ TestTools.compileSourceToJack(new Options(),
+ new File(TestTools.getJackTestsWithJackFolder("frontend/test001"), "test"),
+ TestTools.getDefaultBootclasspathString() + File.pathSeparator + outJackTmpSuper.getPath(),
+ outJackTmpTest, false /* zip */);
+
+ }
+
+}
diff --git a/jack/tests/com/android/jack/frontend/SwitchTest.java b/jack/tests/com/android/jack/frontend/SwitchTest.java
index f5b5f84..fd34953 100644
--- a/jack/tests/com/android/jack/frontend/SwitchTest.java
+++ b/jack/tests/com/android/jack/frontend/SwitchTest.java
@@ -17,13 +17,13 @@
package com.android.jack.frontend;
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JBlock;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JSwitchStatement;
+import com.android.jack.util.filter.SignatureMethodFilter;
import junit.framework.Assert;
@@ -53,7 +53,9 @@
public void testCompileSwitch001() throws Exception {
final String methodSignature = "switch001(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -71,7 +73,9 @@
public void testCompileSwitch002() throws Exception {
final String methodSignature = "switch002(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -98,7 +102,9 @@
public void testCompileSwitch003() throws Exception {
final String methodSignature = "switch003(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -113,7 +119,9 @@
public void testCompileSwitch004() throws Exception {
final String methodSignature = "switch004(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
diff --git a/jack/tests/com/android/jack/frontend/SynchronizedTest.java b/jack/tests/com/android/jack/frontend/SynchronizedTest.java
index d837001..d112ca9 100644
--- a/jack/tests/com/android/jack/frontend/SynchronizedTest.java
+++ b/jack/tests/com/android/jack/frontend/SynchronizedTest.java
@@ -17,7 +17,6 @@
package com.android.jack.frontend;
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.SourceInfo;
import com.android.jack.ir.ast.JClass;
@@ -25,7 +24,7 @@
import com.android.jack.ir.ast.JLock;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JReturnStatement;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JSynchronizedBlock;
@@ -33,6 +32,7 @@
import com.android.jack.lookup.CommonTypes;
import com.android.jack.transformations.request.AppendBefore;
import com.android.jack.transformations.request.TransformationRequest;
+import com.android.jack.util.filter.SignatureMethodFilter;
import junit.framework.Assert;
@@ -61,7 +61,9 @@
public void testSynchronizedBlock() throws Exception {
final String methodSignature = "sync(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -80,7 +82,9 @@
public void testSynchronizedMethod() throws Exception {
final String methodSignature = "syncMethod(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -96,7 +100,9 @@
public void testLockUnlock() throws Exception {
final String methodSignature = "syncMethod(I)I";
Options commandLineArgs = TestTools.buildCommandLineArgs(FILE);
- commandLineArgs.setFilter(new SignatureMethodFilter(methodSignature));
+ commandLineArgs.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ commandLineArgs.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
JMethod method =
FrontendTools.parseMethod(CLASS_SIGNATURE, methodSignature, commandLineArgs);
@@ -111,7 +117,7 @@
SourceInfo srcInfo = firstStmt.getSourceInfo();
TransformationRequest tr = new TransformationRequest(method);
- JClass javaLangClass = method.getParent(JProgram.class).getPhantomLookup()
+ JClass javaLangClass = method.getParent(JSession.class).getPhantomLookup()
.getClass(CommonTypes.JAVA_LANG_CLASS);
tr.append(new AppendBefore(firstStmt, new JLock(srcInfo,
new JClassLiteral(srcInfo, method.getEnclosingType(), javaLangClass))));
diff --git a/jack/tests/com/android/jack/frontend/TypeModifierTest.java b/jack/tests/com/android/jack/frontend/TypeModifierTest.java
index 94d5a13..2ae0a66 100644
--- a/jack/tests/com/android/jack/frontend/TypeModifierTest.java
+++ b/jack/tests/com/android/jack/frontend/TypeModifierTest.java
@@ -20,8 +20,7 @@
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JModifier;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.util.filter.RejectAllMethods;
+import com.android.jack.ir.ast.JSession;
import junit.framework.Assert;
@@ -29,7 +28,7 @@
import org.junit.Test;
public class TypeModifierTest {
- private JProgram program;
+ private JSession session;
private static final String OUTER_CLASS_BINARY_NAME = "com/android/jack/modifier/jack/TypeModifier";
@Before
@@ -38,13 +37,13 @@
Options jackArgs = TestTools.buildCommandLineArgs(
TestTools.getJackTestFromBinaryName(OUTER_CLASS_BINARY_NAME));
- jackArgs.setFilter(new RejectAllMethods());
- program = TestTools.buildProgram(jackArgs);
- Assert.assertNotNull(program);
+ jackArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
+ session = TestTools.buildSession(jackArgs);
+ Assert.assertNotNull(session);
}
private JDefinedClassOrInterface lookupInnerClass(String className) {
- JDefinedClassOrInterface type = (JDefinedClassOrInterface) program.getLookup()
+ JDefinedClassOrInterface type = (JDefinedClassOrInterface) session.getLookup()
.getType("L" + OUTER_CLASS_BINARY_NAME + "$" + className + ";");
Assert.assertNotNull(type);
return type;
diff --git a/jack/tests/com/android/jack/gwt/BinaryLookup.java b/jack/tests/com/android/jack/gwt/BinaryLookup.java
index ab85e6c..37d549e 100644
--- a/jack/tests/com/android/jack/gwt/BinaryLookup.java
+++ b/jack/tests/com/android/jack/gwt/BinaryLookup.java
@@ -24,11 +24,10 @@
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.lookup.CommonTypes;
import com.android.jack.lookup.JLookup;
-import com.android.jack.util.filter.RejectAllMethods;
import com.android.sched.util.RunnableHooks;
import junit.framework.Assert;
@@ -41,7 +40,7 @@
private static RunnableHooks hooks;
private static JLookup lookup;
- private static JProgram program;
+ private static JSession session;
@BeforeClass
public static void setUpClass() throws Exception {
@@ -49,10 +48,10 @@
Options fiboArgs = TestTools.buildCommandLineArgs(
TestTools.getJackTestFromBinaryName("com/android/jack/fibonacci/jack/Fibo"));
- fiboArgs.setFilter(new RejectAllMethods());
+ fiboArgs.addProperty(Options.METHOD_FILTER.getName(), "reject-all-methods");
hooks = new RunnableHooks();
- program = TestTools.buildProgram(fiboArgs, hooks);
- lookup = program.getLookup();
+ session = TestTools.buildSession(fiboArgs, hooks);
+ lookup = session.getLookup();
}
@AfterClass
@@ -65,10 +64,11 @@
JType jls = lookup.getType(CommonTypes.JAVA_LANG_STRING);
Assert.assertTrue(Jack.getLookupFormatter().getName(jls).equals("Ljava/lang/String;"));
- Assert.assertTrue(program.isJavaLangString(jls));
- Assert.assertTrue(program.getLookup().getType(CommonTypes.JAVA_LANG_STRING) == jls);
- Assert.assertTrue(program.getLookup().getType("Ljava/lang/String;") == jls);
- Assert.assertTrue(program.getLookup().getClass(CommonTypes.JAVA_LANG_STRING) ==
+ Assert.assertTrue(jls ==
+ session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING));
+ Assert.assertTrue(session.getLookup().getType(CommonTypes.JAVA_LANG_STRING) == jls);
+ Assert.assertTrue(session.getLookup().getType("Ljava/lang/String;") == jls);
+ Assert.assertTrue(session.getLookup().getClass(CommonTypes.JAVA_LANG_STRING) ==
lookup.getClass("Ljava/lang/String;"));
}
@@ -77,8 +77,8 @@
JType jls = lookup.getType("[[[Ljava/lang/String;");
Assert.assertTrue(Jack.getLookupFormatter().getName(jls).equals("[[[Ljava/lang/String;"));
- Assert.assertTrue(program.getLookup()
- .getArrayType(program.getLookup().getType(CommonTypes.JAVA_LANG_STRING), 3) == jls);
+ Assert.assertTrue(session.getLookup()
+ .getArrayType(session.getLookup().getType(CommonTypes.JAVA_LANG_STRING), 3) == jls);
}
@Test
@@ -199,7 +199,8 @@
JMethod append = TestTools.getMethod(type, "append(Ljava/lang/String;)Ljava/lang/StringBuilder;");
Assert.assertTrue(append.getName().equals("append"));
- Assert.assertTrue(program.isJavaLangString(append.getParams().get(0).getType()));
+ Assert.assertTrue(append.getParams().get(0).getType() ==
+ session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_STRING));
}
@Test
diff --git a/jack/tests/com/android/jack/ir/ast/MarkerCollectorTest.java b/jack/tests/com/android/jack/ir/ast/MarkerCollectorTest.java
index d98ced3..8041496 100644
--- a/jack/tests/com/android/jack/ir/ast/MarkerCollectorTest.java
+++ b/jack/tests/com/android/jack/ir/ast/MarkerCollectorTest.java
@@ -38,7 +38,7 @@
private final JParameter param;
public MarkerCollectorTest() {
- JPackage p = new JPackage("test", new JProgram(), null);
+ JPackage p = new JPackage("test", new JSession(), null);
JDefinedClass classTest = new JDefinedClass(SourceOrigin.UNKNOWN, "Test", JModifier.PUBLIC, p,
NopClassOrInterfaceLoader.INSTANCE);
JMethod method =
diff --git a/jack/tests/com/android/jack/optimizations/ExpressionSimplifierTest.java b/jack/tests/com/android/jack/optimizations/ExpressionSimplifierTest.java
index b4fd726..8fa7eac 100644
--- a/jack/tests/com/android/jack/optimizations/ExpressionSimplifierTest.java
+++ b/jack/tests/com/android/jack/optimizations/ExpressionSimplifierTest.java
@@ -46,7 +46,7 @@
import com.android.jack.ir.ast.JPrefixNegOperation;
import com.android.jack.ir.ast.JPrefixNotOperation;
import com.android.jack.ir.ast.JPrimitiveType.JPrimitiveTypeEnum;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JShortLiteral;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.MethodKind;
@@ -75,7 +75,7 @@
private final JParameter param;
public ExpressionSimplifierTest() {
- JPackage p = new JPackage("test", new JProgram(), null);
+ JPackage p = new JPackage("test", new JSession(), null);
classTest = new JDefinedClass(SourceOrigin.UNKNOWN, "Test", JModifier.PUBLIC, p,
NopClassOrInterfaceLoader.INSTANCE);
method =
diff --git a/jack/tests/com/android/jack/optimizations/NotSimplifierTest.java b/jack/tests/com/android/jack/optimizations/NotSimplifierTest.java
index 086e2e0..b222ba2 100644
--- a/jack/tests/com/android/jack/optimizations/NotSimplifierTest.java
+++ b/jack/tests/com/android/jack/optimizations/NotSimplifierTest.java
@@ -16,7 +16,6 @@
package com.android.jack.optimizations;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JBinaryOperation;
import com.android.jack.ir.ast.JBinaryOperator;
@@ -45,8 +44,8 @@
String methodSignature = "test001(II)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.EQ).accept(m);
@@ -60,8 +59,8 @@
String methodSignature = "test002(II)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.LT).accept(m);
@@ -74,8 +73,8 @@
String methodSignature = "test003(IIII)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.LT).accept(m);
@@ -89,8 +88,8 @@
String methodSignature = "test004(IIZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.LT).accept(m);
@@ -103,8 +102,8 @@
String methodSignature = "test005(IIII)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.LT).accept(m);
@@ -118,8 +117,8 @@
String methodSignature = "test006(II)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.NEQ).accept(m);
@@ -132,8 +131,8 @@
String methodSignature = "test007(II)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.EQ).accept(m);
@@ -146,8 +145,8 @@
String methodSignature = "test008(II)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.NEQ).accept(m);
@@ -160,8 +159,8 @@
String methodSignature = "test009(IIII)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.NEQ).accept(m);
@@ -174,8 +173,8 @@
String methodSignature = "test010(Z)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
Assert
@@ -190,8 +189,8 @@
String methodSignature = "test011(ZZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
checkFirstStatement(m, JBinaryOperator.BIT_OR);
@@ -204,8 +203,8 @@
String methodSignature = "test012(ZZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
checkFirstStatement(m, JBinaryOperator.BIT_AND);
@@ -218,8 +217,8 @@
String methodSignature = "test013(ZZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
checkFirstStatement(m, JBinaryOperator.BIT_XOR);
@@ -232,8 +231,8 @@
String methodSignature = "test014(ZZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.BIT_AND).accept(m);
@@ -246,8 +245,8 @@
String methodSignature = "test015(ZZ)Z";
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
+ + classBinaryName + ";", methodSignature);
Assert.assertNotNull(m);
new CheckAbsenceOfBinaryOp(JBinaryOperator.BIT_OR).accept(m);
diff --git a/jack/tests/com/android/jack/shrob/AbstractTest.java b/jack/tests/com/android/jack/shrob/AbstractTest.java
index 229b7ef..9afc34c 100644
--- a/jack/tests/com/android/jack/shrob/AbstractTest.java
+++ b/jack/tests/com/android/jack/shrob/AbstractTest.java
@@ -233,29 +233,6 @@
}
@Test
- public void test3_001() throws Exception {
- String testName = "shrob/test003";
- File[] defaultBoot = TestTools.getDefaultBootclasspath();
- File[] bootclasspath = new File[defaultBoot.length + 1];
- System.arraycopy(defaultBoot, 0, bootclasspath, 0, defaultBoot.length);
- bootclasspath[defaultBoot.length] =
- new File(TestTools.getJackTestFolder(testName).getAbsolutePath(), "test.jar");
-
- runTest(bootclasspath, null, "003", "001", "");
- }
-
- @Test
- @Category(SlowTests.class)
- public void test3_001_bis() throws Exception {
- String testName = "shrob/test003";
-
- File[] classpath = new File[] {
- new File(TestTools.getJackTestFolder(testName).getAbsolutePath(), "test.jar")
- };
- runTest(defaultBootclasspath, classpath, "003", "001", "");
- }
-
- @Test
public void test4_001() throws Exception {
runTest(defaultBootclasspath, null, "004", "001", "");
}
diff --git a/jack/tests/com/android/jack/shrob/FlattenPackageTest.java b/jack/tests/com/android/jack/shrob/FlattenPackageTest.java
index ee38266..e2d36d6 100644
--- a/jack/tests/com/android/jack/shrob/FlattenPackageTest.java
+++ b/jack/tests/com/android/jack/shrob/FlattenPackageTest.java
@@ -18,13 +18,10 @@
import com.android.jack.Options;
import com.android.jack.TestTools;
-import com.android.jack.category.KnownBugs;
import com.android.jack.category.SlowTests;
import com.android.jack.shrob.proguard.GrammarActions;
import com.android.jack.shrob.spec.Flags;
-import org.junit.Ignore;
-import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.File;
@@ -61,20 +58,4 @@
TestTools.getJackTestsWithJackFolder(testName), flags);
ListingComparator.compare(refOutputMapping, candidateOutputMapping);
}
-
- @Test
- @Category(KnownBugs.class)
- @Override
- @Ignore
- public void test16_001() throws Exception {
- runTest(defaultBootclasspath, null, "016", "001", "");
- }
-
- @Test
- @Category(KnownBugs.class)
- @Override
- @Ignore
- public void test16_002() throws Exception {
- runTest(defaultBootclasspath, null, "016", "002", "");
- }
}
diff --git a/jack/tests/com/android/jack/shrob/ObfuscationWithoutMappingTest.java b/jack/tests/com/android/jack/shrob/ObfuscationWithoutMappingTest.java
index 2531ed8..794dc26 100644
--- a/jack/tests/com/android/jack/shrob/ObfuscationWithoutMappingTest.java
+++ b/jack/tests/com/android/jack/shrob/ObfuscationWithoutMappingTest.java
@@ -86,20 +86,6 @@
@Override
@Test
@Category(KnownBugs.class)
- public void test3_001() throws Exception {
- super.test3_001();
- }
-
- @Override
- @Test
- @Category(KnownBugs.class)
- public void test3_001_bis() throws Exception {
- super.test3_001_bis();
- }
-
- @Override
- @Test
- @Category(KnownBugs.class)
public void test19_001() throws Exception {
super.test19_001();
}
diff --git a/jack/tests/com/android/jack/shrob/SeedTest.java b/jack/tests/com/android/jack/shrob/SeedTest.java
index 024c7c8..841fa81 100644
--- a/jack/tests/com/android/jack/shrob/SeedTest.java
+++ b/jack/tests/com/android/jack/shrob/SeedTest.java
@@ -63,20 +63,6 @@
@Override
@Test
@Category(KnownBugs.class)
- public void test3_001() throws Exception {
- super.test3_001();
- }
-
- @Override
- @Test
- @Category(KnownBugs.class)
- public void test3_001_bis() throws Exception {
- super.test3_001_bis();
- }
-
- @Override
- @Test
- @Category(KnownBugs.class)
public void test19_001() throws Exception {
super.test19_001();
}
diff --git a/jack/tests/com/android/jack/shrob/TreeTest.java b/jack/tests/com/android/jack/shrob/TreeTest.java
index b5c843c..2b9f39f 100644
--- a/jack/tests/com/android/jack/shrob/TreeTest.java
+++ b/jack/tests/com/android/jack/shrob/TreeTest.java
@@ -21,7 +21,6 @@
import com.android.jack.ProguardFlags;
import com.android.jack.TestTools;
import com.android.jack.category.SlowTests;
-import com.android.jack.util.filter.SupportedMethods;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -50,8 +49,8 @@
Options options = TestTools.buildCommandLineArgs(new File[]{CORE_SOURCELIST, testFolder});
options.addProguardFlagsFile(new ProguardFlags(testFolder, "proguard.flags001"));
options.addProguardFlagsFile(dontObfuscateFlagFile);
- options.setFilter(new SupportedMethods());
+ options.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
- TestTools.buildProgram(options);
+ TestTools.buildSession(options);
}
}
diff --git a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
index 0d8ef60..740ed91 100644
--- a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
+++ b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
@@ -21,11 +21,10 @@
import com.android.jack.ir.JavaSourceIr;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.scheduling.adapter.JMethodAdaptor;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
+import com.android.jack.scheduling.adapter.JMethodAdaptor;
import com.android.jack.transformations.parent.ParentSetterChecker;
-import com.android.jack.util.filter.SupportedMethods;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.SchedulableManager;
@@ -50,11 +49,11 @@
public void computeBlockStatOnCore() throws Exception {
Options compilerArgs = TestTools.buildCommandLineArgs(null, null,
TestTools.getFromAndroidTree("libcore/luni/src/main/java/"));
- compilerArgs.setFilter(new SupportedMethods());
- JProgram program = buildProgram(compilerArgs);
- Assert.assertNotNull(program);
+ compilerArgs.addProperty(Options.METHOD_FILTER.getName(), "supported-methods");
+ JSession session = buildSession(compilerArgs);
+ Assert.assertNotNull(session);
- BlockCountMarker bcm = program.getMarker(BlockCountMarker.class);
+ BlockCountMarker bcm = session.getMarker(BlockCountMarker.class);
Assert.assertNotNull(bcm);
assert bcm != null; // Find Bugs will be happy
@@ -70,9 +69,9 @@
}
@Nonnull
- private static JProgram buildProgram(@Nonnull Options options) throws Exception {
- JProgram jprogram = TestTools.buildProgram(options);
- Assert.assertNotNull(jprogram);
+ private static JSession buildSession(@Nonnull Options options) throws Exception {
+ JSession session = TestTools.buildSession(options);
+ Assert.assertNotNull(session);
Scheduler scheduler = Scheduler.getScheduler();
SchedulableManager sm = SchedulableManager.getSchedulableManager();
@@ -82,14 +81,14 @@
sr.addTargetIncludeTagOrMarker(JavaSourceIr.class);
sr.addInitialTagOrMarker(JavaSourceIr.class);
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
- progPlan.append(ParentSetterChecker.class);
- SubPlanBuilder<JDefinedClassOrInterface> typePlan = progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
+ planBuilder.append(ParentSetterChecker.class);
+ SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(BlockStatistics.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
- return (jprogram);
+ return (session);
}
}
diff --git a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
index 6693e80..3ecec25 100644
--- a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
@@ -18,15 +18,15 @@
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.JavaSourceIr;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
-import com.android.jack.ir.ast.JProgram;
-import com.android.jack.scheduling.adapter.JMethodAdaptor;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
+import com.android.jack.scheduling.adapter.JMethodAdaptor;
import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.Scheduler;
@@ -106,9 +106,11 @@
private static JMethod buildMethodWithImplicitBlock(String methodSignature) throws Exception {
Options options = TestTools.buildCommandLineArgs(FILE);
- options.setFilter(new SignatureMethodFilter(methodSignature));
- JProgram jprogram = TestTools.buildJAst(options);
- Assert.assertNotNull(jprogram);
+ options.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ options.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
+ JSession session = TestTools.buildJAst(options);
+ Assert.assertNotNull(session);
Scheduler scheduler = Scheduler.getScheduler();
Request sr = scheduler.createScheduleRequest();
@@ -117,17 +119,17 @@
sr.addTargetIncludeTagOrMarker(JavaSourceIr.class);
sr.addInitialTagOrMarker(JavaSourceIr.class);
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
- progPlan.append(ParentSetterChecker.class);
- SubPlanBuilder<JDefinedClassOrInterface> typePlan = progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
+ planBuilder.append(ParentSetterChecker.class);
+ SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(ImplicitBlocks.class);
methodPlan.append(ImplicitBlocksChecker.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
JDefinedClassOrInterface type = (JDefinedClassOrInterface)
- jprogram.getLookup().getType(CLASS_SIGNATURE);
+ session.getLookup().getType(CLASS_SIGNATURE);
Assert.assertNotNull(type);
JMethod foundMethod = TestTools.getMethod(type, methodSignature);
diff --git a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
index 306e51b..75e1c89 100644
--- a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
@@ -19,14 +19,13 @@
import com.android.jack.Jack;
import com.android.jack.Options;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.ast.JBlock;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JLock;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JMethodBody;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JStatement;
import com.android.jack.ir.ast.JTryStatement;
import com.android.jack.ir.ast.JUnlock;
@@ -34,6 +33,7 @@
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
import com.android.jack.scheduling.adapter.JMethodAdaptor;
import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.Scheduler;
@@ -141,9 +141,11 @@
private static JMethod buildMethodAndRunSynchronizeTransformer(String methodSignature)
throws Exception {
Options options = TestTools.buildCommandLineArgs(FILE);
- options.setFilter(new SignatureMethodFilter(methodSignature));
- JProgram jprogram = TestTools.buildJAst(options);
- Assert.assertNotNull(jprogram);
+ options.addProperty(Options.METHOD_FILTER.getName(), "method-with-signature");
+ options.addProperty(SignatureMethodFilter.METHOD_SIGNATURE_FILTER.getName(),
+ methodSignature);
+ JSession session = TestTools.buildJAst(options);
+ Assert.assertNotNull(session);
Scheduler scheduler = Scheduler.getScheduler();
Request sr = scheduler.createScheduleRequest();
@@ -151,18 +153,18 @@
sr.addSchedulables(scheduler.getAllSchedulable());
sr.addInitialTagsOrMarkers(Jack.getJavaSourceInitialTagSet());
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
- progPlan.append(ParentSetterChecker.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
+ planBuilder.append(ParentSetterChecker.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
- progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdaptor.class);
methodPlan.append(ImplicitBlocks.class);
methodPlan.append(SynchronizeTransformer.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
JDefinedClassOrInterface type = (JDefinedClassOrInterface)
- jprogram.getLookup().getType(CLASS_SIGNATURE);
+ session.getLookup().getType(CLASS_SIGNATURE);
Assert.assertNotNull(type);
// FINDBUGS
assert type != null;
diff --git a/jack/tests/com/android/jack/transformations/ast/string/DummyAction.java b/jack/tests/com/android/jack/transformations/ast/string/DummyAction.java
index 77abfa4..72962ea 100644
--- a/jack/tests/com/android/jack/transformations/ast/string/DummyAction.java
+++ b/jack/tests/com/android/jack/transformations/ast/string/DummyAction.java
@@ -18,6 +18,7 @@
import com.android.jack.signature.GenericSignatureAction;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -25,7 +26,7 @@
*
* It only concatenates the parsed strings.
*/
-public class DummyAction implements GenericSignatureAction {
+public class DummyAction implements GenericSignatureAction<Object> {
@Nonnull
private StringBuilder strBuf = new StringBuilder();
@@ -41,13 +42,17 @@
}
@Override
- public void parsedTypeName(@Nonnull String name) {
+ @CheckForNull
+ public Object parsedTypeName(@Nonnull String name) {
strBuf.append(name);
+ return null;
}
@Override
- public void parsedInnerTypeName(@Nonnull String name) {
+ @CheckForNull
+ public Object parsedInnerTypeName(@CheckForNull Object enclosingTypeName, @Nonnull String name) {
strBuf.append(name);
+ return null;
}
@Override
diff --git a/jack/tests/com/android/jack/transformations/ast/string/StringSplittingTest.java b/jack/tests/com/android/jack/transformations/ast/string/StringSplittingTest.java
index 134cff5..e781bac 100644
--- a/jack/tests/com/android/jack/transformations/ast/string/StringSplittingTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/string/StringSplittingTest.java
@@ -32,7 +32,7 @@
@Test
public void testTypeStringSplitting() {
DummyAction parserActions = new DummyAction();
- GenericSignatureParser parser = new GenericSignatureParser(parserActions);
+ GenericSignatureParser<Object> parser = new GenericSignatureParser<Object>(parserActions);
String signature = "LOuter.Inner;";
parser.parseClassSignature(signature);
Assert.assertEquals(signature, parserActions.getNewSignature());
diff --git a/jack/tests/com/android/jack/transformations/cast/UselessCastRemoverTest.java b/jack/tests/com/android/jack/transformations/cast/UselessCastRemoverTest.java
index f896038..777b1d2 100644
--- a/jack/tests/com/android/jack/transformations/cast/UselessCastRemoverTest.java
+++ b/jack/tests/com/android/jack/transformations/cast/UselessCastRemoverTest.java
@@ -17,7 +17,6 @@
package com.android.jack.transformations.cast;
-import com.android.jack.SignatureMethodFilter;
import com.android.jack.TestTools;
import com.android.jack.ir.InternalCompilerException;
import com.android.jack.ir.ast.JCastOperation;
@@ -144,8 +143,9 @@
private static void buildMethodAndCheckUselessCastRemover(@Nonnull String classBinaryName,
@Nonnull String methodSignature, boolean castRemoved) throws Exception {
JMethod m =
- TestTools.getJMethod(TestTools.getJackTestFromBinaryName(classBinaryName), "L"
- + classBinaryName + ";", methodSignature, new SignatureMethodFilter(methodSignature));
+ TestTools.getJMethodWithSignatureFilter(
+ TestTools.getJackTestFromBinaryName(classBinaryName), "L" + classBinaryName + ";",
+ methodSignature);
Assert.assertNotNull(m);
try {
diff --git a/jack/tests/com/android/jack/util/AllTests.java b/jack/tests/com/android/jack/util/AllTests.java
index aa1b12d..3d9c445 100644
--- a/jack/tests/com/android/jack/util/AllTests.java
+++ b/jack/tests/com/android/jack/util/AllTests.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.jack.util;
import org.junit.runner.RunWith;
diff --git a/jack/tests/com/android/sched/Main.java b/jack/tests/com/android/sched/Main.java
index 0e4efa7..72f32d3 100644
--- a/jack/tests/com/android/sched/Main.java
+++ b/jack/tests/com/android/sched/Main.java
@@ -21,7 +21,7 @@
import com.android.jack.ir.JavaSourceIr;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JNode;
-import com.android.jack.ir.ast.JProgram;
+import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdaptor;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
@@ -55,25 +55,25 @@
static void run(@Nonnull Options options)
throws Exception {
- // Build the plan, verify it and run it onto the program
+ // Build the plan, verify it and run it onto the session
Scheduler scheduler = Scheduler.getScheduler();
Request sr = scheduler.createScheduleRequest();
sr.addSchedulables(scheduler.getAllSchedulable());
sr.addInitialTagOrMarker(JavaSourceIr.class);
- JProgram jprogram = TestTools.buildProgram(options);
- Assert.assertNotNull(jprogram);
+ JSession session = TestTools.buildSession(options);
+ Assert.assertNotNull(session);
// Currently, plan is manually built by adding RunnableSchedulable(s) and sub-plans
// corresponding to visitors.
- PlanBuilder<JProgram> progPlan = sr.getPlanBuilder(JProgram.class);
- SubPlanBuilder<JDefinedClassOrInterface> typePlan = progPlan.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
+ PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
+ SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdaptor.class);
SubPlanBuilder<JNode> nodePlan = typePlan.appendSubPlan(JNodeAdapter.class);
nodePlan.append(JNodeVisitor1.class);
nodePlan.append(JNodeVisitor2.class);
- progPlan.getPlan().getScheduleInstance().process(jprogram);
+ planBuilder.getPlan().getScheduleInstance().process(session);
}
@Nonnull
diff --git a/sched/.settings/findbugs-exclude.xml b/sched/.settings/findbugs-exclude.xml
index 404658b..e21c2b2 100644
--- a/sched/.settings/findbugs-exclude.xml
+++ b/sched/.settings/findbugs-exclude.xml
@@ -23,6 +23,11 @@
</Match>
<!-- See inlined comment in source file -->
<Match>
+ <Class name="com.android.sched.util.log.stats.SampleImpl"/>
+ <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+</Match>
+<!-- See inlined comment in source file -->
+<Match>
<Class name="com.android.sched.util.table.AbstractTable"/>
<Bug pattern="EI_EXPOSE_REP"/>
</Match>
diff --git a/sched/.settings/org.eclipse.jdt.core.prefs b/sched/.settings/org.eclipse.jdt.core.prefs
index 82380d3..34af015 100644
--- a/sched/.settings/org.eclipse.jdt.core.prefs
+++ b/sched/.settings/org.eclipse.jdt.core.prefs
@@ -188,7 +188,7 @@
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=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
diff --git a/sched/src/com/android/sched/SchedProperties.java b/sched/src/com/android/sched/SchedProperties.java
index c9edf55..5594905 100644
--- a/sched/src/com/android/sched/SchedProperties.java
+++ b/sched/src/com/android/sched/SchedProperties.java
@@ -16,6 +16,7 @@
package com.android.sched;
+import com.android.sched.item.onlyfor.Default;
import com.android.sched.item.onlyfor.OnlyForType;
import com.android.sched.util.codec.ClassSelector;
import com.android.sched.util.config.HasKeyId;
@@ -32,10 +33,10 @@
@Nonnull
public static final BooleanPropertyId FAILED_STOP = BooleanPropertyId.create(
"sched.failedstop", "Define if the SchedLib stop at the first failed")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final PropertyId<Class<? extends OnlyForType>> ONLY_FOR = PropertyId.create(
"sched.onlyfor", "Define which items to take into account",
- new ClassSelector<OnlyForType>(OnlyForType.class)).addDefaultValue("default");
+ new ClassSelector<OnlyForType>(OnlyForType.class)).addDefaultValue(Default.class);
}
diff --git a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
index de04742..64da80f 100644
--- a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
+++ b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
@@ -65,7 +65,7 @@
"sched.runner.thread.synchronized",
"If scheduler manages synchronized schedulable by itself").requiredIf(
ScheduleInstance.DEFAULT_RUNNER.getClazz().isSubClassOf(MultiWorkersScheduleInstance.class))
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
private static final IntegerPropertyId CHECK_FREQUENCY = IntegerPropertyId.create(
diff --git a/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java b/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
index 049b935..a8777d5 100644
--- a/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
+++ b/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
@@ -25,24 +25,16 @@
* Represents a type of event whose performance is tracked
*/
enum GeneticEventType implements EventType {
- ENGINE("Genetic engine", "Red"),
- ANALYZER("Genetic analizing plan", "Red"),
- BUILDER("Genetic builder builder", "Red"),
- RANDOM_INIT("Random generator initializer", "Red");
- @Nonnull
- private final String cssColor;
+ ENGINE("Genetic engine"),
+ ANALYZER("Genetic analizing plan"),
+ BUILDER("Genetic builder builder"),
+ RANDOM_INIT("Random generator initializer");
+
@Nonnull
private final String name;
- GeneticEventType(@Nonnull String name, @Nonnull String cssColor) {
+ GeneticEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/Colors.java b/sched/src/com/android/sched/util/Colors.java
deleted file mode 100644
index 69c8372..0000000
--- a/sched/src/com/android/sched/util/Colors.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sched.util;
-
-import java.awt.Color;
-import java.util.Random;
-
-import javax.annotation.Nonnull;
-
-/**
- * Utility class to manipulate Color.
- */
-public class Colors {
- /**
- * Return a valid string describing a color valid for Css.
- * @param color the color
- * @return the string describing the color
- */
- @Nonnull
- public static String getCssColor(@Nonnull Color color) {
- StringBuffer buffer = new StringBuffer(7);
- buffer.append('#');
- buffer.append(getHexColorComponent(color.getRed()));
- buffer.append(getHexColorComponent(color.getGreen()));
- buffer.append(getHexColorComponent(color.getBlue()));
-
- return buffer.toString();
- }
-
- @Nonnull
- private static String getHexColorComponent(int colorComponent) {
- String hex = Integer.toString(colorComponent, 16);
-
- // Make sure hex value is two digits
- if (hex.length() == 1) {
- hex = "0" + hex;
- }
-
- return hex;
- }
-
- /**
- * Create a random pastel color.
- *
- * @return a color
- */
- @Nonnull
- public static Color getRandomPastel() {
- Random random = new Random();
-
- final float hue = random.nextFloat();
- final float saturation = 0.9f; // 1.0 for brilliant, 0.0 for dull
- final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
-
- return Color.getHSBColor(hue, saturation, luminance);
- }
-
- /**
- * Create a random pastel color based on a seed.
- *
- * @param seed the seed
- * @return a color
- */
- @Nonnull
- public static Color getRandomPastel(int seed) {
- final float hue;
- if (seed != 0) {
- hue = 1.0F / ((((long) seed) << 32) >>> 32); // Remove the sign
- } else {
- hue = 1.0F;
- }
-
- final float saturation = 0.9f; // 1.0 for brilliant, 0.0 for dull
- final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
-
- return Color.getHSBColor(hue, saturation, luminance);
- }
-
- private Colors() {}
-}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/sched/src/com/android/sched/util/ConcurrentIOException.java
similarity index 66%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to sched/src/com/android/sched/util/ConcurrentIOException.java
index 0c967d9..b3ea109 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/sched/src/com/android/sched/util/ConcurrentIOException.java
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
-
-import java.util.Collection;
+package com.android.sched.util;
import javax.annotation.Nonnull;
/**
- * Virtual directory.
+ * Thrown when an external change to the file system prevents continuing the current processing.
*/
-public interface VDir extends VElement {
+public class ConcurrentIOException extends UnrecoverableException {
- @Nonnull
- Collection<? extends VElement> list();
+ private static final long serialVersionUID = 1L;
+
+ public ConcurrentIOException(@Nonnull Throwable cause) {
+ super(cause);
+ }
}
diff --git a/sched/src/com/android/sched/util/UnrecoverableException.java b/sched/src/com/android/sched/util/UnrecoverableException.java
new file mode 100644
index 0000000..a3f2dff
--- /dev/null
+++ b/sched/src/com/android/sched/util/UnrecoverableException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.util;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Thrown when a major problem occurred because of an event out of our control.
+ * Handling this error should only be reporting to the user and maybe just retry exactly the same
+ * thing as the one that has thrown.
+ */
+public abstract class UnrecoverableException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UnrecoverableException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+ @Override
+ public String getMessage() {
+ return getCause().getMessage();
+ }
+}
diff --git a/sched/src/com/android/sched/util/codec/ClassSelector.java b/sched/src/com/android/sched/util/codec/ClassSelector.java
index c8f45c5..f3f8cb9 100644
--- a/sched/src/com/android/sched/util/codec/ClassSelector.java
+++ b/sched/src/com/android/sched/util/codec/ClassSelector.java
@@ -18,6 +18,8 @@
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import javax.annotation.Nonnull;
@@ -44,8 +46,8 @@
public void checkValue(@Nonnull CodecContext context, @Nonnull Class<? extends T> cls)
throws CheckingException {
if (!checkClass(cls)) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(cls) + "'");
+ throw new CheckingException("The value must be {" + Joiner.on(',').join(getClasses())
+ + "} but is '" + cls.getCanonicalName() + "'");
}
}
diff --git a/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java b/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
index c357b9d..6a5c110 100644
--- a/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
+++ b/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
@@ -17,6 +17,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.DefaultFactory;
import com.android.sched.util.config.ReflectDefaultCtorFactory;
@@ -56,8 +58,9 @@
public void checkValue(@Nonnull CodecContext context, @Nonnull DefaultFactory<T> factory)
throws CheckingException {
if (!checkClass(factory.getInstanciatedClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(factory) + "'");
+ throw new CheckingException("The value must be a DefaultFactory<{"
+ + Joiner.on(',').join(getClasses()) + "}> but is a DefaultFactory<"
+ + factory.getInstanciatedClass().getCanonicalName() + ">");
}
}
diff --git a/sched/src/com/android/sched/util/codec/DoubleCodec.java b/sched/src/com/android/sched/util/codec/DoubleCodec.java
index 44ee717..a2be42f 100644
--- a/sched/src/com/android/sched/util/codec/DoubleCodec.java
+++ b/sched/src/com/android/sched/util/codec/DoubleCodec.java
@@ -72,7 +72,7 @@
if (v < min || v > max) {
throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(d) + "'");
+ "The value must be " + getUsage() + " but is " + d);
}
}
diff --git a/sched/src/com/android/sched/util/codec/ImplementationSelector.java b/sched/src/com/android/sched/util/codec/ImplementationSelector.java
index 1f06a15..e242be7 100644
--- a/sched/src/com/android/sched/util/codec/ImplementationSelector.java
+++ b/sched/src/com/android/sched/util/codec/ImplementationSelector.java
@@ -16,6 +16,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.ReflectDefaultCtorFactory;
@@ -56,8 +58,9 @@
public void checkValue(@Nonnull CodecContext context, @Nonnull T data)
throws CheckingException {
if (!checkClass((Class<? extends T>) data.getClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(data) + "'");
+ throw new CheckingException("The value must be an instance of {"
+ + Joiner.on(',').join(getClasses()) + "} but is an instance of '"
+ + data.getClass().getCanonicalName() + "'");
}
}
diff --git a/sched/src/com/android/sched/util/codec/KeyValueCodec.java b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
index ec9db66..4f16b47 100644
--- a/sched/src/com/android/sched/util/codec/KeyValueCodec.java
+++ b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
@@ -20,6 +20,8 @@
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
import javax.annotation.Nonnull;
@@ -109,8 +111,28 @@
}
}
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(value) + "'");
+ Set<T> set = new HashSet<T>();
+ for (Entry<T> entry : entries) {
+ set.add(entry.value);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (T data : set) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+
+ sb.append(data);
+ sb.append(" (");
+ sb.append(data.getClass().getCanonicalName());
+ sb.append(')');
+ }
+
+ throw new CheckingException("The value must be {" + sb.toString() + "} but is '" + value + " ("
+ + value.getClass().getCanonicalName() + ")'");
}
@Override
diff --git a/sched/src/com/android/sched/util/codec/LongCodec.java b/sched/src/com/android/sched/util/codec/LongCodec.java
index 4c4153c..cf9b8da 100644
--- a/sched/src/com/android/sched/util/codec/LongCodec.java
+++ b/sched/src/com/android/sched/util/codec/LongCodec.java
@@ -76,7 +76,7 @@
if (v < min || v > max) {
throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(l) + "'");
+ "The value must be " + getUsage() + " but is " + l);
}
}
diff --git a/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java b/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
index 43819f7..3ea1073 100644
--- a/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
+++ b/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
@@ -16,6 +16,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.ReflectFactory;
@@ -78,8 +80,9 @@
public void checkValue(@Nonnull CodecContext context, @Nonnull ReflectFactory<T> factory)
throws CheckingException {
if (!checkClass(factory.getInstanciatedClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(factory) + "'");
+ throw new CheckingException("The value must be a ReflectFactory<{"
+ + Joiner.on(',').join(getClasses()) + "}> but is a ReflectFactory<"
+ + factory.getInstanciatedClass().getCanonicalName() + ">");
}
}
diff --git a/sched/src/com/android/sched/util/codec/Selector.java b/sched/src/com/android/sched/util/codec/Selector.java
index 799f106..3e4d90e 100644
--- a/sched/src/com/android/sched/util/codec/Selector.java
+++ b/sched/src/com/android/sched/util/codec/Selector.java
@@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -85,6 +86,7 @@
public String getName(@Nonnull Class<? extends T> type) {
ensureScan();
assert propertyValues != null;
+
for (Entry<String, Class<? extends T>> entry : propertyValues.entrySet()) {
if (entry.getValue() == type) {
return entry.getKey();
@@ -127,6 +129,17 @@
return list;
}
+ @Nonnull
+ public Set<Class<? extends T>> getClasses() {
+ ensureScan();
+ assert propertyValues != null;
+
+ Set<Class<? extends T>> set = new HashSet<Class<? extends T>>();
+ set.addAll(propertyValues.values());
+
+ return set;
+ }
+
private synchronized void ensureScan() {
if (propertyValues == null) {
propertyValues = new HashMap<String, Class<? extends T>>();
diff --git a/sched/src/com/android/sched/util/config/AsapConfigBuilder.java b/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
index 0b8bdf2..597d44e 100644
--- a/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
+++ b/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
@@ -38,6 +38,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -69,11 +70,11 @@
new HashMap<KeyId<?, ?>, FieldLocation>();
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById =
- new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> valuesById =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<ObjectId<?>, Object> instanceValuesById =
+ private final Map<ObjectId<?>, Object> instances =
new HashMap<ObjectId<?>, Object>();
@Nonnull
@@ -182,13 +183,7 @@
}
@Nonnull
- public AsapConfigBuilder set(@Nonnull String name, @Nonnull String value)
- throws UnknownPropertyNameException, PropertyIdException {
- return set(name, value, defaultLocations.peek());
- }
-
- @Nonnull
- public AsapConfigBuilder set(
+ public AsapConfigBuilder setString(
@Nonnull String name, @Nonnull String value, @Nonnull Location location)
throws UnknownPropertyNameException, PropertyIdException {
KeyId<?, ?> keyId = keyIdsByName.get(name);
@@ -197,7 +192,7 @@
}
try {
- set((PropertyId<?>) keyId, value, location);
+ setString((PropertyId<?>) keyId, value, location);
} catch (UnknownPropertyIdException e) {
throw new AssertionError();
}
@@ -206,13 +201,36 @@
}
@Nonnull
- public AsapConfigBuilder set(@Nonnull PropertyId<?> propertyId, @Nonnull String value)
- throws PropertyIdException {
- return set(propertyId, value, defaultLocations.peek());
+ public <T> AsapConfigBuilder set(
+ @Nonnull String name, @Nonnull T value, @Nonnull Location location)
+ throws UnknownPropertyNameException, PropertyIdException {
+ KeyId<?, ?> keyId = keyIdsByName.get(name);
+ if (keyId == null || !(keyId instanceof PropertyId)) {
+ throw new UnknownPropertyNameException(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ PropertyId<T> propertyId = (PropertyId<T>) keyId;
+
+ if (context.isDebug()) {
+ try {
+ propertyId.getCodec().checkValue(context, value);
+ } catch (Exception e) {
+ throw new ConfigurationError("Property '" + name + "': " + e.getMessage());
+ }
+ }
+
+ try {
+ set(propertyId, value, location);
+ } catch (UnknownPropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
}
@Nonnull
- public AsapConfigBuilder set(
+ public AsapConfigBuilder setString(
@Nonnull PropertyId<?> propertyId, @Nonnull String value, @Nonnull Location location)
throws PropertyIdException {
if (!keyIdsByName.values().contains(propertyId)) {
@@ -227,21 +245,39 @@
}
}
- stringValuesById.put(propertyId, value);
+ valuesById.put(propertyId, propertyId.new Value(value));
+ locationsByKeyId.put(propertyId, location);
+
+ return this;
+ }
+
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(
+ @Nonnull PropertyId<T> propertyId, @Nonnull T value, @Nonnull Location location)
+ throws PropertyIdException {
+ if (!keyIdsByName.values().contains(propertyId)) {
+ throw new UnknownPropertyIdException(propertyId);
+ }
+
+ if (context.isDebug()) {
+ try {
+ propertyId.getCodec().checkValue(context, value);
+ } catch (Exception e) {
+ throw new ConfigurationError("Property '" + propertyId.getName() + "': " + e.getMessage());
+ }
+ }
+
+ valuesById.put(propertyId, propertyId.new Value(value));
locationsByKeyId.put(propertyId, location);
return this;
}
@Nonnull
- public <T> AsapConfigBuilder set(@Nonnull ObjectId<T> objectId, @Nonnull T value) {
- return set(objectId, value, defaultLocations.peek());
- }
-
- @Nonnull
public <T> AsapConfigBuilder set(
@Nonnull ObjectId<T> objectId, @Nonnull T value, @Nonnull Location location) {
- instanceValuesById.put(objectId, value);
+ instances.put(objectId, value);
locationsByKeyId.put(objectId, location);
return this;
@@ -276,7 +312,7 @@
* @throws ConfigurationException
*/
@Nonnull
- public Config build() throws ConfigurationException {
+ public <X> Config build() throws ConfigurationException {
ChainedExceptionBuilder<ConfigurationException> exceptions =
new ChainedExceptionBuilder<ConfigurationException>();
@@ -286,12 +322,14 @@
logger.setLevel(Level.INFO);
}
- @Nonnull Map<PropertyId<?>, String> values = new HashMap<PropertyId<?>, String>();
+ @Nonnull
+ Map<PropertyId<?>, PropertyId<?>.Value> values =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
processValues(values);
processDefaultValues(values);
ConfigChecker checker =
- new ConfigChecker(context, values, instanceValuesById, locationsByKeyId);
+ new ConfigChecker(context, values, instances, locationsByKeyId);
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
boolean needChecks = false;
@@ -343,15 +381,15 @@
if (context.isDebug()) {
return new ConfigDebug(
- context, checker.getStrings(), checker.getInstances(), checker.getDropCauses());
+ context, checker.getValues(), checker.getInstances(), checker.getDropCauses());
} else {
- return new ConfigImpl(context, checker.getStrings(), checker.getInstances());
+ return new ConfigImpl(context, checker.getValues(), checker.getInstances());
}
}
@Nonnull
public Collection<PropertyId<?>> getPropertyIds() {
- ArrayList<PropertyId<?>> result = new ArrayList<PropertyId<?>>(keyIdsByName.size());
+ List<PropertyId<?>> result = new ArrayList<PropertyId<?>>(keyIdsByName.size());
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
if (keyId.isPublic() && keyId instanceof PropertyId<?>) {
@@ -363,15 +401,21 @@
}
@CheckForNull
- public String getDefaultValue(@Nonnull PropertyId<?> propertyId) {
- return propertyId.getDefaultValue(context);
+ public <T> String getDefaultValue(@Nonnull PropertyId<T> propertyId) {
+ PropertyId<T>.Value value = propertyId.getDefaultValue(context);
+
+ if (value != null) {
+ return value.getString();
+ } else {
+ return null;
+ }
}
- private void processValues(@Nonnull Map<PropertyId<?>, String> values) {
- values.putAll(stringValuesById);
+ private void processValues(@Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values) {
+ values.putAll(valuesById);
}
- private void processDefaultValues(@Nonnull Map<PropertyId<?>, String> values) {
+ private void processDefaultValues(@Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values) {
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
if (keyId instanceof PropertyId) {
PropertyId<?> propertyId = (PropertyId<?>) keyId;
@@ -427,7 +471,7 @@
try {
assert propertyId != null;
- set(propertyId, value, new EnvironmentLocation(envKey));
+ setString(propertyId, value, new EnvironmentLocation(envKey));
} catch (ConfigurationException e) {
exceptions.appendException(e);
}
@@ -450,6 +494,10 @@
return this;
}
+ //
+ // Default location
+ //
+
public void pushDefaultLocation(@Nonnull Location location) {
defaultLocations.push(location);
}
@@ -458,4 +506,221 @@
assert defaultLocations.size() > 1;
defaultLocations.pop();
}
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull ObjectId<T> objectId, @Nonnull T value) {
+ return set(objectId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull String name, @Nonnull T value)
+ throws UnknownPropertyNameException, PropertyIdException {
+ return set(name, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull PropertyId<T> propertyId, @Nonnull T value)
+ throws PropertyIdException {
+ return set(propertyId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public AsapConfigBuilder setString(@Nonnull PropertyId<?> propertyId, @Nonnull String value)
+ throws PropertyIdException {
+ return setString(propertyId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public AsapConfigBuilder setString(@Nonnull String name, @Nonnull String value)
+ throws UnknownPropertyNameException, PropertyIdException {
+ return setString(name, value, defaultLocations.peek());
+ }
+
+ //
+ // Commodity helper
+ //
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value) {
+ try {
+ set(propertyId, Boolean.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Boolean.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value) {
+ try {
+ set(propertyId, Byte.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Byte.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value) {
+ try {
+ set(propertyId, Short.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Short.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value) {
+ try {
+ set(propertyId, Character.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Character.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value) {
+ try {
+ set(propertyId, Integer.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Integer.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value) {
+ try {
+ set(propertyId, Long.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Long.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value) {
+ try {
+ set(propertyId, Float.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Float.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value) {
+ try {
+ set(propertyId, Double.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Double.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
}
diff --git a/sched/src/com/android/sched/util/config/Config.java b/sched/src/com/android/sched/util/config/Config.java
index 40faa5c..2bbf884 100644
--- a/sched/src/com/android/sched/util/config/Config.java
+++ b/sched/src/com/android/sched/util/config/Config.java
@@ -17,18 +17,22 @@
package com.android.sched.util.config;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import java.util.Collection;
import javax.annotation.Nonnull;
-
/**
- * The class that deals with configuration properties in 'get' mode.
+ * The interface that deals with configuration properties in 'get' mode.
*/
public interface Config {
@Nonnull
+ public <T> T get(@Nonnull PropertyId<T> propertyId);
+ @Nonnull
+ public <T> T get(@Nonnull ObjectId<T> objectId);
+ @Nonnull
public <T, S> T get(@Nonnull KeyId<T, S> keyId);
@Nonnull
public <T> String getAsString(@Nonnull PropertyId<T> propertyId);
diff --git a/sched/src/com/android/sched/util/config/ConfigChecker.java b/sched/src/com/android/sched/util/config/ConfigChecker.java
index 4f151c8..781d77a 100644
--- a/sched/src/com/android/sched/util/config/ConfigChecker.java
+++ b/sched/src/com/android/sched/util/config/ConfigChecker.java
@@ -18,10 +18,10 @@
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.codec.ParsingException;
-import com.android.sched.util.codec.StringCodec;
import com.android.sched.util.config.id.KeyId;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
+import com.android.sched.util.config.id.PropertyId.Value;
import java.util.HashMap;
import java.util.Map;
@@ -35,14 +35,15 @@
@Nonnull
private final CodecContext context;
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById = new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> values =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<KeyId<?, ?>, Object> instanceValuesById = new HashMap<KeyId<?, ?>, Object>();
+ private final Map<KeyId<?, ?>, Object> instances = new HashMap<KeyId<?, ?>, Object>();
@Nonnull
- private final Map<KeyId<?, ?>, Location> locationsById =
+ private final Map<KeyId<?, ?>, Location> locations =
new HashMap<KeyId<?, ?>, Location>();
@Nonnull
- private final Map<KeyId<?, ?>, String> droppedById = new HashMap<KeyId<?, ?>, String>();
+ private final Map<KeyId<?, ?>, String> dropped = new HashMap<KeyId<?, ?>, String>();
/**
* @param context Context for parsers
@@ -50,57 +51,50 @@
* @param instanceValues All the property values as objects.
*/
ConfigChecker(@Nonnull CodecContext context,
- @Nonnull Map<PropertyId<?>, String> stringValues,
+ @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> stringValues,
@Nonnull Map<ObjectId<?>, Object> instanceValues,
@Nonnull Map<KeyId<?, ?>, Location> locationsById) {
this.context = context;
- this.stringValuesById.putAll(stringValues);
- this.instanceValuesById.putAll(instanceValues);
- this.locationsById.putAll(locationsById);
+ this.values.putAll(stringValues);
+ this.instances.putAll(instanceValues);
+ this.locations.putAll(locationsById);
}
@Nonnull
- public synchronized <T> T parse(@Nonnull PropertyId<T> propertyId) throws PropertyIdException
- {
- @SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(propertyId);
+ public synchronized <T> T parse(@Nonnull PropertyId<T> propertyId) throws PropertyIdException {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) values.get(propertyId);
- if (instance == null) {
- String value = getRawValue(propertyId);
- try {
- StringCodec<T> parser = propertyId.getCodec();
-
- instance = parser.checkString(context, value);
- if (instance == null) {
- instance = parser.parseString(context, value);
- }
-
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(propertyId);
- } catch (ParsingException e) {
- throw new PropertyIdException(propertyId, getLocation(propertyId), e);
- }
+ if (value == null) {
+ throw new MissingPropertyException(propertyId);
}
- return instance;
+ try {
+ value.check(context);
+ return value.getObject(context);
+ } catch (ParsingException e) {
+ throw new PropertyIdException(propertyId, getLocation(propertyId), e);
+ }
}
public synchronized <T, S> void check(@Nonnull KeyId<T, S> keyId) throws PropertyIdException {
- if (instanceValuesById.get(keyId) == null) {
+ if (instances.get(keyId) == null) {
if (keyId instanceof PropertyId) {
@SuppressWarnings("unchecked")
PropertyId<T> propertyId = (PropertyId<T>) keyId;
- String value = getRawValue(propertyId);
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) values.get(propertyId);
+
+ if (value == null) {
+ throw new MissingPropertyException(propertyId);
+ }
+
try {
- T instance = propertyId.getCodec().checkString(context, value);
- if (instance != null) {
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(keyId);
- }
+ value.check(context);
} catch (ParsingException e) {
throw new PropertyIdException(propertyId, getLocation(propertyId), e);
}
-
} else {
assert keyId instanceof ObjectId;
@@ -114,41 +108,42 @@
@Nonnull
public <T> String getRawValue(@Nonnull PropertyId<T> propertyId)
throws MissingPropertyException {
- String value = stringValuesById.get(propertyId);
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ PropertyId<T>.Value value = (Value) values.get(propertyId);
if (value == null) {
throw new MissingPropertyException(propertyId);
}
- return value;
+ return value.getString();
}
@Nonnull
public Map<KeyId<?, ?>, Object> getInstances() {
- return instanceValuesById;
+ return instances;
}
@Nonnull
- public Map<PropertyId<?>, String> getStrings() {
- return stringValuesById;
+ public Map<PropertyId<?>, PropertyId<?>.Value> getValues() {
+ return values;
}
@Nonnull
public Map<KeyId<?, ?>, String> getDropCauses() {
- return droppedById;
+ return dropped;
}
@Nonnull
public Location getLocation(@Nonnull KeyId<?, ?> keyId) {
- assert locationsById.get(keyId) != null;
+ assert locations.get(keyId) != null;
- return locationsById.get(keyId);
+ return locations.get(keyId);
}
public void remove(@Nonnull KeyId<?, ?> keyId, @Nonnull String cause) {
- stringValuesById.remove(keyId);
- instanceValuesById.remove(keyId);
- locationsById.remove(keyId);
- droppedById.put(keyId, cause);
+ values.remove(keyId);
+ instances.remove(keyId);
+ locations.remove(keyId);
+ dropped.put(keyId, cause);
}
}
diff --git a/sched/src/com/android/sched/util/config/ConfigDebug.java b/sched/src/com/android/sched/util/config/ConfigDebug.java
index f7b5a94..db926d1 100644
--- a/sched/src/com/android/sched/util/config/ConfigDebug.java
+++ b/sched/src/com/android/sched/util/config/ConfigDebug.java
@@ -18,6 +18,7 @@
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import com.android.sched.util.log.LoggerFactory;
@@ -47,16 +48,29 @@
}
};
- ConfigDebug(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, String> stringValues,
- @Nonnull Map<KeyId<?, ?>, Object> instanceValues,
+ ConfigDebug(@Nonnull CodecContext context,
+ @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values,
+ @Nonnull Map<KeyId<?, ?>, Object> instances,
@Nonnull Map<KeyId<?, ?>, String> dropCauses) {
- super(context, stringValues, instanceValues);
+ super(context, values, instances);
this.dropCauses = new HashMap<KeyId<?, ?>, String>(dropCauses);
}
@Override
@Nonnull
+ public synchronized <T> T get(@Nonnull PropertyId<T> propertyId) {
+ return get((KeyId<T, ?>) propertyId);
+ }
+
+ @Override
+ @Nonnull
+ public synchronized <T> T get(@Nonnull ObjectId<T> objectId) {
+ return get((KeyId<T, ?>) objectId);
+ }
+
+ @Override
+ @Nonnull
public <T, S> T get(@Nonnull KeyId<T, S> keyId) {
Stack<KeyId<?, ?>> localKeyIds = keyIds.get();
diff --git a/sched/src/com/android/sched/util/config/ConfigImpl.java b/sched/src/com/android/sched/util/config/ConfigImpl.java
index 00a1bce..d3d6ee9 100644
--- a/sched/src/com/android/sched/util/config/ConfigImpl.java
+++ b/sched/src/com/android/sched/util/config/ConfigImpl.java
@@ -26,71 +26,110 @@
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Implementation of a fully built {@code Config}.
*/
-class ConfigImpl implements Config {
+class ConfigImpl implements Config, InternalConfig {
@Nonnull
private final CodecContext context;
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById = new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> valuesById =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<KeyId<?, ?>, Object> instanceValuesById = new HashMap<KeyId<?, ?>, Object>();
+ private final Map<KeyId<?, ?>, Object> instancesById = new HashMap<KeyId<?, ?>, Object>();
/**
* @param context Context for parsers
- * @param stringValues All the property values as {@code String} objects.
- * @param instanceValues All the property values as objects.
+ * @param values All the property values as {@code String} objects.
+ * @param instances All the property values as objects.
*/
- ConfigImpl(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, String> stringValues,
- @Nonnull Map<KeyId<?, ?>, Object> instanceValues) {
+ ConfigImpl(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values,
+ @Nonnull Map<KeyId<?, ?>, Object> instances) {
this.context = context;
- this.stringValuesById.putAll(stringValues);
- this.instanceValuesById.putAll(instanceValues);
+ this.valuesById.putAll(values);
+ this.instancesById.putAll(instances);
}
@Override
@Nonnull
- public synchronized <T, S> T get(@Nonnull KeyId<T, S> keyId) {
+ public <T> T get(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
+
+ return value.getObject(context);
+ }
+
+ @Override
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
+
+ return value.getObjectIfAny();
+ }
+
+ @Override
+ @Nonnull
+ public <T> String getAsString(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
+
+ return value.getString();
+ }
+
+ @Override
+ @Nonnull
+ public synchronized <T> T get(@Nonnull ObjectId<T> objectId) {
@SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(keyId);
+ T instance = (T) instancesById.get(objectId);
if (instance == null) {
- if (keyId instanceof PropertyId) {
- @SuppressWarnings("unchecked")
- PropertyId<T> propertyId = (PropertyId<T>) keyId;
-
- String value = stringValuesById.get(propertyId);
- if (value == null) {
- throw new ConfigurationError("Property '" + propertyId.getName()
- + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
- + " or requiredIf expression)");
- }
-
- instance = propertyId.getCodec().parseString(context, value);
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(propertyId);
- } else {
- @SuppressWarnings("unchecked")
- ObjectId<T> objectId = (ObjectId<T>) keyId;
-
- instance = objectId.createObject();
- instanceValuesById.put(objectId, instance);
- }
+ instance = objectId.createObject();
+ instancesById.put(objectId, instance);
}
return instance;
}
+ @SuppressWarnings("unchecked")
+ @Override
+ @Nonnull
+ public <T, S> T get(@Nonnull KeyId<T, S> keyId) {
+ if (keyId instanceof PropertyId) {
+ return get((PropertyId<T>) keyId);
+ } else {
+ return get((ObjectId<T>) keyId);
+ }
+ }
+
@Override
@Nonnull
public Collection<PropertyId<?>> getPropertyIds() {
ArrayList<PropertyId<?>> result =
- new ArrayList<PropertyId<?>>(instanceValuesById.size() + stringValuesById.size());
+ new ArrayList<PropertyId<?>>(instancesById.size() + valuesById.size());
- for (KeyId<?, ?> keyId : stringValuesById.keySet()) {
+ for (KeyId<?, ?> keyId : valuesById.keySet()) {
if (keyId.isPublic()) {
if (keyId instanceof PropertyId) {
result.add((PropertyId<?>) keyId);
@@ -98,7 +137,7 @@
}
}
- for (KeyId<?, ?> keyId : instanceValuesById.keySet()) {
+ for (KeyId<?, ?> keyId : instancesById.keySet()) {
if (keyId.isPublic()) {
if (keyId instanceof PropertyId) {
result.add((PropertyId<?>) keyId);
@@ -108,25 +147,4 @@
return result;
}
-
- @Override
- @Nonnull
- public <T> String getAsString(@Nonnull PropertyId<T> propertyId) {
- String result;
-
- result = stringValuesById.get(propertyId);
- if (result == null) {
- @SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(propertyId);
- if (instance == null) {
- throw new ConfigurationError("Property '" + propertyId.getName()
- + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
- + " or requiredIf expression)");
- }
-
- result = propertyId.getCodec().formatValue(instance);
- }
-
- return result;
- }
}
diff --git a/sched/src/com/android/sched/util/config/ConfigurationError.java b/sched/src/com/android/sched/util/config/ConfigurationError.java
index 9ca2b2b..fef0795 100644
--- a/sched/src/com/android/sched/util/config/ConfigurationError.java
+++ b/sched/src/com/android/sched/util/config/ConfigurationError.java
@@ -16,6 +16,7 @@
package com.android.sched.util.config;
+import com.android.sched.util.codec.CheckingException;
import com.android.sched.util.codec.ParsingException;
import javax.annotation.Nonnull;
@@ -43,4 +44,8 @@
public ConfigurationError(@Nonnull ParsingException e) {
super(e.getMessage(), e);
}
+
+ public ConfigurationError(@Nonnull CheckingException e) {
+ super(e.getMessage(), e);
+ }
}
diff --git a/sched/src/com/android/sched/util/config/GatherConfigBuilder.java b/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
index b923541..133ef88 100644
--- a/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
+++ b/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
@@ -54,7 +54,21 @@
}
@Nonnull
- public GatherConfigBuilder set(@Nonnull String name, @Nonnull String value) {
+ public GatherConfigBuilder setString(@Nonnull String name, @Nonnull String value) {
+ try {
+ builder.setString(name, value);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (UnknownPropertyNameException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(@Nonnull String name, @Nonnull T value) {
try {
builder.set(name, value);
} catch (PropertyIdException e) {
@@ -67,9 +81,24 @@
}
@Nonnull
- public GatherConfigBuilder set(
+ public GatherConfigBuilder setString(
@Nonnull String name, @Nonnull String value, @Nonnull Location location) {
try {
+ builder.setString(name, value, location);
+ } catch (UnknownPropertyNameException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(
+ @Nonnull String name, @Nonnull T value, @Nonnull Location location) {
+ try {
builder.set(name, value, location);
} catch (UnknownPropertyNameException e) {
exceptions.appendException(e);
@@ -81,7 +110,20 @@
}
@Nonnull
- public GatherConfigBuilder set(@Nonnull PropertyId<?> propertyId, @Nonnull String value) {
+ public GatherConfigBuilder setString(@Nonnull PropertyId<?> propertyId, @Nonnull String value) {
+ try {
+ builder.setString(propertyId, value);
+ } catch (UnknownPropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(@Nonnull PropertyId<T> propertyId, @Nonnull T value) {
try {
builder.set(propertyId, value);
} catch (UnknownPropertyIdException e) {
@@ -94,9 +136,23 @@
}
@Nonnull
- public GatherConfigBuilder set(
+ public GatherConfigBuilder setString(
@Nonnull PropertyId<?> propertyId, @Nonnull String value, @Nonnull Location location) {
try {
+ builder.setString(propertyId, value, location);
+ } catch (UnknownPropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(
+ @Nonnull PropertyId<T> propertyId, @Nonnull T value, @Nonnull Location location) {
+ try {
builder.set(propertyId, value, location);
} catch (UnknownPropertyIdException e) {
exceptions.appendException(e);
@@ -151,12 +207,18 @@
*/
@Nonnull
public Config build() throws ConfigurationException {
+ Config config;
+
try {
- return builder.build();
+ config = builder.build();
} catch (ConfigurationException e) {
exceptions.appendException(e);
throw exceptions.getException();
}
+
+ exceptions.throwIfNecessary();
+
+ return config;
}
@Nonnull
@@ -180,6 +242,10 @@
return this;
}
+ //
+ // Default location
+ //
+
public void pushDefaultLocation(@Nonnull Location location) {
builder.pushDefaultLocation(location);
}
@@ -187,4 +253,128 @@
public void popDefaultLocation() {
builder.popDefaultLocation();
}
+
+ //
+ // Commodity helper
+ //
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value) {
+ set(propertyId, Boolean.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value,
+ @Nonnull Location location) {
+ set(propertyId, Boolean.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value) {
+ set(propertyId, Byte.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value,
+ @Nonnull Location location) {
+ set(propertyId, Byte.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value) {
+ set(propertyId, Short.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value,
+ @Nonnull Location location) {
+ set(propertyId, Short.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value) {
+ set(propertyId, Character.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value,
+ @Nonnull Location location) {
+ set(propertyId, Character.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value) {
+ set(propertyId, Integer.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value,
+ @Nonnull Location location) {
+ set(propertyId, Integer.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value) {
+ set(propertyId, Long.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value,
+ @Nonnull Location location) {
+ set(propertyId, Long.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value) {
+ set(propertyId, Float.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value,
+ @Nonnull Location location) {
+ set(propertyId, Float.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value) {
+ set(propertyId, Double.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value,
+ @Nonnull Location location) {
+ set(propertyId, Double.valueOf(value), location);
+
+ return this;
+ }
}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/sched/src/com/android/sched/util/config/InternalConfig.java
similarity index 62%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to sched/src/com/android/sched/util/config/InternalConfig.java
index 0c967d9..0f96a98 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/sched/src/com/android/sched/util/config/InternalConfig.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.util.config;
-import java.util.Collection;
+import com.android.sched.util.config.id.PropertyId;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
- * Virtual directory.
+ * The interface that deals with configuration properties in private 'get' mode. This interface is
+ * for private use only (config framework itself).
*/
-public interface VDir extends VElement {
-
- @Nonnull
- Collection<? extends VElement> list();
-
+public interface InternalConfig {
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId);
}
diff --git a/sched/src/com/android/sched/util/config/ThreadConfig.java b/sched/src/com/android/sched/util/config/ThreadConfig.java
index df8cfa5..da532fd 100644
--- a/sched/src/com/android/sched/util/config/ThreadConfig.java
+++ b/sched/src/com/android/sched/util/config/ThreadConfig.java
@@ -16,7 +16,14 @@
package com.android.sched.util.config;
-import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
+import com.android.sched.util.config.id.PropertyId;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.Counter;
+import com.android.sched.util.log.stats.CounterImpl;
+import com.android.sched.util.log.stats.StatisticId;
+import com.android.sched.util.log.tracer.TracerEventType;
import javax.annotation.Nonnull;
@@ -25,6 +32,11 @@
*/
public class ThreadConfig {
@Nonnull
+ public static final StatisticId<Counter> TLS_READ = new StatisticId<Counter>(
+ "sched.config.tls.read", "Reading TLS to get current config",
+ CounterImpl.class, Counter.class);
+
+ @Nonnull
private static final Config unitializedConfig = new UninitializedConfig();
@Nonnull
@@ -37,8 +49,27 @@
};
@Nonnull
- public static <T, S> T get(@Nonnull KeyId<T, S> keyId) {
- return threadLocalConfig.get().get(keyId);
+ public static <T> T get(@Nonnull PropertyId<T> propertyId) {
+ Config config = threadLocalConfig.get();
+ updateStatistic(config);
+
+ return config.get(propertyId);
+ }
+
+ @Nonnull
+ public static <T> T get(@Nonnull ObjectId<T> objectId) {
+ Config config = threadLocalConfig.get();
+ updateStatistic(config);
+
+ return config.get(objectId);
+ }
+
+ private static void updateStatistic(@Nonnull Config config) {
+ Tracer tracer = ((InternalConfig) config).<Tracer> getObjectIfAny(TracerFactory.TRACER);
+
+ if (tracer != null && tracer.getCurrentEventType() != TracerEventType.NOEVENT) {
+ tracer.getStatistic(TLS_READ).incValue();
+ }
}
@Nonnull
diff --git a/sched/src/com/android/sched/util/config/UninitializedConfig.java b/sched/src/com/android/sched/util/config/UninitializedConfig.java
index f87e628..b6c8e7f 100644
--- a/sched/src/com/android/sched/util/config/UninitializedConfig.java
+++ b/sched/src/com/android/sched/util/config/UninitializedConfig.java
@@ -17,16 +17,29 @@
package com.android.sched.util.config;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import java.util.Collection;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* This object represents a {@link Config} which has not been created by the builder.
*/
-class UninitializedConfig implements Config {
+class UninitializedConfig implements Config, InternalConfig {
+ @Override
+ @Nonnull
+ public <T> T get(@Nonnull PropertyId<T> propertyId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
+
+ @Override
+ @Nonnull
+ public <T> T get(@Nonnull ObjectId<T> objectId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
@Override
@Nonnull
@@ -45,4 +58,10 @@
public Collection<PropertyId<?>> getPropertyIds() {
throw new ConfigurationError("Configuration has not been initialized");
}
+
+ @Override
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
}
diff --git a/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java b/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
index 06c711c..788e852 100644
--- a/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
+++ b/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
@@ -25,7 +25,7 @@
private static final long serialVersionUID = 1L;
public VariableDoesNotMatchConfigurationException(@Nonnull String variable) {
- super(variable, "Environment variable '" + variable + " does not match any properties");
+ super(variable, "Environment variable '" + variable + "' does not match any properties");
}
public VariableDoesNotMatchConfigurationException(
diff --git a/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java b/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
index f6eaab6..1e00409 100644
--- a/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
+++ b/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
@@ -31,7 +31,7 @@
public VariableMatchesSeveralConfigurationException(
@Nonnull String variable, @Nonnull PropertyId<?> propertyId) {
- super(variable, "Environment variable '" + variable + " matches several properties: '"
+ super(variable, "Environment variable '" + variable + "' matches several properties: '"
+ propertyId.getName() + "'");
this.propertyId = propertyId;
}
diff --git a/sched/src/com/android/sched/util/config/ZipLocation.java b/sched/src/com/android/sched/util/config/ZipLocation.java
index 3a6d9be..af78749 100644
--- a/sched/src/com/android/sched/util/config/ZipLocation.java
+++ b/sched/src/com/android/sched/util/config/ZipLocation.java
@@ -30,11 +30,11 @@
private final Location archive;
@Nonnull
- private final String pathInArchive;
+ private final String entryName;
public ZipLocation(@Nonnull Location archive, @Nonnull ZipEntry entry) {
this.archive = archive;
- this.pathInArchive = '/' + entry.getName();
+ this.entryName = entry.getName();
}
@Override
@@ -46,7 +46,7 @@
sb.append(archive.getDescription()).append(", ");
}
- return sb.append("entry '").append(pathInArchive).append('\'').toString();
+ return sb.append("entry '/").append(entryName).append('\'').toString();
}
@Nonnull
@@ -54,22 +54,20 @@
return archive;
}
- /**
- * @return the pathInArchive
- */
- public String getPathInArchive() {
- return pathInArchive;
+ @Nonnull
+ public String getEntryName() {
+ return entryName;
}
@Override
public final boolean equals(Object obj) {
return obj instanceof ZipLocation
&& ((ZipLocation) obj).archive.equals(archive)
- && ((ZipLocation) obj).getPathInArchive().equals(pathInArchive);
+ && ((ZipLocation) obj).entryName.equals(entryName);
}
@Override
public final int hashCode() {
- return archive.hashCode() ^ pathInArchive.hashCode();
+ return archive.hashCode() ^ entryName.hashCode();
}
}
diff --git a/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java b/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
index ebe2399..a97bd45 100644
--- a/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
@@ -52,6 +52,21 @@
@Override
@Nonnull
+ public BooleanPropertyId addDefaultValue (@Nonnull Boolean defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public BooleanPropertyId addDefaultValue (boolean defaultValue) {
+ super.addDefaultValue(Boolean.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public BooleanPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/DoublePropertyId.java b/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
index 786c9b2..111fd5e 100644
--- a/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
@@ -51,6 +51,21 @@
@Override
@Nonnull
+ public DoublePropertyId addDefaultValue (@Nonnull Double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public DoublePropertyId addDefaultValue (@Nonnull double defaultValue) {
+ super.addDefaultValue(Double.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public DoublePropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
index 493f1e5..c209e3c 100644
--- a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
@@ -51,6 +51,14 @@
@Override
@Nonnull
+ public EnumPropertyId<T> addDefaultValue (@Nonnull T defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public EnumPropertyId<T> requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java b/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
index 4b584cd..ce03c10 100644
--- a/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
@@ -44,6 +44,20 @@
return this;
}
+ @Nonnull
+ public IntegerPropertyId addDefaultValue (@Nonnull Integer defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue.longValue()));
+
+ return this;
+ }
+
+ @Nonnull
+ public IntegerPropertyId addDefaultValue (@Nonnull int defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue));
+
+ return this;
+ }
+
@Override
@Nonnull
public IntegerPropertyId requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/KeyId.java b/sched/src/com/android/sched/util/config/id/KeyId.java
index 40b157c..3576fab 100644
--- a/sched/src/com/android/sched/util/config/id/KeyId.java
+++ b/sched/src/com/android/sched/util/config/id/KeyId.java
@@ -21,9 +21,6 @@
import com.android.sched.util.config.expression.BooleanExpression;
import com.android.sched.util.config.expression.PropertyNotRequiredException;
-import java.util.ArrayList;
-import java.util.List;
-
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -38,12 +35,6 @@
@Nonnull
private final String name;
- @CheckForNull
- private BooleanExpression requiredIf;
-
- @Nonnull
- private final List<S> defaultValues = new ArrayList<S>(2);
-
public KeyId(@Nonnull String name) {
this.name = name;
}
@@ -55,17 +46,8 @@
public abstract boolean isPublic();
- @Nonnull
- public KeyId<T, S> addDefaultValue(@Nonnull S defaultValue) {
- defaultValues.add(defaultValue);
-
- return this;
- }
-
- @Nonnull
- public List<S> getDefaultValues() {
- return defaultValues;
- }
+ @CheckForNull
+ private BooleanExpression requiredIf;
@Nonnull
public KeyId<T, S> requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/ListPropertyId.java b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
index 7f7c999..075fa00 100644
--- a/sched/src/com/android/sched/util/config/id/ListPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
@@ -55,6 +55,15 @@
return this;
}
+
+ @Override
+ @Nonnull
+ public ListPropertyId<T> addDefaultValue (@Nonnull List<T> defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
@Override
@Nonnull
public ListPropertyId<T> requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/LongPropertyId.java b/sched/src/com/android/sched/util/config/id/LongPropertyId.java
index cb1e377..7f95102 100644
--- a/sched/src/com/android/sched/util/config/id/LongPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/LongPropertyId.java
@@ -51,6 +51,21 @@
@Override
@Nonnull
+ public LongPropertyId addDefaultValue (@Nonnull Long defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public LongPropertyId addDefaultValue (@Nonnull long defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public LongPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java b/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
index 1e173e1..f83165b 100644
--- a/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
@@ -45,6 +45,22 @@
@Override
@Nonnull
+ public ProbabilityPropertyId addDefaultValue (@Nonnull Double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public ProbabilityPropertyId addDefaultValue (@Nonnull double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public ProbabilityPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
@@ -70,7 +86,7 @@
}
private boolean checkRange(double value) {
- return value >= 0 && value <= 1;
+ return value >= 0.0 && value <= 1.0;
}
/**
diff --git a/sched/src/com/android/sched/util/config/id/PropertyId.java b/sched/src/com/android/sched/util/config/id/PropertyId.java
index 7e9fa28..280bf08 100644
--- a/sched/src/com/android/sched/util/config/id/PropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/PropertyId.java
@@ -23,6 +23,9 @@
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.expression.BooleanExpression;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -31,48 +34,55 @@
* @param <T> Type of the configuration property.
*/
public class PropertyId<T> extends KeyId<T, String> {
-
@Nonnull
private final String description;
@Nonnull
- private final StringCodec<T> parser;
+ private final StringCodec<T> codec;
+ @Nonnull
+ private final List<Value> defaultValues = new ArrayList<Value>(1);
@CheckForNull
- private String defaultValue = null;
- private boolean defaultValueAvailable = false;
+ private Value defaultValue = null;
+ private boolean defaultValueAvailable = false;
private boolean isPublic = true;
public static <T> PropertyId<T> create(
- @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> parser) {
- return new PropertyId<T>(name, description, parser);
+ @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> codec) {
+ return new PropertyId<T>(name, description, codec);
}
- protected PropertyId(
- @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> parser) {
+ protected PropertyId(@Nonnull String name, @Nonnull String description,
+ @Nonnull StringCodec<T> codec) {
super(name);
this.description = description;
- this.parser = parser;
+ this.codec = codec;
}
- @Override
@Nonnull
public PropertyId<T> addDefaultValue(@Nonnull String defaultValue) {
- super.addDefaultValue(defaultValue);
+ defaultValues.add(new Value(defaultValue));
+
+ return this;
+ }
+
+ @Nonnull
+ public PropertyId<T> addDefaultValue(@Nonnull T defaultValue) {
+ defaultValues.add(new Value(defaultValue));
return this;
}
@CheckForNull
- public String getDefaultValue(@Nonnull CodecContext context) {
+ public Value getDefaultValue(@Nonnull CodecContext context) {
if (!defaultValueAvailable) {
ParsingException lastException = null;
- for (String value : getDefaultValues()) {
+ for (Value value : getDefaultValues()) {
try {
- parser.checkString(context, value);
+ value.check(context);
defaultValue = value;
break;
} catch (ParsingException e) {
@@ -91,6 +101,11 @@
}
@Nonnull
+ public List<Value> getDefaultValues() {
+ return defaultValues;
+ }
+
+ @Nonnull
public String getDescription() {
return description;
}
@@ -100,6 +115,7 @@
return isPublic;
}
+ @Nonnull
public PropertyId<T> makePrivate() {
isPublic = false;
return this;
@@ -107,7 +123,7 @@
@Nonnull
public StringCodec<T> getCodec() {
- return parser;
+ return codec;
}
@Override
@@ -118,4 +134,148 @@
return this;
}
+ public class Value {
+ @Nonnull
+ private IValue<T> value;
+
+ public Value (@Nonnull T value) {
+ this.value = new IValueObject<T>(value);
+ }
+
+ public Value (@Nonnull String value) {
+ this.value = new IValueString(value);
+ }
+
+ public synchronized void check(@Nonnull CodecContext context) throws ParsingException {
+ value = value.check(context);
+ }
+
+ @Nonnull
+ public String getString() {
+ return value.getString();
+ }
+
+ @Nonnull
+ public synchronized T getObject(@Nonnull CodecContext context) {
+ value = value.getValueObject(context);
+
+ return ((IValueObject<T>) value).getObject();
+ }
+
+
+ @CheckForNull
+ public synchronized T getObjectIfAny() {
+ if (value instanceof IValueObject) {
+ return ((IValueObject<T>) value).getObject();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ //
+ // Private IValue hierarchy
+ //
+
+ private static interface IValue<T> {
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) throws ParsingException;
+
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context);
+
+ @Nonnull
+ public String getString();
+ }
+
+ private class IValueString implements IValue<T> {
+ @Nonnull
+ private final String value;
+
+ public IValueString (@Nonnull String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String getString() {
+ return value;
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) throws ParsingException {
+ T val = PropertyId.this.codec.checkString(context, value);
+
+ if (val != null) {
+ return new IValueObject<T>(val);
+ } else {
+ return new IValueCheckedString(value);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<T>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ throw new AssertionError();
+ }
+ }
+
+ private class IValueCheckedString implements IValue<T> {
+ @Nonnull
+ private final String value;
+
+ private IValueCheckedString (@Nonnull String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String getString() {
+ return value;
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ return new IValueObject<T>(PropertyId.this.codec.parseString(context, value));
+ }
+ }
+
+ private class IValueObject<T> implements IValue<T> {
+ @Nonnull
+ private final T value;
+
+ public IValueObject (@Nonnull T value) {
+ this.value = value;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ @Nonnull
+ public String getString() {
+ return ((PropertyId<T>) (PropertyId.this)).codec.formatValue(value);
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Nonnull
+ public T getObject() {
+ return value;
+ }
+ }
}
diff --git a/sched/src/com/android/sched/util/log/EventType.java b/sched/src/com/android/sched/util/log/EventType.java
index 040d99a..418ccc3 100644
--- a/sched/src/com/android/sched/util/log/EventType.java
+++ b/sched/src/com/android/sched/util/log/EventType.java
@@ -20,6 +20,5 @@
* Represents a event type of an event.
*/
public interface EventType {
- public String getColor();
public String getName();
}
\ No newline at end of file
diff --git a/sched/src/com/android/sched/util/log/SchedEventType.java b/sched/src/com/android/sched/util/log/SchedEventType.java
index dd2352b..0344d6e 100644
--- a/sched/src/com/android/sched/util/log/SchedEventType.java
+++ b/sched/src/com/android/sched/util/log/SchedEventType.java
@@ -23,24 +23,15 @@
* Represents a type of event whose performance is tracked
*/
public enum SchedEventType implements EventType {
- REFLECTIONS("Reflections", "Yellow"), //
- INSTANCIER("Schedulable instancier", "Blue"), //
- PLANBUILDER("Plan builder", "Red");
+ REFLECTIONS("Reflections"),
+ INSTANCIER("Schedulable instancier"),
+ PLANBUILDER("Plan builder");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- SchedEventType(@Nonnull String name, @Nonnull String cssColor) {
+ SchedEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
index da5323b..81095e5 100644
--- a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
+++ b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
@@ -36,11 +36,13 @@
import com.android.sched.util.table.SimpleTable;
import com.android.sched.util.table.Table;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -48,6 +50,7 @@
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -147,7 +150,7 @@
@Override
@Nonnull
public String toString() {
- return "Dummy";
+ return "Singleton";
}
@Override
@@ -221,7 +224,7 @@
@Override
@Nonnull
public EventType getCurrentEventType() {
- return TracerEventType.NOEVENT;
+ return TracerEventType.SINGLETON;
}
@Override
@@ -246,77 +249,116 @@
objects = new HashMap<
Class<? extends ObjectWatcher<?>>, WeakHashMap<Object, ObjectWatcher<Object>>>();
+ // Map a class C to a list of watcher classes that watch instances of type C
@Nonnull
- private final Map<Class<?>, Class<? extends ObjectWatcher<?>>> watchers =
- new HashMap<Class<?>, Class<? extends ObjectWatcher<?>>>();
+ private final Map<Class<?>, List<Class<? extends ObjectWatcher<?>>>> watchers =
+ new HashMap<Class<?>, List<Class<? extends ObjectWatcher<?>>>>();
+ // Set of classes not watched (speedup non watched classes)
@Nonnull
private final Set<Class<?>> notWatched = new HashSet<Class<?>>();
@Nonnull
- private final Object watcherLock = new Object();
+ private final ReentrantReadWriteLock watcherLock = new ReentrantReadWriteLock();
@Override
- public synchronized <T> void registerWatcher(@Nonnull Class<T> objectClass,
+ public synchronized <T> void registerWatcher(@Nonnull Class<T> rootWatchedClass,
@Nonnull Class<? extends ObjectWatcher<? extends T>> watcherClass) {
WeakHashMap<Object, ObjectWatcher<Object>> map =
new WeakHashMap<Object, ObjectWatcher<Object>>();
- synchronized (watcherLock) {
+ watcherLock.writeLock().lock();
+ try {
objects.put(watcherClass, map);
- watchers.put(objectClass, watcherClass);
- for (Class<?> cls : notWatched) {
- if (objectClass.isAssignableFrom(cls)) {
+ List<Class<? extends ObjectWatcher<?>>> list = watchers.get(rootWatchedClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+ watchers.put(rootWatchedClass, list);
+ }
+
+ list.add(watcherClass);
+
+ Iterator<Class<?>> iterNotWatched = notWatched.iterator();
+ while (iterNotWatched.hasNext()) {
+ Class<?> watchedClass = iterNotWatched.next();
+ if (rootWatchedClass.isAssignableFrom(watchedClass)) {
logger.log(Level.INFO, "Watcher ''{0}'' missed some instances of type ''{1}''",
- new Object[] {watcherClass.getName(), cls.getName()});
+ new Object[] {watcherClass.getName(), watchedClass.getName()});
- watchers.put(cls, watcherClass);
- notWatched.remove(objectClass);
+ list = watchers.get(watchedClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+ watchers.put(watchedClass, list);
+ }
+
+ list.add(watcherClass);
+ iterNotWatched.remove();
}
}
+ } finally {
+ watcherLock.writeLock().unlock();
}
}
@Override
public void registerObject(@Nonnull Object object, @Nonnegative long size, int count) {
- Class<? extends ObjectWatcher<?>> watcherClass = null;
+ enable.set(Boolean.FALSE);
+ Class<?> objectClass = object.getClass();
+ List<Class<? extends ObjectWatcher<?>>> list = null;
- synchronized (watcherLock) {
- if (notWatched.contains(object.getClass())) {
+ watcherLock.readLock().lock();
+ try {
+ // If this object is not watched explicitly, go away
+ if (notWatched.contains(objectClass)) {
return;
}
- watcherClass = watchers.get(object.getClass());
- if (watcherClass == null) {
- for (Entry<Class<?>, Class<? extends ObjectWatcher<?>>> entry : watchers.entrySet()) {
- if (entry.getKey().isAssignableFrom(object.getClass())) {
- watcherClass = entry.getValue();
- break;
+ list = watchers.get(objectClass);
+ } finally {
+ watcherLock.readLock().unlock();
+ }
+
+ if (list == null) {
+ watcherLock.writeLock().lock();
+ try {
+ list = watchers.get(objectClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+
+ for (Entry<Class<?>, List<Class<? extends ObjectWatcher<?>>>> entry :
+ watchers.entrySet()) {
+ if (entry.getKey().isAssignableFrom(objectClass)) {
+ list.addAll(entry.getValue());
+ }
}
}
- if (watcherClass != null) {
- watchers.put(object.getClass(), watcherClass);
+ if (!list.isEmpty()) {
+ watchers.put(objectClass, list);
} else {
- notWatched.add(object.getClass());
- return;
+ notWatched.add(objectClass);
}
+ } finally {
+ watcherLock.writeLock().unlock();
}
}
- try {
- @SuppressWarnings("unchecked")
- ObjectWatcher<Object> watcher = (ObjectWatcher<Object>) watcherClass.newInstance();
- WeakHashMap<Object, ObjectWatcher<Object>> weak = objects.get(watcherClass);
- assert weak != null; // If watchers contains object.getClass, then objects contains it also,
- // see registerWatcher
- if (watcher.notifyInstantiation(object, size, count, getCurrentEventType())) {
- weak.put(object, watcher);
+ for (Class<? extends ObjectWatcher<?>> watcherClass : list) {
+ try {
+ @SuppressWarnings("unchecked")
+ ObjectWatcher<Object> watcher = (ObjectWatcher<Object>) watcherClass.newInstance();
+
+ if (watcher.notifyInstantiation(object, size, count, getCurrentEventType())) {
+ WeakHashMap<Object, ObjectWatcher<Object>> weak = objects.get(watcherClass);
+ assert weak != null; // If watchers contains object.getClass, then objects contains it
+ // also, see registerWatcher
+ weak.put(object, watcher);
+ }
+ } catch (InstantiationException e) {
+ logger.log(Level.WARNING, "Can not instantiate Watcher", e);
+ } catch (IllegalAccessException e) {
+ logger.log(Level.WARNING, "Can not instantiate Watcher", e);
}
- } catch (InstantiationException e) {
- logger.log(Level.WARNING, "Can not instantiate Watcher", e);
- } catch (IllegalAccessException e) {
- logger.log(Level.WARNING, "Can not instantiate Watcher", e);
}
}
}
diff --git a/sched/src/com/android/sched/util/log/stats/Alloc.java b/sched/src/com/android/sched/util/log/stats/Alloc.java
index 2bf2989..ae1b50b 100644
--- a/sched/src/com/android/sched/util/log/stats/Alloc.java
+++ b/sched/src/com/android/sched/util/log/stats/Alloc.java
@@ -46,53 +46,10 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Count";
- case 1:
- return "Size";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Allocation";
}
-
@Nonnull
private static final String[] HEADER = new String[] {
"Count",
diff --git a/sched/src/com/android/sched/util/log/stats/AllocImpl.java b/sched/src/com/android/sched/util/log/stats/AllocImpl.java
index bbed19c..df2b01a 100644
--- a/sched/src/com/android/sched/util/log/stats/AllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/AllocImpl.java
@@ -18,7 +18,6 @@
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataHeader;
import com.android.sched.util.table.DataRow;
@@ -63,34 +62,6 @@
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(
Long.valueOf(number),
diff --git a/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java b/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
index 5b29bbf..d086b49 100644
--- a/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
+++ b/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
@@ -18,9 +18,9 @@
import com.google.common.collect.ObjectArrays;
+import com.android.sched.util.codec.ByteFormatter;
import com.android.sched.util.codec.Formatter;
import com.android.sched.util.codec.LongCodec;
-import com.android.sched.util.codec.ByteFormatter;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -49,64 +49,6 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Array count";
- case 1:
- return "Total size";
- case 2:
- return "Total elements";
- case 3:
- return "Min elements";
- case 4:
- return "Average elements";
- case 5:
- return "max elements";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- case 3:
- return "number";
- case 4:
- return "number";
- case 5:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Array allocation";
}
diff --git a/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java b/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
index ff59b55..f5b5c5e 100644
--- a/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
@@ -18,7 +18,6 @@
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataRow;
import java.util.Iterator;
@@ -69,34 +68,6 @@
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- default:
- return element.getValue(columnIdx - 1);
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- default:
- return element.getHumanReadableValue(columnIdx - 1);
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.concat(
Iterators.forArray(Long.valueOf(number), Long.valueOf(size)), element.iterator());
diff --git a/sched/src/com/android/sched/util/log/stats/Counter.java b/sched/src/com/android/sched/util/log/stats/Counter.java
index 8001004..fb6b630 100644
--- a/sched/src/com/android/sched/util/log/stats/Counter.java
+++ b/sched/src/com/android/sched/util/log/stats/Counter.java
@@ -24,7 +24,7 @@
/**
- * Represents a counter statistic when statistic is not enabled..
+ * Represents a counter statistic when statistic is not enabled.
*/
public class Counter extends Statistic {
protected Counter(@Nonnull StatisticId<? extends Statistic> id) {
@@ -60,45 +60,6 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Number";
- default:
- throw new AssertionError();
- }
- }
-
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Counter";
}
diff --git a/sched/src/com/android/sched/util/log/stats/CounterImpl.java b/sched/src/com/android/sched/util/log/stats/CounterImpl.java
index 32aca6c..3aeca0a 100644
--- a/sched/src/com/android/sched/util/log/stats/CounterImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/CounterImpl.java
@@ -22,7 +22,6 @@
import java.util.Iterator;
-import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -82,24 +81,6 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- assert columnIdx == 0;
-
- return Long.valueOf(value);
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- assert columnIdx == 0;
-
- return Long.valueOf(value).toString();
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(Long.valueOf(value));
}
diff --git a/sched/src/com/android/sched/util/log/stats/ExtendedSample.java b/sched/src/com/android/sched/util/log/stats/ExtendedSample.java
new file mode 100644
index 0000000..5ade77f
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/stats/ExtendedSample.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.util.log.stats;
+
+import com.android.sched.util.codec.DoubleCodec;
+import com.android.sched.util.codec.Formatter;
+import com.android.sched.util.codec.LongCodec;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Extended statistic computation on a set of values when statistic is not enabled. Have Median,
+ * First quartile, Third quartile.
+ */
+public class ExtendedSample extends Statistic {
+ protected ExtendedSample(@Nonnull StatisticId<? extends Statistic> id) {
+ super(id);
+ }
+
+ public void add(double value) {
+ }
+
+ @Nonnegative
+ public int getCount() {
+ return 0;
+ }
+
+ public double getTotal() {
+ return 0;
+ }
+
+ public double getMin() {
+ return Double.NaN;
+ }
+
+ public double getAverage() {
+ return Double.NaN;
+ }
+
+ public double getMax() {
+ return Double.NaN;
+ }
+
+ public double getFirstQuartile() {
+ return Double.NaN;
+ }
+
+ public double getMedian() {
+ return Double.NaN;
+ }
+
+ public double getThirdQuartile() {
+ return Double.NaN;
+ }
+
+ @Override
+ public void merge(@Nonnull Statistic statistic) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @Nonnull
+ public String getDescription() {
+ return "Sample";
+ }
+
+
+ @Nonnull
+ private static final String[] HEADER = new String[] {
+ "Count",
+ "Total",
+ "Min",
+ "Average",
+ "First Quartile",
+ "Median",
+ "Third Quartile",
+ "Max"
+ };
+
+ @Override
+ @Nonnull
+ public String[] getHeader() {
+ return HEADER.clone();
+ }
+
+ @Nonnull
+ public static String[] getStaticHeader() {
+ return HEADER.clone();
+ }
+
+ @Nonnull
+ public static Formatter<? extends Object>[] getStaticFormatters() {
+ return new Formatter<?>[] {
+ new LongCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec()
+ };
+ }
+
+ @Override
+ @Nonnull
+ public Formatter<? extends Object>[] getFormatters() {
+ return getStaticFormatters();
+ }
+
+ @Override
+ @Nonnegative
+ public int getColumnCount() {
+ return HEADER.length;
+ }
+}
diff --git a/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java b/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java
new file mode 100644
index 0000000..c0e77c4
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.util.log.stats;
+
+import com.google.common.collect.Iterators;
+
+import com.android.sched.util.table.DataHeader;
+import com.android.sched.util.table.DataRow;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Extended statistic computation on a set of values. Have Median, First quartile, Third quartile.
+ */
+public class ExtendedSampleImpl extends ExtendedSample implements DataRow, DataHeader {
+ private static final int INITIAL_CAPACITY = 16;
+ private static final int INCREMENT = 0;
+
+ @Nonnull
+ protected double[] samples = new double[INITIAL_CAPACITY];
+ @Nonnegative
+ protected int count = 0;
+ private double total;
+ private boolean isSorted = true;
+
+ @Nonnegative
+ private final int increment;
+
+ public ExtendedSampleImpl(@Nonnull StatisticId<? extends Statistic> id) {
+ super(id);
+
+ this.increment = INCREMENT;
+ }
+
+ @Override
+ public synchronized void add(double value) {
+ ensureCapacity(count);
+
+ samples[count++] = value;
+ total += value;
+ isSorted = false;
+ }
+
+ @Override
+ @Nonnegative
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public double getTotal() {
+ return total;
+ }
+
+ @Override
+ public synchronized double getMin() {
+ ensureSorted();
+ return samples[0];
+ }
+
+ @Override
+ public synchronized double getAverage() {
+ return total / count;
+ }
+
+ @Override
+ public synchronized double getMax() {
+ ensureSorted();
+ return samples[count];
+ }
+
+ @Override
+ public synchronized double getFirstQuartile() {
+ return getNth(1, 4);
+ }
+
+ @Override
+ public synchronized double getMedian() {
+ return getNth(1, 2);
+ }
+
+ @Override
+ public synchronized double getThirdQuartile() {
+ return getNth(3, 4);
+ }
+
+ @Override
+ public synchronized void merge(@Nonnull Statistic statistic) {
+ ExtendedSampleImpl samples = (ExtendedSampleImpl) statistic;
+
+ synchronized (samples) {
+ ensureCapacity(count + samples.count);
+
+ System.arraycopy(samples.samples, 0, this.samples, count, samples.count);
+ count += samples.count;
+ total += samples.total;
+ isSorted = false;
+ }
+ }
+
+ private void ensureSorted() {
+ if (!isSorted) {
+ Arrays.sort(samples, 0, count);
+ isSorted = true;
+ }
+ }
+
+ private void ensureCapacity (@Nonnegative int index) {
+ if (index >= samples.length) {
+ int newLength;
+
+ if (increment <= 0) {
+ newLength = samples.length * 2 + 1;
+ } else {
+ newLength = samples.length + increment;
+ }
+
+ double[] newArray = new double[newLength];
+ System.arraycopy(samples, 0, newArray, 0, count);
+
+ samples = newArray;
+ }
+ }
+
+ private double getNth(int n, int d) {
+ ensureSorted();
+
+ if (count == 0) {
+ return Double.NaN;
+ }
+
+ if (count == 1) {
+ return samples[0];
+ }
+
+ double pos = (double) (n * (count + 1)) / (double) d;
+
+ if (pos < 1.0) {
+ return samples[0];
+ }
+
+ double floor = Math.floor(pos);
+ double diff = pos - floor;
+ double vLow = samples[(int) pos - 1];
+
+ if (diff == 0) {
+ return vLow;
+ } else {
+ double vHigh = samples[(int) pos];
+ return vLow + diff * (vHigh - vLow);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public synchronized Iterator<Object> iterator() {
+ ensureSorted();
+
+ return Iterators.<Object>forArray(
+ Long.valueOf(getCount()),
+ Double.valueOf(getTotal()),
+ Double.valueOf(getMin()),
+ Double.valueOf(getAverage()),
+ Double.valueOf(getFirstQuartile()),
+ Double.valueOf(getMedian()),
+ Double.valueOf(getThirdQuartile()),
+ Double.valueOf(getMax()));
+ }
+}
diff --git a/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java b/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
index ed57ae4..eb547a2 100644
--- a/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
+++ b/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
@@ -46,52 +46,6 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Object count";
- case 1:
- return "Object size";
- case 2:
- return "Total size";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Object allocation";
}
diff --git a/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java b/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
index 3f511d4..eb0f887 100644
--- a/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
@@ -18,7 +18,6 @@
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataHeader;
import com.android.sched.util.table.DataRow;
@@ -71,38 +70,6 @@
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- case 2:
- return Long.valueOf(size * number);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- case 2:
- return MemoryBytesProbe.formatBytes(size * number);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(
Long.valueOf(number),
diff --git a/sched/src/com/android/sched/util/log/stats/Percent.java b/sched/src/com/android/sched/util/log/stats/Percent.java
index 86096c7..f36cd47 100644
--- a/sched/src/com/android/sched/util/log/stats/Percent.java
+++ b/sched/src/com/android/sched/util/log/stats/Percent.java
@@ -40,6 +40,15 @@
public void add(boolean value) {
}
+ public void removeTrue() {
+ }
+
+ public void removeFalse() {
+ }
+
+ public void remove(boolean value) {
+ }
+
public double getPercent() {
return Double.NaN;
}
@@ -50,52 +59,6 @@
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Percent";
- case 1:
- return "Number";
- case 2:
- return "Total";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Percent";
}
diff --git a/sched/src/com/android/sched/util/log/stats/PercentImpl.java b/sched/src/com/android/sched/util/log/stats/PercentImpl.java
index 7f02617..99f3916 100644
--- a/sched/src/com/android/sched/util/log/stats/PercentImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/PercentImpl.java
@@ -20,10 +20,8 @@
import com.android.sched.util.table.DataRow;
-import java.text.NumberFormat;
import java.util.Iterator;
-import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -59,7 +57,31 @@
}
@Override
+ public synchronized void removeTrue() {
+ this.numTrue--;
+ this.total--;
+ }
+
+ @Override
+ public synchronized void removeFalse() {
+ this.total--;
+ }
+
+ @Override
+ public synchronized void remove(boolean value) {
+ if (value) {
+ removeTrue();
+ } else {
+ removeFalse();
+ }
+ }
+
+ @Override
public synchronized double getPercent() {
+ if (numTrue < 0 || total < 0) {
+ return Double.NaN;
+ }
+
return (double ) numTrue / (double) total;
}
@@ -73,54 +95,6 @@
}
}
- @Override
- @Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Double.valueOf((double ) numTrue / (double) total);
- case 1:
- return Long.valueOf(numTrue);
- case 2:
- return Long.valueOf(total);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- if (total == 0) {
- return notANumber;
- } else {
- return formatter.format((double) numTrue / (double) total);
- }
- case 1:
- return Long.toString(numTrue);
- case 2:
- return Long.toString(total);
- default:
- throw new AssertionError();
- }
- }
-
- @Nonnull
- @Deprecated
- private static NumberFormat formatter = NumberFormat.getPercentInstance();
- @Nonnull
- @Deprecated
- private static String notANumber;
-
- static {
- formatter.setMinimumFractionDigits(2);
- notANumber = formatter.format(0).replace('0', '-');
- }
-
@Nonnull
@Override
public synchronized Iterator<Object> iterator() {
diff --git a/sched/src/com/android/sched/util/log/stats/Sample.java b/sched/src/com/android/sched/util/log/stats/Sample.java
index 027074b..115fb03 100644
--- a/sched/src/com/android/sched/util/log/stats/Sample.java
+++ b/sched/src/com/android/sched/util/log/stats/Sample.java
@@ -26,7 +26,7 @@
import javax.annotation.Nonnull;
/**
- * Simple statistic computation on a set of values.
+ * Simple statistic computation on a set of values when statistic is not enabled.
*/
public class Sample extends Statistic {
protected Sample(@Nonnull StatisticId<? extends Statistic> id) {
@@ -41,66 +41,36 @@
throw new AssertionError();
}
- @Override
- @Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ @Nonnegative
+ public int getCount() {
+ return 0;
}
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ public double getTotal() {
+ return 0;
}
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Count";
- case 1:
- return "Total";
- case 2:
- return "Min";
- case 3:
- return "Average";
- case 4:
- return "Max";
- case 5:
- return "Min Marker";
- case 6:
- return "Max Marker";
- default:
- throw new AssertionError();
- }
+ public double getMin() {
+ return Double.NaN;
}
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- case 3:
- return "number";
- case 4:
- return "number";
- case 5:
- return "string";
- case 6:
- return "string";
- default:
- throw new AssertionError();
- }
+ public double getAverage() {
+ return Double.NaN;
+ }
+
+ public double getMax() {
+ return Double.NaN;
+ }
+
+ @CheckForNull
+ public Object getMinObject() {
+ return null;
+
+ }
+
+ @CheckForNull
+ public Object getMaxObject() {
+ return null;
}
@Override
@@ -110,7 +80,7 @@
}
- @Nonnegative
+ @Nonnull
private static final String[] HEADER = new String[] {
"Count",
"Total",
diff --git a/sched/src/com/android/sched/util/log/stats/SampleImpl.java b/sched/src/com/android/sched/util/log/stats/SampleImpl.java
index 3a51c1a..50d609b 100644
--- a/sched/src/com/android/sched/util/log/stats/SampleImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/SampleImpl.java
@@ -31,7 +31,8 @@
* Simple statistic computation on a set of values.
*/
public class SampleImpl extends Sample implements DataRow, DataHeader {
- private long count;
+ @Nonnegative
+ private int count;
private double min = Double.POSITIVE_INFINITY;
@CheckForNull
@@ -64,6 +65,46 @@
count++;
}
+
+ @Override
+ @Nonnegative
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public double getTotal() {
+ return total;
+ }
+
+ @Override
+ public double getMin() {
+ return min;
+ }
+
+ @Override
+ public synchronized double getAverage() {
+ return total / count;
+ }
+
+ @Override
+ public double getMax() {
+ return max;
+ }
+
+ @Override
+ @CheckForNull
+ public Object getMinObject() {
+ return minObject;
+
+ }
+
+ @Override
+ @CheckForNull
+ public Object getMaxObject() {
+ return maxObject;
+ }
+
@Override
public synchronized void merge(@Nonnull Statistic statistic) {
SampleImpl samples = (SampleImpl) statistic;
@@ -82,94 +123,14 @@
@Nonnull
@Override
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(count);
- case 1:
- return Double.valueOf(total);
- case 2:
- if (min == Double.POSITIVE_INFINITY) {
- return Double.valueOf(Double.MAX_VALUE);
- } else {
- return Double.valueOf(min);
- }
- case 3:
- if (count == 0) {
- return Long.valueOf(0);
- } else {
- return Double.valueOf(total / count);
- }
- case 4:
- if (max == Double.NEGATIVE_INFINITY) {
- return Double.valueOf(Double.MIN_VALUE);
- } else {
- return Double.valueOf(max);
- }
- case 5:
- return "";
- case 6:
- return "";
- default:
- throw new AssertionError();
- }
- }
-
- @Nonnull
- @Override
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(count);
- case 1:
- return Double.toString(total);
- case 2:
- if (min == Double.POSITIVE_INFINITY) {
- return "--";
- } else {
- return Double.toString(min);
- }
- case 3:
- if (count == 0) {
- return "--";
- } else {
- return Double.toString(total / count);
- }
- case 4:
- if (max == Double.NEGATIVE_INFINITY) {
- return "--";
- } else {
- return Double.toString(max);
- }
- case 5:
- if (minObject == null) {
- return "--";
- } else {
- return minObject.toString();
- }
- case 6:
- if (maxObject == null) {
- return "--";
- } else {
- return maxObject.toString();
- }
- default:
- throw new AssertionError();
- }
- }
-
- @Nonnull
- @Override
- public Iterator<Object> iterator() {
+ public synchronized Iterator<Object> iterator() {
return Iterators.forArray(
- Long.valueOf(count),
- Double.valueOf(total),
- Double.valueOf(min),
- Double.valueOf(total / count),
- Double.valueOf(max),
- minObject,
- maxObject);
+ Integer.valueOf(getCount()),
+ Double.valueOf(getTotal()),
+ Double.valueOf(getMin()),
+ Double.valueOf(getAverage()),
+ Double.valueOf(getMax()),
+ getMinObject(),
+ getMaxObject());
}
}
diff --git a/sched/src/com/android/sched/util/log/stats/Statistic.java b/sched/src/com/android/sched/util/log/stats/Statistic.java
index 569d85c..93d2535 100644
--- a/sched/src/com/android/sched/util/log/stats/Statistic.java
+++ b/sched/src/com/android/sched/util/log/stats/Statistic.java
@@ -16,7 +16,12 @@
package com.android.sched.util.log.stats;
+import com.google.common.collect.Iterators;
+
+import com.android.sched.util.codec.Formatter;
+import com.android.sched.util.codec.ToStringFormatter;
import com.android.sched.util.table.DataHeader;
+import com.android.sched.util.table.DataRow;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -40,22 +45,6 @@
}
@Nonnull
- @Deprecated
- public abstract Object getValue(@Nonnegative int columnIdx);
-
- @Nonnull
- @Deprecated
- public abstract String getHumanReadableValue(@Nonnegative int columnIdx);
-
- @Nonnull
- @Deprecated
- public abstract String getDescription(@Nonnegative int columnIdx);
-
- @Nonnull
- @Deprecated
- public abstract String getType(@Nonnegative int columnIdx);
-
- @Nonnull
public abstract String getDescription();
@Override
@@ -63,4 +52,43 @@
public String toString() {
return id.getName();
}
+
+ //
+ // Adapter for deprecated API
+ //
+
+ @Nonnull
+ @Deprecated
+ public final String getDescription(int columnIdx) {
+ return getHeader()[columnIdx];
+ }
+
+ @Nonnull
+ @Deprecated
+ public final String getType(int columnIdx) {
+ if (getFormatters()[columnIdx] instanceof ToStringFormatter) {
+ return "string";
+ } else {
+ return "number";
+ }
+ }
+
+ @Nonnull
+ @Deprecated
+ public final Object getValue(@Nonnegative int columnIdx) {
+ if (this instanceof DataRow) {
+ DataRow data = (DataRow) this;
+
+ return Iterators.get(data.iterator(), columnIdx);
+ }
+
+ throw new AssertionError();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ @Deprecated
+ public final String getHumanReadableValue(@Nonnegative int columnIdx) {
+ return ((Formatter<Object>) (getFormatters()[columnIdx])).formatValue(getValue(columnIdx));
+ }
}
diff --git a/sched/src/com/android/sched/util/log/stats/StatisticId.java b/sched/src/com/android/sched/util/log/stats/StatisticId.java
index c6f0fe5..597a5a3 100644
--- a/sched/src/com/android/sched/util/log/stats/StatisticId.java
+++ b/sched/src/com/android/sched/util/log/stats/StatisticId.java
@@ -18,12 +18,8 @@
import com.android.sched.util.config.ReflectFactory;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
@@ -35,9 +31,6 @@
*/
public class StatisticId<T extends Statistic> {
@Nonnull
- private static Set<StatisticId<? extends Statistic>> ids =
- Collections.synchronizedSet(new HashSet<StatisticId<? extends Statistic>>());
- @Nonnull
private static Map<Class<? extends Statistic>, Statistic> dummies =
new ConcurrentHashMap<Class<? extends Statistic>, Statistic>();
@Nonnull
@@ -70,8 +63,6 @@
dummies.put(dummyClass, newDummyInstance());
regulars.put(dummyClass, regularClass);
}
-
- ids.add(this);
}
@Nonnull
@@ -96,12 +87,6 @@
@Nonnull
@Deprecated
- public static synchronized Collection<StatisticId<? extends Statistic>> getIds() {
- return new ArrayList<StatisticId<? extends Statistic>>(ids);
- }
-
- @Nonnull
- @Deprecated
public static synchronized Collection<? extends Statistic> getDummies() {
return dummies.values();
}
diff --git a/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java b/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
index 2f2ca1b..c9f43ca 100644
--- a/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
+++ b/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
@@ -16,7 +16,6 @@
package com.android.sched.util.log.tracer;
-import com.android.sched.util.Colors;
import com.android.sched.util.log.EventType;
import javax.annotation.Nonnull;
@@ -26,19 +25,10 @@
*/
class DynamicEventType implements EventType {
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
DynamicEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = Colors.getCssColor(Colors.getRandomPastel(name.hashCode()));
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/tracer/TracerEventType.java b/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
index 59d825d..3558a45 100644
--- a/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
+++ b/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
@@ -24,24 +24,16 @@
* Represents a type of event whose performance is tracked.
*/
public enum TracerEventType implements EventType {
- OVERHEAD("Tracer overhead", "Plum"),
- NOEVENT("No Event", "Black"),
- NOTYPE("Not a Type", "Black");
+ OVERHEAD("Tracer overhead"),
+ NOEVENT("No Event"),
+ SINGLETON("Singleton event"),
+ NOTYPE("Not a Type");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- TracerEventType(@Nonnull String name, @Nonnull String cssColor) {
+ TracerEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
index 09a8e18..78fd9b8 100644
--- a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
@@ -22,23 +22,17 @@
import com.android.sched.util.log.TracerFactory;
import com.android.sched.util.log.stats.Alloc;
import com.android.sched.util.log.stats.AllocImpl;
-import com.android.sched.util.log.stats.ArrayAlloc;
-import com.android.sched.util.log.stats.ArrayAllocImpl;
-import com.android.sched.util.log.stats.ObjectAlloc;
-import com.android.sched.util.log.stats.ObjectAllocImpl;
import com.android.sched.util.log.stats.Statistic;
import com.android.sched.util.log.stats.StatisticId;
import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
/**
- * Class to watch {@link Object} creation.
+ * Class to watch {@link Object} creation and make a global statistic about allocation.
*/
public class AllocationWatcher implements ObjectWatcher<Object> {
static class Statistics implements ObjectWatcher.Statistics {
@@ -54,14 +48,6 @@
"Total object and array allocations",
AllocImpl.class, Alloc.class);
- @Nonnull
- private static final Map<Class<?>, StatisticId<ObjectAlloc>> objectStats =
- new ConcurrentHashMap<Class<?>, StatisticId<ObjectAlloc>>();
-
- @Nonnull
- private static final Map<Class<?>, StatisticId<ArrayAlloc>> arrayStats =
- new ConcurrentHashMap<Class<?>, StatisticId<ArrayAlloc>>();
-
@Override
public boolean notifyInstantiation(
@Nonnull Object object, @Nonnegative long size, int count, @Nonnull EventType notUsed) {
@@ -77,46 +63,19 @@
}
private void notifyObject(@Nonnull Class<?> type, @Nonnegative long size) {
- synchronized (AllocationWatcher.class) {
- StatisticId<ObjectAlloc> id = objectStats.get(type);
- if (id == null) {
- String name = type.getName();
-
- id = new StatisticId<ObjectAlloc>("jack.allocation.object." + name,
- "Object allocation of type " + type.getName(), ObjectAllocImpl.class,
- ObjectAlloc.class);
- objectStats.put(type, id);
- }
-
- try {
- Tracer tracer = TracerFactory.getTracer();
- tracer.getStatistic(id).recordObjectAllocation(size);
- tracer.getStatistic(ALLOCATIONS).recordAllocation(size);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
+ try {
+ TracerFactory.getTracer().getStatistic(ALLOCATIONS).recordAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
}
}
private synchronized void notifyArray(@Nonnull Class<?> type, @Nonnegative long size,
@Nonnegative int count) {
- synchronized (AllocationWatcher.class) {
- StatisticId<ArrayAlloc> id = arrayStats.get(type);
- if (id == null) {
- String name = type.getName();
-
- id = new StatisticId<ArrayAlloc>("jack.allocation.array." + name,
- "Array allocation of type " + type.getName(), ArrayAllocImpl.class, ArrayAlloc.class);
- arrayStats.put(type, id);
- }
-
- try {
- Tracer tracer = TracerFactory.getTracer();
- tracer.getStatistic(id).recordObjectAllocation(count, size);
- tracer.getStatistic(ALLOCATIONS).recordAllocation(size);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
+ try {
+ TracerFactory.getTracer().getStatistic(ALLOCATIONS).recordAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
}
}
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
new file mode 100644
index 0000000..f8a97e3
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.util.log.tracer.watcher;
+
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.util.log.EventType;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.ArrayAlloc;
+import com.android.sched.util.log.stats.ArrayAllocImpl;
+import com.android.sched.util.log.stats.ObjectAlloc;
+import com.android.sched.util.log.stats.ObjectAllocImpl;
+import com.android.sched.util.log.stats.Statistic;
+import com.android.sched.util.log.stats.StatisticId;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Class to watch {@link Object} creation and make detailed statistics about allocation.
+ */
+public class DetailedAllocationWatcher implements ObjectWatcher<Object> {
+ static class Statistics implements ObjectWatcher.Statistics {
+ @Override
+ public Iterator<Statistic> iterator() {
+ throw new AssertionError();
+ }
+ }
+
+ @Nonnull
+ private static final Map<Class<?>, StatisticId<ObjectAlloc>> objectStats =
+ new ConcurrentHashMap<Class<?>, StatisticId<ObjectAlloc>>();
+
+ @Nonnull
+ private static final Map<Class<?>, StatisticId<ArrayAlloc>> arrayStats =
+ new ConcurrentHashMap<Class<?>, StatisticId<ArrayAlloc>>();
+
+ @Override
+ public boolean notifyInstantiation(
+ @Nonnull Object object, @Nonnegative long size, int count, @Nonnull EventType notUsed) {
+ Class<?> type = object.getClass();
+
+ if (count == -1) {
+ notifyObject(type, size);
+ } else {
+ notifyArray(type, size, count);
+ }
+
+ return false;
+ }
+
+ private void notifyObject(@Nonnull Class<?> type, @Nonnegative long size) {
+ StatisticId<ObjectAlloc> id;
+
+ synchronized (DetailedAllocationWatcher.class) {
+ id = objectStats.get(type);
+ if (id == null) {
+ String name = type.getName();
+
+ id = new StatisticId<ObjectAlloc>("jack.allocation.object." + name,
+ "Object allocation of type " + name, ObjectAllocImpl.class,
+ ObjectAlloc.class);
+ objectStats.put(type, id);
+ }
+ }
+
+ try {
+ TracerFactory.getTracer().getStatistic(id).recordObjectAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
+ }
+ }
+
+ private synchronized void notifyArray(@Nonnull Class<?> type, @Nonnegative long size,
+ @Nonnegative int count) {
+ StatisticId<ArrayAlloc> id;
+
+ synchronized (DetailedAllocationWatcher.class) {
+ id = arrayStats.get(type);
+ if (id == null) {
+ String name = type.getName();
+
+ id = new StatisticId<ArrayAlloc>("jack.allocation.array." + name,
+ "Array allocation of type " + name, ArrayAllocImpl.class, ArrayAlloc.class);
+ arrayStats.put(type, id);
+ }
+ }
+
+ try {
+ TracerFactory.getTracer().getStatistic(id).recordObjectAllocation(count, size);
+ } catch (RuntimeException e) {
+ // Do best effort here
+ }
+ }
+
+ @Override
+ @Nonnull
+ public ObjectWatcher.Statistics addSample(@Nonnull Object node,
+ @CheckForNull ObjectWatcher.Statistics raw, @Nonnull EventType type) {
+ throw new AssertionError();
+ }
+
+ /**
+ * Install a {@link DetailedAllocationWatcher}
+ */
+ @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc")
+ public static class DetailedAllocationWatcherInstaller implements WatcherInstaller {
+ @Override
+ public void install(@Nonnull Tracer tracer) {
+ tracer.registerWatcher(Object.class, DetailedAllocationWatcher.class);
+ }
+ }
+}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/sched/src/com/android/sched/vfs/AbstractVElement.java
similarity index 74%
copy from jack/src/com/android/jack/vfs/VDir.java
copy to sched/src/com/android/sched/vfs/AbstractVElement.java
index 0c967d9..939f8bc 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/sched/src/com/android/sched/vfs/AbstractVElement.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
-
-import java.util.Collection;
+package com.android.sched.vfs;
import javax.annotation.Nonnull;
/**
- * Virtual directory.
+ * Base class for implementing VElement.
*/
-public interface VDir extends VElement {
+public abstract class AbstractVElement implements VElement {
@Nonnull
- Collection<? extends VElement> list();
-
+ @Override
+ public String toString() {
+ return getLocation().getDescription();
+ }
}
diff --git a/jack/src/com/android/jack/vfs/VDir.java b/sched/src/com/android/sched/vfs/InputVDir.java
similarity index 90%
rename from jack/src/com/android/jack/vfs/VDir.java
rename to sched/src/com/android/sched/vfs/InputVDir.java
index 0c967d9..f57636d 100644
--- a/jack/src/com/android/jack/vfs/VDir.java
+++ b/sched/src/com/android/sched/vfs/InputVDir.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs;
import java.util.Collection;
@@ -23,7 +23,7 @@
/**
* Virtual directory.
*/
-public interface VDir extends VElement {
+public interface InputVDir extends VElement {
@Nonnull
Collection<? extends VElement> list();
diff --git a/jack/src/com/android/jack/vfs/VFile.java b/sched/src/com/android/sched/vfs/InputVFile.java
similarity index 90%
rename from jack/src/com/android/jack/vfs/VFile.java
rename to sched/src/com/android/sched/vfs/InputVFile.java
index a948b2d..3d7d2cd 100644
--- a/jack/src/com/android/jack/vfs/VFile.java
+++ b/sched/src/com/android/sched/vfs/InputVFile.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs;
import java.io.IOException;
import java.io.InputStream;
@@ -24,7 +24,7 @@
/**
* Virtual file.
*/
-public interface VFile extends VElement {
+public interface InputVFile extends VElement {
@Nonnull
InputStream openRead() throws IOException;
diff --git a/jack/src/com/android/jack/vfs/VFile.java b/sched/src/com/android/sched/vfs/OutputVDir.java
similarity index 78%
copy from jack/src/com/android/jack/vfs/VFile.java
copy to sched/src/com/android/sched/vfs/OutputVDir.java
index a948b2d..622c553 100644
--- a/jack/src/com/android/jack/vfs/VFile.java
+++ b/sched/src/com/android/sched/vfs/OutputVDir.java
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs;
import java.io.IOException;
-import java.io.InputStream;
import javax.annotation.Nonnull;
/**
- * Virtual file.
+ * Virtual directory to write to.
*/
-public interface VFile extends VElement {
+public interface OutputVDir extends VElement {
@Nonnull
- InputStream openRead() throws IOException;
+ OutputVFile createOutputVFile(@Nonnull String filePath) throws IOException;
}
diff --git a/jack/src/com/android/jack/vfs/VFile.java b/sched/src/com/android/sched/vfs/OutputVFile.java
similarity index 78%
copy from jack/src/com/android/jack/vfs/VFile.java
copy to sched/src/com/android/sched/vfs/OutputVFile.java
index a948b2d..32154b5 100644
--- a/jack/src/com/android/jack/vfs/VFile.java
+++ b/sched/src/com/android/sched/vfs/OutputVFile.java
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs;
import java.io.IOException;
-import java.io.InputStream;
+import java.io.OutputStream;
import javax.annotation.Nonnull;
/**
- * Virtual file.
+ * Virtual file to write to.
*/
-public interface VFile extends VElement {
+public interface OutputVFile extends VElement {
@Nonnull
- InputStream openRead() throws IOException;
+ OutputStream openWrite() throws IOException;
}
diff --git a/jack/src/com/android/jack/vfs/VElement.java b/sched/src/com/android/sched/vfs/VElement.java
similarity index 96%
rename from jack/src/com/android/jack/vfs/VElement.java
rename to sched/src/com/android/sched/vfs/VElement.java
index d4420a6..748b9bd 100644
--- a/jack/src/com/android/jack/vfs/VElement.java
+++ b/sched/src/com/android/sched/vfs/VElement.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs;
import com.android.sched.util.config.Location;
diff --git a/jack/src/com/android/jack/vfs/direct/DirectDir.java b/sched/src/com/android/sched/vfs/direct/InputDirectDir.java
similarity index 75%
rename from jack/src/com/android/jack/vfs/direct/DirectDir.java
rename to sched/src/com/android/sched/vfs/direct/InputDirectDir.java
index 4144729..4e88043 100644
--- a/jack/src/com/android/jack/vfs/direct/DirectDir.java
+++ b/sched/src/com/android/sched/vfs/direct/InputDirectDir.java
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-package com.android.jack.vfs.direct;
+package com.android.sched.vfs.direct;
-import com.android.jack.JackIOException;
-import com.android.jack.vfs.VDir;
-import com.android.jack.vfs.VElement;
+import com.android.sched.util.ConcurrentIOException;
import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.Location;
import com.android.sched.util.file.NotFileOrDirectoryException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.VElement;
import java.io.File;
import java.util.ArrayList;
@@ -34,14 +35,14 @@
/**
* Directory in the file system.
*/
-public class DirectDir implements VDir {
+public class InputDirectDir extends AbstractVElement implements InputVDir {
@Nonnull
private final File dir;
@CheckForNull
private ArrayList<VElement> list;
- public DirectDir(@Nonnull File dir) throws NotFileOrDirectoryException {
+ public InputDirectDir(@Nonnull File dir) throws NotFileOrDirectoryException {
if (!dir.isDirectory()) {
throw new NotFileOrDirectoryException(dir.getAbsolutePath(), false);
}
@@ -60,7 +61,7 @@
if (list == null) {
File[] subs = dir.listFiles();
if (subs == null) {
- throw new JackIOException("Failed to list content of '" + dir.getAbsolutePath() + "'");
+ throw new ConcurrentIOException(new ListDirException(dir));
}
if (subs.length == 0) {
return Collections.emptyList();
@@ -70,14 +71,12 @@
for (File sub : subs) {
try {
if (sub.isFile()) {
- list.add(new DirectFile(sub));
+ list.add(new InputDirectFile(sub));
} else {
- list.add(new DirectDir(sub));
+ list.add(new InputDirectDir(sub));
}
} catch (NotFileOrDirectoryException e) {
- AssertionError ae = new AssertionError();
- ae.initCause(e);
- throw ae;
+ throw new ConcurrentIOException(e);
}
}
}
@@ -86,12 +85,6 @@
return list;
}
- @Nonnull
- @Override
- public String toString() {
- return dir.getPath();
- }
-
@Override
@Nonnull
public Location getLocation() {
diff --git a/jack/src/com/android/jack/vfs/direct/DirectFile.java b/sched/src/com/android/sched/vfs/direct/InputDirectFile.java
similarity index 83%
rename from jack/src/com/android/jack/vfs/direct/DirectFile.java
rename to sched/src/com/android/sched/vfs/direct/InputDirectFile.java
index 8464183..45ae9ab 100644
--- a/jack/src/com/android/jack/vfs/direct/DirectFile.java
+++ b/sched/src/com/android/sched/vfs/direct/InputDirectFile.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.jack.vfs.direct;
+package com.android.sched.vfs.direct;
-import com.android.jack.vfs.VFile;
import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.Location;
import com.android.sched.util.file.NotFileOrDirectoryException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVFile;
import java.io.File;
import java.io.FileInputStream;
@@ -31,12 +32,12 @@
/**
* A {@code VFile} directly backed but a {@code java.io.File}.
*/
-public class DirectFile implements VFile {
+public class InputDirectFile extends AbstractVElement implements InputVFile {
@Nonnull
private final File file;
- public DirectFile(@Nonnull File file) throws NotFileOrDirectoryException {
+ public InputDirectFile(@Nonnull File file) throws NotFileOrDirectoryException {
if (!file.isFile()) {
throw new NotFileOrDirectoryException(file.getAbsolutePath(), true);
}
@@ -55,12 +56,6 @@
return file.getName();
}
- @Nonnull
- @Override
- public String toString() {
- return file.getPath();
- }
-
@Override
@Nonnull
public Location getLocation() {
diff --git a/jack/src/com/android/jack/vfs/VFile.java b/sched/src/com/android/sched/vfs/direct/ListDirException.java
similarity index 61%
copy from jack/src/com/android/jack/vfs/VFile.java
copy to sched/src/com/android/sched/vfs/direct/ListDirException.java
index a948b2d..802c9d4 100644
--- a/jack/src/com/android/jack/vfs/VFile.java
+++ b/sched/src/com/android/sched/vfs/direct/ListDirException.java
@@ -14,19 +14,28 @@
* limitations under the License.
*/
-package com.android.jack.vfs;
+package com.android.sched.vfs.direct;
+import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import javax.annotation.Nonnull;
/**
- * Virtual file.
+ * Thrown when listing a directory content failed.
*/
-public interface VFile extends VElement {
+public class ListDirException extends IOException {
+ private static final long serialVersionUID = 1L;
@Nonnull
- InputStream openRead() throws IOException;
+ private final File dir;
+ public ListDirException(@Nonnull File dir) {
+ this.dir = dir;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Failed to list directory content '" + dir.getPath() + "'";
+ }
}
diff --git a/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java b/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java
new file mode 100644
index 0000000..58968b1
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.vfs.direct;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.CannotCreateFileException;
+import com.android.sched.util.file.Directory;
+import com.android.sched.util.file.FileAlreadyExistsException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link OutputVDir} using a real directory.
+ */
+public class OutputDirectDir extends AbstractVElement implements OutputVDir {
+
+ @Nonnull
+ private final File dir;
+
+ public OutputDirectDir(@Nonnull Directory dir) {
+ this.dir = dir.getFile();
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return dir.getName();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(dir);
+ }
+
+ @Override
+ @Nonnull
+ public OutputVFile createOutputVFile(@Nonnull String filePath) throws CannotCreateFileException,
+ FileAlreadyExistsException {
+ File file = new File(dir, filePath);
+ if (!file.getParentFile().mkdirs() && !file.getParentFile().isDirectory()) {
+ throw new CannotCreateFileException(file.getParentFile().getAbsolutePath(),
+ /* isFile */ false);
+ }
+ return new OutputDirectFile(file);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java b/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java
new file mode 100644
index 0000000..58b36e9
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.vfs.direct;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.FileAlreadyExistsException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link OutputVFile} directly backed by a {@link File} directory.
+ */
+class OutputDirectFile extends AbstractVElement implements OutputVFile {
+
+ private static boolean checkIfFileAlreadyExists = false;
+
+ @Nonnull
+ private final File file;
+
+ public OutputDirectFile(@Nonnull File file) throws FileAlreadyExistsException {
+ if (checkIfFileAlreadyExists && file.exists()) {
+ throw new FileAlreadyExistsException(file.getAbsolutePath(), !file.isDirectory());
+ }
+ this.file = file;
+ }
+
+ @Nonnull
+ @Override
+ public OutputStream openWrite() throws FileNotFoundException {
+ return new FileOutputStream(file);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return file.getPath();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(file);
+ }
+}
diff --git a/jack/src/com/android/jack/vfs/zip/ZipArchive.java b/sched/src/com/android/sched/vfs/zip/InputZipArchive.java
similarity index 80%
rename from jack/src/com/android/jack/vfs/zip/ZipArchive.java
rename to sched/src/com/android/sched/vfs/zip/InputZipArchive.java
index ff8ba6e..fec4e36 100644
--- a/jack/src/com/android/jack/vfs/zip/ZipArchive.java
+++ b/sched/src/com/android/sched/vfs/zip/InputZipArchive.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.jack.vfs.zip;
+package com.android.sched.vfs.zip;
import java.io.Closeable;
import java.io.File;
@@ -28,7 +28,7 @@
/**
* Virtual directory for viewing the content of a zip file.
*/
-public class ZipArchive extends ZipDir implements Closeable {
+public class InputZipArchive extends InputZipVDir implements Closeable {
@Nonnull
public static final String IN_ZIP_SEPARATOR = "/";
@@ -36,7 +36,7 @@
@Nonnull
private final ZipFile zip;
- public ZipArchive(@Nonnull File zipFile) throws IOException {
+ public InputZipArchive(@Nonnull File zipFile) throws IOException {
super("", zipFile, new ZipEntry(""));
zip = new ZipFile(zipFile);
@@ -47,20 +47,20 @@
String entryName = entry.getName();
String[] names = entryName.split(IN_ZIP_SEPARATOR);
@SuppressWarnings("resource")
- ZipDir dir = this;
+ InputZipVDir dir = this;
StringBuilder inZipPath = new StringBuilder();
for (int i = 0; i < names.length - 1; i++) {
String simpleName = names[i];
inZipPath.append(IN_ZIP_SEPARATOR).append(simpleName);
- ZipDir nextDir = (ZipDir) dir.subs.get(simpleName);
+ InputZipVDir nextDir = (InputZipVDir) dir.subs.get(simpleName);
if (nextDir == null) {
- nextDir = new ZipDir(simpleName, zipFile, new ZipEntry(inZipPath.toString()));
+ nextDir = new InputZipVDir(simpleName, zipFile, new ZipEntry(inZipPath.toString()));
dir.subs.put(simpleName, nextDir);
}
dir = nextDir;
}
String simpleName = names[names.length - 1];
- dir.subs.put(simpleName, new ZipVFile(simpleName, zip, entry));
+ dir.subs.put(simpleName, new InputZipVFile(simpleName, zip, entry));
}
}
}
diff --git a/jack/src/com/android/jack/vfs/zip/ZipDir.java b/sched/src/com/android/sched/vfs/zip/InputZipVDir.java
similarity index 81%
rename from jack/src/com/android/jack/vfs/zip/ZipDir.java
rename to sched/src/com/android/sched/vfs/zip/InputZipVDir.java
index 801f207..7ad1cc5 100644
--- a/jack/src/com/android/jack/vfs/zip/ZipDir.java
+++ b/sched/src/com/android/sched/vfs/zip/InputZipVDir.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.jack.vfs.zip;
+package com.android.sched.vfs.zip;
-import com.android.jack.vfs.VDir;
-import com.android.jack.vfs.VElement;
import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.Location;
import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.VElement;
import java.io.File;
import java.util.Collection;
@@ -29,7 +30,7 @@
import javax.annotation.Nonnull;
-class ZipDir implements VDir {
+class InputZipVDir extends AbstractVElement implements InputVDir {
@Nonnull
protected final HashMap<String, VElement> subs = new HashMap<String, VElement>();
@@ -39,7 +40,7 @@
@Nonnull
private final Location location;
- ZipDir(@Nonnull String name, @Nonnull File zip, @Nonnull ZipEntry entry) {
+ InputZipVDir(@Nonnull String name, @Nonnull File zip, @Nonnull ZipEntry entry) {
this.name = name;
this.location = new ZipLocation(new FileLocation(zip), entry);
}
@@ -56,12 +57,6 @@
return subs.values();
}
- @Nonnull
- @Override
- public String toString() {
- return location.getDescription();
- }
-
@Override
@Nonnull
public Location getLocation() {
diff --git a/jack/src/com/android/jack/vfs/zip/ZipVFile.java b/sched/src/com/android/sched/vfs/zip/InputZipVFile.java
similarity index 83%
rename from jack/src/com/android/jack/vfs/zip/ZipVFile.java
rename to sched/src/com/android/sched/vfs/zip/InputZipVFile.java
index f2f1c62..090dc2f 100644
--- a/jack/src/com/android/jack/vfs/zip/ZipVFile.java
+++ b/sched/src/com/android/sched/vfs/zip/InputZipVFile.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.jack.vfs.zip;
+package com.android.sched.vfs.zip;
-import com.android.jack.vfs.VFile;
import com.android.sched.util.config.FileLocation;
import com.android.sched.util.config.Location;
import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVFile;
import java.io.File;
import java.io.IOException;
@@ -29,7 +30,7 @@
import javax.annotation.Nonnull;
-class ZipVFile implements VFile {
+class InputZipVFile extends AbstractVElement implements InputVFile {
@Nonnull
private final String name;
@@ -38,7 +39,7 @@
@Nonnull
private final ZipEntry entry;
- ZipVFile(@Nonnull String name, @Nonnull ZipFile zip, @Nonnull ZipEntry entry) {
+ InputZipVFile(@Nonnull String name, @Nonnull ZipFile zip, @Nonnull ZipEntry entry) {
this.name = name;
this.zip = zip;
this.entry = entry;
@@ -56,12 +57,6 @@
return zip.getInputStream(entry);
}
- @Nonnull
- @Override
- public String toString() {
- return name;
- }
-
@Override
@Nonnull
public Location getLocation() {
diff --git a/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java b/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java
new file mode 100644
index 0000000..b1b6ae1
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+import com.android.sched.vfs.VElement;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A root {@link OutputVDir} backed by a zip archive.
+ */
+public class OutputZipRootVDir extends AbstractVElement implements OutputVDir, Closeable {
+
+ @Nonnull
+ protected final HashMap<String, VElement> subs = new HashMap<String, VElement>();
+ @Nonnull
+ private final Location location;
+ @Nonnull
+ protected final ZipOutputStream zos;
+ @Nonnull
+ private final File zipFile;
+
+ public OutputZipRootVDir(@Nonnull File zipFile) throws FileNotFoundException {
+ this.zipFile = zipFile;
+ location = new ZipLocation(new FileLocation(zipFile), new ZipEntry(""));
+ zos = new ZipOutputStream(new FileOutputStream(zipFile));
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return zipFile.getName();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return location;
+ }
+
+ @Override
+ @Nonnull
+ public OutputVFile createOutputVFile(@Nonnull String filePath) {
+ return new OutputZipVFile(zos, new ZipEntry(filePath), zipFile);
+ }
+
+ @Override
+ public void close() throws IOException {
+ zos.close();
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java b/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java
new file mode 100644
index 0000000..afee54d
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.util.stream.UncloseableOutputStream;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+class OutputZipVFile extends AbstractVElement implements OutputVFile {
+
+ @Nonnull
+ private final ZipOutputStream zos;
+ @Nonnull
+ private final ZipEntry entry;
+ @Nonnull
+ private final Location location;
+
+ OutputZipVFile(@Nonnull ZipOutputStream zos, @Nonnull ZipEntry entry, @Nonnull File zipFile) {
+ this.zos = zos;
+ this.entry = entry;
+ location = new ZipLocation(new FileLocation(zipFile), entry);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return entry.getName();
+ }
+
+ @Nonnull
+ @Override
+ public OutputStream openWrite() throws IOException {
+ zos.putNextEntry(entry);
+ return new UncloseableOutputStream(zos);
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return location;
+ }
+
+}