diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a8f15edd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,264 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 4 +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_wrap_on_typing = false + +[*.java] +ij_java_align_consecutive_assignments = false +ij_java_align_consecutive_variable_declarations = false +ij_java_align_group_field_declarations = false +ij_java_align_multiline_annotation_parameters = false +ij_java_align_multiline_array_initializer_expression = false +ij_java_align_multiline_assignment = false +ij_java_align_multiline_binary_operation = false +ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_extends_list = false +ij_java_align_multiline_for = true +ij_java_align_multiline_method_parentheses = false +ij_java_align_multiline_parameters = true +ij_java_align_multiline_parameters_in_calls = false +ij_java_align_multiline_parenthesized_expression = false +ij_java_align_multiline_records = true +ij_java_align_multiline_resources = true +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = false +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_annotation_parameter_wrap = off +ij_java_array_initializer_new_line_after_left_brace = false +ij_java_array_initializer_right_brace_on_new_line = false +ij_java_array_initializer_wrap = off +ij_java_assert_statement_colon_on_next_line = false +ij_java_assert_statement_wrap = off +ij_java_assignment_wrap = off +ij_java_binary_operation_sign_on_next_line = false +ij_java_binary_operation_wrap = off +ij_java_blank_lines_after_anonymous_class_header = 0 +ij_java_blank_lines_after_class_header = 0 +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_after_package = 1 +ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_around_field = 0 +ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_initializer = 1 +ij_java_blank_lines_around_method = 1 +ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_before_class_end = 0 +ij_java_blank_lines_before_imports = 1 +ij_java_blank_lines_before_method_body = 0 +ij_java_blank_lines_before_package = 0 +ij_java_block_brace_style = end_of_line +ij_java_block_comment_at_first_column = true +ij_java_call_parameters_new_line_after_left_paren = false +ij_java_call_parameters_right_paren_on_new_line = false +ij_java_call_parameters_wrap = off +ij_java_case_statement_on_separate_line = true +ij_java_catch_on_new_line = false +ij_java_class_annotation_wrap = split_into_lines +ij_java_class_brace_style = end_of_line +ij_java_class_count_to_use_import_on_demand = 5 +ij_java_class_names_in_javadoc = 1 +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_while_brace_force = never +ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_param_comments = false +ij_java_doc_add_blank_line_after_return = false +ij_java_doc_add_p_tag_on_empty_lines = true +ij_java_doc_align_exception_comments = true +ij_java_doc_align_param_comments = true +ij_java_doc_do_not_wrap_if_one_line = false +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = false +ij_java_entity_dd_suffix = EJB +ij_java_entity_eb_suffix = Bean +ij_java_entity_hi_suffix = Home +ij_java_entity_lhi_prefix = Local +ij_java_entity_lhi_suffix = Home +ij_java_entity_li_prefix = Local +ij_java_entity_pk_class = java.lang.String +ij_java_entity_vo_suffix = VO +ij_java_enum_constants_wrap = off +ij_java_extends_keyword_wrap = off +ij_java_extends_list_wrap = off +ij_java_field_annotation_wrap = split_into_lines +ij_java_finally_on_new_line = false +ij_java_for_brace_force = never +ij_java_for_statement_new_line_after_left_paren = false +ij_java_for_statement_right_paren_on_new_line = false +ij_java_for_statement_wrap = off +ij_java_generate_final_locals = false +ij_java_generate_final_parameters = false +ij_java_if_brace_force = never +ij_java_imports_layout = *,|,javax.**,java.**,|,$* +ij_java_indent_case_from_switch = true +ij_java_insert_inner_class_imports = false +ij_java_insert_override_annotation = true +ij_java_keep_blank_lines_before_right_brace = 2 +ij_java_keep_blank_lines_between_package_declaration_and_header = 2 +ij_java_keep_blank_lines_in_code = 2 +ij_java_keep_blank_lines_in_declarations = 2 +ij_java_keep_control_statement_in_one_line = true +ij_java_keep_first_column_comment = true +ij_java_keep_indents_on_empty_lines = false +ij_java_keep_line_breaks = true +ij_java_keep_multiple_expressions_in_one_line = false +ij_java_keep_simple_blocks_in_one_line = false +ij_java_keep_simple_classes_in_one_line = false +ij_java_keep_simple_lambdas_in_one_line = false +ij_java_keep_simple_methods_in_one_line = false +ij_java_label_indent_absolute = false +ij_java_label_indent_size = 0 +ij_java_lambda_brace_style = end_of_line +ij_java_layout_static_imports_separately = true +ij_java_line_comment_add_space = false +ij_java_line_comment_at_first_column = true +ij_java_message_dd_suffix = EJB +ij_java_message_eb_suffix = Bean +ij_java_method_annotation_wrap = split_into_lines +ij_java_method_brace_style = end_of_line +ij_java_method_call_chain_wrap = off +ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_right_paren_on_new_line = false +ij_java_method_parameters_wrap = off +ij_java_modifier_list_wrap = false +ij_java_names_count_to_use_import_on_demand = 3 +ij_java_new_line_after_lparen_in_record_header = false +ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_parameter_annotation_wrap = off +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = off +ij_java_rparen_on_new_line_in_record_header = false +ij_java_session_dd_suffix = EJB +ij_java_session_eb_suffix = Bean +ij_java_session_hi_suffix = Home +ij_java_session_lhi_prefix = Local +ij_java_session_lhi_suffix = Home +ij_java_session_li_prefix = Local +ij_java_session_si_suffix = Service +ij_java_space_after_closing_angle_bracket_in_type_argument = false +ij_java_space_after_colon = true +ij_java_space_after_comma = true +ij_java_space_after_comma_in_type_arguments = true +ij_java_space_after_for_semicolon = true +ij_java_space_after_quest = true +ij_java_space_after_type_cast = true +ij_java_space_before_annotation_array_initializer_left_brace = false +ij_java_space_before_annotation_parameter_list = false +ij_java_space_before_array_initializer_left_brace = false +ij_java_space_before_catch_keyword = true +ij_java_space_before_catch_left_brace = true +ij_java_space_before_catch_parentheses = true +ij_java_space_before_class_left_brace = true +ij_java_space_before_colon = true +ij_java_space_before_colon_in_foreach = true +ij_java_space_before_comma = false +ij_java_space_before_do_left_brace = true +ij_java_space_before_else_keyword = true +ij_java_space_before_else_left_brace = true +ij_java_space_before_finally_keyword = true +ij_java_space_before_finally_left_brace = true +ij_java_space_before_for_left_brace = true +ij_java_space_before_for_parentheses = true +ij_java_space_before_for_semicolon = false +ij_java_space_before_if_left_brace = true +ij_java_space_before_if_parentheses = true +ij_java_space_before_method_call_parentheses = false +ij_java_space_before_method_left_brace = true +ij_java_space_before_method_parentheses = false +ij_java_space_before_opening_angle_bracket_in_type_parameter = false +ij_java_space_before_quest = true +ij_java_space_before_switch_left_brace = true +ij_java_space_before_switch_parentheses = true +ij_java_space_before_synchronized_left_brace = true +ij_java_space_before_synchronized_parentheses = true +ij_java_space_before_try_left_brace = true +ij_java_space_before_try_parentheses = true +ij_java_space_before_type_parameter_list = false +ij_java_space_before_while_keyword = true +ij_java_space_before_while_left_brace = true +ij_java_space_before_while_parentheses = true +ij_java_space_inside_one_line_enum_braces = false +ij_java_space_within_empty_array_initializer_braces = false +ij_java_space_within_empty_method_call_parentheses = false +ij_java_space_within_empty_method_parentheses = false +ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_assignment_operators = true +ij_java_spaces_around_bitwise_operators = true +ij_java_spaces_around_equality_operators = true +ij_java_spaces_around_lambda_arrow = true +ij_java_spaces_around_logical_operators = true +ij_java_spaces_around_method_ref_dbl_colon = false +ij_java_spaces_around_multiplicative_operators = true +ij_java_spaces_around_relational_operators = true +ij_java_spaces_around_shift_operators = true +ij_java_spaces_around_type_bounds_in_type_parameters = true +ij_java_spaces_around_unary_operator = false +ij_java_spaces_within_angle_brackets = false +ij_java_spaces_within_annotation_parentheses = false +ij_java_spaces_within_array_initializer_braces = false +ij_java_spaces_within_braces = false +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_for_parentheses = false +ij_java_spaces_within_if_parentheses = false +ij_java_spaces_within_method_call_parentheses = false +ij_java_spaces_within_method_parentheses = false +ij_java_spaces_within_parentheses = false +ij_java_spaces_within_switch_parentheses = false +ij_java_spaces_within_synchronized_parentheses = false +ij_java_spaces_within_try_parentheses = false +ij_java_spaces_within_while_parentheses = false +ij_java_special_else_if_treatment = true +ij_java_subclass_name_suffix = Impl +ij_java_ternary_operation_signs_on_next_line = false +ij_java_ternary_operation_wrap = off +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = off +ij_java_throws_list_wrap = off +ij_java_use_external_annotations = false +ij_java_use_fq_class_names = false +ij_java_use_relative_indents = false +ij_java_use_single_class_imports = true +ij_java_variable_annotation_wrap = off +ij_java_visibility = public +ij_java_while_brace_force = never +ij_java_while_on_new_line = false +ij_java_wrap_comments = false +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = false diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 4ab9605d..26da3b18 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,12 @@ # Compiled class file *.class -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Maven -target/ -dependency-reduced-pom.xml +# Gradle +.gradle/ +build/ # Eclipse -.settings/ +.setup/ bin/ .classpath .project @@ -25,13 +16,9 @@ bin/ .idea/ out/ -# Package Files # -*.jar -*.war -*.ear -*.zip -*.tar.gz -*.rar +# VS Code +.settings/ -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +# Radon +radon.log +radon.log.lck diff --git a/.travis.yml b/.travis.yml old mode 100644 new mode 100755 index 58a1e9b0..233f982c --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,9 @@ language: java -sudo: false -script: mvn clean verify \ No newline at end of file +install: true +dist: trusty + +jdk: + - oraclejdk11 + +script: + - ./gradlew build diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 097e5758..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,230 +0,0 @@ -## 0.6.0 - -* Added GUI console for GUI users. - -## 0.5.4 - -* GUI updates: - * You can add multiple libraries at a time rather than one. - * You can remove multiple libraries at a time rather than one. - * You can remove multiple exempts at a time rather than one. - * Added GC button which invokes System.gc(). - -## 0.5.3 - -* Added the ability to change between Radon's built-in dictionaries. - -## 0.5.2 - -* You can now resize the GUI. -* Expiry exempts are added. -* StackAnalyzer takes try-catch blocks into account now resulting in possibly better obfuscation by normal flow obfuscation transformer. -* Number obfuscation transformer now operates on longs as well as integers. - -## 0.5.1 - -* Fixes as issue with exempting where global-exempts didn't work. - -## 0.5.0 - -* Exempt update. Exempt-per-transformer is now implemented. - -## 0.4.4 - -* Exempting should work with renamer transformer again. - -## 0.4.3 - -* Changed the heavy invokedynamic transformer so it now replaces field calls with primitive types. - -## 0.4.2 - -* Added UTF-8 source-encoding to Maven. -* Made some changes to the normal flow obfuscation transformer that might make it (very slightly) hard to understand. - -## 0.4.1 - -* Maven-ized the project. -* Removed more ripped-off code. - -## 0.4.0 - -* Completely changed the normal flow obfuscation transformer so that it doesn't have anymore skidded code (lol). -* Added the StackAnaylzer which doesn't work very well at the moment. - -## 0.3.9 - -* Some internal changes, nothing new. - -## 0.3.8 - -* Added super light string encryption setting to GUI. - -## 0.3.7 - -* Renamer transformer kind of works now. There are still cases where it causes abstraction errors and exempting doesn't work at the moment. - -## 0.3.6 - -* Changed number obfuscation transformer so that it splits integers into a xor expression. This is far faster than the old transformer. -* Renamer transformer is still broken, so don't use it expecting it to work each time. - -## 0.3.5 - -* Added super light string encryption transformer which is intended for performance. Note that this transformer is very insecure and is not recommended in code which requires security. - -## 0.3.4 - -* Heavy string encryption transformer is now the normal string encryption transformer. The normal string encryption transformer is now the heavy string encryption transformer with some flow and an extra layer of encryption. The light string encryption got changed completely. - -## 0.3.3 - -* Changed both the Light invokedynamic and normal invokedynamic transformers so they are less ripped-off from IndyProtector. -* Some other edits here and there that I completely forgot. - -## 0.3.2 - -* Lots of GUI fixes. - -## 0.3.1 - -* Quick GUI fix causing Field exempts not to work. - -## 0.3.0 - -* Completely rewrote Renamer transformer. -* Radon now depends on some edits to org/objectweb/asm/ClassNode. - -## 0.2.5 - -* Added Shuffler and InnerClassRemover transformers. -* Updated GUI. - -## 0.2.4 - -* Added more JavaDocs + removed debugging code from heavy invokedynamic. - -## 0.2.3 - -* Added heavy string encryption to gui. - -## 0.2.2 - -* Completely changed light flow obfuscation transformer. - -## 0.2.1 - -* Stuck some more hand-made flow obfuscation into the heavy string encryption transformer. - -## 0.2.0 - -* Added the "heavy" string encryption transformer. - -## 0.1.9 - -* GUI now attempts to auto-fetch rt.jar and jce.jar (stole this idea from ZKM). - -## 0.1.8 - -* Added rest of transformers to GUI. - -## 0.1.7 - -* Un-refactored SnakeYAML and ASM. -* Changed the way transformers are enabled. -* Added more JavaDocs (whoooo). - -## 0.1.6 - -* Added a super buggy heavy invokedynamic transformer that hides not only methods, but fields as well. - -## 0.1.5 - -* Added method size checking to prevent adding too many bytecode instructions to the point where the JVM refuses to run methods for being too big. - -## 0.1.4 - -* Added field signatures and method signatures to crasher. -* Toned down normal flow obfuscation transformer so that it doesn't make method ridiculously huge over useless bytecode transformations. - -## 0.1.3 - -* Changed up Number Obfuscation transformer a bit. - -## 0.1.2 - -* Added custom regex matching system for exempts. - -## 0.1.1 - -* Fixed renaming bug with Bukkit/Bungee plugins. - -## 0.1.0 - -* Completely redesigned transformer system. - -## 0.0.14 - -* Squashed an annoying buggy in the new NumberObfuscation transformer thanks to https://github.com/JoachimVandersmissen/TestingProject - -## 0.0.13 - -* Completely re-worked NumberObfuscation transformer and cleaned some stuff up in general. - -## 0.0.12 - -* Cleaned up StringPool and NumberObfuscation transformers. - -## 0.0.11 - -* Added Expiry transformer. - -## 0.0.10 - -* Switched to ASM6 (FIELD RENAMING STILL NOT WORKING WHYYYYY) - -## 0.0.9 - -* Fixed some JavaDocs. -* Embedded logging into the transformers. -* Relocated bigLDC generator into StringUtils. -* Lots of transformer changes in general. - -## 0.0.8 - -* Sped up library loading. - -## 0.0.7 - -* Fixed a really dumb mistake I made. -* Stole VincBreaker's crasher algorithms (which are probably samczsun's) so lol. -* Stole VincBreaker's idea to use spaces as class names. -* So hopefully I don't invoke the rage of VincBreaker? xD - -## 0.0.6 - -* Even more bug fixes and more blah-blah. -* Beefed up normal flow obfuscation transformer a bit. - -## 0.0.5 - -* Bug fixes plus lots of JavaDocs to make code look a lot bigger than it actually is LOL. -* Removed Light flow obfuscation transformer. -* Normal flow obfuscation transformer is now the Light flow obfuscation transformer. -* Ugly bytecode transformer is now the Normal flow obfuscation transformer. - -## 0.0.4 - -* Make GUI functional. - -## 0.0.3 - -* Added non-functional GUI. - -## 0.0.2 - -* Added transformers plus CLI. - -## 0.0.1 - -* Added base skeleton and blah-blah. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 00000000..8f2a1c13 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,102 @@ +# Radon Contribution Guide + +## Table of Contents +* [GitHub](#github) + * [Issue Reports](#issue-reports) + * [Pull Requests](#pull-requests) +* [Styleguides](#styleguides) + * [Git Commit Messages](#git-commit-messages) + * [Java Styleguide](#java-styleguide) + * [Transformer Documentation](#transformer-documentation) + +## GitHub +### Issue Reports +Found an issue with Radon? Awesome. Make sure you read the following before reporting it: + +#### Before Submitting an Issue Report +* **Check the FAQ in the readme**. Radon has had numerous "bugs/errors/issues" reported which were completely +preventable due to configuration. +* **Check if the issue has already been reported**. Should said issue already exist, add a comment on the issue rather +than starting a new one. +* **Check if you made a YAML error**. You can use an online YAML verifier like +[this one](http://www.yamllint.com/) to catch errors quickly. +* **If possible, please spend a little time debugging before reporting the issue!** This could save a ton of time for +you and anyone who decides to fix the bug. If you are able to locate the precise issue in Radon's codebase, chances are +a fix can be implemented much sooner. + +#### Submitting an Issue Report as a Bug +All bugs are tracked as GitHub issues for organizational purposes. For that reason, please do not report bugs in the +Discord and expect a fix as I am prone to forgetfulness. + +When opening a bug report, please make sure to follow the below: +* **Use a clear and descriptive title**. + * Example of a **good** title: "Using the FastInvokedynamic transformer on any Spigot plugin results in NPE from + radon" + * Example of a **good** title: "Adding an exclusion hangs the renamer" + * Example of a **bad** title: "Adding an exclusions causes bug" + * Example of a **bad** title: "Radon bug" +* **Be as specific and descriptive as possible when describing the issue**. It really annoys me and other people when +your description is vague. I should be able to understand exactly what the issue is with no questions asked. +* **Be as detailed as you can when describing the expected behavior.** Same reason as above. +* **Provide the git commit hash you build Radon from.** This allows me or anyone investigating the issue to instantly +find the version of Radon you are using. Saying "latest" or similar will result in an instant close of your issue with +no help provided. If you're not going to make an effort to make a proper report, then I'm not going to make an effort to +help. +* **Provide the exact configuration used in code blocks**. This means no blanking out lines and no screenshots. I +apologize in advance if privacy is desired, but issues that could have been solved in 5 seconds have lasted multiple +hours because people hid parts of their configuration while requesting help. +* **Provide the relevant errors and exceptions in code blocks.** Please do not put screenshots here and make sure to put +each error in its own markdown code block. Also, please make sure you specify when the error happens. +* **Be as specific and detailed as possible when doing reproduction steps**. This is where some of the worst +miscommunications have happened which resulted in a ton of wasted time. Please just put in a little effort so that I +know *exactly* what you did. +* **Attach / link what you attempted to obfuscate**. This is a mandatory for all software problems created by the +obfuscation. If you are unable to attach or link the software you obfuscated, attach a proof-of-concept JAR which also +causes the same issue to happen. If possible, please also provide the obfuscated output. + +Extra: [this video](https://www.youtube.com/watch?v=53zkBvL4ZB4&vl=en) by +[LiveOverflow](https://github.com/LiveOverflow) and this [webpage](http://www.catb.org/esr/faqs/smart-questions.html) +are good references for properly asking a question. + +#### Submitting an Issue Report as an Enhancement / Feature Request +All enhancements and feature requests are tracked as GitHub issues for organizational purposes. + +When opening an enhancement / feature request, please make sure to follow the below: +* **Use a clear and descriptive title**. Please also prefix the title with [Enhancement/FR] so there's no room for +confusion. + * Example of a **good** title: "[Enhancement] Use dynamic decryption methods for XXXX instead of YYYY" + * Example of a **good** title: "[Feature Request] Transformer to flatten the CFG" + * Example of a **bad** title: "suggestion" + * Example of a **bad** title: "thing to make radon better" +* **Provide an in-depth description of what the feature should do.** You need to be as descriptive as possible to the +point where people shouldn't have to ask question to understand what the feature/enhancement will do. + +#### Pull Requests +Pull requests should fulfill one of the following: +* Spelling / grammatical errors in documentation, Javadocs, or markdown files. +* Fix issues reported on the issue tracker. +* Implement an enhancement / feature request on the issue tracker. + * If a transformer is implemented, it needs to be added as an enum field to + 1. `xyz.itzsomebody.radon.transformers.Transformers` and + 2. (Optional) Be documented accordingly. +* Update code or documentation to adhere to the specified style guides. +* Replace poorly-written or spaghetti code with properly-written and thought-out code. + +The rules for guidelines are pretty simple: +* Follow the style guides. +* Fix your commits should status checks fail. +* If the PR adds features / code, make sure you also appropriately document said additions. +* No need to squash commits -- I will personally do that if I think it's necessary. + +## Style guides +#### Git Commit Messages +* Use present tense. +* Use the imperative mood. + +#### Java +All Java code should adhere to the provided EditorConfig file. Even though the column limit is set to 120, feel free to +ignore that. + +#### Markdown +All markdown files are required to be hard-wrapped at 120 characters. The only exceptions are extremely long URLs and +code snippets. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 670bcca7..00000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ -**Which version of Radon are you using? (Do not say "latest", if you do, your issue will be immediately closed)** - -**What kind of Jar file did you obfuscate?** - -**What transformers did you use which caused an error?** -* Transformer1 -* Transformer2 -* Transformer3 - -**Is Radon the issue or the jar Radon obfuscated the issue?** - -**What is the error produced? (Copy-and-paste error into [PasteBin](http://pastebin.com) or [HasteBin](http://hastebin.com) and link it here)** - -**Any other information? (i.e. You combined Radon with other obfuscators)** diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 index 1a3517aa..94a04532 --- a/LICENSE +++ b/LICENSE @@ -619,56 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - Radon - Copyright (C) 2018 ItzSomebody - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Radon Copyright (C) 2018 ItzSomebody - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 1b800602..f0c7c77e --- a/README.md +++ b/README.md @@ -1,147 +1,127 @@ -# Radon Java Obfuscator ![Build Status](https://travis-ci.org/ItzSomebody/Radon.svg?branch=master) -Yet another Java obfuscator. If I forgot to credit you, just make a pull-request or open an issue. - -Licenses get to go with the manifest in src/META-INF (yay!) - -Usage: ```java -jar Radon.jar --config exampleconfig.yml``` - -Alternatively, you can also use ```java -jar Radon.jar --help``` for help. - -Example config: -```yaml -Input: "C:/Users/Buddy/Desktop/RadonOBF/Counter.jar" -Output: "C:/Users/Buddy/Desktop/Counter-OBF.jar" -StringEncryption: Normal -InvokeDynamic: Heavy -FlowObfuscation: Normal -LocalVariableObfuscation: Remove -LineNumberObfuscation: Remove -SourceNameObfuscation: Remove -SourceDebugObfuscation: Remove -HideCode: True -Crasher: True -Shuffler: True -InnerClassRemover: True -StringPool: True -NumberObfuscation: True -TrashClasses: 50 -Renamer: True -WatermarkType: ConstantPool -WatermarkMessage: ItzSomebody -WatermarkKey: PASSWORD -ExpiryTime: 5/25/2018 -ExpiryMessage: "YOUR SOFTWARE TRIAL HAS ENDED!!! YOU MUST NOW PAY $100000000 FOR THE FULL VERSION LULZ" -Libraries: - - "C:/Program Files/Java/jre1.8.0_xxx/lib/rt.jar" -Exempts: - - "Class: org/objectweb/asm/*" - - "StringPool: me/itzsomebody/counter/Counter$1" - - "InvokeDynamic: me/itzsomebody/counter/Counter" - - "Renamer: me/itzsomebody/counter/Counter$1" - - "Renamer: me/itzsomebody/counter/Counter.process(*" +# [Abandoned] Radon Java Bytecode Obfuscator + +## Radon is no longer maintained + +It's important to note that Radon is intended for __***experimentation only***__. If your software breaks in production +because you protected it with Radon then that is completely on you. + +If you have a quick question about how something works, you can join my [Discord](https://discord.gg/RfuxTea) +server and ask. + +This project is **not** likely to be production-safe nor bug free. If you would +like some pointers to production-safe (more or less) and less buggy Java +bytecode obfuscators that are properly maintained, I would suggest one of these: +* [Proguard](https://www.guardsquare.com/en/products/proguard) (mostly only +class/method/field name obfuscation) +* [Skidfuscator](https://github.com/terminalsin/skidfuscator-java-obfuscator) - [Discord](https://discord.gg/QJC9g8fBU9) +* [Zelix KlassMaster](http://www.zelix.com/) + +Since we're on the topic of obfuscation, consider taking a look at +[Recaf](https://github.com/Col-E/Recaf) ([Discord](https://discord.gg/Bya5HaA)) +if you have not already. Recaf is actively maintained by the contributers to +stay on top of a variety obfuscation techniques found in the wild. I would +highly recommend learning to use Recaf for those who are into Java reverse-engineering. + +[Skidfuscator](https://github.com/terminalsin/skidfuscator-java-obfuscator) is probably +one of the most promising Java bytecode obfuscation projects I have seen and has a much +more sanely-managed codebase than most obfuscators do (including Radon). I would recommend +anyone trying to get into Java obfuscation to spend time learning how Skidfuscator works. + +Another resource (slightly dated, but still a good amount of information) is +GenericException's [SkidSuite](https://github.com/GenericException/SkidSuite) repo. +Some common cheap obfuscation techniques that have become more common in the last +few years are documented there which anyone who is interested in Java reverse-engineering +should know. + +Additionally, here are some other obfuscators/protectors for Java that you could +check out for fun or learning (though not necessarily I would recommend using are): +* [Allatori](http://www.allatori.com/) - Commericial. Somewhat popular choice in industry. +* [avaj](https://github.com/cg-dot/avaj) - FOSS. Has a nice way of generating decryption subroutines on string constants. Also has some CFG flattening which is always nice to see. +* [BisGuard](http://www.bisguard.com/) - Commercial. Relies entirely on class encryption (last time I checked, at least) so protection has quite a bit of room for improvement. +* [Bozar](https://github.com/vimasig/Bozar) - Points for FOSS. Has some cheap tricks that I have seen being used in the Minecraft community. +* [Branchlock](https://branchlock.net/) - Commercial. Shows up a bit in the Minecraft community. +* [Caesium](https://github.com/sim0n/Caesium) - FOSS. Has a transformer that implements a well-known HTML injection into any Java reverse-engineering tool that parses HTML tags. +* [ClassGuard](https://zenofx.com/classguard/) - Commercial. Relies mostly on class encryption with hardcoded AES keys in native libs. Pretty easy IDA/Binary Ninja/Ghidra exercise if you want to flex on your blog on something. +* [DashO](https://www.preemptive.com/products/dasho/overview) - Commercial. Shows up a bit in industry and has some interesting ideas (albeit probably outdated) in flow obfuscation. +* [JBCO](http://www.sable.mcgill.ca/JBCO/) - FOSS. Some interesting flow obfuscation techniques that still work in modern Java. Based on the [Soot](https://github.com/soot-oss/soot) library which is also something worthwhile checking out. +* [JObf](https://github.com/superblaubeere27/obfuscator) - FOSS. Pretty outdated. Some of the transformations done show up in the Minecraft community so it can be worthwhile spending a bit of time takinng a look at this. +* [JObfuscator](https://www.pelock.com/products/jobfuscator) - Commericial. Never seen this used before so I cannot really give any comments. +* [NeonObf](https://github.com/MoofMonkey/NeonObf) - Mostly points for FOSS. Made up of the easier to defeat obfuscation techniques. NeonObf is also the name inspiration for Radon. +* [Obzcure](https://obzcu.re/) [Discord](https://discordapp.com/invite/fUCPxq8) (Dead) - Commericial. Web-based obfuscation service with some inspiration taken from Radon and [SkidSuite2](https://github.com/GenericException/SkidSuite/tree/master/archive/skidsuite-2). Used to go by the name "SpigotProtect" so you might see some Spigot plugins using the obfuscation from this product if you look around hard enough. +* [Paramorphism](https://paramorphism.serenity.enterprises/) - [Discord](https://discordapp.com/invite/k9DPvEy) (Dead) - Commerical. Was one of the most unusual and unique obfuscators at the time it was an active project in that relied a lot more on the JVM's unusual way of loading JAR archives including zip entries with duplicated names and the [fake directory trick](https://github.com/x4e/fakedirectory). Used to be more commonly used before people started ripping ideas from Paramorphism. +* [qProtect](https://mdma.dev/) - Commericial. Implements a lot of the more common obfuscation techiques into a single tool. Shows up a bit in the Minecraft community. +* [Sandmark](http://sandmark.cs.arizona.edu) - FOSS. Really old obfuscator research project led by Christian Collberg at the University of Arizona. Some interesting ideas in watermarking are here and some of the flow obfuscation ideas are good. +* [SkidSuite2](https://github.com/GenericException/SkidSuite/tree/master/archive/skidsuite-2) - FOSS. Some pretty basic obfuscation techniques, nothing too special. +* [Stringer](https://jfxstore.com/stringer/) - Commercial. Pretty infamous for its complicated AES-based encryption/decryption routines and price. Does not really offer a whole lot of protection, but sometimes does show up in industry. +* [yGuard](https://www.yworks.com/products/yguard) - FOSS. Functionally equivalent to ProGuard as far as I can tell. +* [zProtect](https://zprotect.dev/) - [Discord](https://discord.com/invite/dnGKGuwvGH) - Commercial. Newer obfuscator. I have not seen any samples from it so I do not have an opinion on it. + +## Build Instructions + +Run the following (and hope nothing breaks): +``` +./gradlew build +``` +Or if you're on Windows: +``` +gradlew.bat build +``` + +Should that somehow not work, use the following instead: +``` +./gradlew clean shadowJar ``` -Valid config options you can use: - -| Option | Expected Value(s) | Desc | -| --- | --- | --- | -| Input | String | Input file to obfuscate | -| Output | String | Output file to dump result of obfuscation | -| Libraries | String List | Libraries used to compile the input | -| Exempts | String List | Exempted classes, methods, or fields from obfuscation | -| StringEncryption | String (SuperLight/Light/Normal/Heavy) | Type of string encryption to apply | -| FlowObfuscation | String (Light/Normal) | Type of flow obfuscation to apply | -| InvokeDynamic | String (Light/Normal/Heavy) | Type of invokedynamic obfuscation to apply | -| LocalVariableObfuscation | String (Obfuscate/Remove) | Type of local variable obfuscation to apply | -| Crasher | Boolean | Determines if the decompiler crasher should be applied | -| HideCode | Boolean | Determines if synthetic modifiers should be applied | -| StringPool | Boolean | Determines if strings should be pooled | -| LineNumberObfuscation | String (Obfuscate/Remove) | Type of line number obfuscation to apply | -| NumberObfuscation | Boolean | Determines if integers should be split into simple math expressions | -| SourceNameObfuscation | String (Obfuscate/Remove) | Type of source name obfuscation to apply | -| SourceDebugObfuscation | String (Obfuscate/Remove) | Type of source debug obfuscation to apply | -| TrashClasses | Integer | Number of trash classes to generate | -| WatermarkMessage | String | Message to watermark into the output | -| WatermarkType | String (ConstantPool/Signature) | Type of watermark to apply | -| WatermarkKey | String | Key used to encrypt watermarks | -| SpigotPlugin | String | Determines if input should be treated as a spigot/bungee plugin | -| Renamer | Boolean | Determines if obfuscator should rename classes and methods | -| Shuffler | Boolean | Determines if obfuscator should re-arrange class members | -| InnerClassRemover | Boolean | Determines if obfuscator should remove inner-class information | -| ExpiryTime | String | Message to insert for expiry obfuscation (useful for trialware) | -| ExpiryMessage | String | Message to show when set your trialware goes past expiration date (rip) | -| Dictionary | Integer | Type of string generation to use in obfuscation. | - -## Dictionary types - -Valid dictionary types you can use: - -| Option | Description | -| --- | --- | -| 0 | (Default) Generates a string containing 10 characters composed entirely out of space-like characters. | -| 1 | Generates a string containing 10 characters unrecognized by the JVM causing them to show as white-boxes. | -| 2 | Generates an alpha-numeric string of length 4. | - -## Exempting - -The character '\*' can be used as a wildcard for "anything which starts with before this". So "me/itzsomebody/\*" will match "me/itzsomebody/ExampleClass1", "me/itzsomebody/example/ExampleClass2". This also works on method matching, "me/itzsomebody/example/Example.exampleMethod(*" will match any method which has the name "exampleMethod" in "me/itzsomebody/example/Example". - -Valid exempt types you can use: - -| Option | Expected Value(s) | Desc | -| --- | --- | --- | -| Class | Fully qualified name of internal class name (i.e. me/itzsomebody/counter/Counter) | Exempts entire classes from obfuscation. | -| Method | Fully qualified name of internal owner name + '.' + internal method name + internal method descriptor (i.e. me/itzsomebody/counter/Counter.exampleMethod()V) | Exempts entire method from obfuscation. | -| Field | Fully qualified name of internal owner name + '.' + internal field name | Exempts field from obfuscation. | -| StringEncryption | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from string encryption. | -| InvokeDynamic | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from invokedynamic obfuscation. | -| Flow | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from flow control obfuscation. | -| LocalVars | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from local variable obfuscation. | -| SourceName | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class source from name obfuscation. | -| SourceDebug | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class source from debug obfuscation. | -| LineNumbers | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from line number obfuscation. | -| StringPool | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from string pooling. | -| Crasher | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from being added an invalid class signature. | -| HideCode | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from hide code obfuscation. | -| Numbers | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method number obfuscation. | -| Shuffler | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from member shuffling. | -| InnerClasses | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from inner-class information removal. | -| Renamer | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from renaming. | -| Expiry | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from expiration. | - -## Obfuscation description -This table describes the current obfuscation settings Radon has. - -| Obfuscation Type | Description | -| --- | --- | -| StringEncryption | This takes the strings in your program and encrypts them. Each of the current settings are symmetrical and will NOT prevent reverse-engineers from figuring out what your program does. The super light setting uses an extremely simple xor algorithm and is not secure. The light setting uses a simple algorithm which encrypts the strings for speed. There is minimal flow obfuscation in the light setting so be aware this offers minimal protection. The normal string encryption setting is basically a flow-obfuscated version of the light string encryption, it is intended to make the decryption method more confusing. The heavy method uses AES to encrypt the strings. | -| FlowObfuscation | This attempts to confuse the program flow to make the decompiled code harder to understand. The light setting replaces all gotos in the program with conditionals which always evaluate to true. The light setting usually doesn't affect decompiler results by much unless you have methods with some certain flow control situations. The normal flow obfuscation attempts to find places in the bytecode where the stack is empty. It uses an injected predicate which is used to make false jumps and add some extra throw-nulls in random places. | -| InvokeDynamic | This abuses Java 7's new opcode, the invokedynamic. This replaces certain member access with dynamic invocations. The light invokedynamic transformer is very simple and replaces invokestatic, invokevirtual and invokeinterface with invokedynamics. This is easily reversed by experienced reverse-engineers so don't rely on this. The normal invokedynamic protection is a very slight improvement to the light settings, but still is easy to reverse. The heavy invokedynamic hides invokestatic, invokevirtual, getstatic, putstatic, getfield and putfield opcodes with invokedynamics. | -| LocalVariableObfuscation | This attempts to prevent local variable analysis. The obfuscation setting changes the names of the local variables to hard-to-read UTF-8 characters. The remove setting removes the local variable information completely destroying the ability to recover the local variable names. Removal setting tends to shrink jar size since it removes information in the code. | -| Crasher | This adds an invalid signature to classes. The intention of this transformer is to crash a majority of decompiles which attempt to take class signatures into account of the output. This crashes JD-GUI, Procyon, CFR and Javap. | -| HideCode | This adds certain access flag modifiers to members of your code. Synthetic modifiers are added to classes, methods and fields and bridge modifiers are added to methods which aren't initializer methods (\ and \). | -| StringPool | This adds a method into the class which takes all the strings in the class and pools them into the added method. | -| LineNumberObfuscation | This attempts to obscure stacktrace output by changing line number debug information. The obfuscation setting sets line numbers to random ones. The removal setting removes them from your code entirely. The removal setting also shrinks the size of the jar. | -| NumberObfuscation | This splits integers into a xor expression making it difficult to determine what number is being used. This is defeated by Krakatau. | -| SourceNameObfuscation | This attempts to obscure stacktrace output by removing sourcefile debug information. The obfuscation setting sets all the source file names to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | -| SourceDebugObfuscation | This attempts to obscure source debug information. The obfuscation setting sets all the source debug values to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | -| TrashClasses | This generates garbage classes which aren't used to attempt to hide the ones that are actually used. This also prevents JByteEdit usage. | -| Watermark | This marks a message into the classes which is intended for customer-identification. The constant pool option marks the message into the constant pool of each class. The signature option marks the messages into the class signature. | -| Renamer | This renames classes, methods and fields from their original names to random UTF-8 strings. | -| Shuffler | This simply changes the order of class members (methods and fields). | -| InnerClassRemover | This removes innerclass information. | -| ExpirationObfuscation | This adds a block of expiration code into each class initializer to prevent usage of jar after the expiration date has passed. | - -## Credits - -* [OW2 ASM](http://asm.ow2.org) - ObjectWeb ASM. -* [SnakeYaml](http://www.snakeyaml.org) - SnameYAML. -* [VincBreaker](https://github.com/Vinc0682) - Author of Smoke obfuscator which I took some ideas from. (i.e. Renaming classes as spaces and splitting numbers into bitwise xor operations) -* [WindowBuilder by Eclipse](https://www.eclipse.org/windowbuilder/) - Used to make GUI (yes I know it's Java Swing, I didn't feel like remaking it in JavaFX) -* [Licel](https://licelus.com) - Makers of IndyProtect. -* [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator. -* [Artel](https://gitlab.com/artel) - Beta tester. +P.S. For those wondering why there aren't any prebuilt releases, if you can't figure out how to use Gradle, should you really be using an obfuscator? ;) [end of snarkiness] + +## FAQ + +* **Q: Is this uncrackable/undeobfuscatable?** +*A: No. Nothing is impossible to deobfuscate or reverse-engineer. Furthermore, Radon is far from being hard to + deobfuscate. On a scale of 1 to 10 on how hard Radon is to deobfuscate, I'd say 2 in the best possible scenario.* + +* **Q: Why is this open-sourced?** +*A: I made Radon as a way to experiment with obfuscation and to become familiar with the JVM bytecode instruction set + and as a codebase if anyone wants to mess around. Furthermore, I strongly support the FOSS ideology.* + +* **Q: Doesn't Radon being open-sourced make it easier to deobfuscate?** +*A: Probably.* + +* **Q: Can Spring apps be obfuscated with this?** +*A: Out of the box, no. Starting from Radon 3, I will never add support for Spring or multiversion JARs.* + +* **Q: What does '... "org/somelib/TableFactoryBuilder" not found in classpath' mean?** +*A: Radon internally determines how to construct certain entities in the classfile based on the class hierarchy of the + JAR being obfuscated. For this reason, Radon needs access to library classes used by the project. Make sure you add + the appropriate libraries so this doesn't show up.* + +* **Q: Can I use all transformers for maximum protection?** +*A: You could, but you should note that it's very likely that the program will break and/or there will be a large + overhead in file size and/or performance.* + +* **Q: Why do certain combinations of transformers break the program?** +*A: Radon is intended to be an experimental project, not a commercial product protector. Not all features are meant to + work together.* + +* **Q: What version of Java is required to run Radon 3?** +*A: Java 11+.* + +* **Q: What version of Java is my software required to written in to work with Radon?** +*A: Radon can theoretically obfuscate software written in any Java version provided that the `asm` library is compatible + with the classfile version.* + +* **Q: Does Radon support Android?** +*A: While the answer is technically yes, I will not provide support for issues pertaining to Android apps.* + +* **Q: Does Radon have Gradle, Maven, or Ant integration?** +*A: No. You are more than welcome to make a PR to add such functionality if desired.* + +* **Q: Will there be a GUI for Radon 3?** +*A: Yes, however, a GUI is very low on my priority list, so it might be awhile before one is actually made.* + +* **Q: Will there be a Radon 4?** +*A: Probably not.* ## License -GNU General Public License v3.0 \ No newline at end of file +GNU General Public License v3.0 (The cancer license) diff --git a/build.gradle b/build.gradle new file mode 100755 index 00000000..95e994d0 --- /dev/null +++ b/build.gradle @@ -0,0 +1,61 @@ +/* + * Radon - An open-source Java obfuscator + * Copyright (C) 2021 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +plugins { + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +defaultTasks 'clean', 'test', 'build' + +ext { + // ASM + asmVer = '9.4' + asm = 'org.ow2.asm:asm:' + asmVer + asmAnalysis = 'org.ow2.asm:asm-analysis:' + asmVer + asmCommons = 'org.ow2.asm:asm-commons:' + asmVer + asmTree = 'org.ow2.asm:asm-tree:' + asmVer + asmUtil = 'org.ow2.asm:asm-util:' + asmVer + + // junit + junit = 'junit:junit:4.12' + + // Annotations + annotations = 'org.jetbrains:annotations:20.1.0' + + // Jackson + jackson = 'com.fasterxml.jackson.core:jackson-databind:2.12.2' + + // Java version + javaVer = 11 +} + +allprojects { + // Project group and version + group 'xyz.itzsomebody' + version '3.0.0-SNAPSHOT' + + // Compile using UTF-8 encoding + tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' + } + + repositories { + mavenCentral() + } +} + diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100755 index 00000000..61f1bbb8 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,17 @@ +# Changelog + +## 3.0.0 - Full rewrite +There are multiple turning points with the release of Radon 3.0.0 compared to all previous versions of Radon. + +### Differences between Radon 3 and previous versions +* Radon 3 is written in Java 11. Every previous version of Radon was written in Java 8. +* Some of Radon 3's features are not portable to different JVMs whereas every previous version of Radon was intended for +HotSpot. +* Radon 3 removes all "optimizers" from Radon 2. If you need some kind of optimization done, use ProGuard instead. +* Compared to Radon 2, Radon 3 can be significantly more risky in how it performs transformations on bytecode. +* Radon 2 uses the GitHub wiki for documentation of transformers and usage. Radon 3 has no usage guide and uses GitHub +pages for documentation of transformers (however, the wiki will not be removed for ease of reference). +* Radon 3 removes delegation for "shrinking" transformers via the above point. +* Radon 3 adheres to a style guide (sort of) whereas no previous version of Radon has. +* Radon 3 reimplements the exclusion system in a much more efficient matter. +* Radon 3 introduces a high-level code generator to remove some reliance on ASMifier generated code. diff --git a/docs/exclusions.md b/docs/exclusions.md new file mode 100755 index 00000000..622f643c --- /dev/null +++ b/docs/exclusions.md @@ -0,0 +1,57 @@ +# Exclusions + +**Note: You will need a basic understanding of internal class/method/field names to understand how Radon processes +exclusions.** + +Exclusions in Radon are regex-based and are matched using the code below: + +```java +public boolean matches(String other, ExclusionType type) { + if (type == ExclusionType.GLOBAL || type == exclusionType) { + return true; + } + + return invert != matcher.reset(other).matches(); +} +``` + +**The use of `java.util.regex.Matcher#matches()` is intentional and should be considered whilst creating an exclusion.** + +* When **classes** are checked for exclusion, the internal name is passed into `other`. e.g. +```java +// Check for java.lang.Object and java.lang.String +Exclusion exclusion = new Exclusion("java/lang/(Object|String)"); + +System.out.println(exclusion.matches("java/lang/Object")); // true +System.out.println(exclusion.matches("java/lang/String")); // true +System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // false +System.out.println(exclusion.matches("java/lang/Number")); // false +``` +```java +// Check for all classes that start with "java.lang" in their internal name +Exclusion exclusion = new Exclusion("java/lang.*"); + +System.out.println(exclusion.matches("java/lang/Object")); // true +System.out.println(exclusion.matches("java/lang/String")); // true +System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // true - be careful when playing with ".*" +System.out.println(exclusion.matches("java/lang/Number")); // true +``` + +* When **methods** are checked for exclusion, ` ` is +passed into `other`. e.g. +```java +// Check for java.lang.String.isEmpty() +Exclusion exclusion = new Exclusion("java/lang/String isEmpty\\(\\)Z"); + +System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // true +System.out.println(exclusion.matches("java/lang/String toCharArray()[C")); // false +``` +* When **fields** are checked for exclusion, ` ` is +passed into `other`. e.g. +```java +// Check for java.lang.System.out +Exclusion exclusion = new Exclusion("java/lang/System out Ljava/io/PrintStream;"); + +System.out.println(exclusion.matches("java/lang/System out Ljava/lang/PrintStream;")); // true +System.out.println(exclusion.matches("java/lang/System err Ljava/lang/PrintStream;")); // false +``` diff --git a/docs/index.md b/docs/index.md new file mode 100755 index 00000000..460bb523 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,9 @@ +# Radon Java Obfuscator [![Build Status](https://travis-ci.org/ItzSomebody/Radon.svg?branch=master)](https://travis-ci.org/ItzSomebody/Radon) + +Welcome to the documentation page for the Radon Java bytecode obfuscator! Here you can find the documentation and +various parts of stuff put into Radon's internals and transformers. + +* [Changelog](changelog.md) +* [Exclusions](exclusions.md) +* Transformers + * TODO diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 00000000..62d4c053 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100755 index 00000000..ae04661e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..fbd7c515 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100755 index 00000000..a9f778a7 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 9338b77a..00000000 --- a/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - 4.0.0 - - me.itzsomebody - Radon - 0.6.0 - - UTF-8 - - - src/main/java - - - src/main/resources - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - me.itzsomebody.radon.Radon - - - - - - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - -XDignore.symbol.file - - true - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.0 - - - package - - shade - - - - - *:* - - - - - - - - - - - - Sonatype-public - SnakeYAML repository - http://oss.sonatype.org/content/groups/public/ - - - - - - commons-io - commons-io - 2.6 - - - org.yaml - snakeyaml - 1.20-SNAPSHOT - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100755 index 00000000..72a7b6f7 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,24 @@ +/* + * Radon - An open-source Java obfuscator + * Copyright (C) 2020 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +rootProject.name = 'radon' +include 'xyz.itzsomebody.codegen' +include 'xyz.itzsomebody.radon' +include 'xyz.itzsomebody.commons' +include 'xyz.itzsomebody.radon.template' + diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java deleted file mode 100644 index 49c33558..00000000 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.itzsomebody.radon; - -import me.itzsomebody.radon.gui.MainGUI; -import me.itzsomebody.radon.internal.CLI; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * The main class :D - * - * @author ItzSomebody - */ -public class Radon { - /** - * Static abuse variables xD - */ - public static String PREFIX = "[Radon]"; - public static String VERSION = "0.6.0"; - public static String AUTHORS = "ItzSomebody"; - - /** - * Main method. - * - * @param args arguments from command line. - */ - public static void main(String[] args) { - coolThingInConsole(); - - switch (args.length) { - case 0: - new MainGUI(); - break; - default: - new CLI(args); - } - } - - /** - * Logo message for console. - */ - private static void coolThingInConsole() { - System.out.println("##############################################"); - System.out.println("# +----------------------------------------+ #"); - System.out.println("# | _____ _____ ____ _ _ | #"); - System.out.println("# | | __ \\ /\\ | __ \\ / __ \\| \\ | | | #"); - System.out.println("# | | |__) | / \\ | | | | | | | \\| | | #"); - System.out.println("# | | _ / / /\\ \\ | | | | | | | . ` | | #"); - System.out.println("# | | | \\ \\ / ____ \\| |__| | |__| | |\\ | | #"); - System.out.println("# | |_| \\_\\/_/ \\_\\_____/ \\____/|_| \\_| | #"); - System.out.println("# | | #"); - System.out.println("# +----------------------------------------+ #"); - System.out.println("##############################################"); - System.out.println(""); - System.out.println(""); - LoggerUtils.stdOut("Version: " + Radon.VERSION); - LoggerUtils.stdOut("Authors: " + Radon.AUTHORS); - } -} diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java deleted file mode 100644 index 2d5a9e19..00000000 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ /dev/null @@ -1,314 +0,0 @@ -package me.itzsomebody.radon.analyzer; - -import me.itzsomebody.radon.utils.OpcodeUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; - -import java.util.EmptyStackException; -import java.util.HashSet; -import java.util.Set; -import java.util.Stack; - -/** - * Attempts to make a virtual machine-like object which attempts to mimic the - * JVM stack. - * TODO: MAKE IT ACTUALLY WORK LOL - * - * @author ItzSomebody - */ -public class StackAnalyzer implements Opcodes { - /** - * {@link MethodNode} we are checking. - */ - private MethodNode methodNode; - /** - * {@link AbstractInsnNode} opcode which is the breakpoint. - */ - private AbstractInsnNode breakPoint; - /** - * Debug boolean; - */ - private boolean DEBUG = false; - - /** - * Constructor to create a {@link StackAnalyzer} object. - * - * @param methodNode the method node we want to check. - * @param breakPoint the opcode we want to break on. - */ - public StackAnalyzer(MethodNode methodNode, AbstractInsnNode breakPoint) { - this.methodNode = methodNode; - this.breakPoint = breakPoint; - } - - /** - * Returns a simulated stack of the Java bytecode instructions up to the - * specified breakpoint. - * - * @return a simulated stack of the Java bytecode instructions up to the - * specified breakpoint. - */ - public Stack returnStackAtBreak() { - if (DEBUG) - System.out.println("Entering " + this.methodNode.owner + '.' - + this.methodNode.name + this.methodNode.desc); - Stack stack = new Stack<>(); // Simulated stack - Set excHandlers = new HashSet<>(); - methodNode.tryCatchBlocks.forEach(tryCatchBlockNode -> { - excHandlers.add(tryCatchBlockNode.handler); - }); - for (int i = 0; i < this.methodNode.instructions.size(); i++) { - AbstractInsnNode insn = this.methodNode.instructions.get(i); - if (insn instanceof LabelNode - && excHandlers.contains(insn)) { - stack.clear(); // Stack gets cleared and exception is pushed. - stack.push(null); - } - if (this.breakPoint == insn) - break; - try { - switch (insn.getOpcode()) { - case ACONST_NULL: - case ICONST_M1: - case ICONST_0: - case ICONST_1: - case ICONST_2: - case ICONST_3: - case ICONST_4: - case ICONST_5: - case LCONST_0: - case LCONST_1: - case FCONST_0: - case FCONST_1: - case FCONST_2: - case DCONST_0: - case DCONST_1: - case BIPUSH: - case SIPUSH: - case LDC: - case ILOAD: - case LLOAD: - case FLOAD: - case DLOAD: - case ALOAD: - case IALOAD: - case LALOAD: - case FALOAD: - case DALOAD: - case AALOAD: - case BALOAD: - case CALOAD: - case SALOAD: - case DUP: - case DUP_X1: - case DUP_X2: - case NEW: - case GETSTATIC: - case GETFIELD: - if (DEBUG) - System.out.println("Pushing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); - stack.push(null); - break; - case ISTORE: - case LSTORE: - case FSTORE: - case DSTORE: - case ASTORE: - case IASTORE: - case LASTORE: - case DASTORE: - case AASTORE: - case BASTORE: - case CASTORE: - case SASTORE: - case POP: - case SWAP: - case IADD: - case LADD: - case FADD: - case DADD: - case ISUB: - case LSUB: - case FSUB: - case DSUB: - case IMUL: - case LMUL: - case FMUL: - case DMUL: - case IDIV: - case LDIV: - case FDIV: - case DDIV: - case IREM: - case LREM: - case FREM: - case DREM: - case ISHL: - case LSHL: - case ISHR: - case LSHR: - case IUSHR: - case LUSHR: - case IAND: - case LAND: - case IOR: - case LOR: - case IXOR: - case LXOR: - case LCMP: - case FCMPL: - case FCMPG: - case DCMPL: - case DCMPG: - case TABLESWITCH: - case LOOKUPSWITCH: - case IRETURN: - case LRETURN: - case FRETURN: - case DRETURN: - case ARETURN: - case PUTSTATIC: - case PUTFIELD: - case MONITORENTER: - case MONITOREXIT: - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - case IFNULL: - case IFNONNULL: - if (DEBUG) - System.out.println("Popping - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); - stack.pop(); - break; - case POP2: - if (DEBUG) - System.out.println("Double popping - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); - stack.pop(); - stack.pop(); - break; - case DUP2: - case DUP2_X1: - case DUP2_X2: - if (DEBUG) - System.out.println("Double pushing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); - stack.push(null); - stack.push(null); - break; - case INEG: - case LNEG: - case FNEG: - case DNEG: - case IINC: - case I2L: - case I2F: - case I2D: - case L2I: - case L2F: - case L2D: - case F2I: - case F2L: - case F2D: - case D2I: - case D2L: - case D2F: - case I2B: - case I2C: - case I2S: - case RETURN: - case NEWARRAY: - case ANEWARRAY: - case ARRAYLENGTH: - case ATHROW: - case CHECKCAST: - case INSTANCEOF: - case GOTO: - if (DEBUG) - System.out.println("Doing nothing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); - break; - case JSR: - case RET: - throw new IllegalArgumentException("Unsupported " + - "opcode (JSR/RET)"); - case INVOKEVIRTUAL: - case INVOKESPECIAL: - case INVOKEINTERFACE: - if (DEBUG) - System.out.println("Processing static method " + - "invocation - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - MethodInsnNode virtualInvoke = (MethodInsnNode) insn; - stack.pop(); // Objectref - for (int j = 0; j < Type.getArgumentTypes - (virtualInvoke.desc).length; j++) { - stack.pop(); - } - if (!virtualInvoke.desc.endsWith(")V")) { - stack.push(null); - } - break; - case INVOKESTATIC: - if (DEBUG) - System.out.println("Processing virtual method " + - "invocation - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - MethodInsnNode staticInvoke = (MethodInsnNode) insn; - for (int j = 0; j < Type.getArgumentTypes - (staticInvoke.desc).length; j++) { - stack.pop(); - } - if (!staticInvoke.desc.endsWith(")V")) { - stack.push(null); - } - break; - case INVOKEDYNAMIC: - if (DEBUG) - System.out.println("Processing dynamic invocation" + - " - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - InvokeDynamicInsnNode indy = - (InvokeDynamicInsnNode) insn; - for (int j = 0; j < Type.getArgumentTypes(indy.desc) - .length; j++) { - stack.pop(); - } - if (!indy.desc.endsWith(")V")) { - stack.push(null); - } - break; - case MULTIANEWARRAY: - if (DEBUG) - System.out.println("Processing multi-dimension " + - "array - Opcode = " + OpcodeUtils. - getOpcodeName(insn.getOpcode())); - MultiANewArrayInsnNode arrays - = (MultiANewArrayInsnNode) insn; - for (int j = 0; j < arrays.dims; j++) { - stack.pop(); - } - stack.push(null); // Arrayref - break; - } - } catch (EmptyStackException empty) { - if (DEBUG) empty.printStackTrace(); - } - } - return stack; - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java deleted file mode 100644 index 9824c4b9..00000000 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ /dev/null @@ -1,1049 +0,0 @@ -package me.itzsomebody.radon.config; - -import me.itzsomebody.radon.transformers.*; -import me.itzsomebody.radon.transformers.flow.HeavyFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; -import me.itzsomebody.radon.transformers.linenumbers.ObfuscateLineNumbers; -import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; -import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; -import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.*; -import me.itzsomebody.radon.transformers.renamer.Renamer; -import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; -import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; -import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; -import me.itzsomebody.radon.transformers.sourcename.RemoveSourceName; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; -import org.yaml.snakeyaml.Yaml; - -import java.io.File; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * Big config class that looks horrible and has lots of docs to make the code - * look a lot longer than it actually is LOL - * - * @author ItzSomebody - */ -public class Config { - /** - * Valid keys for element map loaded from config. - */ - private ArrayList VALIDKEYS = new ArrayList() { - { - add("Input"); - add("Output"); - add("Libraries"); - add("Exempts"); - add("StringEncryption"); - add("FlowObfuscation"); - add("InvokeDynamic"); - add("LocalVariableObfuscation"); - add("Crasher"); - add("HideCode"); - add("StringPool"); - add("LineNumberObfuscation"); - add("NumberObfuscation"); - add("SourceNameObfuscation"); - add("SourceDebugObfuscation"); - add("TrashClasses"); - add("WatermarkMessage"); - add("WatermarkType"); - add("WatermarkKey"); - add("SpigotPlugin"); - add("Renamer"); - add("ExpiryTime"); - add("ExpiryMessage"); - add("Shuffler"); - add("InnerClassRemover"); - add("Dictionary"); - } - }; - - /** - * The config object as {@link InputStream}. - */ - private InputStream config; - - /** - * The element map object as {@link Map}. - */ - private Map map; - - /** - * The exempt list as {@link ArrayList}. - */ - private List exempts; - - /** - * Exempted classes from any obfuscation. - */ - public List classExempts; - - /** - * Exempted methods from any obfuscation. - */ - public List methodExempts; - - /** - * Exempted fields from any obfuscation. - */ - public List fieldExempts; - - /** - * Exempted classes/methods from string encryption, - */ - public List stringEncExempts; - - /** - * Exempted classes/methods from invokedynamics. - */ - public List indyExempts; - - /** - * Exempted classes/methods from flow control obfuscation. - */ - public List flowExempts; - - /** - * Exempted classes/methods from local variable obfuscation. - */ - public List localVarExempts; - - /** - * Exempted classes from source name obfuscation. - */ - public List sourceNameExempts; - - /** - * Exempted classes from source debug obfuscation. - */ - public List sourceDebugExempts; - - /** - * Exempted classes/methods from line number obfuscation. - */ - public List lineNumbersExempts; - - /** - * Exempted classes/methods from string pooling. - */ - public List stringPoolExempts; - - /** - * Exempted classes from crashers. - */ - public List crasherExempts; - - /** - * Exempted classes/methods/fields from hide code obfuscation. - */ - public List hideCodeExempts; - - /** - * Exempted classes/methods from number obfuscation. - */ - public List numberExempts; - - /** - * Exempted classes from member shuffling. - */ - public List shufflerExempts; - - /** - * Exempted classes from inner-class information removal. - */ - public List innerClassExempts; - - /** - * Exempted classes/methods/fields from renaming. - */ - public List renamerExempts; - - /** - * Exempted classes/methods/fields from expiration. - */ - public List expiryExempts; - - /** - * Constructs a new {@link Config} - * - * @param config the {@link InputStream} to read from. - */ - public Config(InputStream config) { - this.config = config; - } - - /** - * Loads the configuration elements into {@link Config#map} - * using {@link Config#config}. - */ - public void loadIntoMap() { - this.map = new Yaml().load(this.config); - } - - /** - * Checks config for unrecognized keys. - * - * @throws IllegalArgumentException if argument is unrecognized. - */ - public void checkConfig() throws IllegalArgumentException { - for (String key : this.map.keySet()) { - if (!this.VALIDKEYS.contains(key)) { - throw new IllegalArgumentException("Invalid key: " + key); - } - } - } - - /** - * Returns the input element from {@link Config#map} as {@link File}. - * - * @return Returns the input element from {@link Config#map} as - * {@link File}. - * @throws IllegalArgumentException if input is null or not a - * {@link String}. - */ - public File getInput() throws IllegalArgumentException { - Object path = this.map.get("Input"); - if (path == null) - throw new IllegalArgumentException("Input not specified in config!"); - if (!(path instanceof String)) - throw new IllegalArgumentException("Input arg must be a string"); - - return new File((String) path); - } - - /** - * Returns the output element from {@link Config#map} as {@link File}. - * - * @return Returns the output element from {@link Config#map} as - * {@link File}. - * @throws IllegalArgumentException if output is not specified as a - * {@link String}. - */ - public File getOutput() throws IllegalArgumentException { - Object path = this.map.get("Output"); - if (path == null) { - return new File(getInput().getName().replace(".jar", - "-OBF.jar")); - } else { - if (!(path instanceof String)) - throw new IllegalArgumentException("Output arg must be a string"); - return new File((String) path); - } - } - - /** - * Returns the library element from {@link Config#map} as a {@link HashMap}. - * - * @return Returns the library element from {@link Config#map} as a - * {@link HashMap}. or each list element is not a {@link String}. - */ - public HashMap getLibraries() throws - IllegalArgumentException { - HashMap libs = new HashMap<>(); - Object o = this.map.get("Libraries"); - if (o != null) { - if (!(o instanceof List)) - throw new IllegalArgumentException("Libraries must be " + - "represented as list"); - List list = (List) o; - for (Object element : list) { - if (!(element instanceof String)) - throw new IllegalArgumentException("Library args must be " + - "string(s)"); - String lib = (String) element; - libs.put(lib, new File(lib)); - } - } - - return libs; - } - - /** - * Loads the exempt element from {@link Config#map} into - * {@link Config#exempts}. - * - * @throws IllegalArgumentException if the exempt element is not a list or - * each list element is not a {@link String}. - */ - private void setExempts() throws IllegalArgumentException { - this.exempts = new ArrayList<>(); - Object o = this.map.get("Exempts"); - if (o != null) { - if (!(o instanceof List)) - throw new IllegalArgumentException("Exempts must be " + - "represented as list"); - List list = (List) o; - for (Object object : list) { - if (!(object instanceof String)) - throw new IllegalArgumentException("Exemps must be string(s)"); - String value = (String) object; - - this.exempts.add(value); - } - } - } - - /** - * Sorts the elements in {@link Config#exempts} into - * {@link Config#classExempts}, {@link Config#methodExempts} and - * {@link Config#fieldExempts}. - * - * @throws IllegalArgumentException if exempt type is unknown. - */ - public void sortExempts() throws IllegalArgumentException { - this.setExempts(); - this.classExempts = new ArrayList<>(); - this.methodExempts = new ArrayList<>(); - this.fieldExempts = new ArrayList<>(); - this.stringEncExempts = new ArrayList<>(); - this.indyExempts = new ArrayList<>(); - this.flowExempts = new ArrayList<>(); - this.localVarExempts = new ArrayList<>(); - this.sourceNameExempts = new ArrayList<>(); - this.sourceDebugExempts = new ArrayList<>(); - this.lineNumbersExempts = new ArrayList<>(); - this.stringPoolExempts = new ArrayList<>(); - this.crasherExempts = new ArrayList<>(); - this.hideCodeExempts = new ArrayList<>(); - this.numberExempts = new ArrayList<>(); - this.shufflerExempts = new ArrayList<>(); - this.innerClassExempts = new ArrayList<>(); - this.renamerExempts = new ArrayList<>(); - this.expiryExempts = new ArrayList<>(); - - if (this.exempts != null) { - for (String exempt : this.exempts) { - if (exempt.startsWith("Class: ")) { - this.classExempts.add(exempt.replace("Class: ", "")); - } else if (exempt.startsWith("Method: ")) { - this.methodExempts.add(exempt.replace("Method: ", "")); - } else if (exempt.startsWith("Field: ")) { - this.fieldExempts.add(exempt.replace("Field: ", "")); - } else if (exempt.startsWith("StringEncryption: ")) { - this.stringEncExempts.add(exempt.replace("StringEncryption: ", "")); - } else if (exempt.startsWith("InvokeDynamic: ")) { - this.indyExempts.add(exempt.replace("InvokeDynamic: ", "")); - } else if (exempt.startsWith("Flow: ")) { - this.flowExempts.add(exempt.replace("Flow: ", "")); - } else if (exempt.startsWith("LocalVars: ")) { - this.localVarExempts.add(exempt.replace("LocalVars: ", "")); - } else if (exempt.startsWith("SourceName: ")) { - this.sourceNameExempts.add(exempt.replace("SourceName: ", "")); - } else if (exempt.startsWith("SourceDebug: ")) { - this.sourceDebugExempts.add(exempt.replace("SourceDebug: ", "")); - } else if (exempt.startsWith("LineNumbers: ")) { - this.lineNumbersExempts.add(exempt.replace("LineNumbers: ", "")); - } else if (exempt.startsWith("StringPool: ")) { - this.stringPoolExempts.add(exempt.replace("StringPool: ", "")); - } else if (exempt.startsWith("Crasher: ")) { - this.crasherExempts.add(exempt.replace("Crasher: ", "")); - } else if (exempt.startsWith("HideCode: ")) { - this.hideCodeExempts.add(exempt.replace("HideCode: ", "")); - } else if (exempt.startsWith("Numbers: ")) { - this.numberExempts.add(exempt.replace("Numbers: ", "")); - } else if (exempt.startsWith("Shuffler: ")) { - this.shufflerExempts.add(exempt.replace("Shuffler: ", "")); - } else if (exempt.startsWith("InnerClasses: ")) { - this.innerClassExempts.add(exempt.replace("InnerClasses: ", "")); - } else if (exempt.startsWith("Renamer: ")) { - this.renamerExempts.add(exempt.replace("Renamer: ", "")); - } else if (exempt.startsWith("Expiry")) { - this.expiryExempts.add(exempt.replace("Expiry: ", "")); - } else { - throw new IllegalArgumentException("Unrecognized exempt type: " + exempt); - } - } - } - } - - /** - * Returns the exempt element from {@link Config#map} as {@link List}. - * - * @return Returns the exempt element from {@link Config#map} as - * {@link List}. - */ - public List getExempts() { - return this.exempts; - } - - /** - * Returns the string encryption type from {@link Config#map} as - * an {@link AbstractTransformer}.Defaults to null if null. - * - * @return Returns the string encryption type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getStringEncryptionType() - throws IllegalArgumentException { - if (this.map.containsKey("StringEncryption")) { - Object value = this.map.get("StringEncryption"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("String encryption arg" + - " must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("SuperLight")) { - return new SuperLightStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Light")) { - return new LightStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyStringEncryption(this.getSpigotBool()); - } else { - throw new IllegalArgumentException("Invalid string " + - "encryption type: " + s); - } - } else { - throw new IllegalArgumentException("String encryption type is" + - " null"); - } - } - - return null; - } - - /** - * Returns the invokedynamic type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the invokedynamic type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getInvokeDynamicType() - throws IllegalArgumentException { - if (this.map.containsKey("InvokeDynamic")) { - Object value = this.map.get("InvokeDynamic"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("InvokeDynamic arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Light")) { - return new LightInvokeDynamic(); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalInvokeDynamic(); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyInvokeDynamic(); - } else { - throw new IllegalArgumentException("Invalid invokedynamic" + - " type: " + s); - } - } else { - throw new IllegalArgumentException("InvokeDynamic type is null"); - } - } - - return null; - } - - /** - * Returns the flow obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the flow obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getFlowObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("FlowObfuscation")) { - Object value = this.map.get("FlowObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Flow obfuscation arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Light")) { - return new LightFlowObfuscation(); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalFlowObfuscation(); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyFlowObfuscation(); - } else { - throw new IllegalArgumentException("Invalid flow " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Flow obfuscation type is " + - "null"); - } - } - - return null; - } - - /** - * Returns the local variable obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the local variable obfuscation type from - * {@link Config#map} as an {@link AbstractTransformer}. Defaults to null - * if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getLocalVariableObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("LocalVariableObfuscation")) { - Object value = this.map.get("LocalVariableObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Local variable " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateLocalVariables(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveLocalVariables(); - } else { - throw new IllegalArgumentException("Invalid local " + - "variable obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Local variable " + - "obfuscation type is null"); - } - } - - return null; - } - - /** - * Returns the line number obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the line number obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getLineNumberObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("LineNumberObfuscation")) { - Object value = this.map.get("LineNumberObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Line number " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateLineNumbers(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveLineNumbers(); - } else { - throw new IllegalArgumentException("Invalid line number " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Line number obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the source name obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the source name obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getSourceNameObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("SourceNameObfuscation")) { - Object value = this.map.get("SourceNameObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Source name " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateSourceName(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveSourceName(); - } else { - throw new IllegalArgumentException("Invalid source name " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Source name obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the source debug obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the source debug obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getSourceDebugObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("SourceDebugObfuscation")) { - Object value = this.map.get("SourceDebugObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Source debug " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateSourceDebug(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveSourceDebug(); - } else { - throw new IllegalArgumentException("Invalid source debug " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Source debug obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the shuffler type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the shuffler type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or - * not a {@link Boolean} - */ - public AbstractTransformer getShufflerType() - throws IllegalArgumentException { - if (this.map.containsKey("Shuffler")) { - Object value = this.map.get("Shuffler"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Shuffler arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new Shuffler(); - } - } else { - throw new IllegalArgumentException("Shuffler arg is null"); - } - } - - return null; - } - - /** - * Returns the inner class remover type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the inner class remover type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getInnerClassRemoverType() - throws IllegalArgumentException { - if (this.map.containsKey("InnerClassRemover")) { - Object value = this.map.get("InnerClassRemover"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("InnerClassRemover arg" + - " must be true/false"); - boolean s = (Boolean) value; - if (s) { - return new InnerClassRemover(); - } - } else { - throw new IllegalArgumentException("InnerClassRemover arg is " + - "null"); - } - } - - return null; - } - - /** - * Returns the crasher type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the crasher type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or - * not a {@link Boolean} - */ - public AbstractTransformer getCrasherType() - throws IllegalArgumentException { - if (this.map.containsKey("Crasher")) { - Object value = this.map.get("Crasher"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Crasher arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new Crasher(); - } - } else { - throw new IllegalArgumentException("Crasher arg is null"); - } - } - - return null; - } - - /** - * Returns the hide code type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the hide code type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getHideCodeType() - throws IllegalArgumentException { - if (this.map.containsKey("HideCode")) { - Object value = this.map.get("HideCode"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("HideCode arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new HideCode(getSpigotBool()); - } - } else { - throw new IllegalArgumentException("HideCode arg is null"); - } - } - - return null; - } - - /** - * Returns the number of trash classes from {@link Config#map} as an - * {@link Integer}. Defaults to null if null. - * - * @return Returns the number of trash classes from {@link Config#map} as an - * {@link Integer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or not a - * {@link Integer} - */ - public int getTrashClasses() throws IllegalArgumentException { - if (this.map.containsKey("TrashClasses")) { - Object value = this.map.get("TrashClasses"); - if (value != null) { - if (!(value instanceof Integer)) - throw new IllegalArgumentException("TrashClasses arg must" + - " be an Integer"); - return (Integer) value; - } else { - throw new IllegalArgumentException("TrashClasses arg is null"); - } - } - - return -1; - } - - - /** - * Returns the watermark message from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or - * not a {@link String} - */ - public String getWatermarkMsg() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkMessage")) { - Object value = this.map.get("WatermarkMessage"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Watermark message is null"); - } - } - - return null; - } - - /** - * Returns the watermark type from {@link Config#map} as an - * {@link Integer}. Defaults to -1 if null. - * - * @return Returns the crasher type from {@link Config#map} - * as an {@link Integer}. Defaults to -1 if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public int getWatermarkType() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkType")) { - Object value = this.map.get("WatermarkType"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Watermark type arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("ConstantPool")) { - return 0; - } else if (s.equalsIgnoreCase("Signature")) { - return 1; - } else { - throw new IllegalArgumentException("Invalid watermark " + - "type arg: " + value); - } - } else { - throw new IllegalArgumentException("Watermark type arg is null"); - } - } - - return -1; - } - - /** - * Returns the watermark key from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null - * or not a {@link String} - */ - public String getWatermarkKey() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkKey")) { - Object value = this.map.get("WatermarkKey"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Watermark key is null"); - } - } - - return null; - } - - /** - * Returns the boolean value of a spigot plugin from {@link Config#map} - * as a {@link Boolean}. Defaults to false if null. - * - * @return Returns the boolean value of a spigot plugin from - * {@link Config#map} as a {@link Boolean}. Defaults to false if null. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public boolean getSpigotBool() throws IllegalArgumentException { - if (this.map.containsKey("SpigotPlugin")) { - Object value = this.map.get("SpigotPlugin"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Spigot plugin arg " + - "must be true/false"); - return (Boolean) value; - } else { - throw new IllegalArgumentException("Spigot plugin arg is null"); - } - } - - return false; - } - - /** - * Returns the renamer type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the renamer type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getRenamerType() - throws IllegalArgumentException { - if (this.map.containsKey("Renamer")) { - Object value = this.map.get("Renamer"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Renamer arg must be" + - " true/false"); - boolean s = (Boolean) value; - if (s) { - return new Renamer(getSpigotBool()); - } - } else { - throw new IllegalArgumentException("Renamer arg is null"); - } - } - - return null; - } - - /** - * Returns the string pool type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the string pool type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getStringPoolType() - throws IllegalArgumentException { - if (this.map.containsKey("StringPool")) { - Object value = this.map.get("StringPool"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("String pool arg must " + - "be true/false"); - boolean s = (Boolean) value; - if (s) { - return new StringPool(); - } - } else { - throw new IllegalArgumentException("String pool arg is null"); - } - } - - return null; - } - - /** - * Returns the number obfuscation type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the number obfuscation type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getNumberObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("NumberObfuscation")) { - Object value = this.map.get("NumberObfuscation"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Number obfuscation " + - "arg must be true/false"); - boolean s = (Boolean) value; - if (s) { - return new NumberObfuscation(); - } - } else { - throw new IllegalArgumentException("Number obfuscation arg is" + - " null"); - } - } - - return null; - } - - /** - * Returns the expiry time from {@link Config#map} as - * {@link Long}. Defaults to -1. - * - * @return the expiry time from {@link Config#map} as - * {@link Long}. Defaults to -1. - * @throws IllegalArgumentException if value from key is null or not a - * {@link String}, and/or is not a - * proper date format. - */ - public long getExpiryTime() throws IllegalArgumentException { - if (this.map.containsKey("ExpiryTime")) { - Object value = this.map.get("ExpiryTime"); - if (value != null) { - if (!(value instanceof String)) { - throw new IllegalArgumentException("Expiry time must be a" + - " string in simple date format"); - } - - String time = (String) value; - try { - SimpleDateFormat format - = new SimpleDateFormat("MM/dd/yyyy"); - Date date = format.parse(time); - return date.getTime(); - } catch (ParseException e) { - throw new IllegalArgumentException("Could not parse date " + - "as MM/dd/yyyy"); - } - } - } - - return -1; - } - - /** - * Returns the expiry message from {@link Config#map} as - * {@link Integer}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or - * not a {@link String}. - */ - public String getExpiryMsg() throws IllegalArgumentException { - if (this.map.containsKey("ExpiryMessage")) { - Object value = this.map.get("ExpiryMessage"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Expiry message is null"); - } - } - - return null; - } - - /** - * Returns the dictionary type from {@link Config#map} as an - * {@link Integer}. Defaults to 0 if null; - * - * @return Returns the dictionary type from {@link Config#map} as an - * {@link Integer}. Defaults to 0 if null. - * @throws IllegalArgumentException if value from key is null or not - * an {@link Integer} - */ - public int getDictionaryType() - throws IllegalArgumentException { - if (this.map.containsKey("Dictionary")) { - Object value = this.map.get("Dictionary"); - if (value != null) { - if (!(value instanceof Integer)) - throw new IllegalArgumentException("Dictionary arg must " + - "be an integer"); - return (Integer) value; - } else { - throw new IllegalArgumentException("Dictionary arg is null"); - } - } else { - return 0; - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java deleted file mode 100644 index 70bc2fd8..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ /dev/null @@ -1,95 +0,0 @@ -package me.itzsomebody.radon.gui; - -import me.itzsomebody.radon.Radon; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.PrintStream; - -/** - * Makes a "console" GUI so users can see log events when they use the - * GUI rather than the CLI. - * - * @author ItzSomebody - */ -public class ConsoleGUI { - /** - * This GUI JFrame. - */ - private JFrame thisFrame; - - /** - * Just the panel. - */ - private JPanel consolePanel; - - /** - * Scroll pane for the JTextArea. - */ - private JScrollPane consoleScrollPane; - - /** - * Logging area. - */ - private JTextArea consoleOutput; - /** - * Original PrintStream (System.out) so we can restore it later when needed. - */ - private PrintStream stdOut; - - /** - * Original PrintStream (System.err) so we can restore it later when needed. - */ - private PrintStream stdErr; - - /** - * Constructor to create a Console GUI. - */ - public ConsoleGUI() { - this.stdOut = System.out; - this.stdErr = System.err; - this.init(); - } - - /** - * Initializes the JFrame and its contents. - */ - private void init() { - this.thisFrame = new JFrame(); - this.thisFrame.setTitle(Radon.PREFIX + " " + Radon.VERSION); - this.thisFrame.setResizable(true); - this.thisFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - this.thisFrame.setLocationRelativeTo(null); - this.thisFrame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - resetPrintStream(); - thisFrame.dispose(); - } - }); - this.thisFrame.setBounds(400, 400, 400, 400); - - this.consolePanel = new JPanel(new BorderLayout()); - this.consoleOutput = new JTextArea(); - this.consoleOutput.setEditable(false); - this.consoleScrollPane = new JScrollPane(this.consoleOutput); - this.consolePanel.add(this.consoleScrollPane, "Center"); - this.thisFrame.getContentPane().add(this.consolePanel); - - PrintStream customPrintStream = new PrintStream(new OutputStreamRedirect(this.consoleOutput)); - System.setOut(customPrintStream); - System.setErr(customPrintStream); - - this.thisFrame.setVisible(true); - } - - /** - * Restores the default PrintStreams when the logging window is closed - */ - private void resetPrintStream() { - System.setOut(this.stdOut); - System.setErr(this.stdErr); - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java deleted file mode 100644 index 26931123..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ /dev/null @@ -1,1971 +0,0 @@ -package me.itzsomebody.radon.gui; - -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.internal.Bootstrap; -import me.itzsomebody.radon.transformers.*; -import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; -import me.itzsomebody.radon.transformers.linenumbers.ObfuscateLineNumbers; -import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; -import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; -import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.*; -import me.itzsomebody.radon.transformers.renamer.Renamer; -import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; -import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; -import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; -import me.itzsomebody.radon.transformers.sourcename.RemoveSourceName; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; -import me.itzsomebody.radon.utils.WatermarkUtils; - -import javax.swing.*; -import java.awt.BorderLayout; -import java.awt.GridBagLayout; -import java.awt.GridBagConstraints; - -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import java.awt.Font; - - -/** - * This is pretty much all Eclipse WindowBuilder - * - * @author ItzSomebody - * @author Eclipse WindowBuilder - */ -public class MainGUI { - private JFrame frmRadonObfuscator; - private JTextField inputField; - private JTextField outputField; - private JTextField exemptField; - private JTextField trashChanceField; - private JTextField waterMarkMessageField; - private JTextField expirationDateField; - private JTextField expirationMessageField; - private JPasswordField watermarkPassword; - private JTextField extractorInput; - private JPasswordField extractorKey; - private File lastPath; // TODO: Use this for last file selection path - - /** - * Create the application. - */ - public MainGUI() { - initialize(); - } - - /** - * Initialize the contents of the frame. - */ - private void initialize() { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception exception) { - // exception.printStackTrace(); - } - this.frmRadonObfuscator = new JFrame(); - this.frmRadonObfuscator.setTitle(Radon.PREFIX + " " + Radon.VERSION); - this.frmRadonObfuscator.setBounds(100, 100, 440, 570); - this.frmRadonObfuscator.setResizable(true); - this.frmRadonObfuscator - .setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - this.frmRadonObfuscator.getContentPane() - .setLayout(new BorderLayout(0, 0)); - - JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); - this.frmRadonObfuscator.getContentPane().add(tabbedPane); - - JPanel panel_4 = new JPanel(); - tabbedPane.addTab("Files", null, panel_4, null); - GridBagLayout gbl_panel_4 = new GridBagLayout(); - gbl_panel_4.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; - gbl_panel_4.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0}; - gbl_panel_4.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_4.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, Double.MIN_VALUE}; - panel_4.setLayout(gbl_panel_4); - - JLabel lblInput = new JLabel("Input:"); - GridBagConstraints gbc_lblInput = new GridBagConstraints(); - gbc_lblInput.anchor = GridBagConstraints.EAST; - gbc_lblInput.insets = new Insets(0, 0, 5, 5); - gbc_lblInput.gridx = 1; - gbc_lblInput.gridy = 1; - panel_4.add(lblInput, gbc_lblInput); - - this.inputField = new JTextField(); - GridBagConstraints gbc_textField_1 = new GridBagConstraints(); - gbc_textField_1.gridwidth = 9; - gbc_textField_1.insets = new Insets(0, 0, 5, 5); - gbc_textField_1.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_1.gridx = 2; - gbc_textField_1.gridy = 1; - panel_4.add(this.inputField, gbc_textField_1); - this.inputField.setColumns(10); - - JButton btnNewButton = new JButton("Select"); - GridBagConstraints gbc_btnNewButton = new GridBagConstraints(); - gbc_btnNewButton.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton.gridx = 11; - gbc_btnNewButton.gridy = 1; - btnNewButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - inputField.setText(chooser.getSelectedFile() - .getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } - }); - } - } - }); - panel_4.add(btnNewButton, gbc_btnNewButton); - - JLabel lblOutput = new JLabel("Output:"); - GridBagConstraints gbc_lblOutput = new GridBagConstraints(); - gbc_lblOutput.insets = new Insets(0, 0, 5, 5); - gbc_lblOutput.anchor = GridBagConstraints.EAST; - gbc_lblOutput.gridx = 1; - gbc_lblOutput.gridy = 2; - panel_4.add(lblOutput, gbc_lblOutput); - - this.outputField = new JTextField(); - GridBagConstraints gbc_textField_2 = new GridBagConstraints(); - gbc_textField_2.gridwidth = 9; - gbc_textField_2.insets = new Insets(0, 0, 5, 5); - gbc_textField_2.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_2.gridx = 2; - gbc_textField_2.gridy = 2; - panel_4.add(this.outputField, gbc_textField_2); - this.outputField.setColumns(10); - - JButton btnNewButton_1 = new JButton("Select"); - GridBagConstraints gbc_btnNewButton_1 = new GridBagConstraints(); - gbc_btnNewButton_1.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_1.insets = new Insets(0, 0, 5, - 5); - gbc_btnNewButton_1.gridx = 11; - gbc_btnNewButton_1.gridy = 2; - btnNewButton_1.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(outputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - outputField.setText(chooser.getSelectedFile() - .getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } - }); - } - } - }); - panel_4.add(btnNewButton_1, gbc_btnNewButton_1); - - JSeparator separator_2 = new JSeparator(); - GridBagConstraints gbc_separator_2 = new GridBagConstraints(); - gbc_separator_2.fill = GridBagConstraints.HORIZONTAL; - gbc_separator_2.gridwidth = 13; - gbc_separator_2.insets = new Insets(0, 0, 5, 0); - gbc_separator_2.gridx = 0; - gbc_separator_2.gridy = 3; - panel_4.add(separator_2, gbc_separator_2); - - JLabel lblNewLabel_6 = new JLabel("Libraries:"); - GridBagConstraints gbc_lblNewLabel_6 = new GridBagConstraints(); - gbc_lblNewLabel_6.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_6.insets = new Insets(0, 0, 5, 0); - gbc_lblNewLabel_6.gridx = 1; - gbc_lblNewLabel_6.gridy = 4; - panel_4.add(lblNewLabel_6, gbc_lblNewLabel_6); - - JScrollPane scrollPane_2 = new JScrollPane(); - GridBagConstraints gbc_scrollPane_2 = new GridBagConstraints(); - gbc_scrollPane_2.gridheight = 13; - gbc_scrollPane_2.gridwidth = 9; - gbc_scrollPane_2.insets = new Insets(0, 0, 5, 5); - gbc_scrollPane_2.fill = GridBagConstraints.BOTH; - gbc_scrollPane_2.gridx = 2; - gbc_scrollPane_2.gridy = 4; - panel_4.add(scrollPane_2, gbc_scrollPane_2); - - DefaultListModel libList = new DefaultListModel<>(); - String jreHome = System.getProperty("java.home"); - if (jreHome != null) { - libList.addElement(jreHome + "/lib/rt.jar"); - libList.addElement(jreHome + "/lib/jce.jar"); - } - - JList list_2 = new JList<>(libList); - list_2.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - scrollPane_2.setViewportView(list_2); - - JButton btnNewButton_6 = new JButton("Add"); - btnNewButton_6.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(true); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - for (File file : chooser.getSelectedFiles()) { - libList.addElement(file.getAbsolutePath()); - } - - lastPath = chooser.getSelectedFile(); - } - }); - } - } - }); - GridBagConstraints gbc_btnNewButton_6 = new GridBagConstraints(); - gbc_btnNewButton_6.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_6.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_6.gridx = 11; - gbc_btnNewButton_6.gridy = 15; - panel_4.add(btnNewButton_6, gbc_btnNewButton_6); - - JButton btnNewButton_7 = new JButton("Remove"); - btnNewButton_7.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - List removeList = list_2.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - libList.removeElement(s); - } - } - }); - GridBagConstraints gbc_btnNewButton_7 = new GridBagConstraints(); - gbc_btnNewButton_7.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_7.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_7.gridx = 11; - gbc_btnNewButton_7.gridy = 16; - panel_4.add(btnNewButton_7, gbc_btnNewButton_7); - - JPanel panel = new JPanel(); - tabbedPane.addTab("Obfuscation", null, panel, null); - GridBagLayout gbl_panel = new GridBagLayout(); - gbl_panel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0}; - gbl_panel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0}; - gbl_panel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE}; - gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - Double.MIN_VALUE}; - panel.setLayout(gbl_panel); - - JComboBox comboBox = new JComboBox<>(); - comboBox.setEnabled(false); - GridBagConstraints gbc_comboBox = new GridBagConstraints(); - gbc_comboBox.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox.insets = new Insets(0, 0, 5, 5); - gbc_comboBox.gridx = 9; - gbc_comboBox.gridy = 0; - String[] encryptions = {"SuperLight", "Light", "Normal", "Heavy"}; - for (String s : encryptions) { - comboBox.addItem(s); - } - - panel.add(comboBox, gbc_comboBox); - - JCheckBox chckbxStringEncryption = new JCheckBox("String Encryption"); - GridBagConstraints gbc_chckbxStringEncryption = new GridBagConstraints(); - gbc_chckbxStringEncryption.anchor = GridBagConstraints.WEST; - gbc_chckbxStringEncryption.insets = new Insets(0, 0, 5, 5); - gbc_chckbxStringEncryption.gridx = 0; - gbc_chckbxStringEncryption.gridy = 0; - chckbxStringEncryption.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(true); - } else if (!chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(false); - } - } - - }); - panel.add(chckbxStringEncryption, gbc_chckbxStringEncryption); - - JComboBox comboBox_1 = new JComboBox<>(); - comboBox_1.setEnabled(false); - GridBagConstraints gbc_comboBox_1 = new GridBagConstraints(); - gbc_comboBox_1.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_1.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_1.gridx = 9; - gbc_comboBox_1.gridy = 1; - String[] invokeDynamics = {"Light", "Normal", "Heavy"}; - for (String s : invokeDynamics) { - comboBox_1.addItem(s); - } - - panel.add(comboBox_1, gbc_comboBox_1); - - JCheckBox chckbxInvokeDynamic = new JCheckBox("InvokeDynamic"); - GridBagConstraints gbc_chckbxNewCheckBox_1 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_1.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_1.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_1.gridx = 0; - gbc_chckbxNewCheckBox_1.gridy = 1; - chckbxInvokeDynamic.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(true); - } else if (!chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(false); - } - } - - }); - - panel.add(chckbxInvokeDynamic, gbc_chckbxNewCheckBox_1); - - JComboBox comboBox_2 = new JComboBox<>(); - comboBox_2.setEnabled(false); - GridBagConstraints gbc_comboBox_2 = new GridBagConstraints(); - gbc_comboBox_2.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_2.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_2.gridx = 9; - gbc_comboBox_2.gridy = 2; - - String[] flows = {"Light", "Normal"}; - for (String s : flows) { - comboBox_2.addItem(s); - } - - panel.add(comboBox_2, gbc_comboBox_2); - - JCheckBox chckbxFlow = new JCheckBox("Flow"); - GridBagConstraints gbc_chckbxFlow = new GridBagConstraints(); - gbc_chckbxFlow.insets = new Insets(0, 0, 5, 5); - gbc_chckbxFlow.anchor = GridBagConstraints.WEST; - gbc_chckbxFlow.gridx = 0; - gbc_chckbxFlow.gridy = 2; - chckbxFlow.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxFlow.isSelected()) { - comboBox_2.setEnabled(true); - } else if (!chckbxFlow.isSelected()) { - comboBox_2.setEnabled(false); - } - } - - }); - panel.add(chckbxFlow, gbc_chckbxFlow); - - JComboBox comboBox_3 = new JComboBox<>(); - comboBox_3.setEnabled(false); - GridBagConstraints gbc_comboBox_3 = new GridBagConstraints(); - gbc_comboBox_3.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_3.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_3.gridx = 9; - gbc_comboBox_3.gridy = 3; - - String[] localVariables = {"Obfuscate", "Remove"}; - for (String s : localVariables) { - comboBox_3.addItem(s); - } - - panel.add(comboBox_3, gbc_comboBox_3); - - JCheckBox chckbxLocalVariables = new JCheckBox("Local Variables"); - GridBagConstraints gbc_chckbxNewCheckBox_2 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_2.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_2.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_2.gridx = 0; - gbc_chckbxNewCheckBox_2.gridy = 3; - chckbxLocalVariables.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(true); - } else if (!chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(false); - } - } - - }); - panel.add(chckbxLocalVariables, gbc_chckbxNewCheckBox_2); - - this.trashChanceField = new JTextField(); - this.trashChanceField.setToolTipText("Number of trash classes to " + - "generate"); - this.trashChanceField.setEditable(false); - this.trashChanceField.setText("10"); - GridBagConstraints gbc_textField = new GridBagConstraints(); - gbc_textField.fill = GridBagConstraints.HORIZONTAL; - gbc_textField.insets = new Insets(0, 0, 5, 5); - gbc_textField.gridx = 9; - gbc_textField.gridy = 7; - panel.add(this.trashChanceField, gbc_textField); - this.trashChanceField.setColumns(3); - - JCheckBox chckbxTrashClasses = new JCheckBox("Trash Classes"); - GridBagConstraints gbc_chckbxNewCheckBox_3 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_3.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_3.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_3.gridx = 0; - gbc_chckbxNewCheckBox_3.gridy = 7; - chckbxTrashClasses.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(true); - } else if (!chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(false); - } - } - - }); - panel.add(chckbxTrashClasses, gbc_chckbxNewCheckBox_3); - - JComboBox comboBox_123 = new JComboBox<>(); - comboBox_123.setEnabled(false); - GridBagConstraints gbc_comboBox_4 = new GridBagConstraints(); - gbc_comboBox_4.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_4.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_4.gridx = 9; - gbc_comboBox_4.gridy = 5; - - String[] sourceNameTypes = {"Obfuscate", "Remove"}; - for (String s : sourceNameTypes) { - comboBox_123.addItem(s); - } - - panel.add(comboBox_123, gbc_comboBox_4); - - JCheckBox chckbxSourceName = new JCheckBox("Source Name"); - GridBagConstraints gbc_chckbxNewCheckBox_123 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_123.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_123.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_123.gridx = 0; - gbc_chckbxNewCheckBox_123.gridy = 5; - chckbxSourceName.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxSourceName.isSelected()) { - comboBox_123.setEnabled(true); - } else { - comboBox_123.setEnabled(false); - } - } - }); - panel.add(chckbxSourceName, gbc_chckbxNewCheckBox_123); - - JComboBox comboBox_1234 = new JComboBox<>(); - comboBox_1234.setEnabled(false); - GridBagConstraints gbc_comboBox1234 = new GridBagConstraints(); - gbc_comboBox1234.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox1234.insets = new Insets(0, 0, 5, 5); - gbc_comboBox1234.gridx = 9; - gbc_comboBox1234.gridy = 6; - - String[] sourceDebugTypes = {"Obfuscate", "Remove"}; - for (String s : sourceDebugTypes) { - comboBox_1234.addItem(s); - } - panel.add(comboBox_1234, gbc_comboBox1234); - - JCheckBox chckbxSourceDebug = new JCheckBox("Source Debug"); - GridBagConstraints gbc_SourceDebug = new GridBagConstraints(); - gbc_SourceDebug.anchor = GridBagConstraints.WEST; - gbc_SourceDebug.insets = new Insets(0, 0, 5, 5); - gbc_SourceDebug.gridx = 0; - gbc_SourceDebug.gridy = 6; - chckbxSourceDebug.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxSourceDebug.isSelected()) { - comboBox_1234.setEnabled(true); - } else { - comboBox_1234.setEnabled(false); - } - } - }); - panel.add(chckbxSourceDebug, gbc_SourceDebug); - - JComboBox comboBox_5 = new JComboBox<>(); - comboBox_5.setEnabled(false); - GridBagConstraints gbc_comboBox_5 = new GridBagConstraints(); - gbc_comboBox_5.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_5.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_5.gridx = 9; - gbc_comboBox_5.gridy = 4; - - String[] lineTypes = {"Obfuscate", "Remove"}; - for (String s : lineTypes) { - comboBox_5.addItem(s); - } - - panel.add(comboBox_5, gbc_comboBox_5); - - JCheckBox chckbxLineObfuscation = new JCheckBox("Lines"); - GridBagConstraints gbc_chckbxNewCheckBox_10 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_10.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_10.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_10.gridx = 0; - gbc_chckbxNewCheckBox_10.gridy = 4; - chckbxLineObfuscation.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxLineObfuscation.isSelected()) { - comboBox_5.setEnabled(true); - } else { - comboBox_5.setEnabled(false); - } - } - }); - panel.add(chckbxLineObfuscation, gbc_chckbxNewCheckBox_10); - - JCheckBox chckbxSpringPool = new JCheckBox("String Pool"); - GridBagConstraints gbc_chckbxNewCheckBox = new GridBagConstraints(); - gbc_chckbxNewCheckBox.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox.anchor = GridBagConstraints.NORTHWEST; - gbc_chckbxNewCheckBox.gridx = 0; - gbc_chckbxNewCheckBox.gridy = 8; - panel.add(chckbxSpringPool, gbc_chckbxNewCheckBox); - - JCheckBox chckbxCrasher = new JCheckBox("Crasher"); - GridBagConstraints gbc_chckbxAntidecompiler = new GridBagConstraints(); - gbc_chckbxAntidecompiler.anchor = GridBagConstraints.WEST; - gbc_chckbxAntidecompiler.insets = new Insets(0, 0, 5, 5); - gbc_chckbxAntidecompiler.gridx = 0; - gbc_chckbxAntidecompiler.gridy = 9; - panel.add(chckbxCrasher, gbc_chckbxAntidecompiler); - - JCheckBox chckbxHidecode = new JCheckBox("Hide Code"); - GridBagConstraints gbc_chckbxNewCheckBox_4 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_4.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_4.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_4.gridx = 0; - gbc_chckbxNewCheckBox_4.gridy = 10; - panel.add(chckbxHidecode, gbc_chckbxNewCheckBox_4); - - JCheckBox chckbxNumberObfuscation - = new JCheckBox("Number Obfuscation"); - GridBagConstraints gbc_chckbxNewCheckBox_9 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_9.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_9.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_9.gridx = 0; - gbc_chckbxNewCheckBox_9.gridy = 11; - panel.add(chckbxNumberObfuscation, gbc_chckbxNewCheckBox_9); - - JCheckBox chckbxSpigotPlugin = new JCheckBox("Spigot Plugin"); - chckbxSpigotPlugin.setToolTipText("Prevents string encryption from " + - "encrypting strings that contain %%__USER__%% or " + - "%%__RESOURCE__%% or %%__NONCE__%%."); - GridBagConstraints gbc_chckbxNewCheckBox_7 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_7.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_7.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_7.gridx = 0; - gbc_chckbxNewCheckBox_7.gridy = 12; - panel.add(chckbxSpigotPlugin, gbc_chckbxNewCheckBox_7); - - JCheckBox chckbxClassRenammer = new JCheckBox("Member Renamer"); - GridBagConstraints gbc_chckbxClassRenammer = new GridBagConstraints(); - gbc_chckbxClassRenammer.anchor = GridBagConstraints.WEST; - gbc_chckbxClassRenammer.insets = new Insets(0, 0, 5, 5); - gbc_chckbxClassRenammer.gridx = 0; - gbc_chckbxClassRenammer.gridy = 13; - panel.add(chckbxClassRenammer, gbc_chckbxClassRenammer); - - JCheckBox chckbxShuffler = new JCheckBox("Member Shuffler"); - GridBagConstraints gbc_chckbxShuffler = new GridBagConstraints(); - gbc_chckbxShuffler.anchor = GridBagConstraints.WEST; - gbc_chckbxShuffler.insets = new Insets(0, 0, 5, 5); - gbc_chckbxShuffler.gridx = 0; - gbc_chckbxShuffler.gridy = 14; - panel.add(chckbxShuffler, gbc_chckbxShuffler); - - JCheckBox chckbxInnerClasses - = new JCheckBox("InnerClasses Remover"); - GridBagConstraints gbc_chckbxInnerClasses = new GridBagConstraints(); - gbc_chckbxInnerClasses.anchor = GridBagConstraints.WEST; - gbc_chckbxInnerClasses.insets = new Insets(0, 0, 5, 5); - gbc_chckbxInnerClasses.gridx = 0; - gbc_chckbxInnerClasses.gridy = 15; - panel.add(chckbxInnerClasses, gbc_chckbxInnerClasses); - - JPanel panel_2 = new JPanel(); - tabbedPane.addTab("Watermark", null, panel_2, null); - GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 59, 0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gbl_panel_2.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; - panel_2.setLayout(gbl_panel_2); - - JLabel lblNewLabel_1 = new JLabel("Message:"); - GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints(); - gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_1.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_1.gridx = 0; - gbc_lblNewLabel_1.gridy = 2; - panel_2.add(lblNewLabel_1, gbc_lblNewLabel_1); - - this.waterMarkMessageField = new JTextField(); - this.waterMarkMessageField.setEnabled(false); - GridBagConstraints gbc_textField_4 = new GridBagConstraints(); - gbc_textField_4.gridwidth = 11; - gbc_textField_4.insets = new Insets(0, 0, 5, 5); - gbc_textField_4.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_4.gridx = 1; - gbc_textField_4.gridy = 2; - panel_2.add(this.waterMarkMessageField, gbc_textField_4); - this.waterMarkMessageField.setColumns(10); - - JLabel lblNewLabel_2 = new JLabel("Key:"); - GridBagConstraints gbc_lblNewLabel_2 = new GridBagConstraints(); - gbc_lblNewLabel_2.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_2.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_2.gridx = 0; - gbc_lblNewLabel_2.gridy = 3; - panel_2.add(lblNewLabel_2, gbc_lblNewLabel_2); - - this.watermarkPassword = new JPasswordField(); - this.watermarkPassword.setEnabled(false); - GridBagConstraints gbc_passwordField = new GridBagConstraints(); - gbc_passwordField.gridwidth = 11; - gbc_passwordField.insets = new Insets(0, 0, 5, 5); - gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField.gridx = 1; - gbc_passwordField.gridy = 3; - panel_2.add(this.watermarkPassword, gbc_passwordField); - - JLabel lblNewLabel_3 = new JLabel("Embed Type:"); - GridBagConstraints gbc_lblNewLabel_3 = new GridBagConstraints(); - gbc_lblNewLabel_3.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_3.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_3.gridx = 0; - gbc_lblNewLabel_3.gridy = 4; - panel_2.add(lblNewLabel_3, gbc_lblNewLabel_3); - - JComboBox comboBox_05 = new JComboBox<>(); - comboBox_05.setEnabled(false); - GridBagConstraints gbc_comboBox_05 = new GridBagConstraints(); - gbc_comboBox_05.anchor = GridBagConstraints.WEST; - gbc_comboBox_05.gridwidth = 6; - gbc_comboBox_05.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_05.gridx = 1; - gbc_comboBox_05.gridy = 4; - String[] watermarks = {"Constant Pool", "Signature"}; - for (String s : watermarks) { - comboBox_05.addItem(s); - } - panel_2.add(comboBox_05, gbc_comboBox_05); - - - JCheckBox chckbxAddWatermark = new JCheckBox("Watermark"); - GridBagConstraints gbc_chckbxNewCheckBox_8 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_8.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_8.gridx = 0; - gbc_chckbxNewCheckBox_8.gridy = 0; - chckbxAddWatermark.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(true); - waterMarkMessageField.setEnabled(true); - comboBox_05.setEnabled(true); - } else if (!chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(false); - waterMarkMessageField.setEnabled(false); - comboBox_05.setEnabled(false); - } - } - - }); - panel_2.add(chckbxAddWatermark, gbc_chckbxNewCheckBox_8); - - JSeparator separator_1 = new JSeparator(); - GridBagConstraints gbc_separator_1 = new GridBagConstraints(); - gbc_separator_1.insets = new Insets(0, 0, 5, 0); - gbc_separator_1.fill = GridBagConstraints.HORIZONTAL; - gbc_separator_1.gridwidth = 13; - gbc_separator_1.gridx = 0; - gbc_separator_1.gridy = 5; - panel_2.add(separator_1, gbc_separator_1); - - JLabel lblNewLabel = new JLabel("Extractor:"); - GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); - gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel.gridx = 0; - gbc_lblNewLabel.gridy = 6; - panel_2.add(lblNewLabel, gbc_lblNewLabel); - - JLabel lblNewLabel_4 = new JLabel("Input:"); - GridBagConstraints gbc_lblNewLabel_4 = new GridBagConstraints(); - gbc_lblNewLabel_4.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_4.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_4.gridx = 0; - gbc_lblNewLabel_4.gridy = 8; - panel_2.add(lblNewLabel_4, gbc_lblNewLabel_4); - - this.extractorInput = new JTextField(); - GridBagConstraints gbc_textField_5 = new GridBagConstraints(); - gbc_textField_5.gridwidth = 10; - gbc_textField_5.insets = new Insets(0, 0, 5, 5); - gbc_textField_5.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_5.gridx = 1; - gbc_textField_5.gridy = 8; - panel_2.add(this.extractorInput, gbc_textField_5); - this.extractorInput.setColumns(10); - - JButton btnNewButton_4 = new JButton("Select"); - btnNewButton_4.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (extractorInput.getText() != null - && !extractorInput.getText().isEmpty()) { - chooser.setSelectedFile(new File(extractorInput.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - extractorInput.setText(chooser.getSelectedFile() - .getAbsolutePath()); - } - }); - } - } - }); - GridBagConstraints gbc_btnNewButton_4 = new GridBagConstraints(); - gbc_btnNewButton_4.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_4.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_4.gridx = 11; - gbc_btnNewButton_4.gridy = 8; - panel_2.add(btnNewButton_4, gbc_btnNewButton_4); - - JLabel lblNewLabel_5 = new JLabel("Key:"); - GridBagConstraints gbc_lblNewLabel_5 = new GridBagConstraints(); - gbc_lblNewLabel_5.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_5.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_5.gridx = 0; - gbc_lblNewLabel_5.gridy = 9; - panel_2.add(lblNewLabel_5, gbc_lblNewLabel_5); - - this.extractorKey = new JPasswordField(); - GridBagConstraints gbc_passwordField_1 = new GridBagConstraints(); - gbc_passwordField_1.gridwidth = 10; - gbc_passwordField_1.insets = new Insets(0, 0, 5, 5); - gbc_passwordField_1.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField_1.gridx = 1; - gbc_passwordField_1.gridy = 9; - panel_2.add(this.extractorKey, gbc_passwordField_1); - - DefaultListModel listModel = new DefaultListModel(); - - JScrollPane scrollPane = new JScrollPane(); - GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.gridwidth = 13; - gbc_scrollPane.insets = new Insets(0, 4, 3, 5); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridx = 0; - gbc_scrollPane.gridy = 10; - panel_2.add(scrollPane, gbc_scrollPane); - - JList list_1 = new JList(listModel); - scrollPane.setViewportView(list_1); - - JButton btnNewButton_5 = new JButton("Extract"); - GridBagConstraints gbc_btnNewButton_5 = new GridBagConstraints(); - gbc_btnNewButton_5.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_5.gridx = 11; - gbc_btnNewButton_5.gridy = 9; - btnNewButton_5.addActionListener(new ActionListener() { - - @SuppressWarnings("deprecation") - @Override - public void actionPerformed(ActionEvent arg0) { - listModel.clear(); - - if (extractorInput.getText() == null - || extractorInput.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, "No file specified!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (extractorKey.getText() == null || extractorKey.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, "No key entered!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (!extractorInput.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Only Jars are allowed!", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - try { - File input = new File(extractorInput.getText()); - List foundIds = - WatermarkUtils.extractWatermark(input, - new String(extractorKey.getPassword())); - for (String s : foundIds) { - listModel.addElement(s); - } - - JOptionPane.showMessageDialog(null, - "Finished! Found: " + - String.valueOf(foundIds.size()) + " IDs", - "Info", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - }); - panel_2.add(btnNewButton_5, gbc_btnNewButton_5); - - JPanel otherPanel = new JPanel(); - tabbedPane.addTab("Other", null, otherPanel, null); - GridBagLayout gbl_otherPanel = new GridBagLayout(); - gbl_otherPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 59, 0, 0}; - gbl_otherPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0}; - gbl_otherPanel.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_otherPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; - otherPanel.setLayout(gbl_otherPanel); - - JLabel expireMessageLabel = new JLabel("Message:"); - GridBagConstraints gbc_expireMessageLabel = new GridBagConstraints(); - gbc_expireMessageLabel.insets = new Insets(0, 0, 5, 5); - gbc_expireMessageLabel.anchor = GridBagConstraints.EAST; - gbc_expireMessageLabel.gridx = 0; - gbc_expireMessageLabel.gridy = 2; - otherPanel.add(expireMessageLabel, gbc_expireMessageLabel); - - this.expirationMessageField = new JTextField(); - this.expirationMessageField.setEnabled(false); - GridBagConstraints gbc_messageField = new GridBagConstraints(); - gbc_messageField.gridwidth = 11; - gbc_messageField.insets = new Insets(0, 0, 5, 5); - gbc_messageField.fill = GridBagConstraints.HORIZONTAL; - gbc_messageField.gridx = 1; - gbc_messageField.gridy = 2; - otherPanel.add(this.expirationMessageField, gbc_messageField); - this.expirationMessageField.setColumns(10); - - JLabel expiresLabel = new JLabel("Expires:"); - GridBagConstraints gbc_expiresLabel = new GridBagConstraints(); - gbc_expiresLabel.insets = new Insets(0, 0, 5, 5); - gbc_expiresLabel.anchor = GridBagConstraints.EAST; - gbc_expiresLabel.gridx = 0; - gbc_expiresLabel.gridy = 3; - otherPanel.add(expiresLabel, gbc_expiresLabel); - - this.expirationDateField = new JTextField(); - this.expirationDateField.setEnabled(false); - GridBagConstraints gbc_dateField = new GridBagConstraints(); - gbc_dateField.gridwidth = 11; - gbc_dateField.insets = new Insets(0, 0, 5, 5); - gbc_dateField.fill = GridBagConstraints.HORIZONTAL; - gbc_dateField.gridx = 1; - gbc_dateField.gridy = 3; - otherPanel.add(this.expirationDateField, gbc_dateField); - - JCheckBox chckbxAddExpiration = new JCheckBox("Expiration"); - GridBagConstraints gbc_AddExpiration = new GridBagConstraints(); - gbc_AddExpiration.insets = new Insets(0, 0, 5, 5); - gbc_AddExpiration.gridx = 0; - gbc_AddExpiration.gridy = 0; - chckbxAddExpiration.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(true); - expirationMessageField.setEnabled(true); - } else if (!chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(false); - expirationMessageField.setEnabled(false); - } - } - - }); - otherPanel.add(chckbxAddExpiration, gbc_AddExpiration); - - JSeparator expireSeparator = new JSeparator(); - GridBagConstraints gbc_expireSeparator = new GridBagConstraints(); - gbc_expireSeparator.insets = new Insets(0, 0, 5, 0); - gbc_expireSeparator.fill = GridBagConstraints.HORIZONTAL; - gbc_expireSeparator.gridwidth = 13; - gbc_expireSeparator.gridx = 0; - gbc_expireSeparator.gridy = 4; - otherPanel.add(expireSeparator, gbc_expireSeparator); - - JComboBox dictionaryComboBox = new JComboBox<>(); - dictionaryComboBox.setEnabled(true); - GridBagConstraints gbc_dictionaryComboBox = new GridBagConstraints(); - gbc_dictionaryComboBox.fill = GridBagConstraints.HORIZONTAL; - gbc_dictionaryComboBox.insets = new Insets(0, 0, 5, 5); - gbc_dictionaryComboBox.gridx = 11; - gbc_dictionaryComboBox.gridy = 5; - - String[] dictionaries = {"0", "1", "2"}; - for (String s : dictionaries) { - dictionaryComboBox.addItem(s); - } - - otherPanel.add(dictionaryComboBox, gbc_dictionaryComboBox); - - JLabel chckbxDictionary = new JLabel("Dictionary:"); - GridBagConstraints gbc_chckbxDictionary = new GridBagConstraints(); - gbc_chckbxDictionary.anchor = GridBagConstraints.WEST; - gbc_chckbxDictionary.insets = new Insets(0, 5, 5, 5); - gbc_chckbxDictionary.gridx = 0; - gbc_chckbxDictionary.gridy = 5; - otherPanel.add(chckbxDictionary, gbc_chckbxDictionary); - - JButton garbageCollector = new JButton("GC"); - GridBagConstraints gbc_garbageCollector = new GridBagConstraints(); - gbc_garbageCollector.fill = GridBagConstraints.HORIZONTAL; - gbc_garbageCollector.insets = new Insets(0, 0, 5, 5); - gbc_garbageCollector.gridx = 11; - gbc_garbageCollector.gridy = 6; - garbageCollector.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(null, ((Runtime.getRuntime().maxMemory() / 1000000) - (Runtime.getRuntime().freeMemory() / 1000000)) + "mb in use before garbage collector."); - System.gc(); - } - }); - } - }); - otherPanel.add(garbageCollector, gbc_garbageCollector); - - JPanel panel_3 = new JPanel(); - tabbedPane.addTab("Exempt", null, panel_3, null); - GridBagLayout gbl_panel_3 = new GridBagLayout(); - gbl_panel_3.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; - gbl_panel_3.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0}; - gbl_panel_3.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_3.rowWeights = new double[]{0.0, 1.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - panel_3.setLayout(gbl_panel_3); - - JComboBox comboBox_04 = new JComboBox<>(); - GridBagConstraints gbc_comboBox_04 = new GridBagConstraints(); - gbc_comboBox_04.insets = new Insets(0, 5, 5, 5); - gbc_comboBox_04.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_04.gridx = 1; - gbc_comboBox_04.gridy = 12; - String[] options = {"Class", "Method", "Field", "StringEncryption", "InvokeDynamic", - "Flow", "LocalVars", "SourceName", "SourceDebug", "LineNumbers", "StringPool", - "Crasher", "HideCode", "Numbers", "Shuffler", "InnerClasses", "Renamer", - "Expiry"}; - - for (String s : options) { - comboBox_04.addItem(s); - } - - JScrollPane scrollPane_1 = new JScrollPane(); - GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints(); - gbc_scrollPane_1.gridheight = 11; - gbc_scrollPane_1.gridwidth = 11; - gbc_scrollPane_1.insets = new Insets(0, 4, 5, 5); - gbc_scrollPane_1.fill = GridBagConstraints.BOTH; - gbc_scrollPane_1.gridx = 1; - gbc_scrollPane_1.gridy = 1; - panel_3.add(scrollPane_1, gbc_scrollPane_1); - - DefaultListModel exemptList = new DefaultListModel<>(); - - JList list = new JList<>(exemptList); - list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - scrollPane_1.setViewportView(list); - panel_3.add(comboBox_04, gbc_comboBox_04); - - this.exemptField = new JTextField(); - GridBagConstraints gbc_textField_3 = new GridBagConstraints(); - gbc_textField_3.gridwidth = 8; - gbc_textField_3.insets = new Insets(0, 0, 5, 5); - gbc_textField_3.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_3.gridx = 2; - gbc_textField_3.gridy = 12; - panel_3.add(this.exemptField, gbc_textField_3); - this.exemptField.setColumns(10); - - JButton btnNewButton_2 = new JButton("Add"); - btnNewButton_2.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!exemptField.getText().equals("") - && exemptField.getText() != null - && !exemptField.getText().isEmpty()) { - if (comboBox_04.getSelectedIndex() == 0) { - exemptList.addElement("Class: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 1) { - exemptList.addElement("Method: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 2) { - exemptList.addElement("Field: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 3) { - exemptList.addElement("StringEncryption: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 4) { - exemptList.addElement("InvokeDynamic: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 5) { - exemptList.addElement("Flow: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 6) { - exemptList.addElement("LocalVars: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 7) { - exemptList.addElement("SourceName: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 8) { - exemptList.addElement("SourceDebug: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 9) { - exemptList.addElement("LineNumbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 10) { - exemptList.addElement("StringPool: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 11) { - exemptList.addElement("Crasher: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 12) { - exemptList.addElement("HideCode: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 13) { - exemptList.addElement("Numbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 14) { - exemptList.addElement("Shuffler: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 15) { - exemptList.addElement("InnerClasses: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 16) { - exemptList.addElement("Renamer: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 17) { - exemptList.addElement("Expiry: " + exemptField.getText()); - exemptField.setText(""); - } - } - } - }); - GridBagConstraints gbc_btnNewButton_2 = new GridBagConstraints(); - gbc_btnNewButton_2.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_2.gridx = 10; - gbc_btnNewButton_2.gridy = 12; - panel_3.add(btnNewButton_2, gbc_btnNewButton_2); - - JButton btnNewButton_3 = new JButton("Remove"); - btnNewButton_3.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - List removeList = list.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - exemptList.removeElement(s); - } - } - }); - GridBagConstraints gbc_btnNewButton_3 = new GridBagConstraints(); - gbc_btnNewButton_3.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_3.gridx = 11; - gbc_btnNewButton_3.gridy = 12; - panel_3.add(btnNewButton_3, gbc_btnNewButton_3); - - JPanel panel_7 = new JPanel(); - tabbedPane.addTab("About", null, panel_7, null); - GridBagLayout gbl_panel_7 = new GridBagLayout(); - gbl_panel_7.columnWidths = new int[]{0, 0}; - gbl_panel_7.rowHeights = new int[]{0, 0}; - gbl_panel_7.columnWeights = new double[]{1.0, Double.MIN_VALUE}; - gbl_panel_7.rowWeights = new double[]{1.0, Double.MIN_VALUE}; - panel_7.setLayout(gbl_panel_7); - - JTextArea txtrPizzaObfuscatorAuthors = new JTextArea(); - txtrPizzaObfuscatorAuthors.setFont(new Font("Arial", Font.PLAIN, 12)); - txtrPizzaObfuscatorAuthors.setText(Radon.PREFIX + "\nVersion: " + - Radon.VERSION + "\nAuthor: " + Radon.AUTHORS); - txtrPizzaObfuscatorAuthors.setLineWrap(true); - txtrPizzaObfuscatorAuthors.setEditable(false); - GridBagConstraints gbc_txtrPizzaObfuscatorAuthors = - new GridBagConstraints(); - gbc_txtrPizzaObfuscatorAuthors.fill = GridBagConstraints.BOTH; - gbc_txtrPizzaObfuscatorAuthors.insets = new Insets(0, 2, 0, 0); - gbc_txtrPizzaObfuscatorAuthors.gridx = 0; - gbc_txtrPizzaObfuscatorAuthors.gridy = 0; - panel_7.add(txtrPizzaObfuscatorAuthors, gbc_txtrPizzaObfuscatorAuthors); - - JPanel panel_1 = new JPanel(); - this.frmRadonObfuscator.getContentPane().add(panel_1, BorderLayout.SOUTH); - panel_1.setLayout(new BorderLayout(0, 0)); - - JPanel panel_5 = new JPanel(); - panel_1.add(panel_5, BorderLayout.EAST); - - JButton btnObfuscate = new JButton(" Process "); - btnObfuscate.addActionListener(new ActionListener() { - @SuppressWarnings("deprecation") - public void actionPerformed(ActionEvent arg0) { - if (inputField.getText().isEmpty() - || inputField.getText() == null - || !inputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid input JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (outputField.getText().isEmpty() - || outputField.getText() == null - || !outputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid output JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (outputField.getText().equals(inputField.getText())) { - JOptionPane.showMessageDialog(null, - "Output JAR can not have the same name as input " + - "JAR", "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (!chckbxStringEncryption.isSelected() - && !chckbxInvokeDynamic.isSelected() - && !chckbxFlow.isSelected() - && !chckbxLocalVariables.isSelected() - && !chckbxTrashClasses.isSelected() - && !chckbxSpringPool.isSelected() - && !chckbxCrasher.isSelected() - && !chckbxHidecode.isSelected() - && !chckbxClassRenammer.isSelected() - && !chckbxNumberObfuscation.isSelected() - && !chckbxAddWatermark.isSelected() - && !chckbxLineObfuscation.isSelected() - && !chckbxSourceName.isSelected() - && !chckbxSourceDebug.isSelected() - && !chckbxShuffler.isSelected() - && !chckbxAddExpiration.isSelected() - && !chckbxInnerClasses.isSelected()) { - JOptionPane.showMessageDialog(null, - "Please select an obfuscation " + - "setting!\nThe Spigot-Plugin setting " + - "alone is not counted as an option.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddWatermark.isSelected() - && waterMarkMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a message to be watermarked.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddWatermark.isSelected() - && watermarkPassword.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a key to encrypt the watermark message.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddExpiration.isSelected() - && expirationMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration message.", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddExpiration.isSelected() - && expirationDateField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration date.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - btnObfuscate.setText("Processing..."); - btnObfuscate.setEnabled(false); - /*SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - File output = null; - try { - - HashMap libs = new HashMap<>(); - for (int i = 0; i < libList.getSize(); i++) { - libs.put(libList.get(i), new File(libList.get(i))); - } - - File input = new File(inputField.getText()); - if (!input.exists()) { - JOptionPane.showMessageDialog(null, - "Input JAR does not exist.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - output = new File(outputField.getText()); - - int trashChance; - try { - trashChance = - Integer.valueOf(trashChanceField.getText()); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - "Please enter numbers only for the " + - "number of desired trash " + - "classes.", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - exempts.add(exemptList.get(i)); - } - boolean spigotMode = chckbxSpigotPlugin.isSelected(); - List transformers - = new ArrayList<>(); - - if (chckbxClassRenammer.isSelected()) { - transformers.add(new Renamer(spigotMode)); - } - if (chckbxInnerClasses.isSelected()) { - transformers.add(new InnerClassRemover()); - } - if (chckbxNumberObfuscation.isSelected()) { - transformers.add(new NumberObfuscation()); - } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - transformers.add(new LightInvokeDynamic()); - break; - case 1: - transformers.add(new NormalInvokeDynamic()); - break; - case 2: - transformers.add(new HeavyInvokeDynamic()); - break; - } - } - if (chckbxAddExpiration.isSelected()) { - if (!expirationDateField.getText().isEmpty() - && !expirationMessageField.getText() - .isEmpty()) { - long expireTime = - new SimpleDateFormat("MM/dd/yyyy") - .parse(expirationDateField - .getText()).getTime(); - transformers.add(new Expiry(expireTime, - expirationMessageField.getText())); - } - } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); - break; - case 1: - transformers.add(new LightStringEncryption(spigotMode)); - break; - case 2: - transformers.add(new NormalStringEncryption(spigotMode)); - break; - case 3: - transformers.add(new HeavyStringEncryption(spigotMode)); - break; - } - } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - transformers.add(new LightFlowObfuscation()); - break; - case 1: - transformers.add(new NormalFlowObfuscation()); - break; - } - } - if (chckbxSpringPool.isSelected()) { - transformers.add(new StringPool()); - } - if (chckbxShuffler.isSelected()) { - transformers.add(new Shuffler()); - } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLocalVariables()); - break; - case 1: - transformers.add(new RemoveLocalVariables()); - break; - } - } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLineNumbers()); - break; - case 1: - transformers.add(new RemoveLineNumbers()); - break; - } - } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceName()); - break; - case 1: - transformers.add(new RemoveSourceName()); - break; - } - } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceDebug()); - break; - case 1: - transformers.add(new RemoveSourceDebug()); - break; - } - } - if (chckbxCrasher.isSelected()) { - transformers.add(new Crasher()); - } - if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode(spigotMode)); - } - - int trashClasses = -1; - if (chckbxTrashClasses.isSelected()) { - trashClasses = trashChance; - } - - int watermarkType = -1; - if (chckbxAddWatermark.isSelected()) { - watermarkType = comboBox_05.getSelectedIndex(); - } - - int dictionary = dictionaryComboBox.getSelectedIndex(); - - new ConsoleGUI(); - Bootstrap bootstrap = new Bootstrap( - input, - output, - libs, - exempts, - transformers, - trashClasses, - waterMarkMessageField.getText(), - watermarkType, - new String(watermarkPassword.getPassword()), - dictionary); - bootstrap.startTheParty(false); - JOptionPane.showMessageDialog(null, - "Successfully processed file!", - "Done", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, t.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - if (output != null) { - output.delete(); - } - } finally { - btnObfuscate.setEnabled(true); - btnObfuscate.setText(" Process "); - } - } - });*/ - - SwingWorker sw = new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - File output = null; - try { - - HashMap libs = new HashMap<>(); - for (int i = 0; i < libList.getSize(); i++) { - libs.put(libList.get(i), new File(libList.get(i))); - } - - File input = new File(inputField.getText()); - if (!input.exists()) { - JOptionPane.showMessageDialog(null, - "Input JAR does not exist.", - "Error", JOptionPane.ERROR_MESSAGE); - return null; - } - output = new File(outputField.getText()); - - int trashChance; - try { - trashChance = - Integer.valueOf(trashChanceField.getText()); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - "Please enter numbers only for the " + - "number of desired trash " + - "classes.", "Error", - JOptionPane.ERROR_MESSAGE); - return null; - } - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - exempts.add(exemptList.get(i)); - } - boolean spigotMode = chckbxSpigotPlugin.isSelected(); - List transformers - = new ArrayList<>(); - - if (chckbxClassRenammer.isSelected()) { - transformers.add(new Renamer(spigotMode)); - } - if (chckbxInnerClasses.isSelected()) { - transformers.add(new InnerClassRemover()); - } - if (chckbxNumberObfuscation.isSelected()) { - transformers.add(new NumberObfuscation()); - } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - transformers.add(new LightInvokeDynamic()); - break; - case 1: - transformers.add(new NormalInvokeDynamic()); - break; - case 2: - transformers.add(new HeavyInvokeDynamic()); - break; - } - } - if (chckbxAddExpiration.isSelected()) { - if (!expirationDateField.getText().isEmpty() - && !expirationMessageField.getText() - .isEmpty()) { - long expireTime = - new SimpleDateFormat("MM/dd/yyyy") - .parse(expirationDateField - .getText()).getTime(); - transformers.add(new Expiry(expireTime, - expirationMessageField.getText())); - } - } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); - break; - case 1: - transformers.add(new LightStringEncryption(spigotMode)); - break; - case 2: - transformers.add(new NormalStringEncryption(spigotMode)); - break; - case 3: - transformers.add(new HeavyStringEncryption(spigotMode)); - break; - } - } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - transformers.add(new LightFlowObfuscation()); - break; - case 1: - transformers.add(new NormalFlowObfuscation()); - break; - } - } - if (chckbxSpringPool.isSelected()) { - transformers.add(new StringPool()); - } - if (chckbxShuffler.isSelected()) { - transformers.add(new Shuffler()); - } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLocalVariables()); - break; - case 1: - transformers.add(new RemoveLocalVariables()); - break; - } - } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLineNumbers()); - break; - case 1: - transformers.add(new RemoveLineNumbers()); - break; - } - } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceName()); - break; - case 1: - transformers.add(new RemoveSourceName()); - break; - } - } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceDebug()); - break; - case 1: - transformers.add(new RemoveSourceDebug()); - break; - } - } - if (chckbxCrasher.isSelected()) { - transformers.add(new Crasher()); - } - if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode(spigotMode)); - } - - int trashClasses = -1; - if (chckbxTrashClasses.isSelected()) { - trashClasses = trashChance; - } - - int watermarkType = -1; - if (chckbxAddWatermark.isSelected()) { - watermarkType = comboBox_05.getSelectedIndex(); - } - - int dictionary = dictionaryComboBox.getSelectedIndex(); - - new ConsoleGUI(); - Bootstrap bootstrap = new Bootstrap( - input, - output, - libs, - exempts, - transformers, - trashClasses, - waterMarkMessageField.getText(), - watermarkType, - new String(watermarkPassword.getPassword()), - dictionary); - bootstrap.startTheParty(false); - JOptionPane.showMessageDialog(null, - "Successfully processed file!", - "Done", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, t.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - if (output != null) { - output.delete(); - } - } finally { - btnObfuscate.setEnabled(true); - btnObfuscate.setText(" Process "); - } - return null; - } - }; - - sw.execute(); - } - }); - panel_5.add(btnObfuscate); - - JPanel panel_6 = new JPanel(); - panel_1.add(panel_6, BorderLayout.WEST); - - JButton btnLoadConfiguration = new JButton("Load Configuration"); - btnLoadConfiguration.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - File config = new File(chooser.getSelectedFile() - .getAbsolutePath()); - if (!config.exists()) - throw new IOException("Config file does " + - "not exist."); - - Config configParser - = new Config(new FileInputStream(config)); - configParser.loadIntoMap(); - configParser.sortExempts(); - configParser.checkConfig(); - - inputField.setText(configParser.getInput() - .getAbsolutePath()); - outputField.setText(configParser.getOutput() - .getAbsolutePath()); - libList.clear(); - for (String s : configParser.getLibraries() - .keySet()) { - libList.addElement(s); - } - - List exempts = configParser.getExempts(); - if (exempts != null) { - exemptList.clear(); - for (String s : exempts) { - exemptList.addElement(s); - } - } - - AbstractTransformer stringEncryptionMode - = configParser.getStringEncryptionType(); - if (stringEncryptionMode == null) { - chckbxStringEncryption.setSelected(false); - } else if (stringEncryptionMode - instanceof SuperLightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(0); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof LightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(1); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof NormalStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(2); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof HeavyStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(3); - comboBox.setEnabled(true); - } - - AbstractTransformer flowObfuscationMode = - configParser.getFlowObfuscationType(); - if (flowObfuscationMode == null) { - chckbxFlow.setSelected(false); - } else if (flowObfuscationMode - instanceof LightFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(0); - comboBox_2.setEnabled(true); - } else if (flowObfuscationMode - instanceof NormalFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(1); - comboBox_2.setEnabled(true); - } - - AbstractTransformer invokeDynamicMode = - configParser.getInvokeDynamicType(); - if (invokeDynamicMode == null) { - chckbxInvokeDynamic.setSelected(false); - } else if (invokeDynamicMode - instanceof LightInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(0); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof NormalInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(1); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof HeavyInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(2); - comboBox_1.setEnabled(true); - } - - AbstractTransformer localVariablesMode = - configParser.getLocalVariableObfuscationType(); - if (localVariablesMode == null) { - chckbxLocalVariables.setSelected(false); - } else if (localVariablesMode - instanceof ObfuscateLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(0); - comboBox_3.setEnabled(true); - } else if (localVariablesMode - instanceof RemoveLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(1); - comboBox_3.setEnabled(true); - } - - AbstractTransformer crasherMode = - configParser.getCrasherType(); - if (crasherMode instanceof Crasher) { - chckbxCrasher.setSelected(true); - } else { - chckbxCrasher.setSelected(false); - } - - AbstractTransformer hideCodeMode = - configParser.getHideCodeType(); - if (hideCodeMode instanceof HideCode) { - chckbxHidecode.setSelected(true); - } else { - chckbxHidecode.setSelected(false); - } - - AbstractTransformer lineRemoverMode = - configParser.getLineNumberObfuscationType(); - if (lineRemoverMode == null) { - chckbxLineObfuscation.setSelected(false); - } else if (lineRemoverMode - instanceof ObfuscateLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(0); - comboBox_5.setEnabled(true); - } else if (lineRemoverMode - instanceof RemoveLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(1); - comboBox_5.setEnabled(true); - } - - AbstractTransformer numberObfuscationMode = - configParser.getNumberObfuscationType(); - if (numberObfuscationMode - instanceof NumberObfuscation) { - chckbxNumberObfuscation.setSelected(true); - } else { - chckbxNumberObfuscation.setSelected(false); - } - - AbstractTransformer sourceNameObfuscationMode = - configParser.getSourceNameObfuscationType(); - if (sourceNameObfuscationMode == null) { - chckbxSourceName.setSelected(false); - } else if (sourceNameObfuscationMode - instanceof ObfuscateSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(0); - comboBox_123.setEnabled(true); - } else if (sourceNameObfuscationMode - instanceof RemoveSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(1); - comboBox_123.setEnabled(true); - } - - AbstractTransformer sourceDebugObfuscationMode = - configParser.getSourceDebugObfuscationType(); - if (sourceDebugObfuscationMode == null) { - chckbxSourceDebug.setSelected(false); - } else if (sourceDebugObfuscationMode - instanceof ObfuscateSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(0); - comboBox_1234.setEnabled(true); - } else if (sourceDebugObfuscationMode - instanceof RemoveSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(1); - comboBox_1234.setEnabled(true); - } - - - AbstractTransformer stringPoolMode = - configParser.getStringPoolType(); - if (stringPoolMode instanceof StringPool) { - chckbxSpringPool.setSelected(true); - } else { - chckbxSpringPool.setSelected(false); - } - - AbstractTransformer shufflerMode = - configParser.getShufflerType(); - if (shufflerMode instanceof Shuffler) { - chckbxShuffler.setSelected(true); - } else { - chckbxShuffler.setSelected(false); - } - - AbstractTransformer innerClassMode = - configParser.getInnerClassRemoverType(); - if (innerClassMode instanceof InnerClassRemover) { - chckbxInnerClasses.setSelected(true); - } else { - chckbxInnerClasses.setSelected(false); - } - - AbstractTransformer renamer = - configParser.getRenamerType(); - if (renamer instanceof Renamer) { - chckbxClassRenammer.setSelected(true); - } else { - chckbxClassRenammer.setSelected(false); - } - - if (configParser.getSpigotBool()) { - chckbxSpigotPlugin.setSelected(true); - } else { - chckbxSpigotPlugin.setSelected(false); - } - - int trashClassesChance = - configParser.getTrashClasses(); - if (trashClassesChance == -1) { - chckbxTrashClasses.setSelected(false); - } else { - chckbxTrashClasses.setSelected(true); - trashChanceField.setText(String - .valueOf(trashClassesChance)); - trashChanceField.setEditable(true); - } - - waterMarkMessageField.setText(configParser - .getWatermarkMsg()); - watermarkPassword.setText(configParser - .getWatermarkKey()); - - int watermarkType = - configParser.getWatermarkType(); - if (configParser.getWatermarkType() != -1) { - chckbxAddWatermark.setSelected(true); - waterMarkMessageField.setEnabled(true); - watermarkPassword.setEnabled(true); - comboBox_05.setEnabled(true); - comboBox_05.setSelectedIndex(watermarkType); - } - - if (configParser.getExpiryMsg() != null - && configParser.getExpiryTime() != -1) { - expirationMessageField.setText(configParser - .getExpiryMsg()); - expirationMessageField.setEnabled(true); - expirationDateField.setText(String - .valueOf(new SimpleDateFormat("MM/dd/yyyy") - .format(configParser.getExpiryTime()))); - expirationDateField.setEnabled(true); - chckbxAddExpiration.setSelected(true); - } - - int dictionary = configParser.getDictionaryType(); - dictionaryComboBox.setSelectedIndex(dictionary); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } - } - }); - } - } - }); - btnLoadConfiguration.setToolTipText("Loads config for pre-defined " + - "settings."); - panel_6.add(btnLoadConfiguration); - this.frmRadonObfuscator.setVisible(true); - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java deleted file mode 100644 index 9eee6d79..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java +++ /dev/null @@ -1,36 +0,0 @@ -package me.itzsomebody.radon.gui; - -import javax.swing.*; -import java.io.OutputStream; - -/** - * Redirects all PrintStreams to the provided JTextArea. - * - * @author ItzSomebody - */ -public class OutputStreamRedirect extends OutputStream { - /** - * Target JTextArea to log everything to. - */ - private JTextArea consoleOutput; - - /** - * Constructor to create an OutputStreamRedirect. - * - * @param consoleOutput target JTextArea to log everything to. - */ - public OutputStreamRedirect(JTextArea consoleOutput) { - this.consoleOutput = consoleOutput; - } - - /** - * Writes the specified byte to this output stream. - * - * @param b the byte code. - */ - @Override - public void write(int b) { - this.consoleOutput.append(String.valueOf((char) b)); - this.consoleOutput.setCaretPosition(this.consoleOutput.getDocument().getLength()); - } -} diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java deleted file mode 100644 index 23d0b914..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ /dev/null @@ -1,565 +0,0 @@ -package me.itzsomebody.radon.internal; - -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.transformers.misc.Expiry; -import me.itzsomebody.radon.transformers.misc.TrashClasses; -import me.itzsomebody.radon.transformers.renamer.Renamer; -import org.apache.commons.io.IOUtils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.transformers.*; -import me.itzsomebody.radon.utils.*; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -/** - * Bootstraps and runs the obfuscation process. - * - * @author ItzSomebody - */ -public class Bootstrap { // Eyyy bootstrap bill - /** - * HashMap that stores all of the loaded classes. - */ - private Map classPath = new HashMap<>(); - - /** - * HashMap that stores all of the input classes (and as they are obfuscated). - */ - private Map classes = new HashMap<>(); - - /** - * Extra classes that are generated by the obfuscator. - */ - private Map extraClasses = new HashMap<>(); - - /** - * Config object - */ - private Config config; - - /** - * Input file that read from. - */ - private File input; - - /** - * Output file that will be the obfuscation result. - */ - private File output; - - /** - * A {@link ZipOutputStream} which we use to write changes to the classes. - */ - private ZipOutputStream zos; - - /** - * A HashMap that stores the locations to each of the libraries that will - * be loaded into the classpath. - */ - private HashMap libs; - - /** - * Exempt information. - */ - private List exempts; - - /** - * Transformers that will be used. - */ - private List transformers; - - /** - * Dictionary type to use - */ - private int dictionary; - - /** - * Integer that determines how many trash classes to generate if any at all. - */ - private int trashClasses; - - /** - * String to be watermarked into the output if any at all. - */ - private String watermarkMsg; - - /** - * Integer that determines which watermarking technique to use if any at all. - */ - private int watermarkType; - - /** - * String to encrypt {@link Bootstrap#watermarkMsg} if any at all. - */ - private String watermarkKey; - - /** - * Strings to write to log. - */ - private List logStrings; - - /** - * {@link Long} used for entry times. - */ - private long currentTime; - - /** - * Constructor used for CLI to create a {@link Bootstrap} object. - * - * @param config {@link Config} object. - */ - public Bootstrap(Config config) { - this.config = config; - } - - /** - * Constructor used for MainGUI to create a {@link Bootstrap} object. - * - * @param input the input {@link File}. - * @param output the output {@link File}. - * @param libs the {@link HashMap} of libraries. - * @param exempts exempt information. - * @param transformers transformers that will be run. - * @param trashClasses number of trash classes to generate as - * {@link Integer}. - * @param watermarkMsg {@link String} to watermark into the output. - * @param watermarkType watermark type as {@link Integer}. - * @param watermarkKey {@link String} to encrypt watermark message. - * @param dictionary dictionary type used for string generation. - */ - public Bootstrap( - File input, - File output, - HashMap libs, - List exempts, - List transformers, - int trashClasses, - String watermarkMsg, - int watermarkType, - String watermarkKey, - int dictionary) { - this.input = input; - this.output = output; - this.libs = libs; - this.exempts = exempts; - this.transformers = transformers; - this.trashClasses = trashClasses; - this.watermarkMsg = watermarkMsg; - this.watermarkType = watermarkType; - this.watermarkKey = watermarkKey; - this.dictionary = dictionary; - } - - /** - * Actual obfuscation starts here. - * - * @param doInit should obfuscator read and set variables according to - * values of {@link Bootstrap#config}? - * @throws Throwable if any errors are thrown. - */ - public void startTheParty(boolean doInit) throws Throwable { - try { - this.logStrings = new ArrayList<>(); - if (doInit) { - this.init(); - this.logStrings.add(LoggerUtils.stdOut("Successfully parsed " + - "config")); - } else { - if (output.exists()) { - logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " - + FileUtils.renameExistingFile(output))); - } - this.zos = new ZipOutputStream(new FileOutputStream(output)); - } - this.currentTime = System.currentTimeMillis(); - this.loadClassPath(); - this.loadInput(); - - for (AbstractTransformer transformer : this.transformers) { - if (transformer instanceof Renamer) { - transformer.init(this.classes, this.classPath, this.exempts, this.dictionary); - } else { - transformer.init(this.classes, this.exempts, this.dictionary); - } - transformer.obfuscate(); - this.logStrings.addAll(transformer.getLogStrings()); - } - - if (this.trashClasses != -1) { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - for (int i = 0; i < this.trashClasses; i++) { - TrashClasses trashClass = - new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary)); - ClassNode classNode = trashClass.returnTrashClass(); - this.extraClasses.put(classNode.name, classNode); - } - this.logStrings.add(LoggerUtils.stdOut("Generated " - + String.valueOf(this.trashClasses) + " trash classes")); - } - - if (this.extraClasses.values().size() != 0) { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Writing generated classes to output")); - - // Write the contents of extraClasses to zos - for (ClassNode classNode : this.extraClasses.values()) { - ClassWriter cw = new ClassWriter(0); - classNode.accept(cw); - - ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); - newEntry.setTime(this.currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(this.zos, cw.toByteArray()); - } - } - - // Write the contents of classes to zos and recompute maxlocals, maxstack and stackframes - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Writing classes to output")); - for (ClassNode classNode : this.classes.values()) { - ClassWriter cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); - - if (this.watermarkMsg != null) { - if (this.watermarkType == 0 - && NumberUtils.getRandomInt(10) >= 5) { - cw.newUTF8("WMID: " - + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); - } else if (this.watermarkType == 1 - && NumberUtils.getRandomInt(10) >= 5) { - classNode.signature = - StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, - this.watermarkKey); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); - } - } - - cw.newUTF8("RADON" + Radon.VERSION); // :D - try { - classNode.accept(cw); - } catch (Throwable t) { - if (t.getMessage() != null - && t.getMessage().contains("JSR/RET")) { - cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - classNode.accept(cw); - } else { - this.logStrings.add(LoggerUtils - .stdOut("Error while writing " - + classNode.name + " -> " + t.getMessage())); - throw t; - } - } - - ZipEntry newEntry = new ZipEntry(classNode.name - + ".class"); - newEntry.setTime(this.currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(this.zos, cw.toByteArray()); - } - - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - if (this.zos != null) { - this.zos.setComment("Obfuscation by Radon obfuscator developed by ItzSomebody"); // Cause why not xD - this.zos.close(); - this.logStrings.add(LoggerUtils.stdOut("Finished processing file.")); - } - } catch (Throwable t) { - this.logStrings.add(LoggerUtils.stdOut("Error happened while processing: " - + t.getMessage())); - - if (zos != null) { - zos.close(); - } - if (this.output.delete()) { - this.logStrings.add(LoggerUtils.stdOut("Deleted output.")); - } else { - this.logStrings.add(LoggerUtils.stdOut("Unable to delete faulty output.")); - } - - t.printStackTrace(); - throw new RuntimeException(t.getMessage()); - } finally { - this.logStrings.add(LoggerUtils.stdOut("Writing log.")); - LoggerUtils.logWriter(this.logStrings); - } - } - - /** - * Nice big init method that loads details from the configuration file. - * - * @throws RuntimeException if some error pops up while parsing values - * from {@link Bootstrap#config}. - */ - private void init() throws RuntimeException { - try { - this.config.loadIntoMap(); - this.config.sortExempts(); - this.config.checkConfig(); - this.exempts = this.config.getExempts(); - this.input = this.config.getInput(); - this.output = this.config.getOutput(); - this.libs = this.config.getLibraries(); - this.transformers = new ArrayList<>(); - AbstractTransformer transformer; - // Specific order of adding transformers, feel free to change if - // you wish. - if ((transformer = this.config.getRenamerType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getInnerClassRemoverType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getNumberObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getInvokeDynamicType()) != null) { - this.transformers.add(transformer); - } - String expireMsg; - long expireTime; - if ((expireMsg = this.config.getExpiryMsg()) != null - && (expireTime = this.config.getExpiryTime()) != -1) { - transformer = new Expiry(expireTime, expireMsg); - this.transformers.add(transformer); - } - if ((transformer = this.config.getStringEncryptionType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getFlowObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getStringPoolType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getShufflerType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getLocalVariableObfuscationType()) - != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getLineNumberObfuscationType()) != - null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getSourceNameObfuscationType()) != - null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getSourceDebugObfuscationType()) - != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getCrasherType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getHideCodeType()) != null) { - this.transformers.add(transformer); - } - this.trashClasses = this.config.getTrashClasses(); - this.watermarkMsg = this.config.getWatermarkMsg(); - this.watermarkType = this.config.getWatermarkType(); - this.watermarkKey = this.config.getWatermarkKey(); - this.dictionary = this.config.getDictionaryType(); - if (this.output.exists()) { - this.logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " - + FileUtils.renameExistingFile(this.output))); - } - this.zos = new ZipOutputStream(new FileOutputStream(this.output)); - } catch (Throwable t) { - t.printStackTrace(); - throw new RuntimeException("Error while loading config: " - + t.getMessage()); - } - } - - /** - * Loads library classes into classpath. - * - * @throws RuntimeException if library cannot be be opened as Zip or some - * IOE happens. - */ - private void loadClassPath() throws RuntimeException { - ZipFile zipFile; - Enumeration entries; - ZipEntry zipEntry; - for (File lib : this.libs.values()) { - try { - this.logStrings.add(LoggerUtils.stdOut("Loading library " - + lib.getAbsolutePath())); - zipFile = new ZipFile(lib); - entries = zipFile.entries(); - while (entries.hasMoreElements()) { - zipEntry = entries.nextElement(); - if (zipEntry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zipFile - .getInputStream(zipEntry)); - ClassNode classNode = new ClassNode(); - classNode.libraryNode = true; - - // We don't need code in methods for libs - cr.accept(classNode, ClassReader.SKIP_DEBUG | - ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); - - - this.classPath.put(classNode.name, classNode); - } - } - zipFile.close(); - } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " - + lib.getAbsolutePath() + " as a zip!"); - } catch (IOException ioe) { - throw new RuntimeException("Library " + lib.getAbsolutePath() - + " does not exist!"); - } - } - } - - /** - * Loads input JAR classes and adds them to {@link Bootstrap#extraClasses} - * and {@link Bootstrap#classes}. - * - * @throws RuntimeException if input cannot be be opened as Zip or some - * IOE happens. - */ - private void loadInput() throws RuntimeException { - ZipFile zipFile; - Enumeration entries; - ZipEntry zipEntry; - try { - this.logStrings.add(LoggerUtils.stdOut("Loading classes of " - + this.input.getAbsolutePath())); - zipFile = new ZipFile(this.input); - entries = zipFile.entries(); - while (entries.hasMoreElements()) { - zipEntry = entries.nextElement(); - if (zipEntry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zipFile - .getInputStream(zipEntry)); - ClassNode classNode = new ClassNode(); - classNode.libraryNode = false; - - // We will manually compute stack frames later - cr.accept(classNode, ClassReader.SKIP_FRAMES); - - this.classes.put(classNode.name, classNode); - } else { - ZipEntry newEntry = new ZipEntry(zipEntry); - newEntry.setTime(this.currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(zos, IOUtils.toByteArray(zipFile - .getInputStream(zipEntry))); - } - } - zipFile.close(); - } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " - + this.input.getAbsolutePath() + " as a zip!"); - } catch (IOException ioe) { - throw new RuntimeException("Input " - + this.input.getAbsolutePath() + " does not exist!"); - } - - this.classPath.putAll(this.classes); - } - - /** - * CustomClassWriter that doesn't use the internal Java classpath. - * - * @author ItzSomebody - */ - class CustomClassWriter extends ClassWriter { - private CustomClassWriter(int flags) { - super(flags); - } - - @Override - protected String getCommonSuperClass(final String type1, - final String type2) { - if (type1.equals("java/lang/Object") - || type2.equals("java/lang/Object")) { - return "java/lang/Object"; - } - - return deriveCommonSuperName(type1, type2); - } - - /** - * Attempts to find the common superclass. - * - * @param type1 first class name to lookup. - * @param type2 second class name to lookup. - * @return the common superclass. - */ - private String deriveCommonSuperName(String type1, String type2) { - ClassNode first = returnClazz(type1); - ClassNode second = returnClazz(type2); - - if (isAssignableFrom(first, second)) { - return type1; - } - - if (isAssignableFrom(second, first)) { - return type2; - } - - if ((first.access & Opcodes.ACC_INTERFACE) == 0 - || (second.access & Opcodes.ACC_INTERFACE) == 0) { - return "java/lang/Object"; - } else { - do { - first = returnClazz(first.superName); - } while (!isAssignableFrom(first, second)); - return first.name; - } - } - - /** - * Returns the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - * - * @param ref class name to fetch from {@link Bootstrap#classPath}. - * @return the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - */ - private ClassNode returnClazz(String ref) { - ClassNode clazz = classPath.get(ref); - if (clazz == null) { - throw new RuntimeException(ref - + " does not exist in classpath!"); - } - return clazz; - } - - /** - * Returns true/false based on if clazz1 is the superclass of clazz2. - * - * @param clazz1 possible superclass. - * @param clazz2 class to check if assignable from clazz1. - * @return true/false based on if clazz1 is the superclass of clazz2. - */ - private boolean isAssignableFrom(ClassNode clazz1, ClassNode clazz2) { - return (clazz1.name.equals("java/lang/Object") - || clazz1.superName.equals(clazz2.name)); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/internal/CLI.java b/src/main/java/me/itzsomebody/radon/internal/CLI.java deleted file mode 100644 index ed8fa0d5..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/CLI.java +++ /dev/null @@ -1,110 +0,0 @@ -package me.itzsomebody.radon.internal; - -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.internal.climessages.CLIMessages; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.utils.WatermarkUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.util.List; - -/** - * CLI class to manage command line usage - * - * @author ItzSomebody - */ -public class CLI { - /** - * Args passed down from {@link Radon#main(String[])}. - */ - private String[] args; - - /** - * Constructor to create a new {@link CLI} object. - * - * @param args array of {@link String}s from command line arguments. - */ - public CLI(String[] args) { - this.args = args; - this.startTheParty(); - } - - /** - * Parses {@link CLI#args}. - */ - private void startTheParty() { - if (this.args.length == 1) { - switch (this.args[0].toLowerCase()) { - case "--version": - case "-version": - case "version": - case "/version": - break; - case "--help": - case "-help": - case "help": - case "/help": - CLIMessages.helpMsg(); - break; - default: - CLIMessages.usageMsg(); - } - } else if (this.args.length == 2) { - switch (this.args[0].toLowerCase()) { - case "--config": - case "-config": - case "config": - case "/config": - File file = new File(this.args[1]); - Config config; - try { - config = new Config(new FileInputStream(file)); - } catch (FileNotFoundException exc) { - LoggerUtils.stdOut("Config file not found"); - return; - } - Bootstrap bootstrap = new Bootstrap(config); - try { - bootstrap.startTheParty(true); - } catch (Throwable t) { - t.printStackTrace(); - } - break; - default: - CLIMessages.usageMsg(); - break; - } - } else if (this.args.length == 3) { - switch (this.args[0].toLowerCase()) { - case "--extract": - case "-extract": - case "extract": - case "/extract": - File leaked = new File(this.args[1]); - if (!leaked.exists()) { - LoggerUtils.stdOut("Input file not found"); - } - - try { - List ids = WatermarkUtils - .extractWatermark(leaked, this.args[2]); - for (String id : ids) { - LoggerUtils.stdOut(id); - } - return; - } catch (Throwable t) { - t.printStackTrace(); - } - break; - default: - CLIMessages.usageMsg(); - break; - } - } else { - CLIMessages.usageMsg(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java deleted file mode 100644 index 5bb160cf..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.itzsomebody.radon.internal.climessages; - -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Class of static abuse LOL - * - * @author ItzSomebody - */ -public class CLIMessages { - /** - * Prints usage message into console. - */ - public static void usageMsg() { - LoggerUtils.stdOut("Usage: java -jar Radon.jar --config example" + - ".config"); - LoggerUtils.stdOut("USage: java -jar Radon.jar --help"); - LoggerUtils.stdOut("Usage: java -jar Radon.jar"); - } - - /** - * Prints help message into console. - */ - public static void helpMsg() { - LoggerUtils.stdOut("CLI Usage:\t\tjava -jar Radon.jar --config " + - "example.config"); - LoggerUtils.stdOut("Credits:\t\tjava -jar Radon.jar --version"); - LoggerUtils.stdOut("Help Menu:\t\tjava -jar Radon.jar --help"); - LoggerUtils.stdOut("Watermark Extraction:\tjava -jar Radon.jar " + - "--extract Input.jar exampleKey"); - LoggerUtils.stdOut("MainGUI Usage:\t\tjava -jar Radon.jar"); - } -} diff --git a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java deleted file mode 100644 index 03c218d4..00000000 --- a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java +++ /dev/null @@ -1,1090 +0,0 @@ -package me.itzsomebody.radon.methods; - -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import me.itzsomebody.radon.transformers.invokedynamic.*; -import org.objectweb.asm.tree.MethodNode; - -import java.lang.invoke.ConstantCallSite; - -/** - * That returns methods needed to produce a {@link ConstantCallSite} for - * the appropriate InvokeDynamic transformer. - * - * @author ItzSomebody - * @author ASMifier by OW2 - */ -public class InvokeDynamicBSM implements Opcodes { - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link LightInvokeDynamic}. - * - * @param bsmName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link LightInvokeDynamic}. - */ - public static MethodNode lightBSM(String bsmName, String className) { - MethodNode mv = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC - + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_BRIDGE, - bsmName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/Object;", - null, - null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 7); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 8); - Label l4 = new Label(); - mv.visitLabel(l4); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 9); - Label l5 = new Label(); - mv.visitLabel(l5); - Label l6 = new Label(); - mv.visitJumpInsn(GOTO, l6); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 8); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitVarInsn(ILOAD, 9); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 1029); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitIincInsn(9, 1); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, - null); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l7); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 10); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 11); - Label l12 = new Label(); - mv.visitLabel(l12); - Label l13 = new Label(); - mv.visitJumpInsn(GOTO, l13); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitFrame(Opcodes.F_FULL, 12, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 11); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2038); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l15 = new Label(); - mv.visitLabel(l15); - mv.visitIincInsn(11, 1); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l14); - Label l16 = new Label(); - mv.visitLabel(l16); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 11); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 13); - Label l19 = new Label(); - mv.visitLabel(l19); - Label l20 = new Label(); - mv.visitJumpInsn(GOTO, l20); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitFrame(Opcodes.F_FULL, 14, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", - "[C", "[C", "[C", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 12); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 1928); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l22 = new Label(); - mv.visitLabel(l22); - mv.visitIincInsn(13, 1); - mv.visitLabel(l20); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l21); - Label l23 = new Label(); - mv.visitLabel(l23); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", - "()I", false); - mv.visitVarInsn(ISTORE, 14); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitVarInsn(ILOAD, 14); - Label l25 = new Label(); - Label l26 = new Label(); - Label l27 = new Label(); - mv.visitTableSwitchInsn(0, 1, l27, new Label[]{l25, l26}); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "[C", "[C", - "[C", "[C", "[C", "[C", Opcodes.TOP, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", - "findStatic", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l28 = new Label(); - mv.visitLabel(l28); - Label l29 = new Label(); - mv.visitJumpInsn(GOTO, l29); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", "(Ljava/lang/String;" + - "Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", - false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findVirtual", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", - false); - mv.visitVarInsn(ASTORE, 13); - Label l30 = new Label(); - mv.visitLabel(l30); - mv.visitJumpInsn(GOTO, l29); - mv.visitLabel(l27); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", - false); - mv.visitInsn(ATHROW); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - "java/lang/invoke/MethodHandle", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", - "asType", "(Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l31 = new Label(); - mv.visitLabel(l31); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 13); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", - "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l1); - mv.visitInsn(ARETURN); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_FULL, 7, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object"}, - 1, new Object[]{"java/lang/Exception"}); - mv.visitVarInsn(ASTORE, 7); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitMaxs(6, 15); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link NormalInvokeDynamic}. - * - * @param bsmName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link NormalInvokeDynamic}. - */ - public static MethodNode normalBSM(String bsmName, String className) { - MethodNode mv = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC - + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_BRIDGE, - bsmName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/Object;", - null, - null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); - Label l3 = new Label(); - Label l4 = new Label(); - Label l5 = new Label(); - mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Exception"); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 7); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 8); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 9); - Label l8 = new Label(); - mv.visitLabel(l8); - Label l9 = new Label(); - mv.visitJumpInsn(GOTO, l9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 8); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitVarInsn(ILOAD, 9); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2893); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitIincInsn(9, 1); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l10); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 9); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 10); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 11); - Label l15 = new Label(); - mv.visitLabel(l15); - Label l16 = new Label(); - mv.visitJumpInsn(GOTO, l16); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_FULL, 12, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 11); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2993); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitIincInsn(11, 1); - mv.visitLabel(l16); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l17); - Label l19 = new Label(); - mv.visitLabel(l19); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 11); - Label l20 = new Label(); - mv.visitLabel(l20); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 13); - Label l22 = new Label(); - mv.visitLabel(l22); - Label l23 = new Label(); - mv.visitJumpInsn(GOTO, l23); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_FULL, 14, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 12); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 8372); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitIincInsn(13, 1); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l24); - Label l26 = new Label(); - mv.visitLabel(l26); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", - "()I", false); - mv.visitVarInsn(ISTORE, 14); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ILOAD, 14); - mv.visitIntInsn(SIPUSH, 256); - mv.visitInsn(ISHL); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitVarInsn(ISTORE, 14); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitVarInsn(ILOAD, 14); - Label l29 = new Label(); - Label l30 = new Label(); - Label l31 = new Label(); - mv.visitTableSwitchInsn(0, 1, l31, new Label[]{l29, l30}); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - Opcodes.TOP, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findStatic", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l32 = new Label(); - mv.visitLabel(l32); - Label l33 = new Label(); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l30); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findVirtual", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l34 = new Label(); - mv.visitLabel(l34); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l33); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - "java/lang/invoke/MethodHandle", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", - "asType", - "(Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - mv.visitLabel(l0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", - "getRuntime", "()Ljava/lang/Runtime;", false); - mv.visitMethodInsn(INVOKESTATIC, - "java/util/concurrent/ThreadLocalRandom", "current", - "()Ljava/util/concurrent/ThreadLocalRandom;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/util/concurrent/ThreadLocalRandom", "nextInt", - "()I", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", - "(Ljava/lang/String;)Ljava/lang/Process;", false); - mv.visitInsn(POP); - mv.visitLabel(l1); - Label l35 = new Label(); - mv.visitJumpInsn(GOTO, l35); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l35); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 13); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", - "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l4); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_FULL, 7, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object"}, - 1, new Object[]{"java/lang/Exception"}); - mv.visitVarInsn(ASTORE, 7); - Label l36 = new Label(); - mv.visitLabel(l36); - mv.visitVarInsn(ALOAD, 7); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", - "printStackTrace", "()V", false); - Label l37 = new Label(); - mv.visitLabel(l37); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitMaxs(6, 16); - mv.visitEnd(); - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link HeavyInvokeDynamic}. - * - * @param methodName used to determine the name of the generated - * {@link MethodNode}. - * @param className used to determine the classname to use as loader. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link HeavyInvokeDynamic}. - */ - public static MethodNode heavyBSM(String methodName, String className) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_BRIDGE + ACC_SYNTHETIC, methodName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/NoSuchFieldException"); - Label l3 = new Label(); - Label l4 = new Label(); - Label l5 = new Label(); - mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Throwable"); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitVarInsn(ASTORE, 8); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 8); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - mv.visitIntInsn(SIPUSH, 233); - mv.visitInsn(IOR); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitVarInsn(ASTORE, 9); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ALOAD, 8); - Label l9 = new Label(); - mv.visitJumpInsn(IF_ACMPNE, l9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"java/lang/Object", "java/lang/Object"}, 0, null); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ASTORE, 11); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ASTORE, 12); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 13); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ALOAD, 13); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 14); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 15); - Label l14 = new Label(); - mv.visitLabel(l14); - Label l15 = new Label(); - mv.visitJumpInsn(GOTO, l15); - Label l16 = new Label(); - mv.visitLabel(l16); - mv.visitFrame(Opcodes.F_FULL, 16, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 14); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ILOAD, 15); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 4382); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitIincInsn(15, 1); - mv.visitLabel(l15); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 13); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l16); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 14); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitVarInsn(ASTORE, 15); - Label l19 = new Label(); - mv.visitLabel(l19); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l20 = new Label(); - mv.visitLabel(l20); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 18); - Label l22 = new Label(); - mv.visitLabel(l22); - Label l23 = new Label(); - mv.visitJumpInsn(GOTO, l23); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_FULL, 19, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 17); - mv.visitVarInsn(ILOAD, 18); - mv.visitVarInsn(ALOAD, 16); - mv.visitVarInsn(ILOAD, 18); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 3940); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitIincInsn(18, 1); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 18); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l24); - Label l26 = new Label(); - mv.visitLabel(l26); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitVarInsn(ASTORE, 18); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ALOAD, 7); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 19); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 20); - Label l29 = new Label(); - mv.visitLabel(l29); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 21); - Label l30 = new Label(); - mv.visitLabel(l30); - Label l31 = new Label(); - mv.visitJumpInsn(GOTO, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 20); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitVarInsn(ILOAD, 21); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 5739); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitIincInsn(21, 1); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l32); - Label l34 = new Label(); - mv.visitLabel(l34); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitVarInsn(ASTORE, 21); - Label l35 = new Label(); - mv.visitLabel(l35); - mv.visitVarInsn(ALOAD, 11); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l36 = new Label(); - Label l37 = new Label(); - Label l38 = new Label(); - mv.visitTableSwitchInsn(0, 1, l38, new Label[] { l36, l37 }); - mv.visitLabel(l36); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, 22); - Label l39 = new Label(); - mv.visitLabel(l39); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 23); - Label l40 = new Label(); - mv.visitLabel(l40); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 14); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitVarInsn(ASTORE, 24); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND,3, new Object[] {"java/lang/Object", "java/lang/reflect/Field", "java/lang/Class"}, 0, null); - mv.visitVarInsn(ALOAD, 24); - mv.visitVarInsn(ALOAD, 18); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); - mv.visitVarInsn(ASTORE, 23); - mv.visitLabel(l1); - Label l41 = new Label(); - mv.visitJumpInsn(GOTO, l41); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/NoSuchFieldException"}); - mv.visitVarInsn(ASTORE, 25); - Label l42 = new Label(); - mv.visitLabel(l42); - mv.visitVarInsn(ALOAD, 24); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSuperclass", "()Ljava/lang/Class;", false); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 24); - mv.visitJumpInsn(IFNONNULL, l0); - mv.visitLabel(l41); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 23); - Label l43 = new Label(); - mv.visitJumpInsn(IFNONNULL, l43); - Label l44 = new Label(); - mv.visitLabel(l44); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l43); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 22); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l45 = new Label(); - Label l46 = new Label(); - Label l47 = new Label(); - Label l48 = new Label(); - Label l49 = new Label(); - mv.visitTableSwitchInsn(0, 3, l49, new Label[] { l45, l46, l47, l48 }); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l50 = new Label(); - mv.visitLabel(l50); - Label l51 = new Label(); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l46); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l52 = new Label(); - mv.visitLabel(l52); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l47); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l48); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l49); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l37); - mv.visitFrame(Opcodes.F_CHOP,3, null, 0, null); - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, 25); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 21); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); - mv.visitVarInsn(ASTORE, 26); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 25); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l58 = new Label(); - Label l59 = new Label(); - Label l60 = new Label(); - mv.visitTableSwitchInsn(0, 1, l60, new Label[] { l58, l59 }); - mv.visitLabel(l58); - mv.visitFrame(Opcodes.F_FULL, 27, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String", Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "java/lang/Object", "java/lang/invoke/MethodType"}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 26); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findVirtual", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l59); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 26); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l60); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - Label l63 = new Label(); - mv.visitLabel(l63); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l38); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l51); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/invoke/MethodHandle", "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l4); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_FULL, 13, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object"}, 1, new Object[] {"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 13); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitMaxs(4, 27); - mv.visitEnd(); - - return mv; - } -} diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java deleted file mode 100644 index e25b5d84..00000000 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java +++ /dev/null @@ -1,1479 +0,0 @@ -package me.itzsomebody.radon.methods; - -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.MethodNode; -import me.itzsomebody.radon.transformers.stringencryption.*; - -/** - * Class containing {@link MethodNode}s needed to decrypt a {@link String} for the - * appropriate StringEncryption transformer. - * - * @author ItzSomebody - * @author ASMifier by OW2 - */ -public class StringEncryption implements Opcodes { - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. - */ - public static MethodNode superLightMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC - + ACC_SYNTHETIC + ACC_BRIDGE, decryptionMethodName, - "(Ljava/lang/String;I)Ljava/lang/String;", null, - null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 2); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 3); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 4); - Label l3 = new Label(); - mv.visitLabel(l3); - Label l4 = new Label(); - mv.visitJumpInsn(GOTO, l4); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitIincInsn(4, 1); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l5); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitInsn(ARETURN); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitMaxs(4, 5); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link LightStringEncryption}. - * - * @param decryptMethodName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link LightStringEncryption}. - */ - public static MethodNode lightMethod(String decryptMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_SYNTHETIC + ACC_BRIDGE, decryptMethodName, - "(Ljava/lang/Object;I)Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I", - false); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 2); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 3); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", - "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ASTORE, 4); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l4 = new Label(); - mv.visitLabel(l4); - Label l5 = new Label(); - mv.visitJumpInsn(GOTO, l5); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_FULL, 6, new Object[]{"java/lang/Object", - Opcodes.INTEGER, "[C", "[C", "[Ljava/lang/StackTraceElement;", - Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(I2C); - mv.visitVarInsn(ISTORE, 6); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(I2C); - mv.visitVarInsn(ISTORE, 7); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ILOAD, 5); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitIincInsn(5, 1); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 5); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l6); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitInsn(ARETURN); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitMaxs(4, 8); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link NormalStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link NormalStringEncryption}. - */ - public static MethodNode normalMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_BRIDGE + ACC_SYNTHETIC, decryptionMethodName, - "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", - null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable"); - Label l2 = new Label(); - Label l3 = new Label(); - Label l4 = new Label(); - mv.visitTryCatchBlock(l2, l3, l4, "java/lang/Throwable"); - Label l5 = new Label(); - Label l6 = new Label(); - mv.visitTryCatchBlock(l5, l6, l4, "java/lang/Throwable"); - Label l7 = new Label(); - Label l8 = new Label(); - mv.visitTryCatchBlock(l7, l3, l8, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l8, "java/lang/Throwable"); - Label l9 = new Label(); - mv.visitTryCatchBlock(l4, l9, l8, "java/lang/Throwable"); - Label l10 = new Label(); - Label l11 = new Label(); - mv.visitTryCatchBlock(l10, l3, l11, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l11, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l11, "java/lang/Throwable"); - Label l12 = new Label(); - mv.visitTryCatchBlock(l8, l12, l11, "java/lang/Throwable"); - Label l13 = new Label(); - Label l14 = new Label(); - mv.visitTryCatchBlock(l13, l14, l11, "java/lang/Throwable"); - Label l15 = new Label(); - Label l16 = new Label(); - mv.visitTryCatchBlock(l15, l16, l11, "java/lang/Throwable"); - Label l17 = new Label(); - Label l18 = new Label(); - mv.visitTryCatchBlock(l17, l3, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l8, l12, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l13, l14, l18, "java/lang/Throwable"); - Label l19 = new Label(); - mv.visitTryCatchBlock(l15, l19, l18, "java/lang/Throwable"); - Label l20 = new Label(); - Label l21 = new Label(); - mv.visitTryCatchBlock(l20, l3, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l8, l12, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l13, l14, l21, "java/lang/Throwable"); - Label l22 = new Label(); - mv.visitTryCatchBlock(l15, l22, l21, "java/lang/Throwable"); - Label l23 = new Label(); - mv.visitLabel(l23); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitVarInsn(ALOAD, 1); - Label l25 = new Label(); - mv.visitJumpInsn(IFNULL, l25); - mv.visitInsn(ICONST_1); - Label l26 = new Label(); - mv.visitJumpInsn(GOTO, l26); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_0); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER}); - mv.visitVarInsn(ISTORE, 4); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ILOAD, 3); - mv.visitVarInsn(ILOAD, 4); - Label l28 = new Label(); - mv.visitJumpInsn(IF_ICMPNE, l28); - Label l29 = new Label(); - mv.visitLabel(l29); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ASTORE, 0); - mv.visitLabel(l20); - mv.visitJumpInsn(GOTO, l28); - Label l30 = new Label(); - mv.visitLabel(l30); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - Label l31 = new Label(); - mv.visitJumpInsn(IFNULL, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - Label l33 = new Label(); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - Label l34 = new Label(); - mv.visitJumpInsn(IFNONNULL, l34); - mv.visitLabel(l10); - Label l35 = new Label(); - mv.visitJumpInsn(GOTO, l35); - Label l36 = new Label(); - mv.visitLabel(l36); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 2); - mv.visitJumpInsn(IFEQ, l15); - Label l37 = new Label(); - mv.visitLabel(l37); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFNE, l35); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l39 = new Label(); - mv.visitLabel(l39); - mv.visitVarInsn(ILOAD, 5); - Label l40 = new Label(); - mv.visitJumpInsn(IFEQ, l40); - Label l41 = new Label(); - mv.visitLabel(l41); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ISTORE, 6); - Label l42 = new Label(); - mv.visitLabel(l42); - Label l43 = new Label(); - mv.visitJumpInsn(GOTO, l43); - mv.visitLabel(l40); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(BIPUSH, 8); - mv.visitVarInsn(ISTORE, 6); - mv.visitLabel(l43); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 7); - Label l44 = new Label(); - mv.visitLabel(l44); - mv.visitVarInsn(ILOAD, 7); - Label l45 = new Label(); - mv.visitJumpInsn(IFNE, l45); - Label l46 = new Label(); - mv.visitLabel(l46); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IOR); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - Label l47 = new Label(); - mv.visitLabel(l47); - Label l48 = new Label(); - mv.visitJumpInsn(GOTO, l48); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IAND); - mv.visitInsn(ICONST_3); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - mv.visitLabel(l48); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ISHL); - mv.visitVarInsn(ISTORE, 9); - Label l49 = new Label(); - mv.visitLabel(l49); - mv.visitVarInsn(ILOAD, 9); - Label l50 = new Label(); - Label l51 = new Label(); - Label l52 = new Label(); - mv.visitTableSwitchInsn(0, 1, l52, new Label[]{l50, l51}); - mv.visitLabel(l50); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l51); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 10); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l52); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"java/lang/String"}, - 0, null); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_0); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_1); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_2); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l58 = new Label(); - mv.visitLabel(l58); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_3); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_3); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l59 = new Label(); - mv.visitLabel(l59); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", - "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IOR); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l60 = new Label(); - mv.visitLabel(l60); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l1); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 12); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(ICONST_1); - mv.visitInsn(ISUB); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 12); - Label l63 = new Label(); - mv.visitLabel(l63); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 13); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitInsn(IADD); - mv.visitVarInsn(ISTORE, 14); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitJumpInsn(GOTO, l13); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "java/lang/String", "java/lang/StackTraceElement", - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ILOAD, 14); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitInsn(ISUB); - mv.visitVarInsn(ISTORE, 15); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFNE, l13); - Label l67 = new Label(); - mv.visitLabel(l67); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l68 = new Label(); - mv.visitLabel(l68); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - mv.visitLabel(l2); - mv.visitVarInsn(ILOAD, 4); - Label l69 = new Label(); - mv.visitJumpInsn(IFNE, l69); - Label l70 = new Label(); - mv.visitLabel(l70); - Label l71 = new Label(); - mv.visitJumpInsn(GOTO, l71); - Label l72 = new Label(); - mv.visitLabel(l72); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{Opcodes.INTEGER, - "[C", "[C"}, 0, null); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ARRAYLENGTH); - Label l73 = new Label(); - mv.visitJumpInsn(IF_ICMPGE, l73); - Label l74 = new Label(); - mv.visitLabel(l74); - mv.visitVarInsn(ALOAD, 17); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 16); - mv.visitVarInsn(ILOAD, 15); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 12); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 2); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l75 = new Label(); - mv.visitLabel(l75); - mv.visitIincInsn(15, 1); - mv.visitLabel(l71); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l72); - mv.visitLabel(l73); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitJumpInsn(IF_ICMPNE, l69); - Label l76 = new Label(); - mv.visitLabel(l76); - mv.visitJumpInsn(GOTO, l5); - mv.visitLabel(l69); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitLabel(l3); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLabel(l6); - mv.visitInsn(ARETURN); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l9); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l8); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "java/lang/String", "java/lang/StackTraceElement", - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l12); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 6); - mv.visitIntInsn(BIPUSH, 7); - mv.visitInsn(ISHL); - mv.visitJumpInsn(IF_ICMPLT, l7); - mv.visitLabel(l14); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l15); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l35); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l36); - mv.visitLabel(l16); - Label l77 = new Label(); - mv.visitJumpInsn(GOTO, l77); - mv.visitLabel(l11); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l78 = new Label(); - mv.visitLabel(l78); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l34); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l77); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l17); - mv.visitLabel(l19); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l18); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l79 = new Label(); - mv.visitLabel(l79); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l33); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l77); - Label l80 = new Label(); - mv.visitLabel(l80); - mv.visitJumpInsn(GOTO, l28); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l28); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l30); - mv.visitLabel(l22); - Label l81 = new Label(); - mv.visitJumpInsn(GOTO, l81); - mv.visitLabel(l21); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l82 = new Label(); - mv.visitLabel(l82); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l81); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l27); - Label l83 = new Label(); - mv.visitLabel(l83); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - Label l84 = new Label(); - mv.visitLabel(l84); - mv.visitMaxs(4, 19); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link HeavyStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link HeavyStringEncryption}. - */ - public static MethodNode heavyMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_SYNTHETIC + ACC_BRIDGE, decryptionMethodName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable"); - Label l2 = new Label(); - Label l3 = new Label(); - Label l4 = new Label(); - mv.visitTryCatchBlock(l2, l3, l4, "java/lang/Throwable"); - Label l5 = new Label(); - Label l6 = new Label(); - Label l7 = new Label(); - mv.visitTryCatchBlock(l5, l6, l7, "java/lang/Throwable"); - Label l8 = new Label(); - Label l9 = new Label(); - mv.visitTryCatchBlock(l8, l6, l9, "java/lang/Throwable"); - Label l10 = new Label(); - mv.visitTryCatchBlock(l7, l10, l9, "java/lang/Throwable"); - Label l11 = new Label(); - Label l12 = new Label(); - mv.visitTryCatchBlock(l11, l12, l9, "java/lang/Throwable"); - Label l13 = new Label(); - Label l14 = new Label(); - mv.visitTryCatchBlock(l13, l6, l14, "java/lang/Throwable"); - mv.visitTryCatchBlock(l7, l10, l14, "java/lang/Throwable"); - mv.visitTryCatchBlock(l11, l12, l14, "java/lang/Throwable"); - Label l15 = new Label(); - mv.visitTryCatchBlock(l9, l15, l14, "java/lang/Throwable"); - Label l16 = new Label(); - Label l17 = new Label(); - mv.visitTryCatchBlock(l16, l6, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l7, l10, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l11, l12, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l9, l15, l17, "java/lang/Throwable"); - Label l18 = new Label(); - mv.visitTryCatchBlock(l14, l18, l17, "java/lang/Throwable"); - Label l19 = new Label(); - Label l20 = new Label(); - mv.visitTryCatchBlock(l19, l20, l17, "java/lang/Throwable"); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - Label l22 = new Label(); - mv.visitLabel(l22); - mv.visitVarInsn(ALOAD, 1); - Label l23 = new Label(); - mv.visitJumpInsn(IFNULL, l23); - mv.visitInsn(ICONST_1); - Label l24 = new Label(); - mv.visitJumpInsn(GOTO, l24); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_0); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{Opcodes.INTEGER}); - mv.visitVarInsn(ISTORE, 4); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ILOAD, 3); - mv.visitVarInsn(ILOAD, 4); - Label l26 = new Label(); - mv.visitJumpInsn(IF_ICMPEQ, l26); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ASTORE, 1); - mv.visitLabel(l16); - mv.visitJumpInsn(GOTO, l26); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - Label l29 = new Label(); - mv.visitJumpInsn(IFNULL, l29); - Label l30 = new Label(); - mv.visitLabel(l30); - Label l31 = new Label(); - mv.visitJumpInsn(GOTO, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitVarInsn(ILOAD, 5); - Label l34 = new Label(); - mv.visitJumpInsn(IFEQ, l34); - Label l35 = new Label(); - mv.visitLabel(l35); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ISTORE, 6); - Label l36 = new Label(); - mv.visitLabel(l36); - Label l37 = new Label(); - mv.visitJumpInsn(GOTO, l37); - mv.visitLabel(l34); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(BIPUSH, 8); - mv.visitVarInsn(ISTORE, 6); - mv.visitLabel(l37); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 7); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitVarInsn(ILOAD, 7); - Label l39 = new Label(); - mv.visitJumpInsn(IFNE, l39); - Label l40 = new Label(); - mv.visitLabel(l40); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IOR); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - Label l41 = new Label(); - mv.visitLabel(l41); - Label l42 = new Label(); - mv.visitJumpInsn(GOTO, l42); - mv.visitLabel(l39); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IAND); - mv.visitInsn(ICONST_3); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - mv.visitLabel(l42); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ISHL); - mv.visitVarInsn(ISTORE, 9); - Label l43 = new Label(); - mv.visitLabel(l43); - mv.visitVarInsn(ILOAD, 9); - Label l44 = new Label(); - Label l45 = new Label(); - Label l46 = new Label(); - mv.visitTableSwitchInsn(0, 1, l46, new Label[]{l44, l45}); - mv.visitLabel(l44); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - Label l47 = new Label(); - mv.visitLabel(l47); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 10); - Label l48 = new Label(); - mv.visitLabel(l48); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l46); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"java/lang/String"}, - 0, null); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l49 = new Label(); - mv.visitLabel(l49); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_0); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l50 = new Label(); - mv.visitLabel(l50); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_1); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l51 = new Label(); - mv.visitLabel(l51); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_2); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l52 = new Label(); - mv.visitLabel(l52); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_3); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_3); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", - "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IOR); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l1); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 12); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", - "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 12); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 13); - Label l58 = new Label(); - mv.visitLabel(l58); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitInsn(IADD); - mv.visitVarInsn(ISTORE, 14); - Label l59 = new Label(); - mv.visitLabel(l59); - mv.visitJumpInsn(GOTO, l19); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ILOAD, 14); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitInsn(ISUB); - mv.visitVarInsn(ISTORE, 15); - Label l60 = new Label(); - mv.visitLabel(l60); - mv.visitVarInsn(ILOAD, 5); - mv.visitJumpInsn(IFNE, l19); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - mv.visitLabel(l8); - mv.visitVarInsn(ILOAD, 5); - Label l63 = new Label(); - mv.visitJumpInsn(IFNE, l63); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 19); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 20); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 21); - Label l67 = new Label(); - mv.visitLabel(l67); - Label l68 = new Label(); - mv.visitJumpInsn(GOTO, l68); - Label l69 = new Label(); - mv.visitLabel(l69); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "[C", "[C", "java/lang/String", "[C", "[C", - Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 20); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 19); - mv.visitVarInsn(ILOAD, 21); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l70 = new Label(); - mv.visitLabel(l70); - mv.visitIincInsn(21, 1); - mv.visitLabel(l68); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l69); - Label l71 = new Label(); - mv.visitLabel(l71); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitVarInsn(ASTORE, 18); - Label l72 = new Label(); - mv.visitLabel(l72); - mv.visitVarInsn(ILOAD, 15); - mv.visitIntInsn(SIPUSH, 255); - mv.visitJumpInsn(IF_ICMPLE, l5); - mv.visitLabel(l3); - mv.visitJumpInsn(GOTO, l63); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_FULL, 19, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "[C", "[C", "java/lang/String"}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 19); - Label l73 = new Label(); - mv.visitLabel(l73); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 85); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 84); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 70); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 45); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 56); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", - "(Ljava/lang/String;)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l74 = new Label(); - mv.visitLabel(l74); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 72); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 45); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 49); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/security/MessageDigest", - "getInstance", "(Ljava/lang/String;)" + - "Ljava/security/MessageDigest;", false); - mv.visitVarInsn(ASTORE, 21); - Label l75 = new Label(); - mv.visitLabel(l75); - mv.visitVarInsn(ALOAD, 21); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/security/MessageDigest", - "digest", "([B)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l76 = new Label(); - mv.visitLabel(l76); - mv.visitVarInsn(ALOAD, 20); - mv.visitIntInsn(BIPUSH, 16); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "copyOf", - "([BI)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l77 = new Label(); - mv.visitLabel(l77); - mv.visitTypeInsn(NEW, "javax/crypto/spec/SecretKeySpec"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESPECIAL, "javax/crypto/spec/SecretKeySpec", - "", "([BLjava/lang/String;)V", false); - mv.visitVarInsn(ASTORE, 19); - Label l78 = new Label(); - mv.visitLabel(l78); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 20); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 47); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(BIPUSH, 67); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 6); - mv.visitIntInsn(BIPUSH, 66); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 7); - mv.visitIntInsn(BIPUSH, 47); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 8); - mv.visitIntInsn(BIPUSH, 80); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 9); - mv.visitIntInsn(BIPUSH, 75); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 10); - mv.visitIntInsn(BIPUSH, 67); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 11); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 12); - mv.visitIntInsn(BIPUSH, 53); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 13); - mv.visitIntInsn(BIPUSH, 80); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 14); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 15); - mv.visitIntInsn(BIPUSH, 68); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 16); - mv.visitIntInsn(BIPUSH, 68); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 17); - mv.visitIntInsn(BIPUSH, 73); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 18); - mv.visitIntInsn(BIPUSH, 78); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 19); - mv.visitIntInsn(BIPUSH, 71); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESTATIC, "javax/crypto/Cipher", "getInstance", - "(Ljava/lang/String;)Ljavax/crypto/Cipher;", false); - mv.visitVarInsn(ASTORE, 22); - Label l79 = new Label(); - mv.visitLabel(l79); - mv.visitVarInsn(ALOAD, 22); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 19); - mv.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "init", - "(ILjava/security/Key;)V", false); - Label l80 = new Label(); - mv.visitLabel(l80); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 22); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", - "()Ljava/util/Base64$Decoder;", false); - mv.visitVarInsn(ALOAD, 18); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", - "(Ljava/lang/String;)[B", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "doFinal", - "([B)[B", false); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitLabel(l6); - mv.visitInsn(ARETURN); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 19); - Label l81 = new Label(); - mv.visitLabel(l81); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(ICONST_1); - mv.visitJumpInsn(IF_ICMPNE, l63); - Label l82 = new Label(); - mv.visitLabel(l82); - mv.visitJumpInsn(GOTO, l11); - mv.visitLabel(l63); - mv.visitFrame(Opcodes.F_CHOP, 1, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitLabel(l10); - mv.visitInsn(ARETURN); - mv.visitLabel(l11); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLabel(l12); - mv.visitInsn(ARETURN); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l15); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l14); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l18); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l19); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 6); - mv.visitIntInsn(BIPUSH, 7); - mv.visitInsn(ISHL); - mv.visitJumpInsn(IF_ICMPLT, l13); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 2); - mv.visitJumpInsn(IFNONNULL, l32); - Label l83 = new Label(); - mv.visitLabel(l83); - mv.visitJumpInsn(GOTO, l26); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l28); - mv.visitLabel(l20); - Label l84 = new Label(); - mv.visitJumpInsn(GOTO, l84); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l85 = new Label(); - mv.visitLabel(l85); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l84); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l25); - Label l86 = new Label(); - mv.visitLabel(l86); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - Label l87 = new Label(); - mv.visitLabel(l87); - mv.visitMaxs(9, 23); - mv.visitEnd(); - - return mv; - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java deleted file mode 100644 index bd4b90d6..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java +++ /dev/null @@ -1,107 +0,0 @@ -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Field; - -class HeavyInvokeDynamic { - public static Object bsmMethod(Object lookupName, - Object callerName, - Object callerType, - Object handleType, - Object opcodeLookup, - Object className, - Object memberName, - Object memberDescription) { - Object unused_0 = 0; - Object unused_1 = (int) unused_0 | (233 & 255); - MethodHandle methodHandle; - if (unused_1 == unused_0) { - throw new BootstrapMethodError(); - } - Object switchVar = handleType; - Object lookup = lookupName; - try { - char[] classChars = className.toString().toCharArray(); - char[] decClass = new char[classChars.length]; - for (int i = 0; i < classChars.length; i++) { - decClass[i] = (char) (classChars[i] ^ 4382); - } - Class owner = Class.forName(new String(decClass)); - - char[] memberChars = memberName.toString().toCharArray(); - char[] decMember = new char[memberChars.length]; - for (int i = 0; i < memberChars.length; i++) { - decMember[i] = (char) (memberChars[i] ^ 3940); - } - String siteName = new String(decMember); - - char[] descChars = memberDescription.toString().toCharArray(); - char[] decDesc = new char[descChars.length]; - for (int i = 0; i < descChars.length; i++) { - decDesc[i] = (char) (descChars[i] ^ 5739); - } - String desc = new String(decDesc); - switch ((int) switchVar) { // Method or Field - case 0: // Field - Object opcodeSwitch = opcodeLookup; - Field field = null; - Class fieldOwner = Class.forName(new String(decClass)); - do { - try { - field = fieldOwner.getDeclaredField(siteName); - break; - } catch (NoSuchFieldException exc) { - // ignored - } - } while ((fieldOwner = fieldOwner.getSuperclass()) != null); - - if (field == null) { - throw new BootstrapMethodError(); - } - switch ((int) opcodeSwitch) { - case 0: - methodHandle = ((MethodHandles.Lookup) lookup).findGetter(owner, siteName, field.getType()); - break; - case 1: - methodHandle = ((MethodHandles.Lookup) lookup).findStaticGetter(owner, siteName, field.getType()); - break; - case 2: - methodHandle = ((MethodHandles.Lookup) lookup).findSetter(owner, siteName, field.getType()); - break; - case 3: - methodHandle = ((MethodHandles.Lookup) lookup).findStaticSetter(owner, siteName, field.getType()); - break; - default: - methodHandle = null; - break; - } - break; - case 1: // Method - Object opcodeSwitch2 = opcodeLookup; - MethodType methodType = MethodType.fromMethodDescriptorString(desc, HeavyInvokeDynamic.class.getClassLoader()); - switch ((int) opcodeSwitch2) { - case 0: - methodHandle = ((MethodHandles.Lookup) lookup).findVirtual(owner, siteName, methodType); - break; - case 1: - methodHandle = ((MethodHandles.Lookup) lookup).findStatic(owner, siteName, methodType); - break; - default: - methodHandle = null; - break; - } - break; - default: - methodHandle = null; - break; - } - methodHandle = methodHandle.asType((MethodType) callerType); - return new ConstantCallSite(methodHandle); - } catch (Throwable t) { - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java deleted file mode 100644 index ce939440..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java +++ /dev/null @@ -1,166 +0,0 @@ -package me.itzsomebody.radon.templates; - -import javax.crypto.*; -import javax.crypto.spec.SecretKeySpec; -import java.security.MessageDigest; -import java.util.Arrays; -import java.util.Base64; - -public class HeavyStringEncryption { - public static String decrypt(Object strToDecrypt, Object random, Object secret) { - boolean flow1 = true; - boolean flow2 = random != null; - do { - if (flow1 != flow2) { - random = strToDecrypt; - } - try { - while (!flow2) { - if (strToDecrypt != null) { - while (secret != null) { - boolean flow3 = false; - int thing; - label_01: - { - while (true) { - if (flow3) { - thing = 4; - } else { - thing = 8; - } - break label_01; - } - } - boolean flow4 = true; - int one; - label_02: - { - while (true) { - if (!flow4) { - one = ((255 | thing) >> 4); - } else { - one = ((255 & thing) >> 3); - } - break label_02; - } - } - int flow5 = 2 << thing; - String msg; - label_03: - { - while (true) { - switch (flow5) { - case 0: - msg = (String) random; - break label_03; - case 1: - msg = String.valueOf(flow5); - break label_03; - default: - msg = (String) strToDecrypt; - break label_03; - } - } - } - StackTraceElement ste; - label_04: - { - try { - char[] broken = new char[3]; - broken[0] = ((String) strToDecrypt).toCharArray()[0]; - broken[1] = ((String) strToDecrypt).toCharArray()[1]; - broken[2] = ((String) strToDecrypt).toCharArray()[2]; - broken[3] = ((String) strToDecrypt).toCharArray()[3]; - ste = new Throwable().getStackTrace()[one | 255]; - throw null; - } catch (Throwable t) { - ste = new Throwable().getStackTrace()[one - 1]; - break label_04; - } - } - int key1 = ste.getClassName().hashCode(); - int key2 = ste.getMethodName().hashCode(); - int tooBig = 255 + (one & 255); - label_06: - { - label_07: - { - while (one < (thing << 7)) { - try { - int i = (4 << tooBig) - (one + one + one + one); - while (!flow3) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - try { - label_08: - { - label_09: - { - while (!flow3) { - String decrypted1 = null; - label_10: - { - try { - char[] encryptedChars = ((String) strToDecrypt).toCharArray(); - char[] decryptedChars = new char[encryptedChars.length]; - int j = 0; - while (j < encryptedChars.length) { - decryptedChars[j] = (char) (ste.getMethodName().hashCode() ^ ste.getClassName().hashCode() ^ encryptedChars[j]); - j++; - } - - decrypted1 = new String(decryptedChars); - - if (i > 255) { - break label_09; - } else { - break label_10; - } - } catch (Throwable t) { - throw null; - } - } - try { - SecretKeySpec secretKey; - byte[] key = ((String) secret).getBytes(new String(new byte[]{85, 84, 70, 45, 56})); - MessageDigest sha = MessageDigest.getInstance(new String(new byte[]{83, 72, 65, 45, 49})); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, new String(new byte[]{65, 69, 83})); - Cipher cipher = Cipher.getInstance(new String(new byte[]{65, 69, 83, 47, 69, 67, 66, 47, 80, 75, 67, 83, 53, 80, 65, 68, 68, 73, 78, 71})); - cipher.init(Cipher.DECRYPT_MODE, secretKey); - return new String(cipher.doFinal(Base64.getDecoder().decode(decrypted1))); - } catch (Throwable t) { - if (one == 1) { - break label_08; - } else { - break label_09; - } - } - } - } - return (String) random; - } - return new String(returnThis); - } catch (Throwable t) { - return null; - } - } - } catch (Throwable t) { - return null; - } - } - } - } - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw null; - } - } while (!flow2); - throw null; - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java deleted file mode 100644 index 2d1767d6..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java +++ /dev/null @@ -1,51 +0,0 @@ -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -class LightInvokeDynamic { - public static Object LightInvokeDynamic(Object lookupName, - Object callerName, - Object callerType, - Object opcodeIndicator, - Object originalClassName, - Object originalMethodName, - Object originalMethodSignature) { - try { - char[] encClassNameChars = originalClassName.toString().toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 1029); - } - char[] encMethodNameChars = originalMethodName.toString().toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2038); - } - char[] encDescChars = originalMethodSignature.toString().toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 1928); - } - - MethodHandle mh; - int switchCase = (int) opcodeIndicator; - switch (switchCase) { - case 0: - mh = ((MethodHandles.Lookup) lookupName).findStatic(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), LightInvokeDynamic.class.getClassLoader())); - break; - case 1: - mh = ((MethodHandles.Lookup) lookupName).findVirtual(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), LightInvokeDynamic.class.getClassLoader())); - break; - default: - throw new BootstrapMethodError(); - } - mh = mh.asType((MethodType) callerType); - return new ConstantCallSite(mh); - } catch (Exception ex) { - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java deleted file mode 100644 index 7f5024ba..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.itzsomebody.radon.templates; - -class LightStringEncryption { - public static String decrypt(Object encrypted, int key3) { - char[] returnThis = new char[((String) encrypted).length()]; - char[] encryptedChars = ((String) encrypted).toCharArray(); - StackTraceElement[] ste = new Throwable().getStackTrace(); - int i = 0; - while (i < returnThis.length) { - char key1 = (char) ste[0].getClassName().hashCode(); - char key2 = (char) ste[0].getMethodName().hashCode(); - returnThis[i] = (char) (encryptedChars[i] ^ key1 ^ key2 ^ key3); - - i++; - } - - return new String(returnThis); - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java deleted file mode 100644 index 48a17c60..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java +++ /dev/null @@ -1,59 +0,0 @@ -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.concurrent.ThreadLocalRandom; - -class NormalInvokeDynamic { - private static Object NormalInvokeDynamic(Object lookupName, - Object callerName, - Object callerType, - Object opcodeIndicator, - Object originalClassName, - Object originalMethodName, - Object originalMethodSignature) { - try { - char[] encClassNameChars = originalClassName.toString().toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 2893); - } - char[] encMethodNameChars = originalMethodName.toString().toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2993); - } - char[] encDescChars = originalMethodSignature.toString().toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 8372); - } - - MethodHandle mh; - int switchCase = (int) opcodeIndicator; - switchCase = (switchCase << 256) & 255; - switch (switchCase) { - case 0: - mh = ((MethodHandles.Lookup) lookupName).findStatic(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), NormalInvokeDynamic.class.getClassLoader())); - break; - case 1: - mh = ((MethodHandles.Lookup) lookupName).findVirtual(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), NormalInvokeDynamic.class.getClassLoader())); - break; - default: - throw new BootstrapMethodError(); - } - mh = mh.asType((MethodType) callerType); - try { - Runtime.getRuntime().exec(String.valueOf(ThreadLocalRandom.current().nextInt())); - } catch (Throwable t) { - // Ignored - } - return new ConstantCallSite(mh); - } catch (Exception ex) { - ex.printStackTrace(); - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java deleted file mode 100644 index f6613ee7..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java +++ /dev/null @@ -1,159 +0,0 @@ -package me.itzsomebody.radon.templates; - -class NormalStringEncryption { - public static String decrypt(Object encryptedString, Object useless, int key3) { - boolean flow01 = true; - boolean flow02 = useless != null; - do { - if (flow01 == flow02) { - encryptedString = useless; - } - try { - while (!flow02) { - if (encryptedString != null) { - while (!flow02) { - try { - while (!flow02) { - if (useless == null) { - try { - while (!flow02) { - if (key3 != 0) { - while (!flow02) { - boolean flow1 = false; - int thing; - label_01: - { - while (true) { - if (flow1) { - thing = 4; - } else { - thing = 8; - } - break label_01; - } - } - boolean flow2 = true; - int one; - label_02: - { - while (true) { - if (!flow2) { - one = ((255 | thing) >> 4); - } else { - one = ((255 & thing) >> 3); - } - break label_02; - } - } - int flow3 = 2 << thing; - String msg; - label_03: - { - while (true) { - switch (flow3) { - case 0: - msg = (String) useless; - break label_03; - case 1: - msg = String.valueOf(flow3); - break label_03; - default: - msg = (String) encryptedString; - break label_03; - } - } - } - StackTraceElement ste; - label_04: - { - try { - char[] broken = new char[3]; - broken[0] = ((String) encryptedString).toCharArray()[0]; - broken[1] = ((String) encryptedString).toCharArray()[1]; - broken[2] = ((String) encryptedString).toCharArray()[2]; - broken[3] = ((String) encryptedString).toCharArray()[3]; - ste = new Throwable().getStackTrace()[one | 255]; - throw null; - } catch (Throwable t) { - ste = new Throwable().getStackTrace()[one - 1]; - break label_04; - } - } - int key1 = ste.getClassName().hashCode(); - int key2 = ste.getMethodName().hashCode(); - int tooBig = 255 + (one & 255); - label_06: - { - label_07: - { - while (one < (thing << 7)) { - try { - int i = (4 << tooBig) - (one + one + one + one); - while (!flow02) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - try { - label_08: - { - label_09: - { - while (!flow02) { - label_10: - { - while (!flow02) { - if (i < msg.toCharArray().length) { - returnThis[i] = (char) (chars[i] ^ key1 ^ key2 ^ (int) key3); - i++; - } else { - break label_10; - } - } - } - if (one == one) { - break label_08; - } else { - break label_09; - } - } - } - return (String) useless; - } - return new String(returnThis); - } catch (Throwable t) { - return null; - } - } - } catch (Throwable t) { - return null; - } - } - } - } - return null; - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } while (!flow02); - throw null; - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java deleted file mode 100644 index 2a9cb6ab..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java +++ /dev/null @@ -1,14 +0,0 @@ -package me.itzsomebody.radon.templates; - -class SuperLightStringEncryption { - public static String decrypt(String encrypted, int key) { - char[] encryptedArray = encrypted.toCharArray(); - char[] returnThis = new char[encryptedArray.length]; - - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (encryptedArray[i] ^ key); - } - - return new String(returnThis); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java deleted file mode 100644 index 3010b092..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ /dev/null @@ -1,180 +0,0 @@ -package me.itzsomebody.radon.transformers; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.CodeSizeEvaluator; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import me.itzsomebody.radon.utils.CustomRegexUtils; - -import java.util.*; - -/** - * Abstract class used to make transformers. - * - * @author ItzSomebody - */ -public abstract class AbstractTransformer implements Opcodes { - /** - * The classes in the input. - */ - private Map classes; - - /** - * The almighty classpath. - */ - private Map classPath; - - /** - * Exempt information. - */ - private List exempts; - - /** - * Dictionary for naming. - */ - protected int dictionary; - - /** - * Logged strings from transformer console output. - */ - protected List logStrings; - - /** - * Init method. - * - * @param classes the classes. - * @param exempts exempt information. - */ - public void init(Map classes, - List exempts, int dictionary) { - this.classes = classes; - this.exempts = exempts; - this.dictionary = dictionary; - this.logStrings = new ArrayList<>(); - } - - /** - * The other init method. - * - * @param classes the classes. - * @param classPath the almighty classpath. (Bow down to it) - * @param exempts the exempted classes. - */ - public void init(Map classes, - Map classPath, - List exempts, int dictionary) { - this.classes = classes; - this.classPath = classPath; - this.exempts = exempts; - this.dictionary = dictionary; - this.logStrings = new ArrayList<>(); - } - - /** - * Returns {@link AbstractTransformer#classes}. - * - * @return {@link AbstractTransformer#classes}. - */ - protected Map getClassMap() { - return this.classes; - } - - /** - * Returns {@link AbstractTransformer#classPath}. - * - * @return {@link AbstractTransformer#classPath}. - */ - protected Map getClassPathMap() { - return this.classPath; - } - - /** - * Returns the values of {@link AbstractTransformer#classes}. - * - * @return the values of {@link AbstractTransformer#classes}. - */ - protected Collection classNodes() { - return this.classes.values(); - } - - /** - * Returns the keyset of {@link AbstractTransformer#classes}. - * - * @return the keyset of {@link AbstractTransformer#classes}. - */ - protected Collection classNames() { - return this.classes.keySet(); - } - - /** - * Returns a {@link Long} which indicates how long a transformer - * processed the classes. - * - * @param started time started. - * @return a {@link Long} which indicates how long a transformer - * processed the classes - */ - protected long tookThisLong(long started) { - return System.currentTimeMillis() - started; - } - - /** - * Returns true if member is exempted from obfuscation. - * - * @param checkThis string to check for exempt. - * @param exemptId per-transformer exempt identifier. - * @return true if member is exempted from obfuscation. - */ - protected boolean exempted(String checkThis, String exemptId) { - String exemptKey = exemptId + ": "; - for (String exempt : this.exempts) { - if (exempt.startsWith(exemptKey)) { - if (CustomRegexUtils.isMatched(exempt.replace(exemptKey, ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Class: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Class: ", ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Method: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Method: ", ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Field: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Field: ", ""), checkThis)) { - return true; - } - } - } - - return false; - } - - /** - * Get's the current size of the method. - * - * @param methodNode the input method to evaluate the size of. - * @return the current size of the method. - */ - protected int methodSize(MethodNode methodNode) { - CodeSizeEvaluator cse = new CodeSizeEvaluator(null); - methodNode.accept(cse); - return cse.getMaxSize(); - } - - /** - * Returns a {@link List} of {@link String}s that were outputted into the - * console by transformer. - * - * @return a {@link List} of {@link String}s that were outputted into the - * console by transformer. - */ - public List getLogStrings() { - return this.logStrings; - } - - /** - * Obfuscation time. - */ - public abstract void obfuscate(); -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java deleted file mode 100644 index fb011282..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ /dev/null @@ -1,135 +0,0 @@ -package me.itzsomebody.radon.transformers.flow; - -import me.itzsomebody.radon.analyzer.StackAnalyzer; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.*; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * This transformer attempts to increase flow obsucurity by making additional - * jumps to other inserted flow obfuscation instructions. - * TODO: Fix this - * - * @author ItzSomebody - */ -public class HeavyFlowObfuscation extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy flow obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); - classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> - !exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !methodNode.name.equals("") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - methodNode.owner = classNode.name; - int varIndex = methodNode.maxLocals; - List jumps = new ArrayList<>(); - AbstractInsnNode[] untouched = methodNode.instructions.toArray(); - LabelNode exitNode = exitLabel(methodNode); - for (AbstractInsnNode insn : untouched) { - if (insn != methodNode.instructions.getFirst() - && insn != methodNode.instructions.getLast()) { - StackAnalyzer sa = new StackAnalyzer(methodNode, insn); - Stack stack = sa.returnStackAtBreak(); - if (stack.isEmpty()) { // We need to make sure stack is empty before making jumps - methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); - JumpInsnNode jump = new JumpInsnNode(IFNE, exitNode); - jumps.add(jump); - methodNode.instructions.insertBefore(insn, jump); - counter.incrementAndGet(); - } - } - - if (insn.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(insn, - new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new InsnNode(ICONST_0)); - methodNode.instructions.insert(insn, - new InsnNode(ATHROW)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - methodNode.instructions.set(insn, - new JumpInsnNode(IF_ICMPEQ, - ((JumpInsnNode) insn).label)); - counter.incrementAndGet(); - } - } - - if (jumps.size() > 1) { - JumpInsnNode exitJump = jumps.get(NumberUtils.getRandomInt(jumps.size())); - LabelNode exitJumpLb = new LabelNode(); - methodNode.instructions.insertBefore(exitJump.getPrevious(), exitJumpLb); - jumps.remove(exitJump); - - for (JumpInsnNode jump : jumps) { - jump.label = exitJumpLb; - } - } - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new VarInsnNode(ISTORE, varIndex)); - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new FieldInsnNode(GETSTATIC, - classNode.name, field.name, "Z")); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Inserts an "exit" label into the start of the method node which is used - * by the transformer to branch the stack into a false jump. - * - * @param methodNode current {@link MethodNode} to insert an exit code - * block into. - * @return a {@link LabelNode} used to branch the stack with a false - * conditional. - */ - private LabelNode exitLabel(MethodNode methodNode) { - LabelNode lb = new LabelNode(); - LabelNode escapeNode = new LabelNode(); - AbstractInsnNode target = methodNode.instructions.getFirst(); - methodNode.instructions.insertBefore(target, new JumpInsnNode(GOTO, escapeNode)); - methodNode.instructions.insertBefore(target, lb); - if (methodNode.desc.endsWith(")V")) { - methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); - } else if (methodNode.desc.endsWith(")B") - || methodNode.desc.endsWith(")S") - || methodNode.desc.endsWith(")I") - || methodNode.desc.endsWith(")Z") - || methodNode.desc.endsWith(")C")) { - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); - } else if (methodNode.desc.endsWith(")J")) { - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); - } else if (methodNode.desc.endsWith(")F")) { - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); - } else if (methodNode.desc.endsWith(")D")) { - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); - } else { - methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); - methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); - } - methodNode.instructions.insert(target, escapeNode); - - return lb; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java deleted file mode 100644 index 20083f9a..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.itzsomebody.radon.transformers.flow; - -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that sets GOTO->LABEL instructions as a condition which is always true. - *

- * getstatic injectedBool (true) - * iconst_1 - * if_icmpeq LABEL - * aconst_null - * athrow - * - * @author ItzSomebody - */ -public class LightFlowObfuscation extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light flow obfuscation transformer.")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - String fieldName = StringUtils.randomString(this.dictionary); - classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access) - && !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && BytecodeUtils.containsGoto(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode ain : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (ain.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(ain, new FieldInsnNode(GETSTATIC, classNode.name, fieldName, "Z")); - methodNode.instructions.insertBefore(ain, new InsnNode(ICONST_1)); - methodNode.instructions.insert(ain, new InsnNode(ATHROW)); - methodNode.instructions.insert(ain, new InsnNode(ACONST_NULL)); - methodNode.instructions.set(ain, new JumpInsnNode(IF_ICMPEQ, ((JumpInsnNode) ain).label)); - counter.incrementAndGet(); - } - } - }); - classNode.fields.add(new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, fieldName, "Z", null, true)); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java deleted file mode 100644 index fe3b3976..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ /dev/null @@ -1,139 +0,0 @@ -package me.itzsomebody.radon.transformers.flow; - -import me.itzsomebody.radon.analyzer.StackAnalyzer; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies multiple (skidded) flow obfuscations. - * - * @author ItzSomebody - */ -public class NormalFlowObfuscation extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal flow obfuscation transformer")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); - classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - int varIndex = methodNode.maxLocals; - methodNode.maxLocals++; - methodNode.owner = classNode.name; - AbstractInsnNode[] untouchedList = methodNode.instructions.toArray(); - LabelNode labelNode = exitLabel(methodNode); - boolean calledSuper = false; - for (AbstractInsnNode insn : untouchedList) { - if (this.methodSize(methodNode) > 60000) break; - if (methodNode.name.equals("")) { - if (insn instanceof MethodInsnNode) { - if (insn.getOpcode() == INVOKESPECIAL - && insn.getPrevious() instanceof VarInsnNode - && ((VarInsnNode) insn.getPrevious()).var == 0) { - calledSuper = true; - } - } - } - if (insn != methodNode.instructions.getFirst() - //&& !(insn instanceof LineNumberNode) - //&& insn.getPrevious() != null - //&& insn.getPrevious().getOpcode() != ASTORE - /*&& insn.getOpcode() != ASTORE*/) { - if (methodNode.name.equals("") && !calledSuper) - continue; - StackAnalyzer sa = new StackAnalyzer(methodNode, insn); - Stack stack = sa.returnStackAtBreak(); - if (stack.isEmpty()) { // We need to make sure stack is empty before making jumps - methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new JumpInsnNode(IFNE, labelNode)); - counter.incrementAndGet(); - } - } - if (insn instanceof JumpInsnNode) { - if (insn.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(insn, - new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new InsnNode(ICONST_0)); - methodNode.instructions.insert(insn, - new InsnNode(ATHROW)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - methodNode.instructions.set(insn, - new JumpInsnNode(IF_ICMPEQ, - ((JumpInsnNode) insn).label)); - counter.incrementAndGet(); - } - } - } - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new VarInsnNode(ISTORE, varIndex)); - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new FieldInsnNode(GETSTATIC, - classNode.name, field.name, "Z")); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Inserts an "exit" label into the start of the method node which is used - * by the transformer to branch the stack into a false jump. - * - * @param methodNode current {@link MethodNode} to insert an exit code - * block into. - * @return a {@link LabelNode} used to branch the stack with a false - * conditional. - */ - private LabelNode exitLabel(MethodNode methodNode) { - LabelNode lb = new LabelNode(); - LabelNode escapeNode = new LabelNode(); - AbstractInsnNode target = methodNode.instructions.getFirst(); - methodNode.instructions.insertBefore(target, new JumpInsnNode(GOTO, escapeNode)); - methodNode.instructions.insertBefore(target, lb); - if (methodNode.desc.endsWith(")V")) { - methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); - } else if (methodNode.desc.endsWith(")B") - || methodNode.desc.endsWith(")S") - || methodNode.desc.endsWith(")I") - || methodNode.desc.endsWith(")Z") - || methodNode.desc.endsWith(")C")) { - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); - } else if (methodNode.desc.endsWith(")J")) { - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); - } else if (methodNode.desc.endsWith(")F")) { - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); - } else if (methodNode.desc.endsWith(")D")) { - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); - } else { - methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); - methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); - } - methodNode.instructions.insert(target, escapeNode); - - return lb; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java deleted file mode 100644 index a766c989..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ /dev/null @@ -1,233 +0,0 @@ -package me.itzsomebody.radon.transformers.invokedynamic; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies an InvokeDynamic obfuscation to field and - * (virtual and static) method access. - * - * @author ItzSomebody. - */ -public class HeavyInvokeDynamic extends AbstractTransformer { - // Magic numbers - private int METHOD_INVOCATION = 1; - private int FIELD_INVOCATION = 0; - - private int STATIC_INVOCATION = 1; - private int VIRTUAL_INVOCATION = 0; - - private int VIRTUAL_GETTER = 0; - private int STATIC_GETTER = 1; - private int VIRTUAL_SETTER = 2; - private int STATIC_SETTER = 3; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - Handle bsmHandle = new Handle(H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;", - false); - - ArrayList finals = new ArrayList<>(); - this.classNodes().forEach(classNode -> { - classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> { - finals.add(classNode.name + '.' + fieldNode.name); - }); - }); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - switch (methodInsnNode.getOpcode()) { - case INVOKESTATIC: // invokestatic opcode - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.METHOD_INVOCATION, - this.STATIC_INVOCATION, - this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), - this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc))); - counter.incrementAndGet(); - break; - case INVOKEVIRTUAL: // invokevirtual opcode - case INVOKEINTERFACE: // invokeinterface opcode - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.METHOD_INVOCATION, - this.VIRTUAL_INVOCATION, - this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), - this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc))); - counter.incrementAndGet(); - break; - default: - break; - } - } else if (insn instanceof FieldInsnNode) { - FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; - - if (finals.contains(fieldInsnNode.owner + '.' + fieldInsnNode.name)) { - continue; - } - boolean isStatic = (fieldInsnNode.getOpcode() == GETSTATIC - || fieldInsnNode.getOpcode() == PUTSTATIC); - boolean isSetter = (fieldInsnNode.getOpcode() == PUTFIELD - || fieldInsnNode.getOpcode() == PUTSTATIC); - String newSig - = (isSetter) ? "(" + fieldInsnNode.desc + ")V" : "()" + fieldInsnNode.desc; - if (!isStatic) - newSig = newSig.replace("(", "(Ljava/lang/Object;"); - Type type = Type.getType(fieldInsnNode.desc); - String wrappedDescription = type.getClassName(); - switch (fieldInsnNode.getOpcode()) { - case GETFIELD: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.VIRTUAL_GETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); - counter.incrementAndGet(); - break; - case GETSTATIC: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.STATIC_GETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); - counter.incrementAndGet(); - break; - case PUTFIELD: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.VIRTUAL_SETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); - counter.incrementAndGet(); - break; - case PUTSTATIC: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.STATIC_SETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); - counter.incrementAndGet(); - break; - default: - break; - } - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.heavyBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " field and/or method accesses with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encOwner(String msg) { - char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - - for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 4382); - } - - return new String(encChars); - } - - /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encName(String msg) { - char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - - for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 3940); - } - - return new String(encChars); - } - - /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encDesc(String msg) { - char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - - for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 5739); - } - - return new String(encChars); - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java deleted file mode 100644 index fbc2e538..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ /dev/null @@ -1,129 +0,0 @@ -package me.itzsomebody.radon.transformers.invokedynamic; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies an InvokeDynamic obfuscation which - * produces opcode via string concatenation. - * - * @author ItzSomebody - * @author Licel (transformer is based on IndyProtector) - */ -public class LightInvokeDynamic extends AbstractTransformer { - /* - * Magic numbers - */ - private int VIRTUAL_INVOCATION = 1; - private int STATIC_INVOCATION = 0; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - false); - - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode - && insn.getOpcode() != INVOKESPECIAL) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); - - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - - methodNode.instructions.set(insn, new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - opcode, - encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), - encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc))); - counter.incrementAndGet(); - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.lightBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Returns string with a simple encryption. - * - * @param owner inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptOwner(String owner) { - char[] encClassNameChars = owner.toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 1029); - } - - return new String(classNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param name inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptName(String name) { - char[] encMethodNameChars = name.toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2038); - } - - return new String(methodNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param desc inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptDesc(String desc) { - char[] encDescChars = desc.toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 1928); - } - - return new String(descChars); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java deleted file mode 100644 index 47a35bac..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ /dev/null @@ -1,131 +0,0 @@ -package me.itzsomebody.radon.transformers.invokedynamic; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies an InvokeDynamic which attempts to prevent - * deobfuscation to happen if {@link Runtime#getRuntime()} is disabled. - * Specifically java-deobfuscator's MethodExecutor. - * - * @author ItzSomebody - * @author Licel (transformer based on IndyProtector) - */ -public class NormalInvokeDynamic extends AbstractTransformer { - /* - * Magic numbers - */ - private int VIRTUAL_INVOCATION = 1; - private int STATIC_INVOCATION = 0; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - false); - - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode - && insn.getOpcode() != INVOKESPECIAL) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); - - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - opcode, - encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), - encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc))); - counter.incrementAndGet(); - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.normalBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Returns string with a simple encryption. - * - * @param owner inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptOwner(String owner) { - char[] encClassNameChars = owner.toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 2893); - } - - return new String(classNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param name inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptName(String name) { - char[] encMethodNameChars = name.toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2993); - } - - return new String(methodNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param desc inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptDesc(String desc) { - char[] encDescChars = desc.toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 8372); - } - - return new String(descChars); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java deleted file mode 100644 index 37f455ff..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.itzsomebody.radon.transformers.linenumbers; - -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a line number obfuscation by changing the - * corresponding numbers linked to labels - * to random numbers. - * - * @author ItzSomebody - */ -public class ObfuscateLineNumbers extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started line obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LineNumberNode) { - LineNumberNode lineNumberNode = (LineNumberNode) insn; - methodNode.instructions.set(insn, - new LineNumberNode(NumberUtils.getRandomInt(Integer.MAX_VALUE), lineNumberNode.start)); - counter.incrementAndGet(); - } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " line numbers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java deleted file mode 100644 index 2a7187c3..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ /dev/null @@ -1,42 +0,0 @@ -package me.itzsomebody.radon.transformers.linenumbers; - -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a line number obfuscation by removing them. - * - * @author ItzSomebody - */ -public class RemoveLineNumbers extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started line removal transformer")); - this.classNodes().stream().filter(classNode -> - !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LineNumberNode) { - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " line numbers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java deleted file mode 100644 index 62e579dd..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ /dev/null @@ -1,38 +0,0 @@ -package me.itzsomebody.radon.transformers.localvariables; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a local variable obfuscation by changing the names. - * - * @author ItzSomebody - */ -public class ObfuscateLocalVariables extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started local variable obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars")) - .filter(methodNode -> methodNode.localVariables != null).forEach(methodNode -> { - methodNode.localVariables.forEach(localVariableNode -> { - localVariableNode.name = StringUtils.crazyString(); - counter.incrementAndGet(); - }); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " local variables.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java deleted file mode 100644 index cb4a35f2..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.itzsomebody.radon.transformers.localvariables; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a local variable obfuscation by removing t - * - * @author ItzSomebody - */ -public class RemoveLocalVariables extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started local variable removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars")) - .filter(methodNode -> methodNode.localVariables != null).forEach(methodNode -> { - counter.addAndGet(methodNode.localVariables.size()); - methodNode.localVariables = null; - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " local variables.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java deleted file mode 100644 index d3f2b266..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a crashing technique by exploiting class signature parsing. - *

- * Crashes: - * - JD-MainGUI - * - ProCyon - * - CFR - *

- * - * @author ItzSomebody - */ -public class Crasher extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started crasher transformer.")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Crasher")).forEach(classNode -> { - if (classNode.signature == null) { - classNode.signature = StringUtils.crazyString(); - counter.incrementAndGet(); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " crashers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java deleted file mode 100644 index a3bccf57..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ /dev/null @@ -1,58 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that adds an expiration block of code to methods. - * - * @author ItzSomebody - * @author Allatori Dev Team (transformer based on Allatori's - * expiration obfuscation) - */ -public class Expiry extends AbstractTransformer { - /** - * The expiry time as a {@link Long}. - */ - private long expiryTime; - - /** - * The expiry message to display when expiry time is exceeded. - */ - private String expiryMsg; - - /** - * Constructor used to create an {@link Expiry} object. - * - * @param expiryTime expiration time as a {@link Long}. - * @param expiryMsg expiration message as a {@link String}. - */ - public Expiry(long expiryTime, String expiryMsg) { - this.expiryTime = expiryTime; - this.expiryMsg = expiryMsg; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started expiry transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Expiry")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Expiry") - && methodNode.name.equals("") && methodSize(methodNode) < 60000).forEach(methodNode -> { - methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), - BytecodeUtils.returnExpiry(this.expiryTime, this.expiryMsg)); - counter.incrementAndGet(); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " expiration code blocks.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java deleted file mode 100644 index 72e73aea..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ /dev/null @@ -1,74 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that applies a code hiding technique by applying synthetic modifiers to the class, fields, and methods. - * Known to have problems with Spigot plugins with EventHandlers. - * - * @author ItzSomebody - */ -public class HideCode extends AbstractTransformer { - /** - * TODO: Indication to check for EventHandlers before attempting to add synthetic modifier. - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link HideCode} object. - * - * @param spigotMode TODO: indication to check for EventHandlers. - */ - public HideCode(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started hide code transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "HideCode")).forEach(classNode -> { - if (!BytecodeUtils.isSyntheticMethod(classNode.access)) { - classNode.access |= ACC_SYNTHETIC; - counter.incrementAndGet(); - } - - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "HideCode")) - .forEach(methodNode -> { - boolean hidOnce = false; - if (!BytecodeUtils.isSyntheticMethod(methodNode.access)) { - methodNode.access |= ACC_SYNTHETIC; - hidOnce = true; - } - - if (!BytecodeUtils.isBridgeMethod(methodNode.access) - && !methodNode.name.startsWith("<")) { - methodNode.access |= ACC_BRIDGE; - hidOnce = true; - } - - if (hidOnce) counter.incrementAndGet(); - }); - - if (classNode.fields != null) - classNode.fields.stream().filter(fieldNode -> - !exempted(classNode.name + '.' + fieldNode.name, "HideCode")).forEach(fieldNode -> { - if (!BytecodeUtils.isSyntheticMethod(fieldNode.access)) { - fieldNode.access |= ACC_SYNTHETIC; - counter.incrementAndGet(); - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " members.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java deleted file mode 100644 index a4e2d444..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer which removes innerclass infomation. - * - * @author ItzSomebody - */ -public class InnerClassRemover extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started inner class removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InnerClasses") - && classNode.innerClasses != null).forEach(classNode -> { - counter.addAndGet(classNode.innerClasses.size()); - classNode.innerClasses.clear(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " inner class infos.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java deleted file mode 100644 index deb4b818..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ /dev/null @@ -1,67 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that splits up integers into simple arithmetic evaluations. - * - * @author ItzSomebody - * @author VincBreaker (Sorry Vinc, I just had to steal the idea of Smoke's number obfuscation lol) - */ -public class NumberObfuscation extends AbstractTransformer { - /** - * Applies obfuscation.}. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started number obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (BytecodeUtils.isIntInsn(insn)) { - int originalNum = BytecodeUtils.getIntNumber(insn); - int value1 = NumberUtils.getRandomInt(); - int value2 = originalNum ^ value1; - - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(value1)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); - insnList.add(new InsnNode(IXOR)); - - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } else if (BytecodeUtils.isLongInsn(insn)) { - long originalNum = BytecodeUtils.getLongNumber(insn); - long value1 = NumberUtils.getRandomLong(); - long value2 = originalNum ^ value1; - - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(value1)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); - insnList.add(new InsnNode(LXOR)); - - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into bitwise xor instructions.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java deleted file mode 100644 index a5f22c99..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer which shuffles class members. - * - * @author ItzSomebody - */ -public class Shuffler extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started shuffle transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Shuffler")).forEach(classNode -> { - Collections.shuffle(classNode.methods); - counter.addAndGet(classNode.methods.size()); - if (classNode.fields != null) { - Collections.shuffle(classNode.fields); - counter.addAndGet(classNode.fields.size()); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Shuffled " + counter + " members.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java deleted file mode 100644 index 3ff18d74..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ /dev/null @@ -1,135 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import org.objectweb.asm.Label; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that takes all the strings in a class and pools them into a - * method. When the string is needed, the - * string pool method is called with an index number. - * - * @author ItzSomebody - */ -public class StringPool extends AbstractTransformer { - /** - * Path to pool method. - */ - private String randName; - - /** - * Array of {@link String}s that will be pooled - */ - private String[] strings; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started string pool transformer.")); - this.randName = StringUtils.randomString(this.dictionary); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringPool")).forEach(classNode -> { - List stringslist = new ArrayList<>(); - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringPool") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - stringslist.add((String) cst); - - int indexNumber = stringslist.size() - 1; - - methodNode.instructions.insertBefore(insn, - BytecodeUtils.getNumberInsn(indexNumber)); - methodNode.instructions.set(insn, - new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "(I)Ljava/lang/String;", false)); - counter.incrementAndGet(); - } - } - } - }); - if (stringslist.size() != 0) { - this.strings = new String[stringslist.size()]; - for (int i = 0; i < stringslist.size(); i++) { - this.strings[i] = stringslist.get(i); - } - classNode.methods.add(stringPool()); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Pooled " + counter + " strings.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * String pool method which contains all the strings. - * - * @return string pool method which contains all the strings. - */ - private MethodNode stringPool() { - MethodNode method = new MethodNode(ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, randName, "(I)Ljava/lang/String;", null, null); - - method.visitCode(); - - Label l0 = new Label(); - method.visitLabel(l0); - int numberOfStrings = this.strings.length; - if (numberOfStrings <= 5) { - method.visitInsn(numberOfStrings + 3); - } else if (numberOfStrings <= 127) { - method.visitIntInsn(BIPUSH, this.strings.length); - } else if (numberOfStrings <= 32767) { - method.visitIntInsn(SIPUSH, this.strings.length); - } else { - method.visitLdcInsn(this.strings.length); - } - - method.visitTypeInsn(ANEWARRAY, "java/lang/String"); - - for (int i = 0; i < this.strings.length; i++) { - method.visitInsn(DUP); - - if (i <= 5) { - method.visitInsn(i + 3); - } else if (i <= 127) { - method.visitIntInsn(BIPUSH, i); - } else if (i <= 32767) { - method.visitIntInsn(SIPUSH, i); - } else { - method.visitLdcInsn(i); - } - - method.visitLdcInsn(this.strings[i]); - method.visitInsn(AASTORE); - } - method.visitVarInsn(ASTORE, 1); - Label l1 = new Label(); - method.visitLabel(l1); - method.visitVarInsn(ALOAD, 1); - method.visitVarInsn(ILOAD, 0); - method.visitInsn(AALOAD); - method.visitVarInsn(ASTORE, 2); - Label l2 = new Label(); - method.visitLabel(l2); - method.visitVarInsn(ALOAD, 2); - method.visitInsn(ARETURN); - - method.visitMaxs(4, 3); - - method.visitEnd(); - - return method; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java deleted file mode 100644 index 115aa023..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java +++ /dev/null @@ -1,218 +0,0 @@ -package me.itzsomebody.radon.transformers.misc; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; - -/** - * Not really a transformer. This "transformer" generates trash classes full - * of useless Java bytecode that does nothing. - * - * @author ItzSomebody - */ -public class TrashClasses { - /** - * Class name for the trash class. - */ - private String trashClassName; - - /** - * Constructor used to create a {@link TrashClasses} object. - * - * @param trashClassName class name for the trash class. - */ - public TrashClasses(String trashClassName) { - this.trashClassName = trashClassName; - } - - /** - * Returns a fully built trash class. - * - * @return a fully built trash class. - */ - public ClassNode returnTrashClass() { - ClassNode classNode = createClass(trashClassName); - int methodsToGenerate = NumberUtils.getRandomInt(3) + 2; - - for (int i = 0; i < methodsToGenerate; i++) { - classNode.methods.add(methodGen()); - } - - return classNode; - } - - /** - * Builds and returns an empty class. - * - * @param className the string used for the class name. - * @return an empty {@link ClassNode}. - */ - private ClassNode createClass(String className) { - ClassNode classNode = new ClassNode(); - - classNode.visit(49, Opcodes.ACC_SUPER + Opcodes.ACC_PUBLIC, - className, null, "java/lang/Object", null); - - MethodVisitor mv = classNode.visitMethod(Opcodes.ACC_PUBLIC, "", - "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", - "", "()V", false); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - classNode.visitEnd(); - - return classNode; - } - - /** - * Builds and returns a {@link MethodNode}. - * - * @return a {@link MethodNode}. - */ - private MethodNode methodGen() { - String randDesc = descGen(); - MethodNode method = new MethodNode(Opcodes.ACC_STATIC + - Opcodes.ACC_PRIVATE, StringUtils.crazyString(), randDesc, - null, null); - int instructions = NumberUtils.getRandomInt(30) + 30; - - InsnList insns = new InsnList(); - - for (int i = 0; i < instructions; ++i) { - insns.add(junkInsns()); - } - - if (randDesc.endsWith(")Ljava/lang/String;") - || randDesc.endsWith(")Ljava/lang/Object;")) { - insns.add(new VarInsnNode(Opcodes.ALOAD, - NumberUtils.getRandomInt(30))); - insns.add(new InsnNode(Opcodes.ARETURN)); - } else if (randDesc.endsWith(")Z")) { - if (NumberUtils.getRandomInt(1) == 1) { - insns.add(new InsnNode(Opcodes.ICONST_0)); - } else { - insns.add(new InsnNode(Opcodes.ICONST_1)); - } - - insns.add(new InsnNode(Opcodes.IRETURN)); - } else if (randDesc.endsWith(")V")) { - insns.add(new InsnNode(Opcodes.RETURN)); - } - - method.instructions = insns; - return method; - } - - /** - * Generates a description for a trash method. - * - * @return generated description for a trash method. - */ - private String descGen() { - switch (NumberUtils.getRandomInt(7)) { - case 0: - return "(Ljava/lang/String;)Ljava/lang/String;"; - case 1: - return "(Ljava/lang/Object;)Ljava/lang/Object;"; - case 2: - return "(I)Z"; - case 3: - return "()V"; - case 4: - return "(B)V"; - case 5: - return "(Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;"; - case 6: // False BSM lol - default: - return "(Ljava/lang/invoke/MethodHandles$Lookup;" + - "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + - "ILjava/lang/String;Ljava/lang/String;" + - "Ljava/lang/String;)Ljava/lang/Object;"; - } - } - - /** - * Returns a random opcode instruction to add to trash methods. - * - * @return a random opcode instruction to add to trash methods. - */ - private static AbstractInsnNode junkInsns() { - int index = NumberUtils.getRandomInt(20); - switch (index) { - case 0: - return new MethodInsnNode(Opcodes.INVOKESTATIC, - StringUtils.crazyString(), StringUtils.crazyString(), - "(Ljava/lang/String;)V", false); - case 1: - return new FieldInsnNode(Opcodes.GETFIELD, - StringUtils.crazyString(), StringUtils.crazyString(), - "I"); - case 2: - return new InsnNode(NumberUtils.getRandomInt(16)); - case 3: - return new VarInsnNode(Opcodes.ALOAD, - NumberUtils.getRandomInt(30)); - case 4: - return new IntInsnNode(Opcodes.BIPUSH, - NumberUtils.getRandomInt(255)); - case 5: - return new IntInsnNode(Opcodes.SIPUSH, - NumberUtils.getRandomInt(25565)); - case 6: - case 7: - case 8: - return new InsnNode(NumberUtils.getRandomInt(5)); - case 9: - return new LdcInsnNode(StringUtils.crazyString()); - case 10: - return new IincInsnNode(NumberUtils.getRandomInt(16), - NumberUtils.getRandomInt(16)); - case 11: - return new MethodInsnNode(Opcodes.INVOKESPECIAL, - StringUtils.crazyString(), StringUtils.crazyString(), - "()V", false); - case 12: - return new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - StringUtils.crazyString(), StringUtils.crazyString(), - "(Ljava/lang/Object;)Ljava/lang/Object;", false); - case 13: - return new VarInsnNode(Opcodes.ILOAD, - NumberUtils.getRandomInt(30)); - case 14: - return new InsnNode(Opcodes.ATHROW); - case 15: - return new MethodInsnNode(Opcodes.INVOKEINTERFACE, - StringUtils.crazyString(), StringUtils.crazyString(), - "(I)I", false); - case 16: - Handle handle = new Handle(6, StringUtils.crazyString(), - StringUtils.crazyString(), StringUtils.crazyString(), - false); - return new InvokeDynamicInsnNode(StringUtils.crazyString(), - StringUtils.crazyString(), handle, - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5)); - case 17: - return new IntInsnNode(Opcodes.ANEWARRAY, - NumberUtils.getRandomInt(30)); - case 18: - return new VarInsnNode(Opcodes.ASTORE, - NumberUtils.getRandomInt(30)); - case 19: - default: - return new VarInsnNode(Opcodes.ISTORE, - NumberUtils.getRandomInt(30)); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java deleted file mode 100644 index 5ad56458..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.itzsomebody.radon.transformers.renamer; - -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.MethodNode; - -import java.util.HashSet; -import java.util.Set; - -/** - * Specifies subclasses and parents of a class. - * - * @author ItzSomebody - */ -public class ClassTree { - /** - * Class name. - */ - public String className; - - public ClassNode classNode; - - /** - * Set of classes that inherit this class. - */ - public Set subClasses = new HashSet<>(); - - /** - * Set of classes that this class inherits. - */ - public Set parentClasses = new HashSet<>(); - - /** - * Set of methods that this class contains. - */ - public Set methods = new HashSet<>(); - - /** - * Set of fields that this class contains. - */ - public Set fields = new HashSet<>(); - - /** - * Indication of this class being a library (external) class. - */ - public boolean libraryNode; - - /** - * Constructor to make a {@link ClassTree} object. - * - * @param className name to assign to this {@link ClassTree}. - */ - public ClassTree(String className, boolean libraryNode) { - this.className = className; - this.libraryNode = libraryNode; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java deleted file mode 100644 index 724eb0b5..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ /dev/null @@ -1,313 +0,0 @@ -package me.itzsomebody.radon.transformers.renamer; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.commons.SimpleRemapper; -import org.objectweb.asm.tree.*; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that renames classes and their members. - * TODO: Figure out why this doesn't work with TestingProject - * - * @author ItzSomebody - */ -public class Renamer extends AbstractTransformer { - /** - * Used for class, method and field renamming. Format is oldName -> newName. - */ - private Map mappings = new HashMap<>(); - - /** - * Used to determine how the classes interact with each other. - */ - private Map hierarchy = new HashMap<>(); - - /** - * Indication to look for Bukkit/Bungee main methods. - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link Renamer} object. - */ - public Renamer(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Starting renamer transformer")); - this.logStrings.add(LoggerUtils.stdOut("Generating mappings.")); - this.createTrees(); - long current = System.currentTimeMillis(); - AtomicInteger counter = new AtomicInteger(); - this.classNodes().forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isNativeMethod(methodNode.access) - && !methodNode.name.equals("main") - && !methodNode.name.equals("premain") - && !methodNode.name.startsWith("<") - && !methodNode.name.contains("lambda")).forEach(methodNode -> { - if (this.weCanRenameMethod(methodNode)) { - String newName = StringUtils.randomString(this.dictionary); - this.renameMethodTree(new ArrayList<>(), methodNode, classNode.name, newName); - } - }); - - classNode.fields.forEach(fieldNode -> { - if (this.weCanRenameField(fieldNode)) { - String newName = StringUtils.randomString(this.dictionary); - this.renameFieldTree(new ArrayList<>(), fieldNode, classNode.name, newName); - } - }); - - if (!this.exempted(classNode.name, "Renamer") - && !BytecodeUtils.isMain(classNode, this.spigotMode)) { - int packages = NumberUtils.getRandomInt(2) + 1; - StringBuilder newName = new StringBuilder(); - for (int i = 0; i < packages; i++) { - newName.append(StringUtils.randomString(this.dictionary)).append('/'); - } - - this.mappings.put(classNode.name, newName.substring(0, newName.length() - 1)); - counter.incrementAndGet(); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Finished generated mappings. [" + - String.valueOf(System.currentTimeMillis() - current) + "ms]")); - this.logStrings.add(LoggerUtils.stdOut("Applying mappings.")); - current = System.currentTimeMillis(); - - // Apply mapping - Remapper simpleRemapper = new SimpleRemapper(this.mappings); - for (ClassNode classNode : new ArrayList<>(this.classNodes())) { - ClassNode copy = new ClassNode(); - classNode.accept(new ClassRemapper(copy, simpleRemapper)); - copy.access = BytecodeUtils.accessFixer(copy.access); - for (MethodNode methodNode : copy.methods) { - methodNode.access = BytecodeUtils.accessFixer(methodNode.access); - } - - if (copy.fields != null) { - for (FieldNode fieldNode : copy.fields) { - fieldNode.access = BytecodeUtils.accessFixer(fieldNode.access); - } - } - - this.getClassMap().remove(classNode.name); - this.getClassPathMap().put(copy.name, copy); - this.getClassMap().put(copy.name, copy); - } - - this.logStrings.add(LoggerUtils.stdOut("Mapped " + counter + " members.")); - this.logStrings.add(LoggerUtils.stdOut("Finished applying mappings. [" + - String.valueOf(System.currentTimeMillis() - current) + "ms]")); - } - - /** - * Creates {@link ClassTree}s needed for renaming. - */ - private void createTrees() { - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); - this.getClassPathMap().values().forEach(classNode -> { - classNode.methods.forEach(methodNode -> { - methodNode.owner = classNode.name; - }); - classNode.fields.forEach(fieldNode -> { - fieldNode.owner = classNode.name; - }); - ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); - classTree.parentClasses.add(classNode.superName); - classTree.parentClasses.addAll(classNode.interfaces); - this.classNodes().stream().filter(node -> node.superName.equals(classNode.name) - || node.interfaces.contains(classNode.name)).forEach(node -> { - classTree.subClasses.add(node.name); - }); - - classTree.methods.addAll(classNode.methods); - classTree.fields.addAll(classNode.fields); - this.hierarchy.put(classNode.name, classTree); - }); - this.logStrings.add(LoggerUtils.stdOut("Finished creating class hierarchy. [" + tookThisLong(current) + "ms]")); - } - - /** - * Ultimately determines if we can rename a method without running into errors. - * - * @param methodNode {@link MethodNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @return true if we can rename a method without running into errors. - */ - private boolean weCanRenameMethod(MethodNode methodNode) { - for (ClassTree ct : this.hierarchy.values()) { - if (ct.subClasses.contains(methodNode.owner) - && this.isLibInheritedMN(new ArrayList<>(), methodNode, methodNode.owner)) { - return false; - } - } - return true; - } - - /** - * Attempts to determine if the method we input is inherited from a library class or is exempted. - * - * @param visited a list of {@link ClassTree}s which contain the {@link MethodNode}s we already checked. - * @param methodNode {@link MethodNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @param className the name of the class we want to check - * @return true if the method we input is inherited from a library class. - */ - private boolean isLibInheritedMN(List visited, MethodNode methodNode, String className) { - ClassTree ct = this.hierarchy.get(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!visited.contains(ct)) { - visited.add(ct); - if (!methodNode.owner.equals(className)) { - for (MethodNode mn : ct.methods) { - if (mn.name.equals(methodNode.name) && mn.desc.equals(methodNode.desc)) { - if (ct.libraryNode) { - return true; - } - } - } - } - if (exempted(className + '.' + methodNode.name + methodNode.desc, "Renamer")) { - return true; - } - for (String parentClass : ct.parentClasses) { - if (parentClass != null - && this.isLibInheritedMN(visited, methodNode, parentClass)) { - return true; - } - } - - for (String subClass : ct.subClasses) { - if (subClass != null - && this.isLibInheritedMN(visited, methodNode, subClass)) { - return true; - } - } - } - - return false; - } - - /** - * Renames the methods in an inheritance tree to prevent inheritance errors. - * - * @param visited a list of {@link ClassTree}s which contain the {@link MethodNode}s we already renamed. - * @param methodNode the method information. - * @param className the class we are currently browsing through. - * @param newName the new name of the method. - */ - private void renameMethodTree(List visited, MethodNode methodNode, String className, String newName) { - ClassTree ct = this.hierarchy.get(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!ct.libraryNode && !visited.contains(ct)) { - mappings.put(className + '.' + methodNode.name + methodNode.desc, newName); - visited.add(ct); - for (String parentClass : ct.parentClasses) { - this.renameMethodTree(visited, methodNode, parentClass, newName); - } - for (String subClass : ct.subClasses) { - this.renameMethodTree(visited, methodNode, subClass, newName); - } - } - } - - /** - * Ultimately determines if we can rename a field without running into errors. - * - * @param fieldNode {@link FieldNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @return true if we can rename a field without running into errors. - */ - private boolean weCanRenameField(FieldNode fieldNode) { - for (ClassTree ct : this.hierarchy.values()) { - if (ct.subClasses.contains(fieldNode.owner) - && this.isLibInheritedFN(new ArrayList<>(), fieldNode, fieldNode.owner)) { - return false; - } - } - return true; - } - - /** - * Attempts to determine if the method we input is inherited from a library class or is exempted. - * - * @param fieldNode {@link FieldNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @param className the name of the class we want to check - * @return true if the method we input is inherited from a library class. - */ - private boolean isLibInheritedFN(List visited, FieldNode fieldNode, String className) { - ClassTree ct = this.hierarchy.get(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!visited.contains(ct)) { - visited.add(ct); - if (!fieldNode.owner.equals(className)) { - for (MethodNode mn : ct.methods) { - if (mn.name.equals(fieldNode.name) && mn.desc.equals(fieldNode.desc)) { - if (ct.libraryNode) { - return true; - } - } - } - } - if (exempted(className + '.' + fieldNode.name, "Renamer")) { - return true; - } - for (String parentClass : ct.parentClasses) { - if (parentClass != null - && this.isLibInheritedFN(visited, fieldNode, parentClass)) { - return true; - } - } - - for (String subClass : ct.subClasses) { - if (subClass != null - && this.isLibInheritedFN(visited, fieldNode, subClass)) { - return true; - } - } - } - - return false; - } - - /** - * Renames the methods in an inheritance tree to prevent inheritance errors. - * - * @param visited a list of {@link ClassTree}s which contain the - * {@link MethodNode}s we already renamed. - * @param fieldNode the method information. - * @param className the class we are currently browsing through. - * @param newName the new name of the method. - */ - private void renameFieldTree(List visited, FieldNode fieldNode, - String className, String newName) { - ClassTree ct = this.hierarchy.get(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!ct.libraryNode && !visited.contains(ct)) { - this.mappings.put(className + '.' + fieldNode.name, newName); - visited.add(ct); - for (String parentClass : ct.parentClasses) { - this.renameFieldTree(visited, fieldNode, parentClass, newName); - } - for (String subClass : ct.subClasses) { - this.renameFieldTree(visited, fieldNode, subClass, newName); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java deleted file mode 100644 index 765ebd54..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.itzsomebody.radon.transformers.sourcedebug; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that obfuscates the source debug attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class ObfuscateSourceDebug extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source debug obfuscation transformer")); - String newDebug = StringUtils.crazyString(); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceDebug") - && classNode.sourceDebug != null).forEach(classNode -> { - classNode.sourceDebug = newDebug; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " source debug attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java deleted file mode 100644 index 1a1db406..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.itzsomebody.radon.transformers.sourcedebug; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that obfuscates the source debug attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class RemoveSourceDebug extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source debug removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceDebug") - && classNode.sourceDebug != null).forEach(classNode -> { - classNode.sourceDebug = null; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " source debug attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java deleted file mode 100644 index 27c82225..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.itzsomebody.radon.transformers.sourcename; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that obfuscates the source name attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class ObfuscateSourceName extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source name obfuscation transformer")); - String newName = StringUtils.crazyString() + ".java"; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceName")).forEach(classNode -> { - classNode.sourceFile = newName; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " source name attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java deleted file mode 100644 index f6c64ff8..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.itzsomebody.radon.transformers.sourcename; - -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that obfuscates the source name attribute by removing the - * attribute entirely. - * - * @author ItzSomebody - */ -public class RemoveSourceName extends AbstractTransformer { - /** - * Applies obfuscation to. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source name removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceName") - && classNode.sourceFile != null).forEach(classNode -> { - classNode.sourceFile = null; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " source name attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java deleted file mode 100644 index 0ad537ff..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ /dev/null @@ -1,91 +0,0 @@ -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; - -import java.util.concurrent.atomic.AtomicInteger; - -public class HeavyStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link HeavyStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% and - * %%__NONCE__%%). - */ - public HeavyStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - String keyLdc = StringUtils.randomString(this.dictionary); - ((LdcInsnNode) insn).cst = - StringUtils.heavyEncrypt(((String) ((LdcInsnNode) insn).cst), - keyLdc, decryptorPath[0].replace("/", "."), - decryptorPath[1]); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;" + - "Ljava/lang/Object;" + - "Ljava/lang/Object;)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - new LdcInsnNode(keyLdc)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - counter.incrementAndGet(); - } - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.heavyMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java deleted file mode 100644 index a4076b2e..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ /dev/null @@ -1,91 +0,0 @@ -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that encrypts strings using a stacktrace-backed method. - * - * @author ItzSomebody - */ -public class LightStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link LightStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders(%%__USER__%%, %%__RESOURCE__%% - * and %%__NONCE__%%). - */ - public LightStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - int key3 = NumberUtils.getRandomInt(); - ((LdcInsnNode) insn).cst = - StringUtils.lightEncrypt(((String) ((LdcInsnNode) insn).cst), - decryptorPath[0].replace("/", "."), - decryptorPath[1], key3); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key3)); - counter.incrementAndGet(); - } - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.lightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java deleted file mode 100644 index db6ee342..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ /dev/null @@ -1,95 +0,0 @@ -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that encrypts strings the same way {@link LightStringEncryption} - * does, but with flow obfuscation in the decryption method. - * - * @author ItzSomebody - */ -public class NormalStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link NormalStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% and - * %%__NONCE__%%). - */ - public NormalStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - int key3 = NumberUtils.getRandomInt(25000) + 25000; - ((LdcInsnNode) insn).cst = - StringUtils.normalEncrypt(decryptorPath[0].replace("/", "."), - decryptorPath[1], key3, - ((String) ((LdcInsnNode) insn).cst)); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;" + - "Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key3)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - counter.incrementAndGet(); - } - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.normalMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java deleted file mode 100644 index 9149b7ec..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ /dev/null @@ -1,89 +0,0 @@ -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Transformer that encrypts strings using an extremely simple XOR algorithm. - * - * @author ItzSomebody - */ -public class SuperLightStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link LightStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% - * and %%__NONCE__%%). - */ - public SuperLightStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started super light string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - int key = NumberUtils.getRandomInt(); - ((LdcInsnNode) insn).cst = - StringUtils.superLightEncrypt(((String) ((LdcInsnNode) insn).cst), key); - methodNode.instructions.insert(insn, - new MethodInsnNode(INVOKESTATIC, decryptorPath[0], - decryptorPath[1], - "(Ljava/lang/String;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key)); - counter.incrementAndGet(); - } - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.superLightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java deleted file mode 100644 index 2ffa3b10..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ /dev/null @@ -1,251 +0,0 @@ -package me.itzsomebody.radon.utils; - -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -/** - * Utils used for operating on bytecode. - * - * @author ItzSomebody - */ -public class BytecodeUtils { - /** - * Checks if the input class is a main method. - * - * @param clazz {@link ClassNode} to check for main methods. - * @param spigotMode if obfuscator should consider the input - * {@link ClassNode} as a Spigot/Bukkit/Bungee plugin. - * @return true if the input {@link ClassNode} contains a main method, - * false if not. - */ - public static boolean isMain(ClassNode clazz, boolean spigotMode) { - if (spigotMode) { - if (clazz.superName.equals("org/bukkit/plugin/java/JavaPlugin") - || clazz.superName.equals("net/md_5/bungee/api/plugin/Plugin")) { - return true; - } - } - - for (MethodNode methodNode : clazz.methods) { - if (methodNode.name.equals("main") - || methodNode.name.equals("premain")) { - return true; - } - } - return false; - } - - /** - * Returns access modifier without private or protected so that class - * renaming works properly. - * - * @param access input access as {@link Integer}. - * @return new {@link Integer} without restrictive flags. - */ - public static int accessFixer(int access) { - int a = access; - if ((a & Opcodes.ACC_PRIVATE) != 0) { - a ^= Opcodes.ACC_PRIVATE; - } - if ((a & Opcodes.ACC_PROTECTED) != 0) { - a ^= Opcodes.ACC_PROTECTED; - } - if ((a & Opcodes.ACC_PUBLIC) == 0) { - a |= Opcodes.ACC_PUBLIC; - } - return a; - } - - /** - * Returns an {@link InsnList} with bytecode instructions for expiration. - * - * @param expiryTime a {@link Long} representation of the expiration date. - * @return an {@link InsnList} with bytecode instructions for expiration. - */ - public static InsnList returnExpiry(long expiryTime, String expiredMsg) { - InsnList expiryCode = new InsnList(); - LabelNode injectedLabel = new LabelNode(new Label()); - - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/util/Date")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "", "()V", false)); - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/util/Date")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new LdcInsnNode(expiryTime)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "", "(J)V", false)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Date", "after", "(Ljava/util/Date;)Z", false)); - expiryCode.add(new JumpInsnNode(Opcodes.IFEQ, injectedLabel)); - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/lang/Throwable")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new LdcInsnNode(expiredMsg)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Throwable", "", "(Ljava/lang/String;)V", false)); - expiryCode.add(new InsnNode(Opcodes.ATHROW)); - expiryCode.add(injectedLabel); - - return expiryCode; - } - - /** - * Returns a bytecode instruction representing an int. - * - * @param number the {@link Integer} for the obfuscator to contemplate. - * @return a bytecode instruction representing an int. - */ - public static AbstractInsnNode getNumberInsn(int number) { - if (number >= -1 && number <= 5) { - return new InsnNode(number + 3); - } else if (number >= -128 && number <= 127) { - return new IntInsnNode(Opcodes.BIPUSH, number); - } else if (number >= -32768 && number <= 32767) { - return new IntInsnNode(Opcodes.SIPUSH, number); - } else { - return new LdcInsnNode(number); - } - } - - /** - * Returns a bytecode instruction representing a long. - * - * @param number the {@link Long} for the obfuscator to contemplate. - * @return a bytecode instruction representing a long. - */ - public static AbstractInsnNode getNumberInsn(long number) { - if (number >= 0 && number <= 1) { - return new InsnNode((int) (number + 9)); - } else { - return new LdcInsnNode(number); - } - } - - /** - * Returns true if access has native modifier. - * - * @param access method access to check. - * @return true if access has native modifier. - */ - public static boolean isNativeMethod(int access) { - return (access & Opcodes.ACC_NATIVE) != 0; - } - - /** - * Returns true if access has abstract modifier. - * - * @param access method access to check. - * @return true if access has abstract modifier. - */ - public static boolean isAbstractMethod(int access) { - return (access & Opcodes.ACC_ABSTRACT) != 0; - } - - /** - * Returns true if access has synthetic modifier. - * - * @param access method access to check. - * @return true if access has abstract modifier. - */ - public static boolean isSyntheticMethod(int access) { - return (access & Opcodes.ACC_SYNTHETIC) != 0; - } - - /** - * Returns true if access has bride modifier. - * - * @param access method access to check. - * @return true if access has abstract modifier. - */ - public static boolean isBridgeMethod(int access) { - return (access & Opcodes.ACC_BRIDGE) != 0; - } - - /** - * Returns true if input pushes an integer. - * - * @param insn {@link AbstractInsnNode} to check. - * @return true if input pushes an integer. - */ - public static boolean isIntInsn(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - return ((opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) - || opcode == Opcodes.BIPUSH - || opcode == Opcodes.SIPUSH - || (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Integer)); - } - - /** - * Returns true if input pushes a long. - * - * @param insn {@link AbstractInsnNode} to check. - * @return true if input pushes a long. - */ - public static boolean isLongInsn(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - return (opcode == Opcodes.LCONST_0 - || opcode == Opcodes.LCONST_1 - || (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Long)); - } - - /** - * Returns {@link Integer} represented by bytecode instruction and/or - * operand. - * - * @param insn {@link AbstractInsnNode} to check. - * @return {@link Integer} represented by bytecode instruction and/or - * operand. - */ - public static int getIntNumber(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - - if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) { - return opcode - 3; - } else if (insn instanceof IntInsnNode - && insn.getOpcode() != Opcodes.NEWARRAY) { - return ((IntInsnNode) insn).operand; - } else if (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Integer) { - return (Integer) ((LdcInsnNode) insn).cst; - } - - throw new IllegalStateException("Unexpected instruction"); - } - - /** - * Returns {@link Long} represented by bytecode instruction and/or - * operand. - * - * @param insn {@link AbstractInsnNode} to check. - * @return {@link Long} represented by bytecode instruction and/or - * operand. - */ - public static long getLongNumber(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - - if (opcode >= Opcodes.LCONST_0 && opcode <= Opcodes.LCONST_1) { - return opcode - 9; - } else if (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Long) { - return (Long) ((LdcInsnNode) insn).cst; - } - - throw new IllegalStateException("Unexpected instruction"); - } - - /** - * Checks if input methodNode contains goto opcode. - * - * @param methodNode input methodNode. - * @return true if input methodNode contains goto opcode. - */ - public static boolean containsGoto(MethodNode methodNode) { - for (int i = 0; i < methodNode.instructions.size(); i++) { - AbstractInsnNode insn = methodNode.instructions.get(i); - if (insn instanceof JumpInsnNode && insn.getOpcode() == Opcodes.GOTO) { - return true; - } - } - - return false; - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java b/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java deleted file mode 100644 index d386119c..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -package me.itzsomebody.radon.utils; - -/** - * Custom-defined Regex rules. - * - * @author ItzSomebody - */ -public class CustomRegexUtils { - /** - * Returns true/false based on if input is matched to this specific rule. - * - * @param customregex a {@link String} which is used as a "custom regex" - * statement. - * @param string a {@link String} to try to match. - * @return true/false based on if input is matched to this specific rule. - */ - public static boolean isMatched(String customregex, String string) { - return (customregex.equals(string) - || (customregex.contains("*") - && string.contains(customregex.split("\\*")[0]))); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java deleted file mode 100644 index 70971ab5..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -package me.itzsomebody.radon.utils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.ZipOutputStream; - -/** - * Utils for operating on files in general. - * - * @author ItzSomebody - */ -public class FileUtils { - /** - * Renames an existing file to EXISTINGFILE.jar.BACKUP-X. - * - * @param existing existing file to rename. - * @return the new name of the existing name. - */ - public static String renameExistingFile(File existing) { - int i = 0; - - while (true) { - i++; - String newName = existing.getAbsolutePath() + ".BACKUP-" - + String.valueOf(i); - File backUpName = new File(newName); - if (!backUpName.exists()) { - existing.renameTo(backUpName); - existing.delete(); - return newName; - } - } - - } - - /** - * Writes a bytes to a {@link ZipOutputStream}. - * - * @param zos the {@link ZipOutputStream} to write to. - * @param data bytes to write to output - * @throws IOException if an error happens while writing to output stream. - */ - public static void writeToZip(ZipOutputStream zos, byte[] data) - throws IOException { - zos.write(data); - zos.closeEntry(); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java deleted file mode 100644 index 0b890f36..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java +++ /dev/null @@ -1,75 +0,0 @@ -package me.itzsomebody.radon.utils; - -import me.itzsomebody.radon.Radon; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Utils to print fancy stuff in the console and to write log file. - * - * @author ItzSomebody - */ -public class LoggerUtils { - /** - * The {@link SimpleDateFormat} that will be used for logging. - */ - private static SimpleDateFormat FORMAT - = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); - - /** - * Writes an inputted {@link ArrayList} of {@link String}s to a log file. - * - * @param strings {@link String}s to write to log file. - */ - public static void logWriter(List strings) { - BufferedWriter bw; - try { - File log = new File("Radon.log"); - if (!log.exists()) { - log.createNewFile(); - } - bw = new BufferedWriter(new FileWriter(log)); - bw.append("##############################################\n"); - bw.append("# +----------------------------------------+ #\n"); - bw.append("# | _____ _____ ____ _ _ | #\n"); - bw.append("# | | __ \\ /\\ | __ \\ / __ \\| \\ | | | #\n"); - bw.append("# | | |__) | / \\ | | | | | | | \\| | | #\n"); - bw.append("# | | _ / / /\\ \\ | | | | | | | . ` | | #\n"); - bw.append("# | | | \\ \\ / ____ \\| |__| | |__| | |\\ | | #\n"); - bw.append("# | |_| \\_\\/_/ \\_\\_____/ \\____/|_| \\_| | #\n"); - bw.append("# | | #\n"); - bw.append("# +----------------------------------------+ #\n"); - bw.append("##############################################\n"); - bw.append("\n"); - bw.append("\n"); - bw.append("Version: " + Radon.VERSION + "\n"); - bw.append("Author: " + Radon.AUTHORS + "\n"); - for (String msg : strings) { - bw.append(msg); - bw.newLine(); - } - bw.close(); - } catch (Throwable t) { - stdOut("Error: " + t.getMessage()); - } - } - - /** - * Prints a formatted message into the console and returns the result as - * a {@link String}. - * - * @param string to write to the console. - * @return formatted {@link String}. - */ - public static String stdOut(String string) { - String date = FORMAT.format(new Date(System.currentTimeMillis())); - String formatted = "[" + date + "] " + Radon.PREFIX + " - " + string; - System.out.println(formatted); - return formatted; - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java b/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java deleted file mode 100644 index 54f82b2d..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.itzsomebody.radon.utils; - -import java.util.concurrent.ThreadLocalRandom; - -/** - * Number utils. - * - * @author ItzSomebody - */ -public class NumberUtils { - /** - * Gets a random {@link Integer} from {@link ThreadLocalRandom#nextInt()}. - * - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt()}. - */ - public static int getRandomInt() { - return ThreadLocalRandom.current().nextInt(); - } - - /** - * Gets a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt(int)}. - * - * @param bounds {@link Integer} used to define the bounds of the random. - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt(int)}. - */ - public static int getRandomInt(int bounds) { - return ThreadLocalRandom.current().nextInt(bounds); - } - - /** - * Gets a random {@link Long} from {@link ThreadLocalRandom#nextLong()}. - * - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextLong()}. - */ - public static long getRandomLong() { - return ThreadLocalRandom.current().nextLong(); - } - - /** - * Gets a random {@link Long} from - * {@link ThreadLocalRandom#nextLong(long)}. - * - * @param bounds {@link Long} used to define the bounds of the random. - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextLong(long)}. - */ - public static long getRandomLong(int bounds) { - return ThreadLocalRandom.current().nextLong(bounds); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java deleted file mode 100644 index f1f0d61a..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java +++ /dev/null @@ -1,339 +0,0 @@ -package me.itzsomebody.radon.utils; - -import org.objectweb.asm.Opcodes; - -/** - * Contains one utility which maps opcodes to strings for legibility. - * - * @author ItzSomebody - */ -public class OpcodeUtils implements Opcodes { - /** - * Returns a {@link String} representation of inputted opcode. - * - * @param opcode the opcode to get a name from. - * @return a {@link String} representation of inputted opcode. - */ - public static String getOpcodeName(int opcode) { - switch (opcode) { - case NOP: - return "nop"; - case ACONST_NULL: - return "aconst_null"; - case ICONST_M1: - return "iconst_m1"; - case ICONST_0: - return "iconst_0"; - case ICONST_1: - return "iconst_1"; - case ICONST_2: - return "iconst_2"; - case ICONST_3: - return "iconst_3"; - case ICONST_4: - return "iconst_4"; - case ICONST_5: - return "iconst_5"; - case LCONST_0: - return "lconst_0"; - case LCONST_1: - return "lconst_1"; - case FCONST_0: - return "fconst_0"; - case FCONST_1: - return "fconst_1"; - case FCONST_2: - return "fconst_2"; - case DCONST_0: - return "dconst_0"; - case DCONST_1: - return "dconst_1"; - case BIPUSH: - return "bipush"; - case SIPUSH: - return "sipush"; - case LDC: - return "ldc"; - case ILOAD: - return "iload"; - case LLOAD: - return "lload"; - case FLOAD: - return "fload"; - case DLOAD: - return "dload"; - case ALOAD: - return "aload"; - case IALOAD: - return "iaload"; - case LALOAD: - return "laload"; - case FALOAD: - return "faload"; - case DALOAD: - return "daload"; - case AALOAD: - return "aaload"; - case BALOAD: - return "baload"; - case CALOAD: - return "caload"; - case SALOAD: - return "saload"; - case ISTORE: - return "istore"; - case LSTORE: - return "lstore"; - case FSTORE: - return "fstore"; - case DSTORE: - return "dstore"; - case ASTORE: - return "astore"; - case IASTORE: - return "iastore"; - case LASTORE: - return "lastore"; - case FASTORE: - return "fastore"; - case DASTORE: - return "dastore"; - case AASTORE: - return "aastore"; - case BASTORE: - return "bastore"; - case CASTORE: - return "castore"; - case SASTORE: - return "sastore"; - case POP: - return "pop"; - case POP2: - return "pop2"; - case DUP: - return "dup"; - case DUP_X1: - return "dup_x1"; - case DUP_X2: - return "dup_x2"; - case DUP2: - return "dup2"; - case DUP2_X1: - return "dup2_x1"; - case DUP2_X2: - return "dup2_x2"; - case SWAP: - return "swap"; - case IADD: - return "iadd"; - case LADD: - return "ladd"; - case FADD: - return "fadd"; - case DADD: - return "dadd"; - case ISUB: - return "isub"; - case LSUB: - return "lsub"; - case FSUB: - return "fsub"; - case DSUB: - return "dsub"; - case IMUL: - return "imul"; - case LMUL: - return "lmul"; - case FMUL: - return "fmul"; - case DMUL: - return "dmul"; - case IDIV: - return "idiv"; - case LDIV: - return "ldiv"; - case FDIV: - return "fdiv"; - case DDIV: - return "ddiv"; - case IREM: - return "irem"; - case LREM: - return "lrem"; - case FREM: - return "frem"; - case DREM: - return "drem"; - case INEG: - return "ineg"; - case LNEG: - return "lneg"; - case FNEG: - return "fneg"; - case DNEG: - return "dneg"; - case ISHL: - return "ishl"; - case LSHL: - return "lshl"; - case ISHR: - return "ishr"; - case LSHR: - return "lshr"; - case IUSHR: - return "iushr"; - case LUSHR: - return "lushr"; - case IAND: - return "iand"; - case LAND: - return "land"; - case IOR: - return "ior"; - case LOR: - return "lor"; - case IXOR: - return "ixor"; - case LXOR: - return "lxor"; - case IINC: - return "iinc"; - case I2L: - return "i2l"; - case I2F: - return "i2f"; - case I2D: - return "i2d"; - case L2I: - return "l2i"; - case L2F: - return "l2f"; - case L2D: - return "l2d"; - case F2I: - return "f2i"; - case F2L: - return "f2l"; - case F2D: - return "f2d"; - case D2I: - return "d2i"; - case D2L: - return "d2l"; - case D2F: - return "d2f"; - case I2B: - return "i2b"; - case I2C: - return "i2c"; - case I2S: - return "i2s"; - case LCMP: - return "lcmp"; - case FCMPL: - return "fcmpl"; - case FCMPG: - return "fcmpg"; - case DCMPL: - return "dcmpl"; - case DCMPG: - return "dcmpg"; - case IFEQ: - return "ifeq"; - case IFNE: - return "ifne"; - case IFLT: - return "iflt"; - case IFGE: - return "ifge"; - case IFGT: - return "ifgt"; - case IFLE: - return "ifle"; - case IF_ICMPEQ: - return "if_icmpeq"; - case IF_ICMPNE: - return "if_icmpne"; - case IF_ICMPLT: - return "if_icmplt"; - case IF_ICMPGE: - return "if_icmpge"; - case IF_ICMPGT: - return "if_icmpgt"; - case IF_ICMPLE: - return "if_icmple"; - case IF_ACMPEQ: - return "if_acmpeq"; - case IF_ACMPNE: - return "if_acmpne"; - case GOTO: - return "goto"; - case JSR: - return "jsr"; - case RET: - return "ret"; - case TABLESWITCH: - return "tableswitch"; - case LOOKUPSWITCH: - return "lookupswitch"; - case IRETURN: - return "ireturn"; - case LRETURN: - return "lreturn"; - case FRETURN: - return "freturn"; - case DRETURN: - return "dreturn"; - case ARETURN: - return "areturn"; - case RETURN: - return "return"; - case GETSTATIC: - return "getstatic"; - case PUTSTATIC: - return "putstatic"; - case GETFIELD: - return "getfield"; - case PUTFIELD: - return "putfield"; - case INVOKEVIRTUAL: - return "invokevirtual"; - case INVOKESPECIAL: - return "invokespecial"; - case INVOKESTATIC: - return "invokestatic"; - case INVOKEINTERFACE: - return "invokeinterface"; - case INVOKEDYNAMIC: - return "invokedynamic"; - case NEW: - return "new"; - case NEWARRAY: - return "newarray"; - case ANEWARRAY: - return "anewarray"; - case ARRAYLENGTH: - return "arraylength"; - case ATHROW: - return "athrow"; - case CHECKCAST: - return "checkcast"; - case INSTANCEOF: - return "instanceof"; - case MONITORENTER: - return "monitorenter"; - case MONITOREXIT: - return "monitorexit"; - case MULTIANEWARRAY: - return "multianewarray"; - case IFNULL: - return "ifnull"; - case IFNONNULL: - return "ifnonnull"; - case -1: - return "debugging"; - } - - throw new IllegalArgumentException("Unknown opcode"); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java deleted file mode 100644 index be66b0c3..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ /dev/null @@ -1,347 +0,0 @@ -package me.itzsomebody.radon.utils; - -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; -import java.security.MessageDigest; -import java.util.*; - -import me.itzsomebody.radon.transformers.stringencryption.*; - -/** - * Utils for operating, and generating {@link String}s. - * - * @author ItzSomebody - */ -public class StringUtils { - /** - * Returns the proper string generation type given a dictionary type to use. - * - * @param dictionary an integer indicating which pre-defined string - * generation type to use. - * @return the proper string generation type given a dictionary type to use. - */ - public static String randomString(int dictionary) { - switch (dictionary) { - case 0: - return crazyString(); - case 1: - return crazyKey(); - case 2: - return alphaNumString(); - default: - throw new IllegalArgumentException("Illegal dictionary type " + dictionary); - } - } - - /** - * Generates and returns a pseudo-random alpha-numeric string. - * - * @return a pseudo-random alpha-numeric string. - */ - public static String alphaNumString() { - int numberOfChars = 4; - char[] alphaNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < numberOfChars; i++) { - sb.append(alphaNum[NumberUtils.getRandomInt(alphaNum.length)]); - } - - return sb.toString(); - } - - /** - * Generates a {@link String} with a length of 10 consisting of spaces. - * Stole this idea from NeonObf and Smoke. - * - * @return a built {@link String} consisting of spaces. - */ - public static String crazyString() { - int numberOfChars = 10; // Just so I can do a quick switch. - char[] buildString = new char[numberOfChars]; - - for (int i = 0; i < numberOfChars; i++) { - switch (NumberUtils.getRandomInt(16)) { - case 0: - buildString[i] = '\u2000'; - break; - case 1: - buildString[i] = '\u2001'; - break; - case 2: - buildString[i] = '\u2002'; - break; - case 3: - buildString[i] = '\u2003'; - break; - case 4: - buildString[i] = '\u2004'; - break; - case 5: - buildString[i] = '\u2005'; - break; - case 6: - buildString[i] = '\u2006'; - break; - case 7: - buildString[i] = '\u2007'; - break; - case 8: - buildString[i] = '\u2008'; - break; - case 9: - buildString[i] = '\u2009'; - break; - case 10: - buildString[i] = '\u200A'; - break; - case 11: - buildString[i] = '\u200B'; - break; - case 12: - buildString[i] = '\u200C'; - break; - case 13: - buildString[i] = '\u200D'; - break; - case 14: - buildString[i] = '\u200E'; - break; - case 15: - buildString[i] = '\u200F'; - break; - } - } - - return new String(buildString); - } - - /** - * Alternative generator to the method above. - * - * @return a {@link String} consisting of characters the JVM doesn't - * recognize. - */ - public static String crazyKey() { - int numberOfChars = 10; // Just so I can do a quick switch. - char[] buildString = new char[numberOfChars]; - - for (int i = 0; i < numberOfChars; i++) { - switch (NumberUtils.getRandomInt(8)) { - case 0: - buildString[i] = '\ua6ac'; - break; - case 1: - buildString[i] = '\ua6ea'; - break; - case 2: - buildString[i] = '\ua6ba'; - break; - case 3: - buildString[i] = '\ua6a3'; - break; - case 4: - buildString[i] = '\ua6a4'; - break; - case 5: - buildString[i] = '\ua6b5'; - break; - case 6: - buildString[i] = '\ua6b0'; - break; - case 7: - buildString[i] = '\ua6a8'; - break; - } - } - - return new String(buildString); - } - - /** - * Returns an encrypted string used by {@link SuperLightStringEncryption}. - * - * @param msg string to encrypt. - * @param key random integer - * @return an encrypted string used by {@link SuperLightStringEncryption}. - */ - public static String superLightEncrypt(String msg, int key) { - char[] encryptedArray = msg.toCharArray(); - char[] returnThis = new char[encryptedArray.length]; - - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (encryptedArray[i] ^ key); - } - - return new String(returnThis); - } - - /** - * Returns an encrypted string used by {@link LightStringEncryption}. - * - * @param msg string to encrypt. - * @param className name of the class the msg is in. - * @param methodName name of the method the msg is in. - * @param key3 random integer - * @return an encrypted string used by {@link LightStringEncryption}. - */ - public static String lightEncrypt(String msg, String className, - String methodName, int key3) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - for (int i = 0; i < returnThis.length; i++) { - char key2 = (char) methodName.hashCode(); - char key1 = (char) className.hashCode(); - returnThis[i] = (char) (key3 ^ key2 ^ key1 ^ chars[i]); - } - - return new String(returnThis); - } - - /** - * Returns {@link String} encrypted with AES symmetrical encryption - * algorithm to encrypt {@link String}s. - * - * @param msg {@link String} to encrypt. - * @param secret {@link String} to use as a key. - * @return encrypted {@link String} - */ - public static String aesEncrypt(String msg, String secret) { - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); - return Base64.getEncoder().encodeToString(cipher.doFinal(msg. - getBytes("UTF-8"))); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to encrypt string " + - msg + " using " + secret); - } - } - - /** - * Returns {@link String} decrypted AES encrypted {@link String}s. - * - * @param strToDecrypt {@link String} to decrypt. - * @param secret {@link String} to use as a key. - * @return decrypted {@link String} - */ - public static String aesDecrypt(String strToDecrypt, String secret) { - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); - cipher.init(Cipher.DECRYPT_MODE, secretKey); - return new String(cipher.doFinal(Base64.getDecoder() - .decode(strToDecrypt))); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to decrypt string " + - strToDecrypt + " using " + secret); - } - } - - /** - * Returns a generated classname based on current class packages. - * - * @return a generated classname based on current class packages. - */ - public static String randomClassName(Collection theClassNames, int dictionary) { - List classNames = new ArrayList<>(); - classNames.addAll(theClassNames); - - String randomClass = classNames.get(NumberUtils. - getRandomInt(classNames.size())); - String[] split = randomClass.split("/"); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < split.length - 1; i++) { - sb.append(split[i]); - sb.append("/"); - } - - sb.append(StringUtils.randomString(dictionary)); - - return new String(sb); - } - - /** - * Returns a generated classname based on current class packages. - * - * @return a generated classname based on current class packages. - */ - public static String randomClass(Collection theClassNames) { - List classNames = new ArrayList<>(); - classNames.addAll(theClassNames); - - String randomClass = classNames.get(NumberUtils - .getRandomInt(classNames.size())); - return randomClass; - } - - /** - * Returns encrypted {@link String} used by {@link NormalStringEncryption}. - * - * @param className the className to get hashcode from. - * @param methodName the methodName to get hashcode from. - * @param key3 the extra key to ensure a different encryption each - * time. - * @param msg the string to encrypt - * @return encrypted {@link String} used by {@link NormalStringEncryption}. - */ - public static String normalEncrypt(String className, String methodName, - int key3, String msg) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - for (int i = 0; i < chars.length; i++) { - returnThis[i] = (char) (key3 ^ methodName.hashCode() ^ - className.hashCode() ^ chars[i]); - } - - return new String(returnThis); - } - - /** - * Returns encrypted {@link String} used by {@link HeavyStringEncryption}. - * - * @param msg the string to encrypt. - * @param secret the key for AES to use. - * @param className the class name the string is contained in. - * @param methodName the method name the string is contained in. - * @return encrypted {@link String} used by {@link HeavyStringEncryption}. - */ - public static String heavyEncrypt(String msg, String secret, - String className, String methodName) { - char[] base64Chars; - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); - base64Chars = Base64.getEncoder().encodeToString(cipher. - doFinal(msg.getBytes("UTF-8"))).toCharArray(); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to encrypt string " + - msg + " using " + secret); - } - char[] returnThis = new char[base64Chars.length]; - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (base64Chars[i] ^ className.hashCode() ^ - methodName.hashCode()); - } - - return new String(returnThis); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java deleted file mode 100644 index 1d68a771..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -package me.itzsomebody.radon.utils; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; - -import java.io.File; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * Watermarking utils for the obfuscator. - * - * @author ItzSomebody - */ -public class WatermarkUtils { // TODO: Add more secure watermark injection - /** - * Extracts injected watermarks by console and stores them in a - * {@link List} as a {@link String}. - * - * @param jarFile file to extract watermarks from. - * @param key {@link String} to use to decrypt encrypted watemark - * messages. - * @return a {@link List} of all extracted watermarks. - * @throws Throwable should some virtual-disaster should happen. - */ - public static List extractWatermark(File jarFile, String key) - throws Throwable { - List foundIds = new ArrayList<>(); - ZipFile zipFile = new ZipFile(jarFile); - Enumeration entries = zipFile.entries(); - try { - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if (!entry.isDirectory() && entry.getName().endsWith(".class")) { - try (InputStream in = zipFile.getInputStream(entry)) { - ClassReader cr = new ClassReader(in); - ClassNode classNode = new ClassNode(); - cr.accept(classNode, ClassReader.SKIP_FRAMES - | ClassReader.SKIP_DEBUG); - char[] buf = new char[cr.getMaxStringLength()]; - - try { - for (int i = 0; i < cr.getItemCount(); i++) { - int getItem = cr.getItem(i); - String UTF = cr.readUTF8(getItem, buf); - if (UTF != null && UTF.startsWith("WMID: ")) { - if (UTF.length() > 6) { - String getId = StringUtils.aesDecrypt(UTF.substring(6, UTF.length()), key); - foundIds.add("Watermarked ID in constant pool of " + entry.getName() + " -> " + getId); - } - } - } - } catch (Throwable t) { - // ignored; - } - - - if (classNode.signature != null) { - try { - String decrypted = StringUtils.aesDecrypt(classNode.signature, key); - if (decrypted.startsWith("WMID: ")) { - foundIds.add("Watermarked ID in class signature of " + entry.getName() + " -> " + decrypted); - } - } catch (Throwable t) { - // ignored - } - } - } - } - } - } finally { - zipFile.close(); - } - return foundIds; - } -} diff --git a/src/main/java/org/objectweb/asm/AnnotationVisitor.java b/src/main/java/org/objectweb/asm/AnnotationVisitor.java deleted file mode 100644 index a4b2dff0..00000000 --- a/src/main/java/org/objectweb/asm/AnnotationVisitor.java +++ /dev/null @@ -1,149 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java annotation. The methods of this class must be called in the following - * order: ( visit | visitEnum | visitAnnotation | visitArray )* - * visitEnd. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public abstract class AnnotationVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The annotation visitor to which this visitor must delegate method calls. May be null. - */ - protected AnnotationVisitor av; - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public AnnotationVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param annotationVisitor the annotation visitor to which this visitor must delegate method - * calls. May be null. - */ - public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.av = annotationVisitor; - } - - /** - * Visits a primitive value of the annotation. - * - * @param name the value name. - * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link - * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, - * {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This - * value can also be an array of byte, boolean, short, char, int, long, float or double values - * (this is equivalent to using {@link #visitArray} and visiting each array element in turn, - * but is more convenient). - */ - public void visit(final String name, final Object value) { - if (av != null) { - av.visit(name, value); - } - } - - /** - * Visits an enumeration value of the annotation. - * - * @param name the value name. - * @param descriptor the class descriptor of the enumeration class. - * @param value the actual enumeration value. - */ - public void visitEnum(final String name, final String descriptor, final String value) { - if (av != null) { - av.visitEnum(name, descriptor, value); - } - } - - /** - * Visits a nested annotation value of the annotation. - * - * @param name the value name. - * @param descriptor the class descriptor of the nested annotation class. - * @return a visitor to visit the actual nested annotation value, or null if this visitor - * is not interested in visiting this nested annotation. The nested annotation value must - * be fully visited before calling other methods on this annotation visitor. - */ - public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { - if (av != null) { - return av.visitAnnotation(name, descriptor); - } - return null; - } - - /** - * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, - * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit - * visit}. This is what {@link ClassReader} does. - * - * @param name the value name. - * @return a visitor to visit the actual array value elements, or null if this visitor is - * not interested in visiting these values. The 'name' parameters passed to the methods of - * this visitor are ignored. All the array values must be visited before calling other - * methods on this annotation visitor. - */ - public AnnotationVisitor visitArray(final String name) { - if (av != null) { - return av.visitArray(name); - } - return null; - } - - /** - * Visits the end of the annotation. - */ - public void visitEnd() { - if (av != null) { - av.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/AnnotationWriter.java b/src/main/java/org/objectweb/asm/AnnotationWriter.java deleted file mode 100644 index 130d359b..00000000 --- a/src/main/java/org/objectweb/asm/AnnotationWriter.java +++ /dev/null @@ -1,422 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation' - * structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter - * instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations - * attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such - * lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.7.16 - * @see JVMS - * 4.7.20 - */ -final class AnnotationWriter extends AnnotationVisitor { - - /** - * Where the constants used in this AnnotationWriter must be stored. - */ - private final SymbolTable symbolTable; - - /** - * Whether values are named or not. AnnotationWriter instances used for annotation default and - * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each - * value, instead of an element_name_index followed by an element_value). - */ - private final boolean useNamedValues; - - /** - * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values - * visited so far. All the fields of these structures, except the last one - the - * element_value_pairs array, must be set before this ByteVector is passed to the constructor - * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link - * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit() - * methods. - * - *

Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a - * single element_value by definition), this ByteVector is initially empty when passed to the - * constructor, and {@link #numElementValuePairsOffset} is set to -1. - */ - private final ByteVector annotation; - - /** - * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for - * the case of AnnotationDefault attributes). - */ - private final int numElementValuePairsOffset; - - /** - * The number of element value pairs visited so far. - */ - private int numElementValuePairs; - - /** - * The previous AnnotationWriter. This field is used to store the list of annotations of a - * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations - * (annotation values of annotation type), or for AnnotationDefault attributes. - */ - private final AnnotationWriter previousAnnotation; - - /** - * The next AnnotationWriter. This field is used to store the list of annotations of a - * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations - * (annotation values of annotation type), or for AnnotationDefault attributes. - */ - private AnnotationWriter nextAnnotation; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link AnnotationWriter}. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays - * use unnamed values. - * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to - * the visited content must be stored. This ByteVector must already contain all the fields of - * the structure except the last one (the element_value_pairs array). - * @param previousAnnotation the previously visited annotation of the - * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in - * other cases (e.g. nested or array annotations). - */ - AnnotationWriter( - final SymbolTable symbolTable, - final boolean useNamedValues, - final ByteVector annotation, - final AnnotationWriter previousAnnotation) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.useNamedValues = useNamedValues; - this.annotation = annotation; - // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'. - this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2; - this.previousAnnotation = previousAnnotation; - if (previousAnnotation != null) { - previousAnnotation.nextAnnotation = this; - } - } - - /** - * Constructs a new {@link AnnotationWriter} using named values. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to - * the visited content must be stored. This ByteVector must already contain all the fields of - * the structure except the last one (the element_value_pairs array). - * @param previousAnnotation the previously visited annotation of the - * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in - * other cases (e.g. nested or array annotations). - */ - AnnotationWriter( - final SymbolTable symbolTable, - final ByteVector annotation, - final AnnotationWriter previousAnnotation) { - this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation); - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the AnnotationVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public void visit(final String name, final Object value) { - // Case of an element_value with a const_value_index, class_info_index or array_index field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - if (value instanceof String) { - annotation.put12('s', symbolTable.addConstantUtf8((String) value)); - } else if (value instanceof Byte) { - annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index); - } else if (value instanceof Boolean) { - int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0; - annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index); - } else if (value instanceof Character) { - annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index); - } else if (value instanceof Short) { - annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index); - } else if (value instanceof Type) { - annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor())); - } else if (value instanceof byte[]) { - byte[] byteArray = (byte[]) value; - annotation.put12('[', byteArray.length); - for (byte byteValue : byteArray) { - annotation.put12('B', symbolTable.addConstantInteger(byteValue).index); - } - } else if (value instanceof boolean[]) { - boolean[] booleanArray = (boolean[]) value; - annotation.put12('[', booleanArray.length); - for (boolean booleanValue : booleanArray) { - annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index); - } - } else if (value instanceof short[]) { - short[] shortArray = (short[]) value; - annotation.put12('[', shortArray.length); - for (short shortValue : shortArray) { - annotation.put12('S', symbolTable.addConstantInteger(shortValue).index); - } - } else if (value instanceof char[]) { - char[] charArray = (char[]) value; - annotation.put12('[', charArray.length); - for (char charValue : charArray) { - annotation.put12('C', symbolTable.addConstantInteger(charValue).index); - } - } else if (value instanceof int[]) { - int[] intArray = (int[]) value; - annotation.put12('[', intArray.length); - for (int intValue : intArray) { - annotation.put12('I', symbolTable.addConstantInteger(intValue).index); - } - } else if (value instanceof long[]) { - long[] longArray = (long[]) value; - annotation.put12('[', longArray.length); - for (long longValue : longArray) { - annotation.put12('J', symbolTable.addConstantLong(longValue).index); - } - } else if (value instanceof float[]) { - float[] floatArray = (float[]) value; - annotation.put12('[', floatArray.length); - for (float floatValue : floatArray) { - annotation.put12('F', symbolTable.addConstantFloat(floatValue).index); - } - } else if (value instanceof double[]) { - double[] doubleArray = (double[]) value; - annotation.put12('[', doubleArray.length); - for (double doubleValue : doubleArray) { - annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index); - } - } else { - Symbol symbol = symbolTable.addConstant(value); - annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index); - } - } - - @Override - public void visitEnum(final String name, final String descriptor, final String value) { - // Case of an element_value with an enum_const_value field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - annotation - .put12('e', symbolTable.addConstantUtf8(descriptor)) - .putShort(symbolTable.addConstantUtf8(value)); - } - - @Override - public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { - // Case of an element_value with an annotation_value field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. - annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); - return new AnnotationWriter(symbolTable, annotation, null); - } - - @Override - public AnnotationVisitor visitArray(final String name) { - // Case of an element_value with an array_value field. - // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1 - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the - // end of an element_value of array type is similar to the end of an 'annotation' structure: an - // unsigned short num_values followed by num_values element_value, versus an unsigned short - // num_element_value_pairs, followed by num_element_value_pairs { element_name_index, - // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to - // visit the array elements. Its num_element_value_pairs will correspond to the number of array - // elements and will be stored in what is in fact num_values. - annotation.put12('[', 0); - return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); - } - - @Override - public void visitEnd() { - if (numElementValuePairsOffset != -1) { - byte[] data = annotation.data; - data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8); - data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs; - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation - * and all its predecessors (see {@link #previousAnnotation}. Also adds the attribute name - * to the constant pool of the class (if not null). - * - * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null. - * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this - * annotation and all its predecessors. This includes the size of the attribute_name_index and - * attribute_length fields. - */ - int computeAnnotationsSize(final String attributeName) { - if (attributeName != null) { - symbolTable.addConstantUtf8(attributeName); - } - // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes. - int attributeSize = 8; - AnnotationWriter annotationWriter = this; - while (annotationWriter != null) { - attributeSize += annotationWriter.annotation.length; - annotationWriter = annotationWriter.previousAnnotation; - } - return attributeSize; - } - - /** - * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its - * predecessors (see {@link #previousAnnotation} in the given ByteVector. Annotations are - * put in the same order they have been visited. - * - * @param attributeNameIndex the constant pool index of the attribute name (one of - * "Runtime[In]Visible[Type]Annotations"). - * @param output where the attribute must be put. - */ - void putAnnotations(final int attributeNameIndex, final ByteVector output) { - int attributeLength = 2; // For num_annotations. - int numAnnotations = 0; - AnnotationWriter annotationWriter = this; - AnnotationWriter firstAnnotation = null; - while (annotationWriter != null) { - // In case the user forgot to call visitEnd(). - annotationWriter.visitEnd(); - attributeLength += annotationWriter.annotation.length; - numAnnotations++; - firstAnnotation = annotationWriter; - annotationWriter = annotationWriter.previousAnnotation; - } - output.putShort(attributeNameIndex); - output.putInt(attributeLength); - output.putShort(numAnnotations); - annotationWriter = firstAnnotation; - while (annotationWriter != null) { - output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length); - annotationWriter = annotationWriter.nextAnnotation; - } - } - - /** - * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the - * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the - * constant pool of the class. - * - * @param attributeName one of "Runtime[In]VisibleParameterAnnotations". - * @param annotationWriters an array of AnnotationWriter lists (designated by their last - * element). - * @param annotableParameterCount the number of elements in annotationWriters to take into account - * (elements [0..annotableParameterCount[ are taken into account). - * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding - * to the given sub-array of AnnotationWriter lists. This includes the size of the - * attribute_name_index and attribute_length fields. - */ - static int computeParameterAnnotationsSize( - final String attributeName, - final AnnotationWriter[] annotationWriters, - final int annotableParameterCount) { - // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize - // below. This assumes that there is at least one non-null element in the annotationWriters - // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter). - // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each - // element of the parameter_annotations array uses 2 bytes for its num_annotations field. - int attributeSize = 7 + 2 * annotableParameterCount; - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - attributeSize += - annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8; - } - return attributeSize; - } - - /** - * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists - * from the given AnnotationWriter sub-array in the given ByteVector. - * - * @param attributeNameIndex constant pool index of the attribute name (one of - * Runtime[In]VisibleParameterAnnotations). - * @param annotationWriters an array of AnnotationWriter lists (designated by their last - * element). - * @param annotableParameterCount the number of elements in annotationWriters to put (elements - * [0..annotableParameterCount[ are put). - * @param output where the attribute must be put. - */ - static void putParameterAnnotations( - final int attributeNameIndex, - final AnnotationWriter[] annotationWriters, - final int annotableParameterCount, - final ByteVector output) { - // The num_parameters field uses 1 byte, and each element of the parameter_annotations array - // uses 2 bytes for its num_annotations field. - int attributeLength = 1 + 2 * annotableParameterCount; - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - attributeLength += - annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8; - } - output.putShort(attributeNameIndex); - output.putInt(attributeLength); - output.putByte(annotableParameterCount); - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - AnnotationWriter firstAnnotation = null; - int numAnnotations = 0; - while (annotationWriter != null) { - // In case user the forgot to call visitEnd(). - annotationWriter.visitEnd(); - numAnnotations++; - firstAnnotation = annotationWriter; - annotationWriter = annotationWriter.previousAnnotation; - } - output.putShort(numAnnotations); - annotationWriter = firstAnnotation; - while (annotationWriter != null) { - output.putByteArray( - annotationWriter.annotation.data, 0, annotationWriter.annotation.length); - annotationWriter = annotationWriter.nextAnnotation; - } - } - } -} diff --git a/src/main/java/org/objectweb/asm/Attribute.java b/src/main/java/org/objectweb/asm/Attribute.java deleted file mode 100644 index c9732f5f..00000000 --- a/src/main/java/org/objectweb/asm/Attribute.java +++ /dev/null @@ -1,327 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine - * Specification (JVMS). - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.7 - * @see JVMS - * 4.7.3 - */ -public class Attribute { - - /** - * The type of this attribute, also called its name in the JVMS. - */ - public final String type; - - /** - * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}). - * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are not - * included. - */ - private byte[] content; - - /** - * The next attribute in this attribute list (Attribute instances can be linked via this field to - * store a list of class, field, method or code attributes). May be null. - */ - Attribute nextAttribute; - - /** - * Constructs a new empty attribute. - * - * @param type the type of the attribute. - */ - protected Attribute(final String type) { - this.type = type; - } - - /** - * Returns true if this type of attribute is unknown. This means that the attribute - * content can't be parsed to extract constant pool references, labels, etc. Instead, the - * attribute content is read as an opaque byte array, and written back as is. This can lead to - * invalid attributes, if the content actually contains constant pool references, labels, or other - * symbolic references that need to be updated when there are changes to the constant pool, the - * method bytecode, etc. The default implementation of this method always returns true. - * - * @return true if this type of attribute is unknown. - */ - public boolean isUnknown() { - return true; - } - - /** - * Returns true if this type of attribute is a code attribute. - * - * @return true if this type of attribute is a code attribute. - */ - public boolean isCodeAttribute() { - return false; - } - - /** - * Returns the labels corresponding to this attribute. - * - * @return the labels corresponding to this attribute, or null if this attribute is not a - * code attribute that contains labels. - */ - protected Label[] getLabels() { - return new Label[0]; - } - - /** - * Reads a {@link #type} attribute. This method must return a new {@link Attribute} object, - * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given - * ClassReader. - * - * @param classReader the class that contains the attribute to be read. - * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The - * 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param length the length of the attribute's content (excluding the 6 attribute header bytes). - * @param charBuffer the buffer to be used to call the ClassReader methods requiring a - * 'charBuffer' parameter. - * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute - * in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6 - * attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param labels the labels of the method's code, or null if the attribute to be read is - * not a code attribute. - * @return a new {@link Attribute} object corresponding to the specified bytes. - */ - protected Attribute read( - final ClassReader classReader, - final int offset, - final int length, - final char[] charBuffer, - final int codeAttributeOffset, - final Label[] labels) { - Attribute attribute = new Attribute(type); - attribute.content = new byte[length]; - System.arraycopy(classReader.b, offset, attribute.content, 0, length); - return attribute; - } - - /** - * Returns the byte array form of the content of this attribute. The 6 header bytes - * (attribute_name_index and attribute_length) must not be added in the returned - * ByteVector. - * - * @param classWriter the class to which this attribute must be added. This parameter can be used - * to add the items that corresponds to this attribute to the constant pool of this class. - * @param code the bytecode of the method corresponding to this code attribute, or null - * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code - * attribute. - * @param codeLength the length of the bytecode of the method corresponding to this code - * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length' - * field of the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to this code attribute, or - * -1 if this attribute is not a code attribute. - * @param maxLocals the maximum number of local variables of the method corresponding to this code - * attribute, or -1 if this attribute is not a code attribute. - * @return the byte array form of this attribute. - */ - protected ByteVector write( - final ClassWriter classWriter, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals) { - return new ByteVector(content); - } - - /** - * Returns the number of attributes of the attribute list that begins with this attribute. - * - * @return the number of attributes of the attribute list that begins with this attribute. - */ - final int getAttributeCount() { - int count = 0; - Attribute attribute = this; - while (attribute != null) { - count += 1; - attribute = attribute.nextAttribute; - } - return count; - } - - /** - * Returns the total size in bytes of all the attributes in the attribute list that begins with - * this attribute. This size includes the 6 header bytes (attribute_name_index and - * attribute_length) per attribute. Also adds the attribute type names to the constant pool. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @return the size of all the attributes in this attribute list. This size includes the size of - * the attribute headers. - */ - final int computeAttributesSize(final SymbolTable symbolTable) { - final byte[] code = null; - final int codeLength = 0; - final int maxStack = -1; - final int maxLocals = -1; - return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals); - } - - /** - * Returns the total size in bytes of all the attributes in the attribute list that begins with - * this attribute. This size includes the 6 header bytes (attribute_name_index and - * attribute_length) per attribute. Also adds the attribute type names to the constant pool. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param code the bytecode of the method corresponding to these code attributes, or null - * if they are not code attributes. Corresponds to the 'code' field of the Code attribute. - * @param codeLength the length of the bytecode of the method corresponding to these code - * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of - * the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or - * -1 if they are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these - * code attributes, or -1 if they are not code attribute. - * @return the size of all the attributes in this attribute list. This size includes the size of - * the attribute headers. - */ - final int computeAttributesSize( - final SymbolTable symbolTable, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals) { - final ClassWriter classWriter = symbolTable.classWriter; - int size = 0; - Attribute attribute = this; - while (attribute != null) { - symbolTable.addConstantUtf8(attribute.type); - size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length; - attribute = attribute.nextAttribute; - } - return size; - } - - /** - * Puts all the attributes of the attribute list that begins with this attribute, in the given - * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per - * attribute. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param output where the attributes must be written. - */ - final void putAttributes(final SymbolTable symbolTable, final ByteVector output) { - final byte[] code = null; - final int codeLength = 0; - final int maxStack = -1; - final int maxLocals = -1; - putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output); - } - - /** - * Puts all the attributes of the attribute list that begins with this attribute, in the given - * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per - * attribute. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param code the bytecode of the method corresponding to these code attributes, or null - * if they are not code attributes. Corresponds to the 'code' field of the Code attribute. - * @param codeLength the length of the bytecode of the method corresponding to these code - * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of - * the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or - * -1 if they are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these - * code attributes, or -1 if they are not code attribute. - * @param output where the attributes must be written. - */ - final void putAttributes( - final SymbolTable symbolTable, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals, - final ByteVector output) { - final ClassWriter classWriter = symbolTable.classWriter; - Attribute attribute = this; - while (attribute != null) { - ByteVector attributeContent = - attribute.write(classWriter, code, codeLength, maxStack, maxLocals); - // Put attribute_name_index and attribute_length. - output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length); - output.putByteArray(attributeContent.data, 0, attributeContent.length); - attribute = attribute.nextAttribute; - } - } - - /** - * A set of attribute prototypes (attributes with the same type are considered equal). - */ - static final class Set { - - private static final int SIZE_INCREMENT = 6; - - private int size; - private Attribute[] data = new Attribute[SIZE_INCREMENT]; - - void addAttributes(final Attribute attributeList) { - Attribute attribute = attributeList; - while (attribute != null) { - if (!contains(attribute)) { - add(attribute); - } - attribute = attribute.nextAttribute; - } - } - - Attribute[] toArray() { - Attribute[] result = new Attribute[size]; - System.arraycopy(data, 0, result, 0, size); - return result; - } - - private boolean contains(final Attribute attribute) { - for (int i = 0; i < size; ++i) { - if (data[i].type.equals(attribute.type)) { - return true; - } - } - return false; - } - - private void add(final Attribute attribute) { - if (size >= data.length) { - Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT]; - System.arraycopy(data, 0, newData, 0, size); - data = newData; - } - data[size++] = attribute; - } - } -} diff --git a/src/main/java/org/objectweb/asm/ByteVector.java b/src/main/java/org/objectweb/asm/ByteVector.java deleted file mode 100644 index fd3ec214..00000000 --- a/src/main/java/org/objectweb/asm/ByteVector.java +++ /dev/null @@ -1,366 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream - * on top of a ByteArrayOutputStream, but is more efficient. - * - * @author Eric Bruneton - */ -public class ByteVector { - - /** - * The content of this vector. Only the first {@link #length} bytes contain real data. - */ - byte[] data; - - /** - * The actual number of bytes in this vector. - */ - int length; - - /** - * Constructs a new {@link ByteVector} with a default initial capacity. - */ - public ByteVector() { - data = new byte[64]; - } - - /** - * Constructs a new {@link ByteVector} with the given initial capacity. - * - * @param initialCapacity the initial capacity of the byte vector to be constructed. - */ - public ByteVector(final int initialCapacity) { - data = new byte[initialCapacity]; - } - - /** - * Constructs a new {@link ByteVector} from the given initial data. - * - * @param data the initial data of the new byte vector. - */ - ByteVector(final byte[] data) { - this.data = data; - this.length = data.length; - } - - /** - * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param byteValue a byte. - * @return this byte vector. - */ - public ByteVector putByte(final int byteValue) { - int currentLength = length; - if (currentLength + 1 > data.length) { - enlarge(1); - } - data[currentLength++] = (byte) byteValue; - length = currentLength; - return this; - } - - /** - * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param byteValue1 a byte. - * @param byteValue2 another byte. - * @return this byte vector. - */ - final ByteVector put11(final int byteValue1, final int byteValue2) { - int currentLength = length; - if (currentLength + 2 > data.length) { - enlarge(2); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue1; - currentData[currentLength++] = (byte) byteValue2; - length = currentLength; - return this; - } - - /** - * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param shortValue a short. - * @return this byte vector. - */ - public ByteVector putShort(final int shortValue) { - int currentLength = length; - if (currentLength + 2 > data.length) { - enlarge(2); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteValue a byte. - * @param shortValue a short. - * @return this byte vector. - */ - final ByteVector put12(final int byteValue, final int shortValue) { - int currentLength = length; - if (currentLength + 3 > data.length) { - enlarge(3); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteValue1 a byte. - * @param byteValue2 another byte. - * @param shortValue a short. - * @return this byte vector. - */ - final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) { - int currentLength = length; - if (currentLength + 4 > data.length) { - enlarge(4); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue1; - currentData[currentLength++] = (byte) byteValue2; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param intValue an int. - * @return this byte vector. - */ - public ByteVector putInt(final int intValue) { - int currentLength = length; - if (currentLength + 4 > data.length) { - enlarge(4); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - length = currentLength; - return this; - } - - /** - * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged - * if necessary. - * - * @param byteValue a byte. - * @param shortValue1 a short. - * @param shortValue2 another short. - * @return this byte vector. - */ - final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) { - int currentLength = length; - if (currentLength + 5 > data.length) { - enlarge(5); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue; - currentData[currentLength++] = (byte) (shortValue1 >>> 8); - currentData[currentLength++] = (byte) shortValue1; - currentData[currentLength++] = (byte) (shortValue2 >>> 8); - currentData[currentLength++] = (byte) shortValue2; - length = currentLength; - return this; - } - - /** - * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param longValue a long. - * @return this byte vector. - */ - public ByteVector putLong(final long longValue) { - int currentLength = length; - if (currentLength + 8 > data.length) { - enlarge(8); - } - byte[] currentData = data; - int intValue = (int) (longValue >>> 32); - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - intValue = (int) longValue; - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - length = currentLength; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param stringValue a String whose UTF8 encoded length must be less than 65536. - * @return this byte vector. - */ - public ByteVector putUTF8(final String stringValue) { - int charLength = stringValue.length(); - if (charLength > 65535) { - throw new IllegalArgumentException(); - } - int currentLength = length; - if (currentLength + 2 + charLength > data.length) { - enlarge(2 + charLength); - } - byte[] currentData = data; - // Optimistic algorithm: instead of computing the byte length and then serializing the string - // (which requires two loops), we assume the byte length is equal to char length (which is the - // most frequent case), and we start serializing the string right away. During the - // serialization, if we find that this assumption is wrong, we continue with the general method. - currentData[currentLength++] = (byte) (charLength >>> 8); - currentData[currentLength++] = (byte) charLength; - for (int i = 0; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - currentData[currentLength++] = (byte) charValue; - } else { - length = currentLength; - return encodeUTF8(stringValue, i, 65535); - } - } - length = currentLength; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if - * necessary. The string length is encoded in two bytes before the encoded characters, if there is - * space for that (i.e. if this.length - offset - 2 >= 0). - * - * @param stringValue the String to encode. - * @param offset the index of the first character to encode. The previous characters are supposed - * to have already been encoded, using only one byte per character. - * @param maxByteLength the maximum byte length of the encoded string, including the already - * encoded characters. - * @return this byte vector. - */ - final ByteVector encodeUTF8(final String stringValue, final int offset, final int maxByteLength) { - int charLength = stringValue.length(); - int byteLength = offset; - for (int i = offset; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - byteLength++; - } else if (charValue <= '\u07FF') { - byteLength += 2; - } else { - byteLength += 3; - } - } - if (byteLength > maxByteLength) { - throw new IllegalArgumentException(); - } - // Compute where 'byteLength' must be stored in 'data', and store it at this location. - int byteLengthOffset = length - offset - 2; - if (byteLengthOffset >= 0) { - data[byteLengthOffset] = (byte) (byteLength >>> 8); - data[byteLengthOffset + 1] = (byte) byteLength; - } - if (length + byteLength - offset > data.length) { - enlarge(byteLength - offset); - } - int currentLength = length; - for (int i = offset; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - data[currentLength++] = (byte) charValue; - } else if (charValue <= '\u07FF') { - data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F); - data[currentLength++] = (byte) (0x80 | charValue & 0x3F); - } else { - data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF); - data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F); - data[currentLength++] = (byte) (0x80 | charValue & 0x3F); - } - } - length = currentLength; - return this; - } - - /** - * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteArrayValue an array of bytes. May be null to put byteLength null - * bytes into this byte vector. - * @param byteOffset index of the first byte of byteArrayValue that must be copied. - * @param byteLength number of bytes of byteArrayValue that must be copied. - * @return this byte vector. - */ - public ByteVector putByteArray( - final byte[] byteArrayValue, final int byteOffset, final int byteLength) { - if (length + byteLength > data.length) { - enlarge(byteLength); - } - if (byteArrayValue != null) { - System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength); - } - length += byteLength; - return this; - } - - /** - * Enlarges this byte vector so that it can receive 'size' more bytes. - * - * @param size number of additional bytes that this byte vector should be able to receive. - */ - private void enlarge(final int size) { - int doubleCapacity = 2 * data.length; - int minimalCapacity = length + size; - byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity]; - System.arraycopy(data, 0, newData, 0, length); - data = newData; - } -} diff --git a/src/main/java/org/objectweb/asm/ClassReader.java b/src/main/java/org/objectweb/asm/ClassReader.java deleted file mode 100644 index abb1350f..00000000 --- a/src/main/java/org/objectweb/asm/ClassReader.java +++ /dev/null @@ -1,3495 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java - * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the - * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode - * instruction encountered. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS 4 - */ -public class ClassReader { - - /** - * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed - * nor visited. - */ - public static final int SKIP_CODE = 1; - - /** - * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable - * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor - * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and - * {@link MethodVisitor#visitLineNumber} are not called). - */ - public static final int SKIP_DEBUG = 2; - - /** - * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes - * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag - * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames - * that will be ignored and recomputed from scratch. - */ - public static final int SKIP_FRAMES = 4; - - /** - * A flag to expand the stack map frames. By default stack map frames are visited in their - * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" - * for the other classes). If this flag is set, stack map frames are always visited in expanded - * format (this option adds a decompression/compression step in ClassReader and ClassWriter which - * degrades performance quite a lot). - */ - public static final int EXPAND_FRAMES = 8; - - /** - * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode - * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset - * reserved for it is not sufficient to store the bytecode offset. In this case the jump - * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes - * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing - * such instructions, in order to replace them with standard instructions. In addition, when this - * flag is used, goto_w and jsr_w are not converted into goto and jsr, to make sure that - * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a - * goto_w in ClassWriter cannot occur. - */ - static final int EXPAND_ASM_INSNS = 256; - - /** - * The size of the temporary byte array used to read class input streams chunk by chunk. - */ - private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; - - /** - * A byte array containing the JVMS ClassFile structure to be parsed. The content of this array - * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally - * not needed by class visitors. - * - *

NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not - * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct - * ClassFile element offsets within this byte array. - */ - public final byte[] b; - - /** - * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool - * array, plus one. In other words, the offset of constant pool entry i is given by - * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1]. - */ - private final int[] cpInfoOffsets; - - /** - * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing - * of a given CONSTANT_Utf8 constant pool item. - */ - private final String[] constantUtf8Values; - - /** - * A conservative estimate of the maximum length of the strings contained in the constant pool of - * the class. - */ - private final int maxStringLength; - - /** - * The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. - */ - public final int header; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFile the JVMS ClassFile structure to be read. - */ - public ClassReader(final byte[] classFile) { - this(classFile, 0, classFile.length); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param classFileLength the length in bytes of the ClassFile to be read. - */ - public ClassReader( - final byte[] classFileBuffer, final int classFileOffset, final int classFileLength) { - this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); - } - - /** - * Constructs a new {@link ClassReader} object. This internal constructor must not be exposed - * as a public API. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param checkClassVersion whether to check the class version or not. - */ - ClassReader( - final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { - this.b = classFileBuffer; - // Check the class' major_version. This field is after the magic and minor_version fields, which - // use 4 and 2 bytes respectively. - if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V10) { - throw new IllegalArgumentException( - "Unsupported class file major version " + readShort(classFileOffset + 6)); - } - // Create the constant pool arrays. The constant_pool_count field is after the magic, - // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. - int constantPoolCount = readUnsignedShort(classFileOffset + 8); - cpInfoOffsets = new int[constantPoolCount]; - constantUtf8Values = new String[constantPoolCount]; - // Compute the offset of each constant pool entry, as well as a conservative estimate of the - // maximum length of the constant pool strings. The first constant pool entry is after the - // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 - // bytes respectively. - int currentCpInfoIndex = 1; - int currentCpInfoOffset = classFileOffset + 10; - int currentMaxStringLength = 0; - // The offset of the other entries depend on the total size of all the previous entries. - while (currentCpInfoIndex < constantPoolCount) { - cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; - int cpInfoSize; - switch (classFileBuffer[currentCpInfoOffset]) { - case Symbol.CONSTANT_FIELDREF_TAG: - case Symbol.CONSTANT_METHODREF_TAG: - case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: - case Symbol.CONSTANT_INTEGER_TAG: - case Symbol.CONSTANT_FLOAT_TAG: - case Symbol.CONSTANT_NAME_AND_TYPE_TAG: - case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: - cpInfoSize = 5; - break; - case Symbol.CONSTANT_LONG_TAG: - case Symbol.CONSTANT_DOUBLE_TAG: - cpInfoSize = 9; - currentCpInfoIndex++; - break; - case Symbol.CONSTANT_UTF8_TAG: - cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); - if (cpInfoSize > currentMaxStringLength) { - // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate - // of the length in characters of the corresponding string, and is much cheaper to - // compute than this exact length. - currentMaxStringLength = cpInfoSize; - } - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - cpInfoSize = 4; - break; - case Symbol.CONSTANT_CLASS_TAG: - case Symbol.CONSTANT_STRING_TAG: - case Symbol.CONSTANT_METHOD_TYPE_TAG: - case Symbol.CONSTANT_PACKAGE_TAG: - case Symbol.CONSTANT_MODULE_TAG: - cpInfoSize = 3; - break; - default: - throw new IllegalArgumentException(); - } - currentCpInfoOffset += cpInfoSize; - } - this.maxStringLength = currentMaxStringLength; - // The Classfile's access_flags field is just after the last constant pool entry. - this.header = currentCpInfoOffset; - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input - * stream must contain nothing more than the ClassFile structure itself. It is read from its - * current position to its end. - * @throws IOException if a problem occurs during reading. - */ - public ClassReader(final InputStream inputStream) throws IOException { - this(readStream(inputStream, false)); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param className the fully qualified name of the class to be read. The ClassFile structure is - * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. - * @throws IOException if an exception occurs during reading. - */ - public ClassReader(final String className) throws IOException { - this( - readStream( - ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); - } - - /** - * Reads the given input stream and returns its content as a byte array. - * - * @param inputStream an input stream. - * @param close true to close the input stream after reading. - * @return the content of the given input stream. - * @throws IOException if a problem occurs during reading. - */ - private static byte[] readStream(final InputStream inputStream, final boolean close) - throws IOException { - if (inputStream == null) { - throw new IOException("Class not found"); - } - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE]; - int bytesRead; - while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) { - outputStream.write(data, 0, bytesRead); - } - outputStream.flush(); - return outputStream.toByteArray(); - } finally { - if (close) { - inputStream.close(); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated - * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. - * - * @return the class access flags. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public int getAccess() { - return readUnsignedShort(header); - } - - /** - * Returns the internal name of the class (see {@link Type#getInternalName()}). - * - * @return the internal class name. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getClassName() { - // this_class is just after the access_flags field (using 2 bytes). - return readClass(header + 2, new char[maxStringLength]); - } - - /** - * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For - * interfaces, the super class is {@link Object}. - * - * @return the internal name of the super class, or null for {@link Object} class. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getSuperName() { - // super_class is after the access_flags and this_class fields (2 bytes each). - return readClass(header + 4, new char[maxStringLength]); - } - - /** - * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). - * - * @return the internal names of the directly implemented interfaces. Inherited implemented - * interfaces are not returned. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String[] getInterfaces() { - // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). - int currentOffset = header + 6; - int interfacesCount = readUnsignedShort(currentOffset); - String[] interfaces = new String[interfacesCount]; - if (interfacesCount > 0) { - char[] charBuffer = new char[maxStringLength]; - for (int i = 0; i < interfacesCount; ++i) { - currentOffset += 2; - interfaces[i] = readClass(currentOffset, charBuffer); - } - } - return interfaces; - } - - // ----------------------------------------------------------------------------------------------- - // Public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept(final ClassVisitor classVisitor, final int parsingOptions) { - accept(classVisitor, new Attribute[0], parsingOptions); - } - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. This may - * corrupt it if this value contains references to the constant pool, or has syntactic or - * semantic links with a class element that has been transformed by a class adapter between - * the reader and the writer. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept( - final ClassVisitor classVisitor, - final Attribute[] attributePrototypes, - final int parsingOptions) { - Context context = new Context(); - context.attributePrototypes = attributePrototypes; - context.parsingOptions = parsingOptions; - context.charBuffer = new char[maxStringLength]; - - // Read the access_flags, this_class, super_class, interface_count and interfaces fields. - char[] charBuffer = context.charBuffer; - int currentOffset = header; - int accessFlags = readUnsignedShort(currentOffset); - String thisClass = readClass(currentOffset + 2, charBuffer); - String superClass = readClass(currentOffset + 4, charBuffer); - String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; - currentOffset += 8; - for (int i = 0; i < interfaces.length; ++i) { - interfaces[i] = readClass(currentOffset, charBuffer); - currentOffset += 2; - } - - // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the InnerClasses attribute, or 0. - int innerClassesOffset = 0; - // - The offset of the EnclosingMethod attribute, or 0. - int enclosingMethodOffset = 0; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The string corresponding to the SourceFile attribute, or null. - String sourceFile = null; - // - The string corresponding to the SourceDebugExtension attribute, or null. - String sourceDebugExtension = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the Module attribute, or 0. - int moduleOffset = 0; - // - The offset of the ModulePackages attribute, or 0. - int modulePackagesOffset = 0; - // - The string corresponding to the ModuleMainClass attribute, or null. - String moduleMainClass = null; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int currentAttributeOffset = getFirstAttributeOffset(); - for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentAttributeOffset, charBuffer); - int attributeLength = readInt(currentAttributeOffset + 2); - currentAttributeOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.SOURCE_FILE.equals(attributeName)) { - sourceFile = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.INNER_CLASSES.equals(attributeName)) { - innerClassesOffset = currentAttributeOffset; - } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { - enclosingMethodOffset = currentAttributeOffset; - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { - sourceDebugExtension = - readUTF(currentAttributeOffset, attributeLength, new char[attributeLength]); - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.MODULE.equals(attributeName)) { - moduleOffset = currentAttributeOffset; - } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { - moduleMainClass = readClass(currentAttributeOffset, charBuffer); - } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { - modulePackagesOffset = currentAttributeOffset; - } else if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - // Read the num_bootstrap_methods field and create an array of this size. - int[] bootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; - // Compute and store the offset of each 'bootstrap_methods' array field entry. - int currentBootstrapMethodOffset = currentAttributeOffset + 2; - for (int j = 0; j < bootstrapMethodOffsets.length; ++j) { - bootstrapMethodOffsets[j] = currentBootstrapMethodOffset; - // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), - // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). - currentBootstrapMethodOffset += - 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; - } - context.bootstrapMethodOffsets = bootstrapMethodOffsets; - } else { - Attribute attribute = - readAttribute( - attributePrototypes, - attributeName, - currentAttributeOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentAttributeOffset += attributeLength; - } - - // Visit the class declaration. The minor_version and major_version fields start 6 bytes before - // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). - classVisitor.visit( - readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); - - // Visit the SourceFile and SourceDebugExtenstion attributes. - if ((parsingOptions & SKIP_DEBUG) == 0 - && (sourceFile != null || sourceDebugExtension != null)) { - classVisitor.visitSource(sourceFile, sourceDebugExtension); - } - - // Visit the Module, ModulePackages and ModuleMainClass attributes. - if (moduleOffset != 0) { - readModule(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); - } - - // Visit the EnclosingMethod attribute. - if (enclosingMethodOffset != 0) { - String className = readClass(enclosingMethodOffset, charBuffer); - int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); - String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); - String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); - classVisitor.visitOuterClass(className, name, type); - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - classVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the InnerClasses attribute. - if (innerClassesOffset != 0) { - int numberOfClasses = readUnsignedShort(innerClassesOffset); - int currentClassesOffset = innerClassesOffset + 2; - while (numberOfClasses-- > 0) { - classVisitor.visitInnerClass( - readClass(currentClassesOffset, charBuffer), - readClass(currentClassesOffset + 2, charBuffer), - readUTF8(currentClassesOffset + 4, charBuffer), - readUnsignedShort(currentClassesOffset + 6)); - currentClassesOffset += 8; - } - } - - // Visit the fields and methods. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (fieldsCount-- > 0) { - currentOffset = readField(classVisitor, context, currentOffset); - } - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - currentOffset = readMethod(classVisitor, context, currentOffset); - } - - // Visit the end of the class. - classVisitor.visitEnd(); - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse modules, fields and methods - // ---------------------------------------------------------------------------------------------- - - /** - * Reads the module attribute and visit it. - * - * @param classVisitor the current class visitor - * @param context information about the class being parsed. - * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's - * attribute_name_index and attribute_length fields). - * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the - * attribute_info's attribute_name_index and attribute_length fields), or 0. - * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null. - */ - private void readModule( - final ClassVisitor classVisitor, - final Context context, - final int moduleOffset, - final int modulePackagesOffset, - final String moduleMainClass) { - char[] buffer = context.charBuffer; - - // Read the module_name_index, module_flags and module_version_index fields and visit them. - int currentOffset = moduleOffset; - String moduleName = readModule(currentOffset, buffer); - int moduleFlags = readUnsignedShort(currentOffset + 2); - String moduleVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); - if (moduleVisitor == null) { - return; - } - - // Visit the ModuleMainClass attribute. - if (moduleMainClass != null) { - moduleVisitor.visitMainClass(moduleMainClass); - } - - // Visit the ModulePackages attribute. - if (modulePackagesOffset != 0) { - int packageCount = readUnsignedShort(modulePackagesOffset); - int currentPackageOffset = modulePackagesOffset + 2; - while (packageCount-- > 0) { - moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); - currentPackageOffset += 2; - } - } - - // Read the 'requires_count' and 'requires' fields. - int requiresCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (requiresCount-- > 0) { - // Read the requires_index, requires_flags and requires_version fields and visit them. - String requires = readModule(currentOffset, buffer); - int requiresFlags = readUnsignedShort(currentOffset + 2); - String requiresVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); - } - - // Read the 'exports_count' and 'exports' fields. - int exportsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exportsCount-- > 0) { - // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields - // and visit them. - String exports = readPackage(currentOffset, buffer); - int exportsFlags = readUnsignedShort(currentOffset + 2); - int exportsToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] exportsTo = null; - if (exportsToCount != 0) { - exportsTo = new String[exportsToCount]; - for (int i = 0; i < exportsToCount; ++i) { - exportsTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; - } - } - moduleVisitor.visitExport(exports, exportsFlags, exportsTo); - } - - // Reads the 'opens_count' and 'opens' fields. - int opensCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (opensCount-- > 0) { - // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. - String opens = readPackage(currentOffset, buffer); - int opensFlags = readUnsignedShort(currentOffset + 2); - int opensToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] opensTo = null; - if (opensToCount != 0) { - opensTo = new String[opensToCount]; - for (int i = 0; i < opensToCount; ++i) { - opensTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; - } - } - moduleVisitor.visitOpen(opens, opensFlags, opensTo); - } - - // Read the 'uses_count' and 'uses' fields. - int usesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (usesCount-- > 0) { - moduleVisitor.visitUse(readClass(currentOffset, buffer)); - currentOffset += 2; - } - - // Read the 'provides_count' and 'provides' fields. - int providesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (providesCount-- > 0) { - // Read the provides_index, provides_with_count and provides_with_index fields and visit them. - String provides = readClass(currentOffset, buffer); - int providesWithCount = readUnsignedShort(currentOffset + 2); - currentOffset += 4; - String[] providesWith = new String[providesWithCount]; - for (int i = 0; i < providesWithCount; ++i) { - providesWith[i] = readClass(currentOffset, buffer); - currentOffset += 2; - } - moduleVisitor.visitProvide(provides, providesWith); - } - - // Visit the end of the module attributes. - moduleVisitor.visitEnd(); - } - - /** - * Reads a JVMS field_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the field. - * @param context information about the class being parsed. - * @param fieldInfoOffset the start offset of the field_info structure. - * @return the offset of the first byte following the field_info structure. - */ - private int readField( - final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = fieldInfoOffset; - int accessFlags = readUnsignedShort(currentOffset); - String name = readUTF8(currentOffset + 2, charBuffer); - String descriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The value corresponding to the ConstantValue attribute, or null. - Object constantValue = null; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CONSTANT_VALUE.equals(attributeName)) { - int constantvalueIndex = readUnsignedShort(currentOffset); - constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentOffset, charBuffer); - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the field declaration. - FieldVisitor fieldVisitor = - classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); - if (fieldVisitor == null) { - return currentOffset; - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - fieldVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the end of the field. - fieldVisitor.visitEnd(); - return currentOffset; - } - - /** - * Reads a JVMS method_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the method. - * @param context information about the class being parsed. - * @param methodInfoOffset the start offset of the method_info structure. - * @return the offset of the first byte following the method_info structure. - */ - private int readMethod( - final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = methodInfoOffset; - context.currentMethodAccessFlags = readUnsignedShort(currentOffset); - context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); - context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the Code attribute, or 0. - int codeOffset = 0; - // - The offset of the Exceptions attribute, or 0. - int exceptionsOffset = 0; - // - The strings corresponding to the Exceptions attribute, or null. - String[] exceptions = null; - // - The string corresponding to the Signature attribute, or null. - int signature = 0; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. - int runtimeVisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. - int runtimeInvisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the AnnotationDefault attribute, or 0. - int annotationDefaultOffset = 0; - // - The offset of the MethodParameters attribute, or 0. - int methodParametersOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CODE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_CODE) == 0) { - codeOffset = currentOffset; - } - } else if (Constants.EXCEPTIONS.equals(attributeName)) { - exceptionsOffset = currentOffset; - exceptions = new String[readUnsignedShort(exceptionsOffset)]; - int currentExceptionOffset = exceptionsOffset + 2; - for (int i = 0; i < exceptions.length; ++i) { - exceptions[i] = readClass(currentExceptionOffset, charBuffer); - currentExceptionOffset += 2; - } - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUnsignedShort(currentOffset); - } else if (Constants.DEPRECATED.equals(attributeName)) { - context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { - annotationDefaultOffset = currentOffset; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { - methodParametersOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the method declaration. - MethodVisitor methodVisitor = - classVisitor.visitMethod( - context.currentMethodAccessFlags, - context.currentMethodName, - context.currentMethodDescriptor, - signature == 0 ? null : readUTF(signature, charBuffer), - exceptions); - if (methodVisitor == null) { - return currentOffset; - } - - // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method - // adapter between the reader and the writer. If, in addition, the writer's constant pool was - // copied from this reader (mw.getSource() == this), and the signature and exceptions of the - // method have not been changed, then it is possible to skip all visit events and just copy the - // original code of the method to the writer (the access_flags, name_index and descriptor_index - // can have been changed, this is not important since they are not copied from the reader). - if (methodVisitor instanceof MethodWriter) { - MethodWriter methodWriter = (MethodWriter) methodVisitor; - if (methodWriter.getSource() == this && signature == methodWriter.signatureIndex) { - boolean sameExceptions = false; - if (exceptions == null) { - sameExceptions = methodWriter.numberOfExceptions == 0; - } else if (exceptions.length == methodWriter.numberOfExceptions) { - sameExceptions = true; - int currentExceptionOffset = exceptionsOffset + 2; - for (int i = 0; i < exceptions.length; ++i) { - if (methodWriter.exceptionIndexTable[i] != readUnsignedShort(currentExceptionOffset)) { - sameExceptions = false; - break; - } - currentExceptionOffset += 2; - } - } - if (sameExceptions) { - // We do not copy directly the code into methodWriter to save a byte array copy operation. - // The real copy will be done in {@link MethodWriter#putMethodInfo}. - methodWriter.sourceOffset = methodInfoOffset + 6; - methodWriter.sourceLength = currentOffset - methodWriter.sourceOffset; - return currentOffset; - } - } - } - - // Visit the MethodParameters attribute. - if (methodParametersOffset != 0) { - int parametersCount = readByte(methodParametersOffset); - int currentParameterOffset = methodParametersOffset + 1; - while (parametersCount-- > 0) { - // Read the name_index and access_flags fields and visit them. - methodVisitor.visitParameter( - readUTF8(currentParameterOffset, charBuffer), - readUnsignedShort(currentParameterOffset + 2)); - currentParameterOffset += 4; - } - } - - // Visit the AnnotationDefault attribute. - if (annotationDefaultOffset != 0) { - AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); - readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleParameterAnnotations attribute. - if (runtimeVisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); - } - - // Visit the RuntimeInvisibleParameterAnnotations attribute. - if (runtimeInvisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, - context, - runtimeInvisibleParameterAnnotationsOffset, - /* visible = */ false); - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the Code attribute. - if (codeOffset != 0) { - methodVisitor.visitCode(); - readCode(methodVisitor, context, codeOffset); - } - - // Visit the end of the method. - methodVisitor.visitEnd(); - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse a Code attribute - // ---------------------------------------------------------------------------------------------- - - /** - * Reads a JVMS 'Code' attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the Code attribute. - * @param context information about the class being parsed. - * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its - * attribute_name_index and attribute_length fields. - */ - private void readCode( - final MethodVisitor methodVisitor, final Context context, final int codeOffset) { - int currentOffset = codeOffset; - - // Read the max_stack, max_locals and code_length fields. - final byte[] classFileBuffer = b; - final char[] charBuffer = context.charBuffer; - final int maxStack = readUnsignedShort(currentOffset); - final int maxLocals = readUnsignedShort(currentOffset + 2); - final int codeLength = readInt(currentOffset + 4); - currentOffset += 8; - - // Read the bytecode 'code' array to create a label for each referenced instruction. - final int bytecodeStartOffset = currentOffset; - final int bytecodeEndOffset = currentOffset + codeLength; - final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; - while (currentOffset < bytecodeEndOffset) { - final int bytecodeOffset = currentOffset - bytecodeStartOffset; - final int opcode = classFileBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Constants.NOP: - case Constants.ACONST_NULL: - case Constants.ICONST_M1: - case Constants.ICONST_0: - case Constants.ICONST_1: - case Constants.ICONST_2: - case Constants.ICONST_3: - case Constants.ICONST_4: - case Constants.ICONST_5: - case Constants.LCONST_0: - case Constants.LCONST_1: - case Constants.FCONST_0: - case Constants.FCONST_1: - case Constants.FCONST_2: - case Constants.DCONST_0: - case Constants.DCONST_1: - case Constants.IALOAD: - case Constants.LALOAD: - case Constants.FALOAD: - case Constants.DALOAD: - case Constants.AALOAD: - case Constants.BALOAD: - case Constants.CALOAD: - case Constants.SALOAD: - case Constants.IASTORE: - case Constants.LASTORE: - case Constants.FASTORE: - case Constants.DASTORE: - case Constants.AASTORE: - case Constants.BASTORE: - case Constants.CASTORE: - case Constants.SASTORE: - case Constants.POP: - case Constants.POP2: - case Constants.DUP: - case Constants.DUP_X1: - case Constants.DUP_X2: - case Constants.DUP2: - case Constants.DUP2_X1: - case Constants.DUP2_X2: - case Constants.SWAP: - case Constants.IADD: - case Constants.LADD: - case Constants.FADD: - case Constants.DADD: - case Constants.ISUB: - case Constants.LSUB: - case Constants.FSUB: - case Constants.DSUB: - case Constants.IMUL: - case Constants.LMUL: - case Constants.FMUL: - case Constants.DMUL: - case Constants.IDIV: - case Constants.LDIV: - case Constants.FDIV: - case Constants.DDIV: - case Constants.IREM: - case Constants.LREM: - case Constants.FREM: - case Constants.DREM: - case Constants.INEG: - case Constants.LNEG: - case Constants.FNEG: - case Constants.DNEG: - case Constants.ISHL: - case Constants.LSHL: - case Constants.ISHR: - case Constants.LSHR: - case Constants.IUSHR: - case Constants.LUSHR: - case Constants.IAND: - case Constants.LAND: - case Constants.IOR: - case Constants.LOR: - case Constants.IXOR: - case Constants.LXOR: - case Constants.I2L: - case Constants.I2F: - case Constants.I2D: - case Constants.L2I: - case Constants.L2F: - case Constants.L2D: - case Constants.F2I: - case Constants.F2L: - case Constants.F2D: - case Constants.D2I: - case Constants.D2L: - case Constants.D2F: - case Constants.I2B: - case Constants.I2C: - case Constants.I2S: - case Constants.LCMP: - case Constants.FCMPL: - case Constants.FCMPG: - case Constants.DCMPL: - case Constants.DCMPG: - case Constants.IRETURN: - case Constants.LRETURN: - case Constants.FRETURN: - case Constants.DRETURN: - case Constants.ARETURN: - case Constants.RETURN: - case Constants.ARRAYLENGTH: - case Constants.ATHROW: - case Constants.MONITORENTER: - case Constants.MONITOREXIT: - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - currentOffset += 1; - break; - case Constants.IFEQ: - case Constants.IFNE: - case Constants.IFLT: - case Constants.IFGE: - case Constants.IFGT: - case Constants.IFLE: - case Constants.IF_ICMPEQ: - case Constants.IF_ICMPNE: - case Constants.IF_ICMPLT: - case Constants.IF_ICMPGE: - case Constants.IF_ICMPGT: - case Constants.IF_ICMPLE: - case Constants.IF_ACMPEQ: - case Constants.IF_ACMPNE: - case Constants.GOTO: - case Constants.JSR: - case Constants.IFNULL: - case Constants.IFNONNULL: - createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: - createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - case Constants.ASM_GOTO_W: - createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); - currentOffset += 5; - break; - case Constants.WIDE: - switch (classFileBuffer[currentOffset + 1] & 0xFF) { - case Constants.ILOAD: - case Constants.FLOAD: - case Constants.ALOAD: - case Constants.LLOAD: - case Constants.DLOAD: - case Constants.ISTORE: - case Constants.FSTORE: - case Constants.ASTORE: - case Constants.LSTORE: - case Constants.DSTORE: - case Constants.RET: - currentOffset += 4; - break; - case Constants.IINC: - currentOffset += 6; - break; - default: - throw new IllegalArgumentException(); - } - break; - case Constants.TABLESWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of table entries. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; - currentOffset += 12; - // Read the table labels. - while (numTableEntries-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset), labels); - currentOffset += 4; - } - break; - case Constants.LOOKUPSWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of switch cases. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numSwitchCases = readInt(currentOffset + 4); - currentOffset += 8; - // Read the switch labels. - while (numSwitchCases-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); - currentOffset += 8; - } - break; - case Constants.ILOAD: - case Constants.LLOAD: - case Constants.FLOAD: - case Constants.DLOAD: - case Constants.ALOAD: - case Constants.ISTORE: - case Constants.LSTORE: - case Constants.FSTORE: - case Constants.DSTORE: - case Constants.ASTORE: - case Constants.RET: - case Constants.BIPUSH: - case Constants.NEWARRAY: - case Constants.LDC: - currentOffset += 2; - break; - case Constants.SIPUSH: - case Constants.LDC_W: - case Constants.LDC2_W: - case Constants.GETSTATIC: - case Constants.PUTSTATIC: - case Constants.GETFIELD: - case Constants.PUTFIELD: - case Constants.INVOKEVIRTUAL: - case Constants.INVOKESPECIAL: - case Constants.INVOKESTATIC: - case Constants.NEW: - case Constants.ANEWARRAY: - case Constants.CHECKCAST: - case Constants.INSTANCEOF: - case Constants.IINC: - currentOffset += 3; - break; - case Constants.INVOKEINTERFACE: - case Constants.INVOKEDYNAMIC: - currentOffset += 5; - break; - case Constants.MULTIANEWARRAY: - currentOffset += 4; - break; - default: - throw new IllegalArgumentException(); - } - } - - // Read the 'exception_table_length' and 'exception_table' field to create a label for each - // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. - { - int exceptionTableLength = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exceptionTableLength-- > 0) { - Label start = createLabel(readUnsignedShort(currentOffset), labels); - Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); - Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); - String catchType = - readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); - currentOffset += 8; - methodVisitor.visitTryCatchBlock(start, end, handler, catchType); - } - } - - // Read the Code attributes to create a label for each referenced instruction (the variables - // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the - // attribute_name_index and attribute_length fields. - // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. - // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is - // updated after each stack_map_frame is read. - int stackMapFrameOffset = 0; - // - The end offset of the StackMap[Table] attribute, or 0. - int stackMapTableEndOffset = 0; - // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. - boolean compressedFrames = true; - // - The offset of the LocalVariableTable attribute, or 0. - int localVariableTableOffset = 0; - // - The offset of the LocalVariableTypeTable attribute, or 0. - int localVariableTypeTableOffset = 0; - // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations - // attribute, or null. - int[] visibleTypeAnnotationOffsets = null; - // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations - // attribute, or null. - int[] invisibleTypeAnnotationOffsets = null; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - localVariableTableOffset = currentOffset; - // Parse the attribute to find the corresponding (debug only) labels. - int currentLocalVariableTableOffset = currentOffset; - int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); - currentLocalVariableTableOffset += 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentLocalVariableTableOffset); - createDebugLabel(startPc, labels); - int length = readUnsignedShort(currentLocalVariableTableOffset + 2); - createDebugLabel(startPc + length, labels); - // Skip the name_index, descriptor_index and index fields (2 bytes each). - currentLocalVariableTableOffset += 10; - } - } - } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { - localVariableTypeTableOffset = currentOffset; - // Here we do not extract the labels corresponding to the attribute content. We assume they - // are the same or a subset of those of the LocalVariableTable attribute. - } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - // Parse the attribute to find the corresponding (debug only) labels. - int currentLineNumberTableOffset = currentOffset; - int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); - currentLineNumberTableOffset += 2; - while (lineNumberTableLength-- > 0) { - int startPc = readUnsignedShort(currentLineNumberTableOffset); - int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); - currentLineNumberTableOffset += 4; - createDebugLabel(startPc, labels); - labels[startPc].addLineNumber(lineNumber); - } - } - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - visibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // type annotation at a time (i.e. after a type annotation has been visited, the next type - // annotation is read), and the labels it contains are also extracted one annotation at a - // time. This assumes that type annotations are ordered by increasing bytecode offset. - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - invisibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); - // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. - } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - } - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // frame at a time (i.e. after a frame has been visited, the next frame is read), and the - // labels it contains are also extracted one frame at a time. Thanks to the ordering of - // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to - // see an offset smaller than the offset of the current instruction and for which no Label - // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map - // table without a full decoding (see below). - } else if ("StackMap".equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - compressedFrames = false; - } - // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, - // although this is not guaranteed by the attribute format. This allows an incremental - // extraction of the labels corresponding to this attribute (see the comment above for the - // StackMapTable attribute). - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - codeOffset, - labels); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Initialize the context fields related to stack map frames, and generate the first - // (implicit) stack map frame, if needed. - final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; - if (stackMapFrameOffset != 0) { - // The bytecode offset of the first explicit frame is not offset_delta + 1 but only - // offset_delta. Setting the implicit frame offset to -1 allows us to use of the - // "offset_delta + 1" rule in all cases. - context.currentFrameOffset = -1; - context.currentFrameType = 0; - context.currentFrameLocalCount = 0; - context.currentFrameLocalCountDelta = 0; - context.currentFrameLocalTypes = new Object[maxLocals]; - context.currentFrameStackCount = 0; - context.currentFrameStackTypes = new Object[maxStack]; - if (expandFrames) { - computeImplicitFrame(context); - } - // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the - // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type - // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). - // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, - // and the only consequence will be the creation of an unneeded label. This is better than - // creating a label for each NEW instruction, and faster than fully decoding the whole stack - // map table. - for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { - if (classFileBuffer[offset] == Frame.ITEM_UNINITIALIZED) { - int potentialBytecodeOffset = readUnsignedShort(offset + 1); - if (potentialBytecodeOffset >= 0 - && potentialBytecodeOffset < codeLength - && (classFileBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) - == Opcodes.NEW) { - createLabel(potentialBytecodeOffset, labels); - } - } - } - } - if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { - // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method - // does not currently have any frame. These inserted frames must be computed by simulating the - // effect of the bytecode instructions, one by one, starting from the implicit first frame. - // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To - // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is - // computed in MethodWriter). - methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); - } - - // Visit the bytecode instructions. First, introduce state variables for the incremental parsing - // of the type annotations. - - // Index of the next runtime visible type annotation to read (in the - // visibleTypeAnnotationOffsets array). - int currentVisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime visible type annotation to read, or -1. - int currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); - // Index of the next runtime invisible type annotation to read (in the - // invisibleTypeAnnotationOffsets array). - int currentInvisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime invisible type annotation to read, or -1. - int currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); - - // Whether a F_INSERT stack map frame must be inserted before the current instruction. - boolean insertFrame = false; - - // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr - // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific - // instructions). - final int wideJumpOpcodeDelta = - (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; - - currentOffset = bytecodeStartOffset; - while (currentOffset < bytecodeEndOffset) { - final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; - - // Visit the label and the line number(s) for this bytecode offset, if any. - Label currentLabel = labels[currentBytecodeOffset]; - if (currentLabel != null) { - currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); - } - - // Visit the stack map frame for this bytecode offset, if any. - while (stackMapFrameOffset != 0 - && (context.currentFrameOffset == currentBytecodeOffset - || context.currentFrameOffset == -1)) { - // If there is a stack map frame for this offset, make methodVisitor visit it, and read the - // next stack map frame if there is one. - if (context.currentFrameOffset != -1) { - if (!compressedFrames || expandFrames) { - methodVisitor.visitFrame( - Opcodes.F_NEW, - context.currentFrameLocalCount, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } else { - methodVisitor.visitFrame( - context.currentFrameType, - context.currentFrameLocalCountDelta, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } - // Since there is already a stack map frame for this bytecode offset, there is no need to - // insert a new one. - insertFrame = false; - } - if (stackMapFrameOffset < stackMapTableEndOffset) { - stackMapFrameOffset = - readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); - } else { - stackMapFrameOffset = 0; - } - } - - // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to - // true during the previous iteration. The actual frame content is computed in MethodWriter. - if (insertFrame) { - if ((context.parsingOptions & EXPAND_FRAMES) != 0) { - methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); - } - insertFrame = false; - } - - // Visit the instruction at this bytecode offset. - int opcode = classFileBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Constants.NOP: - case Constants.ACONST_NULL: - case Constants.ICONST_M1: - case Constants.ICONST_0: - case Constants.ICONST_1: - case Constants.ICONST_2: - case Constants.ICONST_3: - case Constants.ICONST_4: - case Constants.ICONST_5: - case Constants.LCONST_0: - case Constants.LCONST_1: - case Constants.FCONST_0: - case Constants.FCONST_1: - case Constants.FCONST_2: - case Constants.DCONST_0: - case Constants.DCONST_1: - case Constants.IALOAD: - case Constants.LALOAD: - case Constants.FALOAD: - case Constants.DALOAD: - case Constants.AALOAD: - case Constants.BALOAD: - case Constants.CALOAD: - case Constants.SALOAD: - case Constants.IASTORE: - case Constants.LASTORE: - case Constants.FASTORE: - case Constants.DASTORE: - case Constants.AASTORE: - case Constants.BASTORE: - case Constants.CASTORE: - case Constants.SASTORE: - case Constants.POP: - case Constants.POP2: - case Constants.DUP: - case Constants.DUP_X1: - case Constants.DUP_X2: - case Constants.DUP2: - case Constants.DUP2_X1: - case Constants.DUP2_X2: - case Constants.SWAP: - case Constants.IADD: - case Constants.LADD: - case Constants.FADD: - case Constants.DADD: - case Constants.ISUB: - case Constants.LSUB: - case Constants.FSUB: - case Constants.DSUB: - case Constants.IMUL: - case Constants.LMUL: - case Constants.FMUL: - case Constants.DMUL: - case Constants.IDIV: - case Constants.LDIV: - case Constants.FDIV: - case Constants.DDIV: - case Constants.IREM: - case Constants.LREM: - case Constants.FREM: - case Constants.DREM: - case Constants.INEG: - case Constants.LNEG: - case Constants.FNEG: - case Constants.DNEG: - case Constants.ISHL: - case Constants.LSHL: - case Constants.ISHR: - case Constants.LSHR: - case Constants.IUSHR: - case Constants.LUSHR: - case Constants.IAND: - case Constants.LAND: - case Constants.IOR: - case Constants.LOR: - case Constants.IXOR: - case Constants.LXOR: - case Constants.I2L: - case Constants.I2F: - case Constants.I2D: - case Constants.L2I: - case Constants.L2F: - case Constants.L2D: - case Constants.F2I: - case Constants.F2L: - case Constants.F2D: - case Constants.D2I: - case Constants.D2L: - case Constants.D2F: - case Constants.I2B: - case Constants.I2C: - case Constants.I2S: - case Constants.LCMP: - case Constants.FCMPL: - case Constants.FCMPG: - case Constants.DCMPL: - case Constants.DCMPG: - case Constants.IRETURN: - case Constants.LRETURN: - case Constants.FRETURN: - case Constants.DRETURN: - case Constants.ARETURN: - case Constants.RETURN: - case Constants.ARRAYLENGTH: - case Constants.ATHROW: - case Constants.MONITORENTER: - case Constants.MONITOREXIT: - methodVisitor.visitInsn(opcode); - currentOffset += 1; - break; - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - opcode -= Constants.ILOAD_0; - methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - opcode -= Constants.ISTORE_0; - methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Constants.IFEQ: - case Constants.IFNE: - case Constants.IFLT: - case Constants.IFGE: - case Constants.IFGT: - case Constants.IFLE: - case Constants.IF_ICMPEQ: - case Constants.IF_ICMPNE: - case Constants.IF_ICMPLT: - case Constants.IF_ICMPGE: - case Constants.IF_ICMPGT: - case Constants.IF_ICMPLE: - case Constants.IF_ACMPEQ: - case Constants.IF_ACMPNE: - case Constants.GOTO: - case Constants.JSR: - case Constants.IFNULL: - case Constants.IFNONNULL: - methodVisitor.visitJumpInsn( - opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - methodVisitor.visitJumpInsn( - opcode - wideJumpOpcodeDelta, - labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - currentOffset += 5; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: { - // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO - // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx with IFNOTxxx GOTO_W L:..., - // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and - // where designates the instruction just after the GOTO_W. - // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and - // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. - opcode = - opcode < Constants.ASM_IFNULL - ? opcode - Constants.ASM_OPCODE_DELTA - : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; - Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; - if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { - // Replace GOTO with GOTO_W and JSR with JSR_W. - methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); - } else { - // Compute the "opposite" of opcode. This can be done by flipping the least - // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ - // (with a pre and post offset by 1). - opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; - Label endif = createLabel(currentBytecodeOffset + 3, labels); - methodVisitor.visitJumpInsn(opcode, endif); - methodVisitor.visitJumpInsn(Constants.GOTO_W, target); - // endif designates the instruction just after GOTO_W, and is visited as part of the - // next instruction. Since it is a jump target, we need to insert a frame here. - insertFrame = true; - } - currentOffset += 3; - break; - } - case Constants.ASM_GOTO_W: { - // Replace ASM_GOTO_W with GOTO_W. - methodVisitor.visitJumpInsn( - Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns - // IFNOTxxx ASM_GOTO_W L:..., see MethodWriter), so we need to insert a frame - // here. - insertFrame = true; - currentOffset += 5; - break; - } - case Constants.WIDE: - opcode = classFileBuffer[currentOffset + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - methodVisitor.visitIincInsn( - readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); - currentOffset += 6; - } else { - methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); - currentOffset += 4; - } - break; - case Constants.TABLESWITCH: { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int low = readInt(currentOffset + 4); - int high = readInt(currentOffset + 8); - currentOffset += 12; - Label[] table = new Label[high - low + 1]; - for (int i = 0; i < table.length; ++i) { - table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; - currentOffset += 4; - } - methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); - break; - } - case Constants.LOOKUPSWITCH: { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int nPairs = readInt(currentOffset + 4); - currentOffset += 8; - int[] keys = new int[nPairs]; - Label[] values = new Label[nPairs]; - for (int i = 0; i < nPairs; ++i) { - keys[i] = readInt(currentOffset); - values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; - currentOffset += 8; - } - methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); - break; - } - case Constants.ILOAD: - case Constants.LLOAD: - case Constants.FLOAD: - case Constants.DLOAD: - case Constants.ALOAD: - case Constants.ISTORE: - case Constants.LSTORE: - case Constants.FSTORE: - case Constants.DSTORE: - case Constants.ASTORE: - case Constants.RET: - methodVisitor.visitVarInsn(opcode, classFileBuffer[currentOffset + 1] & 0xFF); - currentOffset += 2; - break; - case Constants.BIPUSH: - case Constants.NEWARRAY: - methodVisitor.visitIntInsn(opcode, classFileBuffer[currentOffset + 1]); - currentOffset += 2; - break; - case Constants.SIPUSH: - methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); - currentOffset += 3; - break; - case Constants.LDC: - methodVisitor.visitLdcInsn( - readConst(classFileBuffer[currentOffset + 1] & 0xFF, charBuffer)); - currentOffset += 2; - break; - case Constants.LDC_W: - case Constants.LDC2_W: - methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); - currentOffset += 3; - break; - case Constants.GETSTATIC: - case Constants.PUTSTATIC: - case Constants.GETFIELD: - case Constants.PUTFIELD: - case Constants.INVOKEVIRTUAL: - case Constants.INVOKESPECIAL: - case Constants.INVOKESTATIC: - case Constants.INVOKEINTERFACE: { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String owner = readClass(cpInfoOffset, charBuffer); - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - if (opcode < Opcodes.INVOKEVIRTUAL) { - methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); - } else { - boolean isInterface = - classFileBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - if (opcode == Opcodes.INVOKEINTERFACE) { - currentOffset += 5; - } else { - currentOffset += 3; - } - break; - } - case Constants.INVOKEDYNAMIC: { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - int bootstrapMethodOffset = - context.bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; - Handle handle = - (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - Object[] boostrapMethodArguments = - new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; - bootstrapMethodOffset += 4; - for (int i = 0; i < boostrapMethodArguments.length; i++) { - boostrapMethodArguments[i] = - readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - bootstrapMethodOffset += 2; - } - methodVisitor.visitInvokeDynamicInsn(name, descriptor, handle, boostrapMethodArguments); - currentOffset += 5; - break; - } - case Constants.NEW: - case Constants.ANEWARRAY: - case Constants.CHECKCAST: - case Constants.INSTANCEOF: - methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); - currentOffset += 3; - break; - case Constants.IINC: - methodVisitor.visitIincInsn( - classFileBuffer[currentOffset + 1] & 0xFF, classFileBuffer[currentOffset + 2]); - currentOffset += 3; - break; - case Constants.MULTIANEWARRAY: - methodVisitor.visitMultiANewArrayInsn( - readClass(currentOffset + 1, charBuffer), classFileBuffer[currentOffset + 3] & 0xFF); - currentOffset += 4; - break; - default: - throw new AssertionError(); - } - - // Visit the runtime visible instruction annotations, if any. - while (visibleTypeAnnotationOffsets != null - && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length - && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); - } - - // Visit the runtime invisible instruction annotations, if any. - while (invisibleTypeAnnotationOffsets != null - && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length - && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); - } - } - if (labels[codeLength] != null) { - methodVisitor.visitLabel(labels[codeLength]); - } - - // Visit LocalVariableTable and LocalVariableTypeTable attributes. - if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { - // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. - int[] typeTable = null; - if (localVariableTypeTableOffset != 0) { - typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; - currentOffset = localVariableTypeTableOffset + 2; - int typeTableIndex = typeTable.length; - while (typeTableIndex > 0) { - // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. - typeTable[--typeTableIndex] = currentOffset + 6; - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); - currentOffset += 10; - } - } - int localVariableTableLength = readUnsignedShort(localVariableTableOffset); - currentOffset = localVariableTableOffset + 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - String name = readUTF8(currentOffset + 4, charBuffer); - String descriptor = readUTF8(currentOffset + 6, charBuffer); - int index = readUnsignedShort(currentOffset + 8); - currentOffset += 10; - String signature = null; - if (typeTable != null) { - for (int i = 0; i < typeTable.length; i += 3) { - if (typeTable[i] == startPc && typeTable[i + 1] == index) { - signature = readUTF8(typeTable[i + 2], charBuffer); - break; - } - } - } - methodVisitor.visitLocalVariable( - name, descriptor, signature, labels[startPc], labels[startPc + length], index); - } - } - - // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. - if (visibleTypeAnnotationOffsets != null) { - for (int i = 0; i < visibleTypeAnnotationOffsets.length; ++i) { - int targetType = readByte(visibleTypeAnnotationOffsets[i]); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, visibleTypeAnnotationOffsets[i]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ true), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. - if (invisibleTypeAnnotationOffsets != null) { - for (int i = 0; i < invisibleTypeAnnotationOffsets.length; ++i) { - int targetType = readByte(invisibleTypeAnnotationOffsets[i]); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, invisibleTypeAnnotationOffsets[i]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ false), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the max stack and max locals values. - methodVisitor.visitMaxs(maxStack, maxLocals); - } - - /** - * Returns the label corresponding to the given bytecode offset. The default implementation of - * this method creates a label for the given offset if it has not been already created. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. If a label already exists - * for bytecodeOffset this method must not create a new one. Otherwise it must store the new - * label in this array. - * @return a non null Label, which must be equal to labels[bytecodeOffset]. - */ - protected Label readLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - labels[bytecodeOffset] = new Label(); - } - return labels[bytecodeOffset]; - } - - /** - * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode - * offset. The label is created with a call to {@link #readLabel} and its {@link - * Label#FLAG_DEBUG_ONLY} flag is cleared. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. - */ - private Label createLabel(final int bytecodeOffset, final Label[] labels) { - Label label = readLabel(bytecodeOffset, labels); - label.flags &= ~Label.FLAG_DEBUG_ONLY; - return label; - } - - /** - * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already - * existing label for the given bytecode offset (otherwise does nothing). The label is created - * with a call to {@link #readLabel}. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - */ - private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; - } - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse annotations, type annotations and parameter annotations - // ---------------------------------------------------------------------------------------------- - - /** - * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation - * entry it contains, to find the corresponding labels, and to visit the try catch block - * annotations. - * - * @param methodVisitor the method visitor to be used to visit the try catch block annotations. - * @param context information about the class being parsed. - * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations - * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, - * false it is a RuntimeInvisibleTypeAnnotations attribute. - * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's - * 'annotations' array field. - */ - private int[] readTypeAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeTypeAnnotationsOffset, - final boolean visible) { - char[] charBuffer = context.charBuffer; - int currentOffset = runtimeTypeAnnotationsOffset; - // Read the num_annotations field and create an array to store the type_annotation offsets. - int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; - currentOffset += 2; - // Parse the 'annotations' array field. - for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { - typeAnnotationsOffsets[i] = currentOffset; - // Parse the type_annotation's target_type and the target_info fields. The size of the - // target_info field depends on the value of target_type. - int targetType = readInt(currentOffset); - switch (targetType >>> 24) { - case TypeReference.LOCAL_VARIABLE: - case TypeReference.RESOURCE_VARIABLE: - // A localvar_target has a variable size, which depends on the value of their table_length - // field. It also references bytecode offsets, for which we need labels. - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - while (tableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - // Skip the index field (2 bytes). - currentOffset += 6; - createLabel(startPc, context.currentMethodLabels); - createLabel(startPc + length, context.currentMethodLabels); - } - break; - case TypeReference.CAST: - case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: - case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - currentOffset += 4; - break; - case TypeReference.CLASS_EXTENDS: - case TypeReference.CLASS_TYPE_PARAMETER_BOUND: - case TypeReference.METHOD_TYPE_PARAMETER_BOUND: - case TypeReference.THROWS: - case TypeReference.EXCEPTION_PARAMETER: - case TypeReference.INSTANCEOF: - case TypeReference.NEW: - case TypeReference.CONSTRUCTOR_REFERENCE: - case TypeReference.METHOD_REFERENCE: - currentOffset += 3; - break; - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: - default: - // TypeReference type which can't be used in Code attribute, or which is unknown. - throw new IllegalArgumentException(); - } - // Parse the rest of the type_annotation structure, starting with the target_path structure - // (whose size depends on its path_length field). - int pathLength = readByte(currentOffset); - if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { - // Parse the target_path structure and create a corresponding TypePath. - TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset); - currentOffset += 1 + 2 * pathLength; - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitTryCatchAnnotation( - targetType & 0xFFFFFF00, path, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } else { - // We don't want to visit the other target_type annotations, so we just skip them (which - // requires some parsing because the element_value_pairs array has a variable size). First, - // skip the target_path structure: - currentOffset += 3 + 2 * pathLength; - // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them - // with a null AnnotationVisitor). - currentOffset = - readElementValues( - /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); - } - } - return typeAnnotationsOffsets; - } - - /** - * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or - * -1 if there is no such type_annotation of if it does not have a bytecode offset. - * - * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a - * Runtime[In]VisibleTypeAnnotations attribute, or null. - * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. - * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 - * if there is no such type_annotation of if it does not have a bytecode offset. - */ - private int getTypeAnnotationBytecodeOffset( - final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { - if (typeAnnotationOffsets == null - || typeAnnotationIndex >= typeAnnotationOffsets.length - || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { - return -1; - } - return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); - } - - /** - * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info - * and target_path (the result is stored in the given context), and returns the start offset of - * the rest of the type_annotation structure. - * - * @param context information about the class being parsed. This is where the extracted - * target_type and target_path must be stored. - * @param typeAnnotationOffset the start offset of a type_annotation structure. - * @return the start offset of the rest of the type_annotation structure. - */ - private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { - int currentOffset = typeAnnotationOffset; - // Parse and store the target_type structure. - int targetType = readInt(typeAnnotationOffset); - switch (targetType >>> 24) { - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - targetType &= 0xFFFF0000; - currentOffset += 2; - break; - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: - targetType &= 0xFF000000; - currentOffset += 1; - break; - case TypeReference.LOCAL_VARIABLE: - case TypeReference.RESOURCE_VARIABLE: - targetType &= 0xFF000000; - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; - for (int i = 0; i < tableLength; ++i) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - int index = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - context.currentLocalVariableAnnotationRangeStarts[i] = - createLabel(startPc, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeEnds[i] = - createLabel(startPc + length, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeIndices[i] = index; - } - break; - case TypeReference.CAST: - case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: - case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - targetType &= 0xFF0000FF; - currentOffset += 4; - break; - case TypeReference.CLASS_EXTENDS: - case TypeReference.CLASS_TYPE_PARAMETER_BOUND: - case TypeReference.METHOD_TYPE_PARAMETER_BOUND: - case TypeReference.THROWS: - case TypeReference.EXCEPTION_PARAMETER: - targetType &= 0xFFFFFF00; - currentOffset += 3; - break; - case TypeReference.INSTANCEOF: - case TypeReference.NEW: - case TypeReference.CONSTRUCTOR_REFERENCE: - case TypeReference.METHOD_REFERENCE: - targetType &= 0xFF000000; - currentOffset += 3; - break; - default: - throw new IllegalArgumentException(); - } - context.currentTypeAnnotationTarget = targetType; - // Parse and store the target_path structure. - int pathLength = readByte(currentOffset); - context.currentTypeAnnotationTargetPath = - pathLength == 0 ? null : new TypePath(b, currentOffset); - // Return the start offset of the rest of the type_annotation structure. - return currentOffset + 1 + 2 * pathLength; - } - - /** - * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the parameter annotations. - * @param context information about the class being parsed. - * @param runtimeParameterAnnotationsOffset the start offset of a - * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's - * attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations - * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. - */ - private void readParameterAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeParameterAnnotationsOffset, - final boolean visible) { - int currentOffset = runtimeParameterAnnotationsOffset; - int numParameters = b[currentOffset++] & 0xFF; - methodVisitor.visitAnnotableParameterCount(numParameters, visible); - char[] charBuffer = context.charBuffer; - for (int i = 0; i < numParameters; ++i) { - int numAnnotations = readUnsignedShort(currentOffset); - currentOffset += 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - /** - * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit - * them. This method can also be used to read the values of the JVMS 'array_value' field of an - * annotation's 'element_value'. - * - * @param annotationVisitor the visitor that must visit the values. - * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index - * field) or of an 'array_value' structure. - * @param named if the annotation values are named or not. This should be true to parse the values - * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an - * annotation's element_value. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'annotation' or 'array_value' structure. - */ - private int readElementValues( - final AnnotationVisitor annotationVisitor, - final int annotationOffset, - final boolean named, - final char[] charBuffer) { - int currentOffset = annotationOffset; - // Read the num_element_value_pairs field (or num_values field for an array_value). - int numElementValuePairs = readUnsignedShort(currentOffset); - currentOffset += 2; - if (named) { - // Parse the element_value_pairs array. - while (numElementValuePairs-- > 0) { - String elementName = readUTF8(currentOffset, charBuffer); - currentOffset = - readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); - } - } else { - // Parse the array_value array. - while (numElementValuePairs-- > 0) { - currentOffset = - readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer); - } - } - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - return currentOffset; - } - - /** - * Reads a JVMS 'element_value' structure and makes the given visitor visit it. - * - * @param annotationVisitor the visitor that must visit the element_value structure. - * @param elementValueOffset the start offset in {@link #b} of the element_value structure to be - * read. - * @param elementName the name of the element_value structure to be read, or null. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'element_value' structure. - */ - private int readElementValue( - final AnnotationVisitor annotationVisitor, - final int elementValueOffset, - final String elementName, - final char[] charBuffer) { - int currentOffset = elementValueOffset; - if (annotationVisitor == null) { - switch (b[currentOffset] & 0xFF) { - case 'e': // enum_const_value - return currentOffset + 5; - case '@': // annotation_value - return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); - case '[': // array_value - return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); - default: - return currentOffset + 3; - } - } - switch (b[currentOffset++] & 0xFF) { - case 'B': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'C': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'D': // const_value_index, CONSTANT_Double - case 'F': // const_value_index, CONSTANT_Float - case 'I': // const_value_index, CONSTANT_Integer - case 'J': // const_value_index, CONSTANT_Long - annotationVisitor.visit( - elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); - currentOffset += 2; - break; - case 'S': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - - case 'Z': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, - readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 - ? Boolean.FALSE - : Boolean.TRUE); - currentOffset += 2; - break; - case 's': // const_value_index, CONSTANT_Utf8 - annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); - currentOffset += 2; - break; - case 'e': // enum_const_value - annotationVisitor.visitEnum( - elementName, - readUTF8(currentOffset, charBuffer), - readUTF8(currentOffset + 2, charBuffer)); - currentOffset += 4; - break; - case 'c': // class_info - annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); - currentOffset += 2; - break; - case '@': // annotation_value - currentOffset = - readElementValues( - annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), - currentOffset + 2, - true, - charBuffer); - break; - case '[': // array_value - int numValues = readUnsignedShort(currentOffset); - currentOffset += 2; - if (numValues == 0) { - return readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, - charBuffer); - } - switch (b[currentOffset] & 0xFF) { - case 'B': - byte[] byteValues = new byte[numValues]; - for (int i = 0; i < numValues; i++) { - byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, byteValues); - break; - case 'Z': - boolean[] booleanValues = new boolean[numValues]; - for (int i = 0; i < numValues; i++) { - booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; - currentOffset += 3; - } - annotationVisitor.visit(elementName, booleanValues); - break; - case 'S': - short[] shortValues = new short[numValues]; - for (int i = 0; i < numValues; i++) { - shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, shortValues); - break; - case 'C': - char[] charValues = new char[numValues]; - for (int i = 0; i < numValues; i++) { - charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, charValues); - break; - case 'I': - int[] intValues = new int[numValues]; - for (int i = 0; i < numValues; i++) { - intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, intValues); - break; - case 'J': - long[] longValues = new long[numValues]; - for (int i = 0; i < numValues; i++) { - longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, longValues); - break; - case 'F': - float[] floatValues = new float[numValues]; - for (int i = 0; i < numValues; i++) { - floatValues[i] = - Float.intBitsToFloat( - readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, floatValues); - break; - case 'D': - double[] doubleValues = new double[numValues]; - for (int i = 0; i < numValues; i++) { - doubleValues[i] = - Double.longBitsToDouble( - readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, doubleValues); - break; - default: - currentOffset = - readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, - charBuffer); - break; - } - break; - default: - throw new IllegalArgumentException(); - } - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse stack map frames - // ---------------------------------------------------------------------------------------------- - - /** - * Computes the implicit frame of the method currently being parsed (as defined in the given - * {@link Context}) and stores it in the given context. - * - * @param context information about the class being parsed. - */ - private void computeImplicitFrame(final Context context) { - String methodDescriptor = context.currentMethodDescriptor; - Object[] locals = context.currentFrameLocalTypes; - int nLocal = 0; - if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { - if ("".equals(context.currentMethodName)) { - locals[nLocal++] = Opcodes.UNINITIALIZED_THIS; - } else { - locals[nLocal++] = readClass(header + 2, context.charBuffer); - } - } - // Parse the method descriptor, one argument type descriptor at each iteration. Start by - // skipping the first method descriptor character, which is always '('. - int currentMethodDescritorOffset = 1; - while (true) { - int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; - switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - locals[nLocal++] = Opcodes.INTEGER; - break; - case 'F': - locals[nLocal++] = Opcodes.FLOAT; - break; - case 'J': - locals[nLocal++] = Opcodes.LONG; - break; - case 'D': - locals[nLocal++] = Opcodes.DOUBLE; - break; - case '[': - while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { - ++currentMethodDescritorOffset; - } - if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { - ++currentMethodDescritorOffset; - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; - } - } - locals[nLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); - break; - case 'L': - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; - } - locals[nLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); - break; - default: - context.currentFrameLocalCount = nLocal; - return; - } - } - } - - /** - * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} - * object. This method can also be used to read a full_frame structure, excluding its frame_type - * field (this is used to parse the legacy StackMap attributes). - * - * @param stackMapFrameOffset the start offset in {@link #b} of the stack_map_frame_value - * structure to be read, or the start offset of a full_frame structure (excluding its - * frame_type field). - * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' - * structure without its frame_type field. - * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. - * @param context where the parsed stack map frame must be stored. - * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. - */ - private int readStackMapFrame( - final int stackMapFrameOffset, - final boolean compressed, - final boolean expand, - final Context context) { - int currentOffset = stackMapFrameOffset; - final char[] charBuffer = context.charBuffer; - final Label[] labels = context.currentMethodLabels; - int frameType; - if (compressed) { - // Read the frame_type field. - frameType = b[currentOffset++] & 0xFF; - } else { - frameType = Frame.FULL_FRAME; - context.currentFrameOffset = -1; - } - int offsetDelta; - context.currentFrameLocalCountDelta = 0; - if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { - offsetDelta = frameType; - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.RESERVED) { - offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - offsetDelta = readUnsignedShort(currentOffset); - currentOffset += 2; - if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_CHOP; - context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; - context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else if (frameType == Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.FULL_FRAME) { - int local = expand ? context.currentFrameLocalCount : 0; - for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); - } - context.currentFrameType = Opcodes.F_APPEND; - context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; - context.currentFrameLocalCount += context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else { - final int numberOfLocals = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameType = Opcodes.F_FULL; - context.currentFrameLocalCountDelta = numberOfLocals; - context.currentFrameLocalCount = numberOfLocals; - for (int local = 0; local < numberOfLocals; ++local) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); - } - final int numberOfStackItems = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameStackCount = numberOfStackItems; - for (int stack = 0; stack < numberOfStackItems; ++stack) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); - } - } - } else { - throw new IllegalArgumentException(); - } - context.currentFrameOffset += offsetDelta + 1; - createLabel(context.currentFrameOffset, labels); - return currentOffset; - } - - /** - * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given - * array. - * - * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to - * read. - * @param frame the array where the parsed type must be stored. - * @param index the index in 'frame' where the parsed type must be stored. - * @param charBuffer the buffer used to read strings in the constant pool. - * @param labels the labels of the method currently being parsed, indexed by their offset. If the - * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is - * stored in this array if it does not already exist. - * @return the end offset of the JVMS 'verification_type_info' structure. - */ - private int readVerificationTypeInfo( - final int verificationTypeInfoOffset, - final Object[] frame, - final int index, - final char[] charBuffer, - final Label[] labels) { - int currentOffset = verificationTypeInfoOffset; - int tag = b[currentOffset++] & 0xFF; - switch (tag) { - case Frame.ITEM_TOP: - frame[index] = Opcodes.TOP; - break; - case Frame.ITEM_INTEGER: - frame[index] = Opcodes.INTEGER; - break; - case Frame.ITEM_FLOAT: - frame[index] = Opcodes.FLOAT; - break; - case Frame.ITEM_DOUBLE: - frame[index] = Opcodes.DOUBLE; - break; - case Frame.ITEM_LONG: - frame[index] = Opcodes.LONG; - break; - case Frame.ITEM_NULL: - frame[index] = Opcodes.NULL; - break; - case Frame.ITEM_UNINITIALIZED_THIS: - frame[index] = Opcodes.UNINITIALIZED_THIS; - break; - case Frame.ITEM_OBJECT: - frame[index] = readClass(currentOffset, charBuffer); - currentOffset += 2; - break; - case Frame.ITEM_UNINITIALIZED: - frame[index] = createLabel(readUnsignedShort(currentOffset), labels); - currentOffset += 2; - break; - default: - throw new IllegalArgumentException(); - } - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse attributes - // ---------------------------------------------------------------------------------------------- - - /** - * @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry. - */ - final int getFirstAttributeOffset() { - // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes - // each), as well as the interfaces array field (2 bytes per interface). - int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; - - // Read the fields_count field. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - // Skip the 'fields' array field. - while (fieldsCount-- > 0) { - // Invariant: currentOffset is the offset of a field_info structure. - // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the - // attributes_count field. - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - // Skip the 'attributes' array field. - while (attributesCount-- > 0) { - // Invariant: currentOffset is the offset of an attribute_info structure. - // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip - // this many bytes, plus 6 for the attribute_name_index and attribute_length fields - // (yielding the total size of the attribute_info structure). - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the methods_count and 'methods' fields, using the same method as above. - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - while (attributesCount-- > 0) { - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the ClassFile's attributes_count field. - return currentOffset + 2; - } - - /** - * Reads a non standard JVMS 'attribute' structure in {@link #b}. - * - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. - * @param type the type of the attribute. - * @param offset the start offset of the JVMS 'attribute' structure in {@link #b}. The 6 attribute - * header bytes (attribute_name_index and attribute_length) are not taken into account here. - * @param length the length of the attribute's content (excluding the 6 attribute header bytes). - * @param charBuffer the buffer to be used to read strings in the constant pool. - * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link #b}, or - * -1 if the attribute to be read is not a code attribute. The 6 attribute header bytes - * (attribute_name_index and attribute_length) are not taken into account here. - * @param labels the labels of the method's code, or null if the attribute to be read is - * not a code attribute. - * @return the attribute that has been read. - */ - private Attribute readAttribute( - final Attribute[] attributePrototypes, - final String type, - final int offset, - final int length, - final char[] charBuffer, - final int codeAttributeOffset, - final Label[] labels) { - for (int i = 0; i < attributePrototypes.length; ++i) { - if (attributePrototypes[i].type.equals(type)) { - return attributePrototypes[i].read( - this, offset, length, charBuffer, codeAttributeOffset, labels); - } - } - return new Attribute(type).read(this, offset, length, null, -1, null); - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: low level parsing - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the number of entries in the class's constant pool table. - * - * @return the number of entries in the class's constant pool table. - */ - public int getItemCount() { - return cpInfoOffsets.length; - } - - /** - * Returns the start offset in {@link #b} of a JVMS 'cp_info' structure (i.e. a constant pool - * entry), plus one. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool - * table. - * @return the start offset in {@link #b} of the corresponding JVMS 'cp_info' structure, plus one. - */ - public int getItem(final int constantPoolEntryIndex) { - return cpInfoOffsets[constantPoolEntryIndex]; - } - - /** - * Returns a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - * - * @return a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - */ - public int getMaxStringLength() { - return maxStringLength; - } - - /** - * Reads a byte value in {@link #b}. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public int readByte(final int offset) { - return b[offset] & 0xFF; - } - - /** - * Reads an unsigned short value in {@link #b}. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start index of the value to be read in {@link #b}. - * @return the read value. - */ - public int readUnsignedShort(final int offset) { - byte[] classFileBuffer = b; - return ((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF); - } - - /** - * Reads a signed short value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public short readShort(final int offset) { - byte[] classFileBuffer = b; - return (short) (((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF)); - } - - /** - * Reads a signed int value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public int readInt(final int offset) { - byte[] classFileBuffer = b; - return ((classFileBuffer[offset] & 0xFF) << 24) - | ((classFileBuffer[offset + 1] & 0xFF) << 16) - | ((classFileBuffer[offset + 2] & 0xFF) << 8) - | (classFileBuffer[offset + 3] & 0xFF); - } - - /** - * Reads a signed long value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public long readLong(final int offset) { - long l1 = readInt(offset); - long l0 = readInt(offset + 4) & 0xFFFFFFFFL; - return (l1 << 32) | l0; - } - - /** - * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Utf8 entry in the class's constant pool table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - public String readUTF8(final int offset, final char[] charBuffer) { - int constantPoolEntryIndex = readUnsignedShort(offset); - if (offset == 0 || constantPoolEntryIndex == 0) { - return null; - } - return readUTF(constantPoolEntryIndex, charBuffer); - } - - /** - * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool - * table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) { - String value = constantUtf8Values[constantPoolEntryIndex]; - if (value != null) { - return value; - } - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - return constantUtf8Values[constantPoolEntryIndex] = - readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); - } - - /** - * Reads an UTF8 string in {@link #b}. - * - * @param utfOffset the start offset of the UTF8 string to be read. - * @param utfLength the length of the UTF8 string to be read. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified UTF8 string. - */ - private String readUTF(final int utfOffset, final int utfLength, final char[] charBuffer) { - int currentOffset = utfOffset; - int endOffset = currentOffset + utfLength; - int strLength = 0; - byte[] classFileBuffer = b; - while (currentOffset < endOffset) { - int currentByte = classFileBuffer[currentOffset++]; - if ((currentByte & 0x80) == 0) { - charBuffer[strLength++] = (char) (currentByte & 0x7F); - } else if ((currentByte & 0xE0) == 0xC0) { - charBuffer[strLength++] = - (char) (((currentByte & 0x1F) << 6) + (classFileBuffer[currentOffset++] & 0x3F)); - } else { - charBuffer[strLength++] = - (char) - (((currentByte & 0xF) << 12) - + ((classFileBuffer[currentOffset++] & 0x3F) << 6) - + (classFileBuffer[currentOffset++] & 0x3F)); - } - } - return new String(charBuffer, 0, strLength); - } - - /** - * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or - * CONSTANT_Package constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or - * CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified constant pool entry. - */ - private String readStringish(final int offset, final char[] charBuffer) { - // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry - // designated by the first two bytes of this cp_info. - return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); - } - - /** - * Reads a CONSTANT_Class constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Class entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Class entry. - */ - public String readClass(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Module constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Module entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Module entry. - */ - public String readModule(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Package constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Package entry. - */ - public String readPackage(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a numeric or string constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, - * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType or - * CONSTANT_MethodHandle entry in the class's constant pool. - * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, - * {@link Type} or {@link Handle} corresponding to the specified constant pool entry. - */ - public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - switch (b[cpInfoOffset - 1]) { - case Symbol.CONSTANT_INTEGER_TAG: - return readInt(cpInfoOffset); - case Symbol.CONSTANT_FLOAT_TAG: - return Float.intBitsToFloat(readInt(cpInfoOffset)); - case Symbol.CONSTANT_LONG_TAG: - return readLong(cpInfoOffset); - case Symbol.CONSTANT_DOUBLE_TAG: - return Double.longBitsToDouble(readLong(cpInfoOffset)); - case Symbol.CONSTANT_CLASS_TAG: - return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_STRING_TAG: - return readUTF8(cpInfoOffset, charBuffer); - case Symbol.CONSTANT_METHOD_TYPE_TAG: - return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - int referenceKind = readByte(cpInfoOffset); - int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; - String owner = readClass(referenceCpInfoOffset, charBuffer); - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - boolean isInterface = - b[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - return new Handle(referenceKind, owner, name, descriptor, isInterface); - default: - throw new IllegalArgumentException(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ClassVisitor.java b/src/main/java/org/objectweb/asm/ClassVisitor.java deleted file mode 100644 index 88a19e47..00000000 --- a/src/main/java/org/objectweb/asm/ClassVisitor.java +++ /dev/null @@ -1,293 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java class. The methods of this class must be called in the following order: - * visit [ visitSource ] [ visitModule ][ visitOuterClass ] ( - * visitAnnotation | visitTypeAnnotation | visitAttribute )* ( - * visitInnerClass | visitField | visitMethod )* visitEnd. - * - * @author Eric Bruneton - */ -public abstract class ClassVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The class visitor to which this visitor must delegate method calls. May be null. - */ - protected ClassVisitor cv; - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public ClassVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param classVisitor the class visitor to which this visitor must delegate method calls. May be - * null. - */ - public ClassVisitor(final int api, final ClassVisitor classVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.cv = classVisitor; - } - - /** - * Visits the header of the class. - * - * @param version the class version. The minor version is stored in the 16 most significant bits, - * and the major version in the 16 least significant bits. - * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if - * the class is deprecated. - * @param name the internal name of the class (see {@link Type#getInternalName()}). - * @param signature the signature of this class. May be null if the class is not a - * generic one, and does not extend or implement generic classes or interfaces. - * @param superName the internal of name of the super class (see {@link Type#getInternalName()}). - * For interfaces, the super class is {@link Object}. May be null, but only for the - * {@link Object} class. - * @param interfaces the internal names of the class's interfaces (see {@link - * Type#getInternalName()}). May be null. - */ - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - if (cv != null) { - cv.visit(version, access, name, signature, superName, interfaces); - } - } - - /** - * Visits the source of the class. - * - * @param source the name of the source file from which the class was compiled. May be - * null. - * @param debug additional debug information to compute the correspondence between source and - * compiled elements of the class. May be null. - */ - public void visitSource(final String source, final String debug) { - if (cv != null) { - cv.visitSource(source, debug); - } - } - - /** - * Visit the module corresponding to the class. - * - * @param name the fully qualified name (using dots) of the module. - * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code - * ACC_MANDATED}. - * @param version the module version, or null. - * @return a visitor to visit the module values, or null if this visitor is not - * interested in visiting this module. - */ - public ModuleVisitor visitModule(final String name, final int access, final String version) { - if (api < Opcodes.ASM6) { - throw new UnsupportedOperationException(); - } - if (cv != null) { - return cv.visitModule(name, access, version); - } - return null; - } - - /** - * Visits the enclosing class of the class. This method must be called only if the class has an - * enclosing class. - * - * @param owner internal name of the enclosing class of the class. - * @param name the name of the method that contains the class, or null if the class is - * not enclosed in a method of its enclosing class. - * @param descriptor the descriptor of the method that contains the class, or null if the - * class is not enclosed in a method of its enclosing class. - */ - public void visitOuterClass(final String owner, final String name, final String descriptor) { - if (cv != null) { - cv.visitOuterClass(owner, name, descriptor); - } - } - - /** - * Visits an annotation of the class. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (cv != null) { - return cv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the class signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link - * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See - * {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(); - } - if (cv != null) { - return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the class. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (cv != null) { - cv.visitAttribute(attribute); - } - } - - /** - * Visits information about an inner class. This inner class is not necessarily a member of the - * class being visited. - * - * @param name the internal name of an inner class (see {@link Type#getInternalName()}). - * @param outerName the internal name of the class to which the inner class belongs (see {@link - * Type#getInternalName()}). May be null for not member classes. - * @param innerName the (simple) name of the inner class inside its enclosing class. May be - * null for anonymous inner classes. - * @param access the access flags of the inner class as originally declared in the enclosing - * class. - */ - public void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (cv != null) { - cv.visitInnerClass(name, outerName, innerName, access); - } - } - - /** - * Visits a field of the class. - * - * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if - * the field is synthetic and/or deprecated. - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be null if the field's type does not use - * generic types. - * @param value the field's initial value. This parameter, which may be null if the field - * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link - * Long}, a {@link Double} or a {@link String} (for int, float, - * long or String fields respectively). This parameter is only used for - * static fields. Its value is ignored for non static fields, which must be initialized - * through bytecode instructions in constructors or methods. - * @return a visitor to visit field annotations and attributes, or null if this class - * visitor is not interested in visiting these annotations and attributes. - */ - public FieldVisitor visitField( - final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - if (cv != null) { - return cv.visitField(access, name, descriptor, signature, value); - } - return null; - } - - /** - * Visits a method of the class. This method must return a new {@link MethodVisitor} - * instance (or null) each time it is called, i.e., it should not return a previously - * returned visitor. - * - * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if - * the method is synthetic and/or deprecated. - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be null if the method parameters, return - * type and exceptions do not use generic types. - * @param exceptions the internal names of the method's exception classes (see {@link - * Type#getInternalName()}). May be null. - * @return an object to visit the byte code of the method, or null if this class visitor - * is not interested in visiting the code of this method. - */ - public MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - if (cv != null) { - return cv.visitMethod(access, name, descriptor, signature, exceptions); - } - return null; - } - - /** - * Visits the end of the class. This method, which is the last one to be called, is used to inform - * the visitor that all the fields and methods of the class have been visited. - */ - public void visitEnd() { - if (cv != null) { - cv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ClassWriter.java b/src/main/java/org/objectweb/asm/ClassWriter.java deleted file mode 100644 index 5981f7fc..00000000 --- a/src/main/java/org/objectweb/asm/ClassWriter.java +++ /dev/null @@ -1,906 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java - * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from - * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a - * modified class from one or more existing Java classes. - * - * @author Eric Bruneton - * @see JVMS 4 - */ -public class ClassWriter extends ClassVisitor { - - /** - * A flag to automatically compute the maximum stack size and the maximum number of local - * variables of methods. If this flag is set, then the arguments of the {@link - * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link - * #visitMethod} method will be ignored, and computed automatically from the signature and the - * bytecode of each method. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_MAXS = 1; - - /** - * A flag to automatically compute the stack map frames of methods from scratch. If this flag is - * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack - * map frames are recomputed from the methods bytecode. The arguments of the {@link - * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other - * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_FRAMES = 2; - - // Note: fields are ordered as in the ClassFile structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is - * stored in the 16 most significant bits, and major_version in the 16 least significant bits. - */ - private int version; - - /** - * The symbol table for this class (contains the constant_pool and the BootstrapMethods). - */ - private final SymbolTable symbolTable; - - /** - * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private int accessFlags; - - /** - * The this_class field of the JVMS ClassFile structure. - */ - private int thisClass; - - /** - * The super_class field of the JVMS ClassFile structure. - */ - private int superClass; - - /** - * The interface_count field of the JVMS ClassFile structure. - */ - private int interfaceCount; - - /** - * The 'interfaces' array of the JVMS ClassFile structure. - */ - private int[] interfaces; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the first element of this list. - */ - private FieldWriter firstField; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the last element of this list. - */ - private FieldWriter lastField; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the first element of this list. - */ - private MethodWriter firstMethod; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the last element of this list. - */ - private MethodWriter lastMethod; - - /** - * The number_of_classes field of the InnerClasses attribute, or 0. - */ - private int numberOfClasses; - - /** - * The 'classes' array of the InnerClasses attribute, or null. - */ - private ByteVector classes; - - /** - * The class_index field of the EnclosingMethod attribute, or 0. - */ - private int enclosingClassIndex; - - /** - * The method_index field of the EnclosingMethod attribute. - */ - private int enclosingMethodIndex; - - /** - * The signature_index field of the Signature attribute, or 0. - */ - private int signatureIndex; - - /** - * The source_file_index field of the SourceFile attribute, or 0. - */ - private int sourceFileIndex; - - /** - * The debug_extension field of the SourceDebugExtension attribute, or null. - */ - private ByteVector debugExtension; - - /** - * The last runtime visible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The last runtime visible type annotation of this class. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this class. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The Module attribute of this class, or null. - */ - private ModuleWriter moduleWriter; - - /** - * The first non standard attribute of this class. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - /** - * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link - * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link - * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. - */ - private int compute; - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link ClassWriter} object. - * - * @param flags option flags that can be used to modify the default behavior of this class. Must - * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. - */ - public ClassWriter(final int flags) { - this(null, flags); - } - - /** - * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode - * transformations. These optimizations are the following: - * - *

    - *
  • The constant pool and bootstrap methods from the original class are copied as is in the - * new class, which saves time. New constant pool entries and new bootstrap methods will be - * added at the end if necessary, but unused constant pool entries or bootstrap methods - * won't be removed. - *
  • Methods that are not transformed are copied as is in the new class, directly from the - * original class bytecode (i.e. without emitting visit events for all the method - * instructions), which saves a lot of time. Untransformed methods are detected by - * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come - * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance). - *
- * - * @param classReader the {@link ClassReader} used to read the original class. It will be used to - * copy the entire constant pool and bootstrap methods from the original class and also to - * copy other fragments of original bytecode where applicable. - * @param flags option flags that can be used to modify the default behavior of this class.Must be - * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. These option flags do - * not affect methods that are copied as is in the new class. This means that neither the - * maximum stack size nor the stack frames will be computed for these methods. - */ - public ClassWriter(final ClassReader classReader, final int flags) { - super(Opcodes.ASM6); - symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); - if ((flags & COMPUTE_FRAMES) != 0) { - this.compute = MethodWriter.COMPUTE_ALL_FRAMES; - } else if ((flags & COMPUTE_MAXS) != 0) { - this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; - } else { - this.compute = MethodWriter.COMPUTE_NOTHING; - } - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the ClassVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public final void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - this.version = version; - this.accessFlags = access; - this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name); - if (signature != null) { - this.signatureIndex = symbolTable.addConstantUtf8(signature); - } - this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; - if (interfaces != null && interfaces.length > 0) { - interfaceCount = interfaces.length; - this.interfaces = new int[interfaceCount]; - for (int i = 0; i < interfaceCount; ++i) { - this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; - } - } - } - - @Override - public final void visitSource(final String file, final String debug) { - if (file != null) { - sourceFileIndex = symbolTable.addConstantUtf8(file); - } - if (debug != null) { - debugExtension = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE); - } - } - - @Override - public final ModuleVisitor visitModule( - final String name, final int access, final String version) { - return moduleWriter = - new ModuleWriter( - symbolTable, - symbolTable.addConstantModule(name).index, - access, - version == null ? 0 : symbolTable.addConstantUtf8(version)); - } - - @Override - public final void visitOuterClass( - final String owner, final String name, final String descriptor) { - enclosingClassIndex = symbolTable.addConstantClass(owner).index; - if (name != null && descriptor != null) { - enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); - } - } - - @Override - public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public final AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public final void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - - @Override - public final void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (classes == null) { - classes = new ByteVector(); - } - // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table - // which represents a class or interface C that is not a package member must have exactly one - // corresponding entry in the classes array". To avoid duplicates we keep track in the info - // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has - // already been added for C. If so, we store the index of this inner class entry (plus one) in - // the info field. This trick allows duplicate detection in O(1) time. - Symbol nameSymbol = symbolTable.addConstantClass(name); - if (nameSymbol.info == 0) { - ++numberOfClasses; - classes.putShort(nameSymbol.index); - classes.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); - classes.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); - classes.putShort(access); - nameSymbol.info = numberOfClasses; - } else { - // Compare the inner classes entry nameSymbol.info - 1 with the arguments of this method and - // throw an exception if there is a difference? - } - } - - @Override - public final FieldVisitor visitField( - final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - FieldWriter fieldWriter = - new FieldWriter(symbolTable, access, name, descriptor, signature, value); - if (firstField == null) { - firstField = fieldWriter; - } else { - lastField.fv = fieldWriter; - } - return lastField = fieldWriter; - } - - @Override - public final MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - MethodWriter methodWriter = - new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); - if (firstMethod == null) { - firstMethod = methodWriter; - } else { - lastMethod.mv = methodWriter; - } - return lastMethod = methodWriter; - } - - @Override - public final void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Other public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the content of the class file that was built by this ClassWriter. - * - * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. - */ - public byte[] toByteArray() { - // First step: compute the size in bytes of the ClassFile structure. - // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, - // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, - // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. - int size = 24 + 2 * interfaceCount; - int fieldsCount = 0; - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - ++fieldsCount; - size += fieldWriter.computeFieldInfoSize(); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - int methodsCount = 0; - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - ++methodsCount; - size += methodWriter.computeMethodInfoSize(); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributesCount = 0; - if (classes != null) { - ++attributesCount; - size += 8 + classes.length; - symbolTable.addConstantUtf8(Constants.INNER_CLASSES); - } - if (enclosingClassIndex != 0) { - ++attributesCount; - size += 10; - symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - } - if (signatureIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SIGNATURE); - } - if (sourceFileIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SOURCE_FILE); - } - if (debugExtension != null) { - ++attributesCount; - size += 6 + debugExtension.length; - symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.DEPRECATED); - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (symbolTable.computeBootstrapMethodsSize() > 0) { - ++attributesCount; - size += symbolTable.computeBootstrapMethodsSize(); - } - if (moduleWriter != null) { - attributesCount += moduleWriter.getAttributeCount(); - size += moduleWriter.computeAttributesSize(); - } - if (firstAttribute != null) { - attributesCount += firstAttribute.getAttributeCount(); - size += firstAttribute.computeAttributesSize(symbolTable); - } - // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous - // statements can add attribute names to the constant pool, thereby changing its size! - size += symbolTable.getConstantPoolLength(); - if (symbolTable.getConstantPoolCount() > 0xFFFF) { - throw new IndexOutOfBoundsException("Class file too large!"); - } - - // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in - // dynamic resizes) and fill it with the ClassFile content. - ByteVector result = new ByteVector(size); - result.putInt(0xCAFEBABE).putInt(version); - symbolTable.putConstantPool(result); - int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; - result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); - result.putShort(interfaceCount); - for (int i = 0; i < interfaceCount; ++i) { - result.putShort(interfaces[i]); - } - result.putShort(fieldsCount); - fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.putFieldInfo(result); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - result.putShort(methodsCount); - boolean hasFrames = false; - boolean hasAsmInstructions = false; - methodWriter = firstMethod; - while (methodWriter != null) { - hasFrames |= methodWriter.hasFrames(); - hasAsmInstructions |= methodWriter.hasAsmInstructions(); - methodWriter.putMethodInfo(result); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - result.putShort(attributesCount); - if (classes != null) { - result - .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) - .putInt(classes.length + 2) - .putShort(numberOfClasses) - .putByteArray(classes.data, 0, classes.length); - } - if (enclosingClassIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) - .putInt(4) - .putShort(enclosingClassIndex) - .putShort(enclosingMethodIndex); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if (sourceFileIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) - .putInt(2) - .putShort(sourceFileIndex); - } - if (debugExtension != null) { - int length = debugExtension.length; - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) - .putInt(length) - .putByteArray(debugExtension.data, 0, length); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result); - } - symbolTable.putBootstrapMethods(result); - if (moduleWriter != null) { - moduleWriter.putAttributes(result); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, result); - } - - // Third step: do a ClassReader->ClassWriter round trip if the generated class contains ASM - // specific instructions due to large forward jumps. - if (hasAsmInstructions) { - Attribute[] attributes = getAttributePrototypes(); - firstField = null; - lastField = null; - firstMethod = null; - lastMethod = null; - lastRuntimeVisibleAnnotation = null; - lastRuntimeInvisibleAnnotation = null; - lastRuntimeVisibleTypeAnnotation = null; - lastRuntimeInvisibleTypeAnnotation = null; - moduleWriter = null; - firstAttribute = null; - compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; - new ClassReader(result.data, 0, /* checkClassVersion = */ false) - .accept( - this, - attributes, - (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); - return toByteArray(); - } else { - return result.data; - } - } - - /** - * Returns the prototypes of the attributes used by this class, its fields and its methods. - * - * @return the prototypes of the attributes used by this class, its fields and its methods. - */ - private Attribute[] getAttributePrototypes() { - Attribute.Set attributePrototypes = new Attribute.Set(); - attributePrototypes.addAttributes(firstAttribute); - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.collectAttributePrototypes(attributePrototypes); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - methodWriter.collectAttributePrototypes(attributePrototypes); - methodWriter = (MethodWriter) methodWriter.mv; - } - return attributePrototypes.toArray(); - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: constant pool management for Attribute sub classes - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a number or string constant to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param value the value of the constant to be added to the constant pool. This parameter must be - * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. - * @return the index of a new or already existing constant item with the given value. - */ - public int newConst(final Object value) { - return symbolTable.addConstant(value).index; - } - - /** - * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant - * pool already contains a similar item. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param value the String value. - * @return the index of a new or already existing UTF8 item. - */ - public int newUTF8(final String value) { - return symbolTable.addConstantUtf8(value); - } - - /** - * Adds a class reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param value the internal name of the class. - * @return the index of a new or already existing class reference item. - */ - public int newClass(final String value) { - return symbolTable.addConstantClass(value).index; - } - - /** - * Adds a method type reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param methodDescriptor method descriptor of the method type. - * @return the index of a new or already existing method type reference item. - */ - public int newMethodType(final String methodDescriptor) { - return symbolTable.addConstantMethodType(methodDescriptor).index; - } - - /** - * Adds a module reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param moduleName name of the module. - * @return the index of a new or already existing module reference item. - */ - public int newModule(final String moduleName) { - return symbolTable.addConstantModule(moduleName).index; - } - - /** - * Adds a package reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param packageName name of the package in its internal form. - * @return the index of a new or already existing module reference item. - */ - public int newPackage(final String packageName) { - return symbolTable.addConstantPackage(packageName).index; - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @return the index of a new or already existing method type reference item. - * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, - * boolean)}. - */ - @Deprecated - public int newHandle( - final int tag, final String owner, final String name, final String descriptor) { - return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @param isInterface true if the owner is an interface. - * @return the index of a new or already existing method type reference item. - */ - public int newHandle( - final int tag, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; - } - - /** - * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param descriptor descriptor of the invoke method. - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. - * @return the index of a new or already existing invokedynamic reference item. - */ - public int newInvokeDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - return symbolTable.addConstantInvokeDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) - .index; - } - - /** - * Adds a field reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param descriptor the field's descriptor. - * @return the index of a new or already existing field reference item. - */ - public int newField(final String owner, final String name, final String descriptor) { - return symbolTable.addConstantFieldref(owner, name, descriptor).index; - } - - /** - * Adds a method reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param descriptor the method's descriptor. - * @param isInterface true if owner is an interface. - * @return the index of a new or already existing method reference item. - */ - public int newMethod( - final String owner, final String name, final String descriptor, final boolean isInterface) { - return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; - } - - /** - * Adds a name and type to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param name a name. - * @param descriptor a type descriptor. - * @return the index of a new or already existing name and type item. - */ - public int newNameType(final String name, final String descriptor) { - return symbolTable.addConstantNameAndType(name, descriptor); - } - - // ----------------------------------------------------------------------------------------------- - // Default method to compute common super classes when computing stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the common super type of the two given types. The default implementation of this method - * loads the two given classes and uses the java.lang.Class methods to find the common - * super class. It can be overridden to compute this common super type in other ways, in - * particular without actually loading any class, or to take into account the class that is - * currently being generated by this ClassWriter, which can of course not be loaded since it is - * under construction. - * - * @param type1 the internal name of a class. - * @param type2 the internal name of another class. - * @return the internal name of the common super class of the two given classes. - */ - protected String getCommonSuperClass(final String type1, final String type2) { - ClassLoader classLoader = getClass().getClassLoader(); - Class class1; - try { - class1 = Class.forName(type1.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new TypeNotPresentException(type1, e); - } - Class class2; - try { - class2 = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new TypeNotPresentException(type2, e); - } - if (class1.isAssignableFrom(class2)) { - return type1; - } - if (class2.isAssignableFrom(class1)) { - return type2; - } - if (class1.isInterface() || class2.isInterface()) { - return "java/lang/Object"; - } else { - do { - class1 = class1.getSuperclass(); - } while (!class1.isAssignableFrom(class2)); - return class1.getName().replace('.', '/'); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Constants.java b/src/main/java/org/objectweb/asm/Constants.java deleted file mode 100644 index e0ec65de..00000000 --- a/src/main/java/org/objectweb/asm/Constants.java +++ /dev/null @@ -1,176 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public - * API. - * - * @author Eric Bruneton - * @see JVMS 6 - */ -final class Constants implements Opcodes { - - private Constants() { - } - - // The ClassFile attribute names, in the order they are defined in - // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7-300. - - static final String CONSTANT_VALUE = "ConstantValue"; - static final String CODE = "Code"; - static final String STACK_MAP_TABLE = "StackMapTable"; - static final String EXCEPTIONS = "Exceptions"; - static final String INNER_CLASSES = "InnerClasses"; - static final String ENCLOSING_METHOD = "EnclosingMethod"; - static final String SYNTHETIC = "Synthetic"; - static final String SIGNATURE = "Signature"; - static final String SOURCE_FILE = "SourceFile"; - static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension"; - static final String LINE_NUMBER_TABLE = "LineNumberTable"; - static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable"; - static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; - static final String DEPRECATED = "Deprecated"; - static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; - static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; - static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; - static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = - "RuntimeInvisibleParameterAnnotations"; - static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; - static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; - static final String ANNOTATION_DEFAULT = "AnnotationDefault"; - static final String BOOTSTRAP_METHODS = "BootstrapMethods"; - static final String METHOD_PARAMETERS = "MethodParameters"; - static final String MODULE = "Module"; - static final String MODULE_PACKAGES = "ModulePackages"; - static final String MODULE_MAIN_CLASS = "ModuleMainClass"; - - // ASM specific access flags. - // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard - // access flags, and also to make sure that these flags are automatically filtered out when - // written in class files (because access flags are stored using 16 bits only). - - static final int ACC_CONSTRUCTOR = 0x40000; // method access flag. - - // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. - - /** - * A frame inserted between already existing frames. This internal stack map frame type (in - * addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be - * computed from the previous existing frame and from the instructions between this existing frame - * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only - * used when an unconditional jump is inserted in a method while expanding an ASM specific - * instruction. Keep in sync with Opcodes.java. - */ - static final int F_INSERT = 256; - - // The JVM opcode values which are not part of the ASM public API. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. - - static final int LDC_W = 19; - static final int LDC2_W = 20; - static final int ILOAD_0 = 26; - static final int ILOAD_1 = 27; - static final int ILOAD_2 = 28; - static final int ILOAD_3 = 29; - static final int LLOAD_0 = 30; - static final int LLOAD_1 = 31; - static final int LLOAD_2 = 32; - static final int LLOAD_3 = 33; - static final int FLOAD_0 = 34; - static final int FLOAD_1 = 35; - static final int FLOAD_2 = 36; - static final int FLOAD_3 = 37; - static final int DLOAD_0 = 38; - static final int DLOAD_1 = 39; - static final int DLOAD_2 = 40; - static final int DLOAD_3 = 41; - static final int ALOAD_0 = 42; - static final int ALOAD_1 = 43; - static final int ALOAD_2 = 44; - static final int ALOAD_3 = 45; - static final int ISTORE_0 = 59; - static final int ISTORE_1 = 60; - static final int ISTORE_2 = 61; - static final int ISTORE_3 = 62; - static final int LSTORE_0 = 63; - static final int LSTORE_1 = 64; - static final int LSTORE_2 = 65; - static final int LSTORE_3 = 66; - static final int FSTORE_0 = 67; - static final int FSTORE_1 = 68; - static final int FSTORE_2 = 69; - static final int FSTORE_3 = 70; - static final int DSTORE_0 = 71; - static final int DSTORE_1 = 72; - static final int DSTORE_2 = 73; - static final int DSTORE_3 = 74; - static final int ASTORE_0 = 75; - static final int ASTORE_1 = 76; - static final int ASTORE_2 = 77; - static final int ASTORE_3 = 78; - static final int WIDE = 196; - static final int GOTO_W = 200; - static final int JSR_W = 201; - - // Constants to convert between normal and wide jump instructions. - - // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP. - static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO; - - // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa. - - // The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes - // and IFEQ, ..., IF_ACMPNE, GOTO and JSR. - static final int ASM_OPCODE_DELTA = 49; - - // The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL. - static final int ASM_IFNULL_OPCODE_DELTA = 20; - - // ASM specific opcodes, used for long forward jump instructions. - - static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA; - static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA; - static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA; - static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA; - static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA; - static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA; - static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA; - static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA; - static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA; - static final int ASM_JSR = JSR + ASM_OPCODE_DELTA; - static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA; - static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA; - static final int ASM_GOTO_W = 220; -} diff --git a/src/main/java/org/objectweb/asm/Context.java b/src/main/java/org/objectweb/asm/Context.java deleted file mode 100644 index 330ef5d5..00000000 --- a/src/main/java/org/objectweb/asm/Context.java +++ /dev/null @@ -1,164 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * Information about a class being parsed in a {@link ClassReader}. - * - * @author Eric Bruneton - */ -final class Context { - - /** - * The prototypes of the attributes that must be parsed in this class. - */ - Attribute[] attributePrototypes; - - /** - * The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link - * ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or - * {@link ClassReader#EXPAND_ASM_INSNS}. - */ - int parsingOptions; - - /** - * The buffer used to read strings in the constant pool. - */ - char[] charBuffer; - - /** - * The start offsets in {@link ClassReader#b} of each element of the bootstrap_methods array (in - * the BootstrapMethod attribute). - * - * @see JVMS - * 4.7.23 - */ - int[] bootstrapMethodOffsets; - - // Information about the current method, i.e. the one read in the current (or latest) call - // to {@link ClassReader#readMethod()}. - - /** - * The access flags of the current method. - */ - int currentMethodAccessFlags; - - /** - * The name of the current method. - */ - String currentMethodName; - - /** - * The descriptor of the current method. - */ - String currentMethodDescriptor; - - /** - * The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a - * label is needed have a non null associated Label). - */ - Label[] currentMethodLabels; - - // Information about the current type annotation target, i.e. the one read in the current - // (or latest) call to {@link ClassReader#readAnnotationTarget()}. - - /** - * The target_type and target_info of the current type annotation target, encoded as described in - * {@link TypeReference}. - */ - int currentTypeAnnotationTarget; - - /** - * The target_path of the current type annotation target. - */ - TypePath currentTypeAnnotationTargetPath; - - /** - * The start of each local variable range in the current local variable annotation. - */ - Label[] currentLocalVariableAnnotationRangeStarts; - - /** - * The end of each local variable range in the current local variable annotation. - */ - Label[] currentLocalVariableAnnotationRangeEnds; - - /** - * The local variable index of each local variable range in the current local variable annotation. - */ - int[] currentLocalVariableAnnotationRangeIndices; - - // Information about the current stack map frame, i.e. the one read in the current (or latest) - // call to {@link ClassReader#readFrame()}. - - /** - * The bytecode offset of the current stack map frame. - */ - int currentFrameOffset; - - /** - * The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link - * Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}. - */ - int currentFrameType; - - /** - * The number of local variable types in the current stack map frame. Each type is represented - * with a single array element (even long and double). - */ - int currentFrameLocalCount; - - /** - * The delta number of local variable types in the current stack map frame (each type is - * represented with a single array element - even long and double). This is the number of local - * variable types in this frame, minus the number of local variable types in the previous frame. - */ - int currentFrameLocalCountDelta; - - /** - * The types of the local variables in the current stack map frame. Each type is represented with - * a single array element (even long and double), using the format described in {@link - * MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of - * all the local variables, or only those of the additional ones (compared to the previous frame). - */ - Object[] currentFrameLocalTypes; - - /** - * The number stack element types in the current stack map frame. Each type is represented with a - * single array element (even long and double). - */ - int currentFrameStackCount; - - /** - * The types of the stack elements in the current stack map frame. Each type is represented with a - * single array element (even long and double), using the format described in {@link - * MethodVisitor#visitFrame}. - */ - Object[] currentFrameStackTypes; -} diff --git a/src/main/java/org/objectweb/asm/CurrentFrame.java b/src/main/java/org/objectweb/asm/CurrentFrame.java deleted file mode 100644 index 69cfe12a..00000000 --- a/src/main/java/org/objectweb/asm/CurrentFrame.java +++ /dev/null @@ -1,56 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * Information about the input stack map frame at the "current" instruction of a method. This is - * implemented as a Frame subclass for a "basic block" containing only one instruction. - * - * @author Eric Bruneton - */ -final class CurrentFrame extends Frame { - - CurrentFrame(final Label owner) { - super(owner); - } - - /** - * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the - * instruction just after the given one. It is assumed that the value of this object when this - * method is called is the stack map frame status just before the given instruction is executed. - */ - @Override - void execute( - final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) { - super.execute(opcode, arg, symbolArg, symbolTable); - Frame successor = new Frame(null); - merge(symbolTable, successor, 0); - copyFrom(successor); - } -} diff --git a/src/main/java/org/objectweb/asm/Edge.java b/src/main/java/org/objectweb/asm/Edge.java deleted file mode 100644 index dff553d2..00000000 --- a/src/main/java/org/objectweb/asm/Edge.java +++ /dev/null @@ -1,93 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An edge in the control flow graph of a method. Each node of this graph is a basic block, - * represented with the Label corresponding to its first instruction. Each edge goes from one node - * to another, i.e. from one basic block to another (called the predecessor and successor blocks, - * respectively). An edge corresponds either to a jump or ret instruction or to an exception - * handler. - * - * @author Eric Bruneton - * @see Label - */ -final class Edge { - - /** - * A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link - * ClassWriter#COMPUTE_FRAMES}. - */ - static final int JUMP = 0; - - /** - * A control flow graph edge corresponding to an exception handler. Only used with {@link - * ClassWriter#COMPUTE_MAXS}. - */ - static final int EXCEPTION = 0x7FFFFFFF; - - /** - * Information about this control flow graph edge. - * - *
    - *
  • If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size - * delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an - * edge corresponding to an exception handler). The stack size delta is the stack size just - * after the jump instruction, minus the stack size at the beginning of the predecessor - * basic block, i.e. the one containing the jump instruction. - *
  • If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP - * (for an edge corresponding to a jump instruction), or the index, in the {@link - * ClassWriter} type table, of the exception type that is handled (for an edge corresponding - * to an exception handler). - *
- */ - final int info; - - /** - * The successor block of this control flow graph edge. - */ - final Label successor; - - /** - * The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}. - */ - Edge nextEdge; - - /** - * Constructs a new Edge. - * - * @param info see {@link #info}. - * @param successor see {@link #successor}. - * @param nextEdge see {@link #nextEdge}. - */ - Edge(final int info, final Label successor, final Edge nextEdge) { - this.info = info; - this.successor = successor; - this.nextEdge = nextEdge; - } -} diff --git a/src/main/java/org/objectweb/asm/FieldVisitor.java b/src/main/java/org/objectweb/asm/FieldVisitor.java deleted file mode 100644 index e2f2979a..00000000 --- a/src/main/java/org/objectweb/asm/FieldVisitor.java +++ /dev/null @@ -1,135 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java field. The methods of this class must be called in the following order: - * ( visitAnnotation | visitTypeAnnotation | visitAttribute )* - * visitEnd. - * - * @author Eric Bruneton - */ -public abstract class FieldVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The field visitor to which this visitor must delegate method calls. May be null. - */ - protected FieldVisitor fv; - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public FieldVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be - * null. - */ - public FieldVisitor(final int api, final FieldVisitor fieldVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.fv = fieldVisitor; - } - - /** - * Visits an annotation of the field. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (fv != null) { - return fv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on the type of the field. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#FIELD}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(); - } - if (fv != null) { - return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the field. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (fv != null) { - fv.visitAttribute(attribute); - } - } - - /** - * Visits the end of the field. This method, which is the last one to be called, is used to inform - * the visitor that all the annotations and attributes of the field have been visited. - */ - public void visitEnd() { - if (fv != null) { - fv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/FieldWriter.java b/src/main/java/org/objectweb/asm/FieldWriter.java deleted file mode 100644 index f57a0eef..00000000 --- a/src/main/java/org/objectweb/asm/FieldWriter.java +++ /dev/null @@ -1,352 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the - * Java Virtual Machine Specification (JVMS). - * - * @author Eric Bruneton - * @see JVMS - * 4.5 - */ -final class FieldWriter extends FieldVisitor { - - /** - * Where the constants used in this FieldWriter must be stored. - */ - private final SymbolTable symbolTable; - - // Note: fields are ordered as in the field_info structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The access_flags field of the field_info JVMS structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private final int accessFlags; - - /** - * The name_index field of the field_info JVMS structure. - */ - private final int nameIndex; - - /** - * The descriptor_index field of the field_info JVMS structure. - */ - private final int descriptorIndex; - - /** - * The signature_index field of the Signature attribute of this field_info, or 0 if there is no - * Signature attribute. - */ - private int signatureIndex; - - /** - * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there - * is no ConstantValue attribute. - */ - private int constantValueIndex; - - /** - * The last runtime visible annotation of this field. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this field. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The last runtime visible type annotation of this field. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this field. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The first non standard attribute of this field. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link FieldWriter}. - * - * @param symbolTable where the constants used in this FieldWriter must be stored. - * @param access the field's access flags (see {@link Opcodes}). - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be null. - * @param constantValue the field's constant value. May be null. - */ - FieldWriter( - final SymbolTable symbolTable, - final int access, - final String name, - final String descriptor, - final String signature, - final Object constantValue) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.accessFlags = access; - this.nameIndex = symbolTable.addConstantUtf8(name); - this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); - if (signature != null) { - this.signatureIndex = symbolTable.addConstantUtf8(signature); - } - if (constantValue != null) { - this.constantValueIndex = symbolTable.addConstant(constantValue).index; - } - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the FieldVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the - * names of the attributes of this field in the constant pool. - * - * @return the size in bytes of the field_info JVMS structure. - */ - int computeFieldInfoSize() { - // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes. - int size = 8; - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (constantValueIndex != 0) { - // ConstantValue attributes always use 8 bytes. - symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE); - size += 8; - } - // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 - && symbolTable.getMajorVersion() < Opcodes.V1_5) { - // Synthetic attributes always use 6 bytes. - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - size += 6; - } - if (signatureIndex != 0) { - // Signature attributes always use 8 bytes. - symbolTable.addConstantUtf8(Constants.SIGNATURE); - size += 8; - } - // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead. - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - // Deprecated attributes always use 6 bytes. - symbolTable.addConstantUtf8(Constants.DEPRECATED); - size += 6; - } - if (lastRuntimeVisibleAnnotation != null) { - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (firstAttribute != null) { - size += firstAttribute.computeAttributesSize(symbolTable); - } - return size; - } - - /** - * Puts the content of the field_info JVMS structure generated by this FieldWriter into the given - * ByteVector. - * - * @param output where the field_info structure must be put. - */ - void putFieldInfo(final ByteVector output) { - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - // Put the access_flags, name_index and descriptor_index fields. - int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; - output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); - // Compute and put the attributes_count field. - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributesCount = 0; - if (constantValueIndex != 0) { - ++attributesCount; - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - ++attributesCount; - } - if (signatureIndex != 0) { - ++attributesCount; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributesCount; - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributesCount; - } - if (firstAttribute != null) { - attributesCount += firstAttribute.getAttributeCount(); - } - output.putShort(attributesCount); - // Put the field_info attributes. - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (constantValueIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE)) - .putInt(2) - .putShort(constantValueIndex); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, output); - } - } - - /** - * Collects the attributes of this field into the given set of attribute prototypes. - * - * @param attributePrototypes a set of attribute prototypes. - */ - final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { - attributePrototypes.addAttributes(firstAttribute); - } -} diff --git a/src/main/java/org/objectweb/asm/Frame.java b/src/main/java/org/objectweb/asm/Frame.java deleted file mode 100644 index a729f37c..00000000 --- a/src/main/java/org/objectweb/asm/Frame.java +++ /dev/null @@ -1,1484 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The input and output stack map frames of a basic block. - * - *

Stack map frames are computed in two steps: - * - *

    - *
  • During the visit of each instruction in MethodWriter, the state of the frame at the end of - * the current basic block is updated by simulating the action of the instruction on the - * previous state of this so called "output frame". - *
  • After all instructions have been visited, a fix point algorithm is used in MethodWriter to - * compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of - * the basic block). See {@link MethodWriter#computeAllFrames}. - *
- * - *

Output stack map frames are computed relatively to the input frame of the basic block, which - * is not yet known when output frames are computed. It is therefore necessary to be able to - * represent abstract types such as "the type at position x in the input frame locals" or "the type - * at position x from the top of the input frame stack" or even "the type at position x in the input - * frame, with y more (or less) array dimensions". This explains the rather complicated type format - * used in this class, explained below. - * - *

The local variables and the operand stack of input and output frames contain values called - * "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS - * and VALUE, packed in a single int value for better performance and memory efficiency: - * - *

- *   =====================================
- *   |.DIM|KIND|FLAG|...............VALUE|
- *   =====================================
- * 
- * - *
    - *
  • the DIM field, stored in the 4 most significant bits, is a signed number of array - * dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right - * shift of {@link #DIM_SHIFT}. - *
  • the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be - * retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link - * #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND} - * or {@link #STACK_KIND}. - *
  • the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag - * is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}. - *
  • the VALUE field, stored in the remaining 20 bits, contains either - *
      - *
    • one of the constants {@link #ITEM_TOP}, {@link #ITEM_ASM_BOOLEAN}, {@link - * #ITEM_ASM_BYTE}, {@link #ITEM_ASM_CHAR} or {@link #ITEM_ASM_SHORT}, {@link - * #ITEM_INTEGER}, {@link #ITEM_FLOAT}, {@link #ITEM_LONG}, {@link #ITEM_DOUBLE}, {@link - * #ITEM_NULL} or {@link #ITEM_UNINITIALIZED_THIS}, if KIND is equal to {@link - * #CONSTANT_KIND}. - *
    • the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link - * SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}. - *
    • the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type - * table of a SymbolTable, if KIND is equal to {@link #UNINITIALIZED_KIND}. - *
    • the index of a local variable in the input stack frame, if KIND is equal to {@link - * #LOCAL_KIND}. - *
    • a position relatively to the top of the stack of the input stack frame, if KIND is - * equal to {@link #STACK_KIND}, - *
    - *
- * - *

Output frames can contain abstract types of any kind and with a positive or negative array - * dimension (and even unassigned types, represented by 0 - which does not correspond to any valid - * abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or - * UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type - * table contains only internal type names (array type descriptors are forbidden - array dimensions - * must be represented through the DIM field). - * - *

The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + - * TOP), for local variables as well as in the operand stack. This is necessary to be able to - * simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented - * by the abstract types in the stack (which are not always known). - * - * @author Eric Bruneton - */ -class Frame { - - // Constants used in the StackMapTable attribute. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4. - - static final int SAME_FRAME = 0; - static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; - static final int RESERVED = 128; - static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; - static final int CHOP_FRAME = 248; - static final int SAME_FRAME_EXTENDED = 251; - static final int APPEND_FRAME = 252; - static final int FULL_FRAME = 255; - - static final int ITEM_TOP = 0; - static final int ITEM_INTEGER = 1; - static final int ITEM_FLOAT = 2; - static final int ITEM_DOUBLE = 3; - static final int ITEM_LONG = 4; - static final int ITEM_NULL = 5; - static final int ITEM_UNINITIALIZED_THIS = 6; - static final int ITEM_OBJECT = 7; - static final int ITEM_UNINITIALIZED = 8; - // Additional, ASM specific constants used in abstract types below. - private static final int ITEM_ASM_BOOLEAN = 9; - private static final int ITEM_ASM_BYTE = 10; - private static final int ITEM_ASM_CHAR = 11; - private static final int ITEM_ASM_SHORT = 12; - - // Bitmasks to get each field of an abstract type. - - private static final int DIM_MASK = 0xF0000000; - private static final int KIND_MASK = 0x0F000000; - private static final int FLAGS_MASK = 0x00F00000; - private static final int VALUE_MASK = 0x000FFFFF; - - // Constants to manipulate the DIM field of an abstract type. - - /** - * The number of right shift bits to use to get the array dimensions of an abstract type. - */ - private static final int DIM_SHIFT = 28; - - /** - * The constant to be added to an abstract type to get one with one more array dimension. - */ - private static final int ARRAY_OF = +1 << DIM_SHIFT; - - /** - * The constant to be added to an abstract type to get one with one less array dimension. - */ - private static final int ELEMENT_OF = -1 << DIM_SHIFT; - - // Possible values for the KIND field of an abstract type. - - private static final int CONSTANT_KIND = 0x01000000; - private static final int REFERENCE_KIND = 0x02000000; - private static final int UNINITIALIZED_KIND = 0x03000000; - private static final int LOCAL_KIND = 0x04000000; - private static final int STACK_KIND = 0x05000000; - - // Possible flags for the FLAGS field of an abstract type. - - /** - * A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, - * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been - * partially overridden with an xSTORE instruction). - */ - private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK; - - // Useful predefined abstract types (all the possible CONSTANT_KIND types). - - private static final int TOP = CONSTANT_KIND | ITEM_TOP; - private static final int BOOLEAN = CONSTANT_KIND | ITEM_ASM_BOOLEAN; - private static final int BYTE = CONSTANT_KIND | ITEM_ASM_BYTE; - private static final int CHAR = CONSTANT_KIND | ITEM_ASM_CHAR; - private static final int SHORT = CONSTANT_KIND | ITEM_ASM_SHORT; - private static final int INTEGER = CONSTANT_KIND | ITEM_INTEGER; - private static final int FLOAT = CONSTANT_KIND | ITEM_FLOAT; - private static final int LONG = CONSTANT_KIND | ITEM_LONG; - private static final int DOUBLE = CONSTANT_KIND | ITEM_DOUBLE; - private static final int NULL = CONSTANT_KIND | ITEM_NULL; - private static final int UNINITIALIZED_THIS = CONSTANT_KIND | ITEM_UNINITIALIZED_THIS; - - // ----------------------------------------------------------------------------------------------- - // Instance fields - // ----------------------------------------------------------------------------------------------- - - /** - * The basic block to which these input and output stack map frames correspond. - */ - Label owner; - - /** - * The input stack map frame locals. This is an array of abstract types. - */ - private int[] inputLocals; - - /** - * The input stack map frame stack. This is an array of abstract types. - */ - private int[] inputStack; - - /** - * The output stack map frame locals. This is an array of abstract types. - */ - private int[] outputLocals; - - /** - * The output stack map frame stack. This is an array of abstract types. - */ - private int[] outputStack; - - /** - * The start of the output stack, relatively to the input stack. This offset is always negative or - * null. A null offset means that the output stack must be appended to the input stack. A -n - * offset means that the first n output stack elements must replace the top n input stack - * elements, and that the other elements must be appended to the input stack. - */ - private short outputStackStart; - - /** - * The index of the top stack element in {@link #outputStack}. - */ - private short outputStackTop; - - /** - * The number of types that are initialized in the basic block. See {@link #initializations}. - */ - private int initializationCount; - - /** - * The abstract types that are initialized in the basic block. A constructor invocation on an - * UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace every occurrence of this - * type in the local variables and in the operand stack. This cannot be done during the first step - * of the algorithm since, during this step, the local variables and the operand stack types are - * still abstract. It is therefore necessary to store the abstract types of the constructors which - * are invoked in the basic block, in order to do this replacement during the second step of the - * algorithm, where the frames are fully computed. Note that this array can contain abstract types - * that are relative to the input locals or to the input stack. - */ - private int[] initializations; - - // ----------------------------------------------------------------------------------------------- - // Static methods to get abstract types from other type formats - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the abstract type corresponding to the given public API frame element type. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param type a frame element type described using the same format as in {@link - * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or - * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating - * a NEW instruction (for uninitialized types). - * @return the abstract type corresponding to the given frame element type. - */ - static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) { - if (type instanceof Integer) { - return CONSTANT_KIND | ((Integer) type).intValue(); - } else if (type instanceof String) { - String descriptor = Type.getObjectType((String) type).getDescriptor(); - return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0); - } else { - return UNINITIALIZED_KIND - | symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset); - } - } - - /** - * Returns the abstract type corresponding to the internal name of a class. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param internalName the internal name of a class. This must not be an array type - * descriptor. - * @return the abstract type value corresponding to the given internal name. - */ - static int getAbstractTypeFromInternalName( - final SymbolTable symbolTable, final String internalName) { - return REFERENCE_KIND | symbolTable.addType(internalName); - } - - /** - * Returns the abstract type corresponding to the given type descriptor. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param buffer a string ending with a type descriptor. - * @param offset the start offset of the type descriptor in buffer. - * @return the abstract type corresponding to the given type descriptor. - */ - private static int getAbstractTypeFromDescriptor( - final SymbolTable symbolTable, final String buffer, final int offset) { - String internalName; - switch (buffer.charAt(offset)) { - case 'V': - return 0; - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - return INTEGER; - case 'F': - return FLOAT; - case 'J': - return LONG; - case 'D': - return DOUBLE; - case 'L': - internalName = buffer.substring(offset + 1, buffer.length() - 1); - return REFERENCE_KIND | symbolTable.addType(internalName); - case '[': - int elementDescriptorOffset = offset + 1; - while (buffer.charAt(elementDescriptorOffset) == '[') { - ++elementDescriptorOffset; - } - int typeValue; - switch (buffer.charAt(elementDescriptorOffset)) { - case 'Z': - typeValue = BOOLEAN; - break; - case 'C': - typeValue = CHAR; - break; - case 'B': - typeValue = BYTE; - break; - case 'S': - typeValue = SHORT; - break; - case 'I': - typeValue = INTEGER; - break; - case 'F': - typeValue = FLOAT; - break; - case 'J': - typeValue = LONG; - break; - case 'D': - typeValue = DOUBLE; - break; - case 'L': - internalName = buffer.substring(elementDescriptorOffset + 1, buffer.length() - 1); - typeValue = REFERENCE_KIND | symbolTable.addType(internalName); - break; - default: - throw new IllegalArgumentException(); - } - return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue; - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new Frame. - * - * @param owner the basic block to which these input and output stack map frames correspond. - */ - Frame(final Label owner) { - this.owner = owner; - } - - /** - * Sets this frame to the value of the given frame. - * - *

WARNING: after this method is called the two frames share the same data structures. It is - * recommended to discard the given frame to avoid unexpected side effects. - * - * @param frame The new frame value. - */ - final void copyFrom(final Frame frame) { - inputLocals = frame.inputLocals; - inputStack = frame.inputStack; - outputStackStart = 0; - outputLocals = frame.outputLocals; - outputStack = frame.outputStack; - outputStackTop = frame.outputStackTop; - initializationCount = frame.initializationCount; - initializations = frame.initializations; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to the input frame - // ----------------------------------------------------------------------------------------------- - - /** - * Sets the input frame from the given method description. This method is used to initialize the - * first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable - * attribute). - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param access the method's access flags. - * @param descriptor the method descriptor. - * @param maxLocals the maximum number of local variables of the method. - */ - final void setInputFrameFromDescriptor( - final SymbolTable symbolTable, - final int access, - final String descriptor, - final int maxLocals) { - inputLocals = new int[maxLocals]; - inputStack = new int[0]; - int inputLocalIndex = 0; - if ((access & Opcodes.ACC_STATIC) == 0) { - if ((access & Constants.ACC_CONSTRUCTOR) == 0) { - inputLocals[inputLocalIndex++] = - REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); - } else { - inputLocals[inputLocalIndex++] = UNINITIALIZED_THIS; - } - } - for (Type argumentType : Type.getArgumentTypes(descriptor)) { - int abstractType = - getAbstractTypeFromDescriptor(symbolTable, argumentType.getDescriptor(), 0); - inputLocals[inputLocalIndex++] = abstractType; - if (abstractType == LONG || abstractType == DOUBLE) { - inputLocals[inputLocalIndex++] = TOP; - } - } - while (inputLocalIndex < maxLocals) { - inputLocals[inputLocalIndex++] = TOP; - } - } - - /** - * Sets the input frame from the given public API frame description. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param nLocal the number of local variables. - * @param local the local variable types, described using the same format as in {@link - * MethodVisitor#visitFrame}. - * @param nStack the number of operand stack elements. - * @param stack the operand stack types, described using the same format as in {@link - * MethodVisitor#visitFrame}. - */ - final void setInputFrameFromApiFormat( - final SymbolTable symbolTable, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - int inputLocalIndex = 0; - for (int i = 0; i < nLocal; ++i) { - inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]); - if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) { - inputLocals[inputLocalIndex++] = TOP; - } - } - while (inputLocalIndex < inputLocals.length) { - inputLocals[inputLocalIndex++] = TOP; - } - int nStackTop = 0; - for (int i = 0; i < nStack; ++i) { - if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { - ++nStackTop; - } - } - inputStack = new int[nStack + nStackTop]; - int inputStackIndex = 0; - for (int i = 0; i < nStack; ++i) { - inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]); - if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { - inputStack[inputStackIndex++] = TOP; - } - } - outputStackTop = 0; - initializationCount = 0; - } - - final int getInputStackSize() { - return inputStack.length; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to the output frame - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the abstract type stored at the given local variable index in the output frame. - * - * @param localIndex the index of the local variable whose value must be returned. - * @return the abstract type stored at the given local variable index in the output frame. - */ - private int getLocal(final int localIndex) { - if (outputLocals == null || localIndex >= outputLocals.length) { - // If this local has never been assigned in this basic block, it is still equal to its value - // in the input frame. - return LOCAL_KIND | localIndex; - } else { - int abstractType = outputLocals[localIndex]; - if (abstractType == 0) { - // If this local has never been assigned in this basic block, so it is still equal to its - // value in the input frame. - abstractType = outputLocals[localIndex] = LOCAL_KIND | localIndex; - } - return abstractType; - } - } - - /** - * Replaces the abstract type stored at the given local variable index in the output frame. - * - * @param localIndex the index of the output frame local variable that must be set. - * @param abstractType the value that must be set. - */ - private void setLocal(final int localIndex, final int abstractType) { - // Create and/or resize the output local variables array if necessary. - if (outputLocals == null) { - outputLocals = new int[10]; - } - int outputLocalsLength = outputLocals.length; - if (localIndex >= outputLocalsLength) { - int[] newOutputLocals = new int[Math.max(localIndex + 1, 2 * outputLocalsLength)]; - System.arraycopy(outputLocals, 0, newOutputLocals, 0, outputLocalsLength); - outputLocals = newOutputLocals; - } - // Set the local variable. - outputLocals[localIndex] = abstractType; - } - - /** - * Pushes the given abstract type on the output frame stack. - * - * @param abstractType an abstract type. - */ - private void push(final int abstractType) { - // Create and/or resize the output stack array if necessary. - if (outputStack == null) { - outputStack = new int[10]; - } - int outputStackLength = outputStack.length; - if (outputStackTop >= outputStackLength) { - int[] newOutputStack = new int[Math.max(outputStackTop + 1, 2 * outputStackLength)]; - System.arraycopy(outputStack, 0, newOutputStack, 0, outputStackLength); - outputStack = newOutputStack; - } - // Pushes the abstract type on the output stack. - outputStack[outputStackTop++] = abstractType; - // Updates the maximum size reached by the output stack, if needed (note that this size is - // relative to the input stack size, which is not known yet). - short outputStackSize = (short) (outputStackStart + outputStackTop); - if (outputStackSize > owner.outputStackMax) { - owner.outputStackMax = outputStackSize; - } - } - - /** - * Pushes the abstract type corresponding to the given descriptor on the output frame stack. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param descriptor a type or method descriptor (in which case its return type is pushed). - */ - private void push(final SymbolTable symbolTable, final String descriptor) { - int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0; - int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset); - if (abstractType != 0) { - push(abstractType); - if (abstractType == LONG || abstractType == DOUBLE) { - push(TOP); - } - } - } - - /** - * Pops an abstract type from the output frame stack and returns its value. - * - * @return the abstract type that has been popped from the output frame stack. - */ - private int pop() { - if (outputStackTop > 0) { - return outputStack[--outputStackTop]; - } else { - // If the output frame stack is empty, pop from the input stack. - return STACK_KIND | -(--outputStackStart); - } - } - - /** - * Pops the given number of abstract types from the output frame stack. - * - * @param elements the number of abstract types that must be popped. - */ - private void pop(final int elements) { - if (outputStackTop >= elements) { - outputStackTop -= elements; - } else { - // If the number of elements to be popped is greater than the number of elements in the output - // stack, clear it, and pop the remaining elements from the input stack. - outputStackStart -= elements - outputStackTop; - outputStackTop = 0; - } - } - - /** - * Pops as many abstract types from the output frame stack as described by the given descriptor. - * - * @param descriptor a type or method descriptor (in which case its argument types are popped). - */ - private void pop(final String descriptor) { - char firstDescriptorChar = descriptor.charAt(0); - if (firstDescriptorChar == '(') { - pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1); - } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { - pop(2); - } else { - pop(1); - } - } - - // ----------------------------------------------------------------------------------------------- - // Methods to handle uninitialized types - // ----------------------------------------------------------------------------------------------- - - /** - * Adds an abstract type to the list of types on which a constructor is invoked in the basic - * block. - * - * @param abstractType an abstract type on a which a constructor is invoked. - */ - private void addInitializedType(final int abstractType) { - // Create and/or resize the initializations array if necessary. - if (initializations == null) { - initializations = new int[2]; - } - int initializationsLength = initializations.length; - if (initializationCount >= initializationsLength) { - int[] newInitializations = - new int[Math.max(initializationCount + 1, 2 * initializationsLength)]; - System.arraycopy(initializations, 0, newInitializations, 0, initializationsLength); - initializations = newInitializations; - } - // Store the abstract type. - initializations[initializationCount++] = abstractType; - } - - /** - * Returns the "initialized" abstract type corresponding to the given abstract type. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param abstractType an abstract type. - * @return the REFERENCE_KIND abstract type corresponding to abstractType if it is - * UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a - * constructor is invoked in the basic block. Otherwise returns abstractType. - */ - private int getInitializedType(final SymbolTable symbolTable, final int abstractType) { - if (abstractType == UNINITIALIZED_THIS - || (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND) { - for (int i = 0; i < initializationCount; ++i) { - int initializedType = initializations[i]; - int dim = initializedType & DIM_MASK; - int kind = initializedType & KIND_MASK; - int value = initializedType & VALUE_MASK; - if (kind == LOCAL_KIND) { - initializedType = dim + inputLocals[value]; - } else if (kind == STACK_KIND) { - initializedType = dim + inputStack[inputStack.length - value]; - } - if (abstractType == initializedType) { - if (abstractType == UNINITIALIZED_THIS) { - return REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); - } else { - return REFERENCE_KIND - | symbolTable.addType(symbolTable.getType(abstractType & VALUE_MASK).value); - } - } - } - } - return abstractType; - } - - // ----------------------------------------------------------------------------------------------- - // Main method, to simulate the execution of each instruction on the output frame - // ----------------------------------------------------------------------------------------------- - - /** - * Simulates the action of the given instruction on the output stack frame. - * - * @param opcode the opcode of the instruction. - * @param arg the numeric operand of the instruction, if any. - * @param argSymbol the Symbol operand of the instruction, if any. - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - */ - void execute( - final int opcode, final int arg, final Symbol argSymbol, final SymbolTable symbolTable) { - // Abstract types popped from the stack or read from local variables. - int abstractType1; - int abstractType2; - int abstractType3; - int abstractType4; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.GOTO: - case Opcodes.RETURN: - break; - case Opcodes.ACONST_NULL: - push(NULL); - break; - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - case Opcodes.ILOAD: - push(INTEGER); - break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.LLOAD: - push(LONG); - push(TOP); - break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.FLOAD: - push(FLOAT); - break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.DLOAD: - push(DOUBLE); - push(TOP); - break; - case Opcodes.LDC: - switch (argSymbol.tag) { - case Symbol.CONSTANT_INTEGER_TAG: - push(INTEGER); - break; - case Symbol.CONSTANT_LONG_TAG: - push(LONG); - push(TOP); - break; - case Symbol.CONSTANT_FLOAT_TAG: - push(FLOAT); - break; - case Symbol.CONSTANT_DOUBLE_TAG: - push(DOUBLE); - push(TOP); - break; - case Symbol.CONSTANT_CLASS_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/Class")); - break; - case Symbol.CONSTANT_STRING_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/String")); - break; - case Symbol.CONSTANT_METHOD_TYPE_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodType")); - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodHandle")); - break; - default: - throw new AssertionError(); - } - break; - case Opcodes.ALOAD: - push(getLocal(arg)); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(LONG); - push(TOP); - break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(DOUBLE); - push(TOP); - break; - case Opcodes.AALOAD: - pop(1); - abstractType1 = pop(); - push(abstractType1 == NULL ? abstractType1 : ELEMENT_OF + abstractType1); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - abstractType1 = pop(); - setLocal(arg, abstractType1); - if (arg > 0) { - int previousLocalType = getLocal(arg - 1); - if (previousLocalType == LONG || previousLocalType == DOUBLE) { - setLocal(arg - 1, TOP); - } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND - || (previousLocalType & KIND_MASK) == STACK_KIND) { - // The type of the previous local variable is not known yet, but if it later appears - // to be LONG or DOUBLE, we should then use TOP instead. - setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); - } - } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - abstractType1 = pop(); - setLocal(arg, abstractType1); - setLocal(arg + 1, TOP); - if (arg > 0) { - int previousLocalType = getLocal(arg - 1); - if (previousLocalType == LONG || previousLocalType == DOUBLE) { - setLocal(arg - 1, TOP); - } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND - || (previousLocalType & KIND_MASK) == STACK_KIND) { - // The type of the previous local variable is not known yet, but if it later appears - // to be LONG or DOUBLE, we should then use TOP instead. - setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); - } - } - break; - case Opcodes.IASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.FASTORE: - case Opcodes.AASTORE: - pop(3); - break; - case Opcodes.LASTORE: - case Opcodes.DASTORE: - pop(4); - break; - case Opcodes.POP: - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IRETURN: - case Opcodes.FRETURN: - case Opcodes.ARETURN: - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - pop(1); - break; - case Opcodes.POP2: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.LRETURN: - case Opcodes.DRETURN: - pop(2); - break; - case Opcodes.DUP: - abstractType1 = pop(); - push(abstractType1); - push(abstractType1); - break; - case Opcodes.DUP_X1: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType1); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP_X2: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - push(abstractType1); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2_X1: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2_X2: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - abstractType4 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType4); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.SWAP: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType1); - push(abstractType2); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - case Opcodes.IADD: - case Opcodes.ISUB: - case Opcodes.IMUL: - case Opcodes.IDIV: - case Opcodes.IREM: - case Opcodes.IAND: - case Opcodes.IOR: - case Opcodes.IXOR: - case Opcodes.ISHL: - case Opcodes.ISHR: - case Opcodes.IUSHR: - case Opcodes.L2I: - case Opcodes.D2I: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - pop(2); - push(INTEGER); - break; - case Opcodes.LADD: - case Opcodes.LSUB: - case Opcodes.LMUL: - case Opcodes.LDIV: - case Opcodes.LREM: - case Opcodes.LAND: - case Opcodes.LOR: - case Opcodes.LXOR: - pop(4); - push(LONG); - push(TOP); - break; - case Opcodes.FALOAD: - case Opcodes.FADD: - case Opcodes.FSUB: - case Opcodes.FMUL: - case Opcodes.FDIV: - case Opcodes.FREM: - case Opcodes.L2F: - case Opcodes.D2F: - pop(2); - push(FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(DOUBLE); - push(TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(LONG); - push(TOP); - break; - case Opcodes.IINC: - setLocal(arg, INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(LONG); - push(TOP); - break; - case Opcodes.I2F: - pop(1); - push(FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(DOUBLE); - push(TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new IllegalArgumentException("JSR/RET are not supported with computeFrames option"); - case Opcodes.GETSTATIC: - push(symbolTable, argSymbol.value); - break; - case Opcodes.PUTSTATIC: - pop(argSymbol.value); - break; - case Opcodes.GETFIELD: - pop(1); - push(symbolTable, argSymbol.value); - break; - case Opcodes.PUTFIELD: - pop(argSymbol.value); - pop(); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - pop(argSymbol.value); - if (opcode != Opcodes.INVOKESTATIC) { - abstractType1 = pop(); - if (opcode == Opcodes.INVOKESPECIAL && argSymbol.name.charAt(0) == '<') { - addInitializedType(abstractType1); - } - } - push(symbolTable, argSymbol.value); - break; - case Opcodes.INVOKEDYNAMIC: - pop(argSymbol.value); - push(symbolTable, argSymbol.value); - break; - case Opcodes.NEW: - push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg)); - break; - case Opcodes.NEWARRAY: - pop(); - switch (arg) { - case Opcodes.T_BOOLEAN: - push(ARRAY_OF | BOOLEAN); - break; - case Opcodes.T_CHAR: - push(ARRAY_OF | CHAR); - break; - case Opcodes.T_BYTE: - push(ARRAY_OF | BYTE); - break; - case Opcodes.T_SHORT: - push(ARRAY_OF | SHORT); - break; - case Opcodes.T_INT: - push(ARRAY_OF | INTEGER); - break; - case Opcodes.T_FLOAT: - push(ARRAY_OF | FLOAT); - break; - case Opcodes.T_DOUBLE: - push(ARRAY_OF | DOUBLE); - break; - case Opcodes.T_LONG: - push(ARRAY_OF | LONG); - break; - default: - throw new IllegalArgumentException(); - } - break; - case Opcodes.ANEWARRAY: - String arrayElementType = argSymbol.value; - pop(); - if (arrayElementType.charAt(0) == '[') { - push(symbolTable, '[' + arrayElementType); - } else { - push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType)); - } - break; - case Opcodes.CHECKCAST: - String castType = argSymbol.value; - pop(); - if (castType.charAt(0) == '[') { - push(symbolTable, castType); - } else { - push(REFERENCE_KIND | symbolTable.addType(castType)); - } - break; - case Opcodes.MULTIANEWARRAY: - pop(arg); - push(symbolTable, argSymbol.value); - break; - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Frame merging methods, used in the second step of the stack map frame computation algorithm - // ----------------------------------------------------------------------------------------------- - - /** - * Merges the input frame of the given {@link Frame} with the input and output frames of this - * {@link Frame}. Returns true if the given frame has been changed by this operation (the - * input and output frames of this {@link Frame} are never changed). - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param dstFrame the {@link Frame} whose input frame must be updated. This should be the frame - * of a successor, in the control flow graph, of the basic block corresponding to this frame. - * @param catchTypeIndex if 'frame' corresponds to an exception handler basic block, the type - * table index of the caught exception type, otherwise 0. - * @return true if the input frame of 'frame' has been changed by this operation. - */ - final boolean merge( - final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) { - boolean frameChanged = false; - - // Compute the concrete types of the local variables at the end of the basic block corresponding - // to this frame, by resolving its abstract output types, and merge these concrete types with - // those of the local variables in the input frame of dstFrame. - int nLocal = inputLocals.length; - int nStack = inputStack.length; - if (dstFrame.inputLocals == null) { - dstFrame.inputLocals = new int[nLocal]; - frameChanged = true; - } - for (int i = 0; i < nLocal; ++i) { - int concreteOutputType; - if (outputLocals != null && i < outputLocals.length) { - int abstractOutputType = outputLocals[i]; - if (abstractOutputType == 0) { - // If the local variable has never been assigned in this basic block, it is equal to its - // value at the beginning of the block. - concreteOutputType = inputLocals[i]; - } else { - int dim = abstractOutputType & DIM_MASK; - int kind = abstractOutputType & KIND_MASK; - if (kind == LOCAL_KIND) { - // By definition, a LOCAL_KIND type designates the concrete type of a local variable at - // the beginning of the basic block corresponding to this frame (which is known when - // this method is called, but was not when the abstract type was computed). - concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else if (kind == STACK_KIND) { - // By definition, a STACK_KIND type designates the concrete type of a local variable at - // the beginning of the basic block corresponding to this frame (which is known when - // this method is called, but was not when the abstract type was computed). - concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else { - concreteOutputType = abstractOutputType; - } - } - } else { - // If the local variable has never been assigned in this basic block, it is equal to its - // value at the beginning of the block. - concreteOutputType = inputLocals[i]; - } - // concreteOutputType might be an uninitialized type from the input locals or from the input - // stack. However, if a constructor has been called for this class type in the basic block, - // then this type is no longer uninitialized at the end of basic block. - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i); - } - - // If dstFrame is an exception handler block, it can be reached from any instruction of the - // basic block corresponding to this frame, in particular from the first one. Therefore, the - // input locals of dstFrame should be compatible (i.e. merged) with the input locals of this - // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one - // element stack containing the caught exception type). - if (catchTypeIndex > 0) { - for (int i = 0; i < nLocal; ++i) { - frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i); - } - if (dstFrame.inputStack == null) { - dstFrame.inputStack = new int[1]; - frameChanged = true; - } - frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0); - return frameChanged; - } - - // Compute the concrete types of the stack operands at the end of the basic block corresponding - // to this frame, by resolving its abstract output types, and merge these concrete types with - // those of the stack operands in the input frame of dstFrame. - int nInputStack = inputStack.length + outputStackStart; - if (dstFrame.inputStack == null) { - dstFrame.inputStack = new int[nInputStack + outputStackTop]; - frameChanged = true; - } - // First, do this for the stack operands that have not been popped in the basic block - // corresponding to this frame, and which are therefore equal to their value in the input - // frame (except for uninitialized types, which may have been initialized). - for (int i = 0; i < nInputStack; ++i) { - int concreteOutputType = inputStack[i]; - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i); - } - // Then, do this for the stack operands that have pushed in the basic block (this code is the - // same as the one above for local variables). - for (int i = 0; i < outputStackTop; ++i) { - int concreteOutputType; - int abstractOutputType = outputStack[i]; - int dim = abstractOutputType & DIM_MASK; - int kind = abstractOutputType & KIND_MASK; - if (kind == LOCAL_KIND) { - concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else if (kind == STACK_KIND) { - concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else { - concreteOutputType = abstractOutputType; - } - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, nInputStack + i); - } - return frameChanged; - } - - /** - * Merges the type at the given index in the given abstract type array with the given type. - * Returns true if the type array has been modified by this operation. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param sourceType the abstract type with which the abstract type array element must be merged. - * This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link - * #UNINITIALIZED_KIND} kind, with positive or null array dimensions. - * @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND}, - * {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array - * dimensions. - * @param dstIndex the index of the type that must be merged in dstTypes. - * @return true if the type array has been modified by this operation. - */ - private static boolean merge( - final SymbolTable symbolTable, - final int sourceType, - final int[] dstTypes, - final int dstIndex) { - int dstType = dstTypes[dstIndex]; - if (dstType == sourceType) { - // If the types are equal, merge(sourceType, dstType) = dstType, so there is no change. - return false; - } - int srcType = sourceType; - if ((sourceType & ~DIM_MASK) == NULL) { - if (dstType == NULL) { - return false; - } - srcType = NULL; - } - if (dstType == 0) { - // If dstTypes[dstIndex] has never been assigned, merge(srcType, dstType) = srcType. - dstTypes[dstIndex] = srcType; - return true; - } - int mergedType; - if ((dstType & DIM_MASK) != 0 || (dstType & KIND_MASK) == REFERENCE_KIND) { - // If dstType is a reference type of any array dimension. - if (srcType == NULL) { - // If srcType is the NULL type, merge(srcType, dstType) = dstType, so there is no change. - return false; - } else if ((srcType & (DIM_MASK | KIND_MASK)) == (dstType & (DIM_MASK | KIND_MASK))) { - // If srcType has the same array dimension and the same kind as dstType. - if ((dstType & KIND_MASK) == REFERENCE_KIND) { - // If srcType and dstType are reference types with the same array dimension, - // merge(srcType, dstType) = dim(srcType) | common super class of srcType and dstType. - mergedType = - (srcType & DIM_MASK) - | REFERENCE_KIND - | symbolTable.addMergedType(srcType & VALUE_MASK, dstType & VALUE_MASK); - } else { - // If srcType and dstType are array types of equal dimension but different element types, - // merge(srcType, dstType) = dim(srcType) - 1 | java/lang/Object. - int mergedDim = ELEMENT_OF + (srcType & DIM_MASK); - mergedType = mergedDim | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); - } - } else if ((srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND) { - // If srcType is any other reference or array type, - // merge(srcType, dstType) = min(srcDdim, dstDim) | java/lang/Object - // where srcDim is the array dimension of srcType, minus 1 if srcType is an array type - // with a non reference element type (and similarly for dstDim). - int srcDim = srcType & DIM_MASK; - if (srcDim != 0 && (srcType & KIND_MASK) != REFERENCE_KIND) { - srcDim = ELEMENT_OF + srcDim; - } - int dstDim = dstType & DIM_MASK; - if (dstDim != 0 && (dstType & KIND_MASK) != REFERENCE_KIND) { - dstDim = ELEMENT_OF + dstDim; - } - mergedType = - Math.min(srcDim, dstDim) | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); - } else { - // If srcType is any other type, merge(srcType, dstType) = TOP. - mergedType = TOP; - } - } else if (dstType == NULL) { - // If dstType is the NULL type, merge(srcType, dstType) = srcType, or TOP if srcType is not a - // an array type or a reference type. - mergedType = - (srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND ? srcType : TOP; - } else { - // If dstType is any other type, merge(srcType, dstType) = TOP whatever srcType. - mergedType = TOP; - } - if (mergedType != dstType) { - dstTypes[dstIndex] = mergedType; - return true; - } - return false; - } - - // ----------------------------------------------------------------------------------------------- - // Frame output methods, to generate StackMapFrame attributes - // ----------------------------------------------------------------------------------------------- - - /** - * Makes the given {@link MethodWriter} visit the input frame of this {@link Frame}. The visit is - * done with the {@link MethodWriter#visitFrameStart}, {@link MethodWriter#visitAbstractType} and - * {@link MethodWriter#visitFrameEnd} methods. - * - * @param methodWriter the {@link MethodWriter} that should visit the input frame of this {@link - * Frame}. - */ - final void accept(final MethodWriter methodWriter) { - // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and - // all trailing TOP types. - int[] localTypes = inputLocals; - int nLocal = 0; - int nTrailingTop = 0; - int i = 0; - while (i < localTypes.length) { - int localType = localTypes[i]; - i += (localType == LONG || localType == DOUBLE) ? 2 : 1; - if (localType == TOP) { - nTrailingTop++; - } else { - nLocal += nTrailingTop + 1; - nTrailingTop = 0; - } - } - // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE. - int[] stackTypes = inputStack; - int nStack = 0; - i = 0; - while (i < stackTypes.length) { - int stackType = stackTypes[i]; - i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; - nStack++; - } - // Visit the frame and its content. - int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, nLocal, nStack); - i = 0; - while (nLocal-- > 0) { - int localType = localTypes[i]; - i += (localType == LONG || localType == DOUBLE) ? 2 : 1; - methodWriter.visitAbstractType(frameIndex++, localType); - } - i = 0; - while (nStack-- > 0) { - int stackType = stackTypes[i]; - i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; - methodWriter.visitAbstractType(frameIndex++, stackType); - } - methodWriter.visitFrameEnd(); - } - - /** - * Put the given abstract type in the given ByteVector, using the JVMS verification_type_info - * format used in StackMapTable attributes. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link - * Frame#REFERENCE_KIND} or {@link Frame#UNINITIALIZED_KIND} types. - * @param output where the abstract type must be put. - * @see JVMS - * 4.7.4 - */ - static void putAbstractType( - final SymbolTable symbolTable, final int abstractType, final ByteVector output) { - int arrayDimensions = (abstractType & Frame.DIM_MASK) >> DIM_SHIFT; - if (arrayDimensions == 0) { - int typeValue = abstractType & VALUE_MASK; - switch (abstractType & KIND_MASK) { - case CONSTANT_KIND: - output.putByte(typeValue); - break; - case REFERENCE_KIND: - output - .putByte(ITEM_OBJECT) - .putShort(symbolTable.addConstantClass(symbolTable.getType(typeValue).value).index); - break; - case UNINITIALIZED_KIND: - output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data); - break; - default: - throw new AssertionError(); - } - } else { - // Case of an array type, we need to build its descriptor first. - StringBuilder typeDescriptor = new StringBuilder(); - while (arrayDimensions-- > 0) { - typeDescriptor.append('['); - } - if ((abstractType & KIND_MASK) == REFERENCE_KIND) { - typeDescriptor - .append('L') - .append(symbolTable.getType(abstractType & VALUE_MASK).value) - .append(';'); - } else { - switch (abstractType & VALUE_MASK) { - case Frame.ITEM_ASM_BOOLEAN: - typeDescriptor.append('Z'); - break; - case Frame.ITEM_ASM_BYTE: - typeDescriptor.append('B'); - break; - case Frame.ITEM_ASM_CHAR: - typeDescriptor.append('C'); - break; - case Frame.ITEM_ASM_SHORT: - typeDescriptor.append('S'); - break; - case Frame.ITEM_INTEGER: - typeDescriptor.append('I'); - break; - case Frame.ITEM_FLOAT: - typeDescriptor.append('F'); - break; - case Frame.ITEM_LONG: - typeDescriptor.append('J'); - break; - case Frame.ITEM_DOUBLE: - typeDescriptor.append('D'); - break; - default: - throw new AssertionError(); - } - } - output - .putByte(ITEM_OBJECT) - .putShort(symbolTable.addConstantClass(typeDescriptor.toString()).index); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Handle.java b/src/main/java/org/objectweb/asm/Handle.java deleted file mode 100644 index d475f10c..00000000 --- a/src/main/java/org/objectweb/asm/Handle.java +++ /dev/null @@ -1,197 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * A reference to a field or a method. - * - * @author Remi Forax - * @author Eric Bruneton - */ -public final class Handle { - - /** - * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - final int tag; - - /** - * The internal name of the class that owns the field or method designated by this handle. - */ - final String owner; - - /** - * The name of the field or method designated by this handle. - */ - final String name; - - /** - * The descriptor of the field or method designated by this handle. - */ - final String descriptor; - - /** - * Whether the owner is an interface or not. - */ - final boolean isInterface; - - /** - * Constructs a new field or method handle. - * - * @param tag the kind of field or method designated by this Handle. Must be {@link - * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link - * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link - * Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the class that owns the field or method designated by this - * handle. - * @param name the name of the field or method designated by this handle. - * @param descriptor the descriptor of the field or method designated by this handle. - * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String, - * boolean)}. - */ - @Deprecated - public Handle(final int tag, final String owner, final String name, final String descriptor) { - this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); - } - - /** - * Constructs a new field or method handle. - * - * @param tag the kind of field or method designated by this Handle. Must be {@link - * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link - * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link - * Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the class that owns the field or method designated by this - * handle. - * @param name the name of the field or method designated by this handle. - * @param descriptor the descriptor of the field or method designated by this handle. - * @param isInterface whether the owner is an interface or not. - */ - public Handle( - final int tag, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - this.tag = tag; - this.owner = owner; - this.name = name; - this.descriptor = descriptor; - this.isInterface = isInterface; - } - - /** - * Returns the kind of field or method designated by this handle. - * - * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, - * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - public int getTag() { - return tag; - } - - /** - * Returns the internal name of the class that owns the field or method designated by this handle. - * - * @return the internal name of the class that owns the field or method designated by this handle. - */ - public String getOwner() { - return owner; - } - - /** - * Returns the name of the field or method designated by this handle. - * - * @return the name of the field or method designated by this handle. - */ - public String getName() { - return name; - } - - /** - * Returns the descriptor of the field or method designated by this handle. - * - * @return the descriptor of the field or method designated by this handle. - */ - public String getDesc() { - return descriptor; - } - - /** - * Returns true if the owner of the field or method designated by this handle is an interface. - * - * @return true if the owner of the field or method designated by this handle is an interface. - */ - public boolean isInterface() { - return isInterface; - } - - @Override - public boolean equals(final Object object) { - if (object == this) { - return true; - } - if (!(object instanceof Handle)) { - return false; - } - Handle handle = (Handle) object; - return tag == handle.tag - && isInterface == handle.isInterface - && owner.equals(handle.owner) - && name.equals(handle.name) - && descriptor.equals(handle.descriptor); - } - - @Override - public int hashCode() { - return tag - + (isInterface ? 64 : 0) - + owner.hashCode() * name.hashCode() * descriptor.hashCode(); - } - - /** - * Returns the textual representation of this handle. The textual representation is: - * - *

    - *
  • for a reference to a class: owner "." name descriptor " (" tag ")", - *
  • for a reference to an interface: owner "." name descriptor " (" tag " itf)". - *
- */ - @Override - public String toString() { - return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')'; - } -} diff --git a/src/main/java/org/objectweb/asm/Handler.java b/src/main/java/org/objectweb/asm/Handler.java deleted file mode 100644 index c5d34585..00000000 --- a/src/main/java/org/objectweb/asm/Handler.java +++ /dev/null @@ -1,200 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * Information about an exception handler. Corresponds to an element of the exception_table array of - * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances - * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS - * exception_table array. - * - * @author Eric Bruneton - * @see JVMS - * 4.7.3 - */ -final class Handler { - - /** - * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the - * exception handler's scope (inclusive). - */ - final Label startPc; - - /** - * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception - * handler's scope (exclusive). - */ - final Label endPc; - - /** - * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the - * exception handler's code. - */ - final Label handlerPc; - - /** - * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the - * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions. - */ - final int catchType; - - /** - * The internal name of the type of exceptions handled by this handler, or null to catch - * any exceptions. - */ - final String catchTypeDescriptor; - - /** - * The next exception handler. - */ - Handler nextHandler; - - /** - * Constructs a new Handler. - * - * @param startPc the start_pc field of this JVMS exception_table entry. - * @param endPc the end_pc field of this JVMS exception_table entry. - * @param handlerPc the handler_pc field of this JVMS exception_table entry. - * @param catchType The catch_type field of this JVMS exception_table entry. - * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler, - * or null to catch any exceptions. - */ - Handler( - final Label startPc, - final Label endPc, - final Label handlerPc, - final int catchType, - final String catchTypeDescriptor) { - this.startPc = startPc; - this.endPc = endPc; - this.handlerPc = handlerPc; - this.catchType = catchType; - this.catchTypeDescriptor = catchTypeDescriptor; - } - - /** - * Constructs a new Handler from the given one, with a different scope. - * - * @param handler an existing Handler. - * @param startPc the start_pc field of this JVMS exception_table entry. - * @param endPc the end_pc field of this JVMS exception_table entry. - */ - Handler(final Handler handler, final Label startPc, final Label endPc) { - this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor); - this.nextHandler = handler.nextHandler; - } - - /** - * Removes the range between start and end from the Handler list that begins with the given - * element. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @param start the start of the range to be removed. - * @param end the end of the range to be removed. Maybe null. - * @return the exception handler list with the start-end range removed. - */ - static Handler removeRange(final Handler firstHandler, final Label start, final Label end) { - if (firstHandler == null) { - return null; - } else { - firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end); - } - int handlerStart = firstHandler.startPc.bytecodeOffset; - int handlerEnd = firstHandler.endPc.bytecodeOffset; - int rangeStart = start.bytecodeOffset; - int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset; - // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect. - if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { - return firstHandler; - } - if (rangeStart <= handlerStart) { - if (rangeEnd >= handlerEnd) { - // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler. - return firstHandler.nextHandler; - } else { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[ - return new Handler(firstHandler, end, firstHandler.endPc); - } - } else if (rangeEnd >= handlerEnd) { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[ - return new Handler(firstHandler, firstHandler.startPc, start); - } else { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = - // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[ - firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc); - return new Handler(firstHandler, firstHandler.startPc, start); - } - } - - /** - * Returns the number of elements of the Handler list that begins with the given element. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @return the number of elements of the Handler list that begins with 'handler'. - */ - static int getExceptionTableLength(final Handler firstHandler) { - int length = 0; - Handler handler = firstHandler; - while (handler != null) { - length++; - handler = handler.nextHandler; - } - return length; - } - - /** - * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that - * begins with the given element. This includes the exception_table_length field. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @return the size in bytes of the exception_table_length and exception_table structures. - */ - static int getExceptionTableSize(final Handler firstHandler) { - return 2 + 8 * getExceptionTableLength(firstHandler); - } - - /** - * Puts the JVMS exception_table corresponding to the Handler list that begins with the given - * element. This includes the exception_table_length field. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @param output where the exception_table_length and exception_table structures must be put. - */ - static void putExceptionTable(final Handler firstHandler, final ByteVector output) { - output.putShort(getExceptionTableLength(firstHandler)); - Handler handler = firstHandler; - while (handler != null) { - output - .putShort(handler.startPc.bytecodeOffset) - .putShort(handler.endPc.bytecodeOffset) - .putShort(handler.handlerPc.bytecodeOffset) - .putShort(handler.catchType); - handler = handler.nextHandler; - } - } -} diff --git a/src/main/java/org/objectweb/asm/Label.java b/src/main/java/org/objectweb/asm/Label.java deleted file mode 100644 index c75a406e..00000000 --- a/src/main/java/org/objectweb/asm/Label.java +++ /dev/null @@ -1,673 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions, - * and for try catch blocks. A label designates the instruction that is just after. Note - * however that there can be other elements between a label and the instruction it designates (such - * as other labels, stack map frames, line numbers, etc.). - * - * @author Eric Bruneton - */ -public class Label { - - /** - * A flag indicating that a label is only used for debug attributes. Such a label is not the start - * of a basic block, the target of a jump instruction, or an exception handler. It can be safely - * ignored in control flow graph analysis algorithms (for optimization purposes). - */ - static final int FLAG_DEBUG_ONLY = 1; - - /** - * A flag indicating that a label is the target of a jump instruction, or the start of an - * exception handler. - */ - static final int FLAG_JUMP_TARGET = 2; - - /** - * A flag indicating that the bytecode offset of a label is known. - */ - static final int FLAG_RESOLVED = 4; - - /** - * A flag indicating that a label corresponds to a reachable basic block. - */ - static final int FLAG_REACHABLE = 8; - - /** - * A flag indicating that the basic block corresponding to a label ends with a subroutine call. By - * construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two - * outgoing edges: - * - *
    - *
  • the first one corresponds to the instruction that follows the jsr instruction in the - * bytecode, i.e. where execution continues when it returns from the jsr call. This is a - * virtual control flow edge, since execution never goes directly from the jsr to the next - * instruction. Instead, it goes to the subroutine and eventually returns to the instruction - * following the jsr. This virtual edge is used to compute the real outgoing edges of the - * basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}. - *
  • the second one corresponds to the target of the jsr instruction, - *
- */ - static final int FLAG_SUBROUTINE_CALLER = 16; - - /** - * A flag indicating that the basic block corresponding to a label is the start of a subroutine. - */ - static final int FLAG_SUBROUTINE_START = 32; - - /** - * A flag indicating that the basic block corresponding to a label is part of a subroutine. - */ - static final int FLAG_SUBROUTINE_BODY = 64; - - /** - * A flag indicating that the basic block corresponding to a label is the end of a subroutine. - */ - static final int FLAG_SUBROUTINE_END = 128; - - /** - * The number of elements to add to the {@link #otherLineNumbers} array when it needs to be - * resized to store a new source line number. - */ - static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4; - - /** - * The number of elements to add to the {@link #values} array when it needs to be resized to store - * a new value. - */ - static final int VALUES_CAPACITY_INCREMENT = 6; - - /** - * The bit mask to extract the type of a forward reference to this label. The extracted type is - * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}. - * - * @see #values - */ - static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000; - - /** - * The type of forward references stored with two bytes in the bytecode. This is the case, for - * instance, of a forward reference from an ifnull instruction. - */ - static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000; - - /** - * The type of forward references stored in four bytes in the bytecode. This is the case, for - * instance, of a forward reference from a lookupswitch instruction. - */ - static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000; - - /** - * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle - * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes, - * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}). - * - * @see #values - */ - static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF; - - /** - * A sentinel element used to indicate the end of a list of labels. - * - * @see #nextListElement - */ - static final Label EMPTY_LIST = new Label(); - - /** - * A user managed state associated with this label. Warning: this field is used by the ASM tree - * package. In order to use it with the ASM tree package you must override the getLabelNode method - * in MethodNode. - */ - public Object info; - - /** - * The type and status of this label or its corresponding basic block. Must be zero or more of - * {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link - * #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link - * #FLAG_SUBROUTINE_BODY}, {@link #FLAG_SUBROUTINE_END}. - */ - short flags; - - /** - * The source line number corresponding to this label, or 0. If there are several source line - * numbers corresponding to this label, the first one is stored in this field, and the remaining - * ones are stored in {@link #otherLineNumbers}. - */ - private short lineNumber; - - /** - * The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or - * null. The first element of this array is the number n of source line numbers it contains, which - * are stored between indices 1 and n (inclusive). - */ - private int[] otherLineNumbers; - - /** - * The offset of this label in the bytecode of its method, in bytes. This value is set if and only - * if the {@link #FLAG_RESOLVED} flag is set. - */ - int bytecodeOffset; - - /** - * The number of elements actually used in the {@link #values} array. - */ - private short valueCount; - - /** - * The additional values associated with this label. - * - *
    - *
  • before {@link MethodWriter#computeMaxStackAndLocal}, this array contains the forward - * references to this label. Each forward reference is described with two consecutive - * integers noted 'sourceInsnBytecodeOffset' and 'reference': - *
      - *
    • 'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains - * the forward reference, - *
    • 'reference' contains the type and the offset in the bytecode where the forward - * reference value must be stored, which can be extracted with {@link - * #FORWARD_REFERENCE_TYPE_MASK} and {@link #FORWARD_REFERENCE_HANDLE_MASK}. - *
    - * For instance, for an ifnull instruction at bytecode offset x, 'source' is equal to x, and - * 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1 (because - * the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after the - * start of the instruction itself). For the default case of a lookupswitch instruction at - * bytecode offset x, 'source' is equal to x, and 'reference' is of type {@link - * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the - * lookupswitch instruction uses a 4 bytes bytecode offset operand stored one to four bytes - * after the start of the instruction itself). - *
  • during {@link MethodWriter#computeMaxStackAndLocal}, this array is used as a bit field in - * order to store, for each basic block, the set of subroutines to which it belongs - * (subroutines are numbered from 0 to n, and a basic block belongs to subroutine i if and - * only if the bit number i of this bit field is set). - *
- */ - private int[] values; - - // ----------------------------------------------------------------------------------------------- - - // Fields for the control flow and data flow graph analysis algorithms (used to compute the - // maximum stack size or the stack map frames). A control flow graph contains one node per "basic - // block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic - // block) is represented with the Label object that corresponds to the first instruction of this - // basic block. Each node also stores the list of its successors in the graph, as a linked list of - // Edge objects. - // - // The control flow analysis algorithms used to compute the maximum stack size or the stack map - // frames are similar and use two steps. The first step, during the visit of each instruction, - // builds information about the state of the local variables and the operand stack at the end of - // each basic block, called the "output frame", relatively to the frame state at the - // beginning of the basic block, which is called the "input frame", and which is unknown - // during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link - // MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm - // that computes information about the input frame of each basic block, from the input state of - // the first basic block (known from the method signature), and by the using the previously - // computed relative output frames. - // - // The algorithm used to compute the maximum stack size only computes the relative output and - // absolute input stack heights, while the algorithm used to compute stack map frames computes - // relative output frames and absolute input frames. - - /** - * The number of elements in the input stack of the basic block corresponding to this label. This - * field is computed in {@link MethodWriter#computeMaxStackAndLocal}. - */ - short inputStackSize; - - /** - * The number of elements in the output stack, at the end of the basic block corresponding to this - * label. This field is only computed for basic blocks that end with a RET instruction. - */ - short outputStackSize; - - /** - * The maximum height reached by the output stack, relatively to the top of the input stack, in - * the basick block corresponding to this label. This maximum is always positive or null. - */ - short outputStackMax; - - /** - * The input and output stack map frames of the basic block corresponding to this label. This - * field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link - * MethodWriter#COMPUTE_INSERTED_FRAMES} option is used. - */ - Frame frame; - - /** - * The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}. - * This linked list does not include labels used for debug info only. If the {@link - * MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used - * then it does not contain either successive labels that denote the same bytecode offset (in this - * case only the first label appears in this list). - */ - Label nextBasicBlock; - - /** - * The outgoing edges of the basic block corresponding to this label, in the control flow graph of - * its method. These edges are stored in a linked list of {@link Edge} objects, linked to each - * other by their {@link Edge#nextEdge} field. - */ - Edge outgoingEdges; - - /** - * The next element in the list of labels to which this label belongs, or null if it does not - * belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in - * order to ensure that this field is null if and only if this label does not belong to a list of - * labels. Note that there can be several lists of labels at the same time, but that a label can - * belong to at most one list at a time (unless some lists share a common tail, but this is not - * used in practice). - * - *

List of labels are used in {@link MethodWriter#computeAllFrames} and {@link - * MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size, - * respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to - * compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these - * methods, this field should be null (this property is a precondition and a postcondition of - * these methods). - */ - Label nextListElement; - - // ----------------------------------------------------------------------------------------------- - // Constructor and accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new label. - */ - public Label() { - // Nothing to do. - } - - /** - * Returns the bytecode offset corresponding to this label. This offset is computed from the start - * of the method's bytecode. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @return the bytecode offset corresponding to this label. - * @throws IllegalStateException if this label is not resolved yet. - */ - public int getOffset() { - if ((flags & FLAG_RESOLVED) == 0) { - throw new IllegalStateException("Label offset position has not been resolved yet"); - } - return bytecodeOffset; - } - - /** - * Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset, - * if known, otherwise the label itself. The canonical instance is the first label (in the order - * of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It - * cannot be known for labels which have not been visited yet. - * - *

This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option - * is used. - * - * @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This - * corresponds to the "canonical" label instance described above thanks to the way the label - * frame is set in {@link MethodWriter#visitLabel}. - */ - final Label getCanonicalInstance() { - return frame == null ? this : frame.owner; - } - - // ----------------------------------------------------------------------------------------------- - // Methods to manage line numbers - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a source line number corresponding to this label. - * - * @param lineNumber a source line number (which should be strictly positive). - */ - final void addLineNumber(final int lineNumber) { - if (this.lineNumber == 0) { - this.lineNumber = (short) lineNumber; - } else { - if (otherLineNumbers == null) { - otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT]; - } - int otherLineNumberIndex = ++otherLineNumbers[0]; - if (otherLineNumberIndex >= otherLineNumbers.length) { - int[] newLineNumbers = new int[otherLineNumbers.length + VALUES_CAPACITY_INCREMENT]; - System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length); - otherLineNumbers = newLineNumbers; - } - otherLineNumbers[otherLineNumberIndex] = lineNumber; - } - } - - /** - * Makes the given visitor visit this label and its source line numbers, if applicable. - * - * @param methodVisitor a method visitor. - * @param visitLineNumbers whether to visit of the label's source line numbers, if any. - */ - final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) { - methodVisitor.visitLabel(this); - if (visitLineNumbers && lineNumber != 0) { - methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this); - if (otherLineNumbers != null) { - for (int i = 1; i <= otherLineNumbers[0]; ++i) { - methodVisitor.visitLineNumber(otherLineNumbers[i], this); - } - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Methods to compute offsets and to manage forward references - // ----------------------------------------------------------------------------------------------- - - /** - * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label - * is known, the relative bytecode offset between the label and the instruction referencing it is - * computed and written directly. Otherwise, a null relative offset is written and a new forward - * reference is declared for this label. - * - * @param code the bytecode of the method. This is where the reference is appended. - * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the - * reference to be appended. - * @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes). - */ - final void put( - final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) { - if ((flags & FLAG_RESOLVED) == 0) { - if (wideReference) { - addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length); - code.putInt(-1); - } else { - addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length); - code.putShort(-1); - } - } else { - if (wideReference) { - code.putInt(bytecodeOffset - sourceInsnBytecodeOffset); - } else { - code.putShort(bytecodeOffset - sourceInsnBytecodeOffset); - } - } - } - - /** - * Adds a forward reference to this label. This method must be called only for a true forward - * reference, i.e. only if this label is not resolved yet. For backward references, the relative - * bytecode offset of the reference can be, and must be, computed and stored directly. - * - * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the - * reference stored at referenceHandle. - * @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link - * #FORWARD_REFERENCE_TYPE_WIDE}. - * @param referenceHandle the offset in the bytecode where the forward reference value must be - * stored. - */ - private void addForwardReference( - final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) { - if (values == null) { - values = new int[VALUES_CAPACITY_INCREMENT]; - } - if (valueCount >= values.length) { - int[] newValues = new int[values.length + VALUES_CAPACITY_INCREMENT]; - System.arraycopy(values, 0, newValues, 0, values.length); - values = newValues; - } - values[valueCount++] = sourceInsnBytecodeOffset; - values[valueCount++] = referenceType | referenceHandle; - } - - /** - * Sets the bytecode offset of this label to the given value and resolves the forward references - * to this label, if any. This method must be called when this label is added to the bytecode of - * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that - * where left in the bytecode by each forward reference previously added to this label. - * - * @param code the bytecode of the method. - * @param bytecodeOffset the bytecode offset of this label. - * @return true if a blank that was left for this label was too small to store the - * offset. In such a case the corresponding jump instruction is replaced with an equivalent - * ASM specific instruction using an unsigned two bytes offset. These ASM specific - * instructions are later replaced with standard bytecode instructions with wider offsets (4 - * bytes instead of 2), in ClassReader. - */ - final boolean resolve(final byte[] code, final int bytecodeOffset) { - this.flags |= FLAG_RESOLVED; - this.bytecodeOffset = bytecodeOffset; - boolean hasAsmInstructions = false; - for (int i = 0; i < valueCount; i += 2) { - final int sourceInsnBytecodeOffset = values[i]; - final int reference = values[i + 1]; - final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset; - int handle = reference & FORWARD_REFERENCE_HANDLE_MASK; - if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) { - if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) { - // Change the opcode of the jump instruction, in order to be able to find it later in - // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except - // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to - // 65535, which is sufficient since the size of a method is limited to 65535 bytes). - int opcode = code[sourceInsnBytecodeOffset] & 0xFF; - if (opcode < Opcodes.IFNULL) { - // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR. - code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA); - } else { - // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL. - code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA); - } - hasAsmInstructions = true; - } - code[handle++] = (byte) (relativeOffset >>> 8); - code[handle] = (byte) relativeOffset; - } else { - code[handle++] = (byte) (relativeOffset >>> 24); - code[handle++] = (byte) (relativeOffset >>> 16); - code[handle++] = (byte) (relativeOffset >>> 8); - code[handle] = (byte) relativeOffset; - } - } - return hasAsmInstructions; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to subroutines - // ----------------------------------------------------------------------------------------------- - - /** - * Finds the basic blocks that belong to the subroutine starting with the basic block - * corresponding to this label, and marks these blocks as belonging to this subroutine. This - * method follows the control flow graph to find all the blocks that are reachable from the - * current basic block WITHOUT following any jsr target. - * - *

Note: a precondition and postcondition of this method is that all labels must have a null - * {@link #nextListElement}. - * - * @param subroutineId the id of the subroutine starting with the basic block corresponding to - * this label. - * @param numSubroutine the total number of subroutines in the method. - */ - final void markSubroutine(final int subroutineId, final int numSubroutine) { - // Data flow algorithm: put this basic block in a list of blocks to process (which are blocks - // belonging to subroutine subroutineId) and, while there are blocks to process, remove one from - // the list, mark it as belonging to the subroutine, and add its successor basic blocks in the - // control flow graph to the list of blocks to process (if not already done). - Label listOfBlocksToProcess = this; - listOfBlocksToProcess.nextListElement = EMPTY_LIST; - while (listOfBlocksToProcess != EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - basicBlock.nextListElement = null; - - // If it is not already marked as belonging to the subroutine subroutineId, mark it and add - // its successors to the list of blocks to process (unless already done). - if (!basicBlock.isInSubroutine(subroutineId)) { - basicBlock.addToSubroutine(subroutineId, numSubroutine); - listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); - } - } - } - - /** - * Finds the basic blocks that end a subroutine starting with the basic block corresponding to - * this label and, for each one of them, adds an outgoing edge to the basic block following the - * given subroutine call. In other words, completes the control flow graph by adding the edges - * corresponding to the return from this subroutine, when called from the given caller basic - * block. - * - *

Note: a precondition and postcondition of this method is that all labels must have a null - * {@link #nextListElement}. - * - * @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to - * this label. This label is supposed to correspond to the start of a subroutine. - */ - final void addSubroutineRetSuccessors(final Label subroutineCaller) { - // Data flow algorithm: put this basic block in a list blocks to process (which are blocks - // belonging to a subroutine starting with this label) and, while there are blocks to process, - // remove one from the list, put it in a list of blocks that have been processed, add a return - // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks - // in the control flow graph to the list of blocks to process (if not already done). - Label listOfProcessedBlocks = EMPTY_LIST; - Label listOfBlocksToProcess = this; - listOfBlocksToProcess.nextListElement = EMPTY_LIST; - while (listOfBlocksToProcess != EMPTY_LIST) { - // Move a basic block from the list of blocks to process to the list of processed blocks. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = basicBlock.nextListElement; - basicBlock.nextListElement = listOfProcessedBlocks; - listOfProcessedBlocks = basicBlock; - - // Add an edge from this block to the successor of the caller basic block, if this block is - // the end of a subroutine and if this block and subroutineCaller do not belong to a common - // subroutine. - if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0 - && !basicBlock.isInSameSubroutine(subroutineCaller)) { - basicBlock.outgoingEdges = - new Edge( - basicBlock.outputStackSize, - // By construction, the first outgoing edge of a basic block that ends with a jsr - // instruction leads to the jsr continuation block, i.e. where execution continues - // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}). - subroutineCaller.outgoingEdges.successor, - basicBlock.outgoingEdges); - } - // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does - // not push basic blocks which are already in a list. Here this means either in the list of - // blocks to process, or in the list of already processed blocks. This second list is - // important to make sure we don't reprocess an already processed block. - listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); - } - // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null, - // so that this method can be called again with a different subroutine or subroutine caller. - while (listOfProcessedBlocks != EMPTY_LIST) { - Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement; - listOfProcessedBlocks.nextListElement = null; - listOfProcessedBlocks = newListOfProcessedBlocks; - } - } - - /** - * Adds the successors of this label in the method's control flow graph (except those - * corresponding to a jsr target, and those already in a list of labels) to the given list of - * blocks to process, and returns the new list. - * - * @param listOfLabelsToProcess a list of basic blocks to process, linked together with their - * {@link #nextListElement} field. - * @return the new list of blocks to process. - */ - private Label pushSuccessors(final Label listOfLabelsToProcess) { - Label newListOfLabelsToProcess = listOfLabelsToProcess; - Edge outgoingEdge = outgoingEdges; - while (outgoingEdge != null) { - // By construction, the second outgoing edge of a basic block that ends with a jsr instruction - // leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}). - boolean isJsrTarget = - (flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge; - if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) { - // Add this successor to the list of blocks to process, if it does not already belong to a - // list of labels. - outgoingEdge.successor.nextListElement = newListOfLabelsToProcess; - newListOfLabelsToProcess = outgoingEdge.successor; - } - outgoingEdge = outgoingEdge.nextEdge; - } - return newListOfLabelsToProcess; - } - - /** - * @param subroutineId a subroutine id, between 0 and the total number of subroutines in the - * method. - * @return whether this basic block belongs to the given subroutine. - */ - private boolean isInSubroutine(final int subroutineId) { - if ((flags & Label.FLAG_SUBROUTINE_BODY) != 0) { - return (values[subroutineId / 32] & (1 << (subroutineId % 32))) != 0; - } - return false; - } - - /** - * @param basicBlock another basic block. - * @return whether this basic block and the given one belong to a common subroutine. - */ - private boolean isInSameSubroutine(final Label basicBlock) { - if ((flags & FLAG_SUBROUTINE_BODY) == 0 || (basicBlock.flags & FLAG_SUBROUTINE_BODY) == 0) { - return false; - } - for (int i = 0; i < values.length; ++i) { - if ((values[i] & basicBlock.values[i]) != 0) { - return true; - } - } - return false; - } - - /** - * Marks the basic block corresponding to this label as belonging to the given subroutine. - * - * @param subroutineId a subroutine id, between 0 and numSubroutine (inclusive). - * @param numSubroutine the total number of subroutines in the method. - */ - private void addToSubroutine(final int subroutineId, final int numSubroutine) { - if ((flags & FLAG_SUBROUTINE_BODY) == 0) { - flags |= FLAG_SUBROUTINE_BODY; - values = new int[numSubroutine / 32 + 1]; - } - values[subroutineId / 32] |= (1 << (subroutineId % 32)); - } - - // ----------------------------------------------------------------------------------------------- - // Overridden Object methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns a string representation of this label. - * - * @return a string representation of this label. - */ - @Override - public String toString() { - return "L" + System.identityHashCode(this); - } -} diff --git a/src/main/java/org/objectweb/asm/MethodVisitor.java b/src/main/java/org/objectweb/asm/MethodVisitor.java deleted file mode 100644 index a7658e70..00000000 --- a/src/main/java/org/objectweb/asm/MethodVisitor.java +++ /dev/null @@ -1,779 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java method. The methods of this class must be called in the following - * order: ( visitParameter )* [ visitAnnotationDefault ] ( - * visitAnnotation | visitAnnotableParameterCount | - * visitParameterAnnotation visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | visitLabel | - * visitInsnAnnotation | visitTryCatchBlock | visitTryCatchAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | visitLineNumber )* - * visitMaxs ] visitEnd. In addition, the visitXInsn and - * visitLabel methods must be called in the sequential order of the bytecode instructions - * of the visited code, visitInsnAnnotation must be called after the annotated - * instruction, visitTryCatchBlock must be called before the labels passed as - * arguments have been visited, visitTryCatchBlockAnnotation must be called after - * the corresponding try catch block has been visited, and the visitLocalVariable, - * visitLocalVariableAnnotation and visitLineNumber methods must be called - * after the labels passed as arguments have been visited. - * - * @author Eric Bruneton - */ -public abstract class MethodVisitor { - - private static final String REQUIRES_ASM5 = "This feature requires ASM5"; - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The method visitor to which this visitor must delegate method calls. May be null. - */ - protected MethodVisitor mv; - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public MethodVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param methodVisitor the method visitor to which this visitor must delegate method calls. May - * be null. - */ - public MethodVisitor(final int api, final MethodVisitor methodVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.mv = methodVisitor; - } - - // ----------------------------------------------------------------------------------------------- - // Parameters, annotations and non standard attributes - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a parameter of this method. - * - * @param name parameter name or null if none is provided. - * @param access the parameter's access flags, only ACC_FINAL, ACC_SYNTHETIC - * or/and ACC_MANDATED are allowed (see {@link Opcodes}). - */ - public void visitParameter(final String name, final int access) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitParameter(name, access); - } - } - - /** - * Visits the default value of this annotation interface method. - * - * @return a visitor to the visit the actual default value of this annotation interface method, or - * null if this visitor is not interested in visiting this default value. The 'name' - * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly - * one visit method must be called on this annotation visitor, followed by visitEnd. - */ - public AnnotationVisitor visitAnnotationDefault() { - if (mv != null) { - return mv.visitAnnotationDefault(); - } - return null; - } - - /** - * Visits an annotation of this method. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (mv != null) { - return mv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the method signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#METHOD_TYPE_PARAMETER}, {@link - * TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link TypeReference#METHOD_RETURN}, {@link - * TypeReference#METHOD_RECEIVER}, {@link TypeReference#METHOD_FORMAL_PARAMETER} or {@link - * TypeReference#THROWS}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits the number of method parameters that can have annotations. By default (i.e. when this - * method is not called), all the method parameters defined by the method descriptor can have - * annotations. - * - * @param parameterCount the number of method parameters than can have annotations. This number - * must be less or equal than the number of parameter types in the method descriptor. It can - * be strictly less when a method has synthetic parameters and when these parameters are - * ignored when computing parameter indices for the purpose of parameter annotations (see - * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). - * @param visible true to define the number of method parameters that can have - * annotations visible at runtime, false to define the number of method parameters - * that can have annotations invisible at runtime. - */ - public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { - if (mv != null) { - mv.visitAnnotableParameterCount(parameterCount, visible); - } - } - - /** - * Visits an annotation of a parameter this method. - * - * @param parameter the parameter index. This index must be strictly smaller than the number of - * parameters in the method descriptor, and strictly smaller than the parameter count - * specified in {@link #visitAnnotableParameterCount}. Important note: a parameter index i - * is not required to correspond to the i'th parameter descriptor in the method - * descriptor, in particular in case of synthetic parameters (see - * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitParameterAnnotation( - final int parameter, final String descriptor, final boolean visible) { - if (mv != null) { - return mv.visitParameterAnnotation(parameter, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of this method. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (mv != null) { - mv.visitAttribute(attribute); - } - } - - /** - * Starts the visit of the method's code, if any (i.e. non abstract method). - */ - public void visitCode() { - if (mv != null) { - mv.visitCode(); - } - } - - /** - * Visits the current state of the local variables and operand stack elements. This method must(*) - * be called just before any instruction i that follows an unconditional branch - * instruction such as GOTO or THROW, that is the target of a jump instruction, or that starts an - * exception handler block. The visited types must describe the values of the local variables and - * of the operand stack elements just before i is executed.
- *
- * (*) this is mandatory only for classes whose version is greater than or equal to {@link - * Opcodes#V1_6}.
- *
- * The frames of a method must be given either in expanded form, or in compressed form (all frames - * must use the same format, i.e. you must not mix expanded and compressed frames within a single - * method): - * - *

    - *
  • In expanded form, all frames must have the F_NEW type. - *
  • In compressed form, frames are basically "deltas" from the state of the previous frame: - *
      - *
    • {@link Opcodes#F_SAME} representing frame with exactly the same locals as the - * previous frame and with the empty stack. - *
    • {@link Opcodes#F_SAME1} representing frame with exactly the same locals as the - * previous frame and with single value on the stack ( nStack is 1 and - * stack[0] contains value for the type of the stack item). - *
    • {@link Opcodes#F_APPEND} representing frame with current locals are the same as the - * locals in the previous frame, except that additional locals are defined ( - * nLocal is 1, 2 or 3 and local elements contains values - * representing added types). - *
    • {@link Opcodes#F_CHOP} representing frame with current locals are the same as the - * locals in the previous frame, except that the last 1-3 locals are absent and with - * the empty stack (nLocals is 1, 2 or 3). - *
    • {@link Opcodes#F_FULL} representing complete frame data. - *
    - *
- * - *
- * In both cases the first frame, corresponding to the method's parameters and access flags, is - * implicit and must not be visited. Also, it is illegal to visit two or more frames for the same - * code location (i.e., at least one instruction must be visited between two calls to visitFrame). - * - * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded - * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link - * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. - * @param nLocal the number of local variables in the visited frame. - * @param local the local variable types in this frame. This array must not be modified. Primitive - * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or - * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element). - * Reference types are represented by String objects (representing internal names), and - * uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). - * @param nStack the number of operand stack elements in the visited frame. - * @param stack the operand stack types in this frame. This array must not be modified. Its - * content has the same format as the "local" array. - * @throws IllegalStateException if a frame is visited just after another one, without any - * instruction between the two (unless this frame is a Opcodes#F_SAME frame, in which case it - * is silently ignored). - */ - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - if (mv != null) { - mv.visitFrame(type, nLocal, local, nStack, stack); - } - } - - // ----------------------------------------------------------------------------------------------- - // Normal instructions - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a zero operand instruction. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, - * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, - * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, - * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, - * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, - * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, - * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, - * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, - * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, - * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT. - */ - public void visitInsn(final int opcode) { - if (mv != null) { - mv.visitInsn(opcode); - } - } - - /** - * Visits an instruction with a single int operand. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH - * or NEWARRAY. - * @param operand the operand of the instruction to be visited.
- * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE. - *
- * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE. - *
- * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link - * Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, - * {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. - */ - public void visitIntInsn(final int opcode, final int operand) { - if (mv != null) { - mv.visitIntInsn(opcode, operand); - } - } - - /** - * Visits a local variable instruction. A local variable instruction is an instruction that loads - * or stores the value of a local variable. - * - * @param opcode the opcode of the local variable instruction to be visited. This opcode is either - * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. - * @param var the operand of the instruction to be visited. This operand is the index of a local - * variable. - */ - public void visitVarInsn(final int opcode, final int var) { - if (mv != null) { - mv.visitVarInsn(opcode, var); - } - } - - /** - * Visits a type instruction. A type instruction is an instruction that takes the internal name of - * a class as parameter. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, - * ANEWARRAY, CHECKCAST or INSTANCEOF. - * @param type the operand of the instruction to be visited. This operand must be the internal - * name of an object or array class (see {@link Type#getInternalName()}). - */ - public void visitTypeInsn(final int opcode, final String type) { - if (mv != null) { - mv.visitTypeInsn(opcode, type); - } - } - - /** - * Visits a field instruction. A field instruction is an instruction that loads or stores the - * value of a field of an object. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. - * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}). - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - */ - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String descriptor) { - if (mv != null) { - mv.visitFieldInsn(opcode, owner, name, descriptor); - } - } - - /** - * Visits a method instruction. A method instruction is an instruction that invokes a method. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link - * Type#getInternalName()}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @deprecated - */ - @Deprecated - public void visitMethodInsn( - final int opcode, final String owner, final String name, final String descriptor) { - if (api >= Opcodes.ASM5) { - boolean isInterface = opcode == Opcodes.INVOKEINTERFACE; - visitMethodInsn(opcode, owner, name, descriptor, isInterface); - return; - } - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, descriptor); - } - } - - /** - * Visits a method instruction. A method instruction is an instruction that invokes a method. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link - * Type#getInternalName()}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param isInterface if the method's owner class is an interface. - */ - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - if (api < Opcodes.ASM5) { - if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) { - throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5"); - } - visitMethodInsn(opcode, owner, name, descriptor); - return; - } - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - } - - /** - * Visits an invokedynamic instruction. - * - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be - * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link - * Type} or {@link Handle} value. This method is allowed to modify the content of the array so - * a caller should expect that this array may change. - */ - public void visitInvokeDynamicInsn( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); - } - } - - /** - * Visits a jump instruction. A jump instruction is an instruction that may jump to another - * instruction. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, - * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, - * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. - * @param label the operand of the instruction to be visited. This operand is a label that - * designates the instruction to which the jump instruction may jump. - */ - public void visitJumpInsn(final int opcode, final Label label) { - if (mv != null) { - mv.visitJumpInsn(opcode, label); - } - } - - /** - * Visits a label. A label designates the instruction that will be visited just after it. - * - * @param label a {@link Label} object. - */ - public void visitLabel(final Label label) { - if (mv != null) { - mv.visitLabel(label); - } - } - - // ----------------------------------------------------------------------------------------------- - // Special instructions - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a LDC instruction. Note that new constant types may be added in future versions of the - * Java Virtual Machine. To easily detect new constant types, implementations of this method - * should check for unexpected constant types, like this: - * - *
-     * if (cst instanceof Integer) {
-     *     // ...
-     * } else if (cst instanceof Float) {
-     *     // ...
-     * } else if (cst instanceof Long) {
-     *     // ...
-     * } else if (cst instanceof Double) {
-     *     // ...
-     * } else if (cst instanceof String) {
-     *     // ...
-     * } else if (cst instanceof Type) {
-     *     int sort = ((Type) cst).getSort();
-     *     if (sort == Type.OBJECT) {
-     *         // ...
-     *     } else if (sort == Type.ARRAY) {
-     *         // ...
-     *     } else if (sort == Type.METHOD) {
-     *         // ...
-     *     } else {
-     *         // throw an exception
-     *     }
-     * } else if (cst instanceof Handle) {
-     *     // ...
-     * } else {
-     *     // throw an exception
-     * }
-     * 
- * - * @param value the constant to be loaded on the stack. This parameter must be a non null {@link - * Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link - * Type} of OBJECT or ARRAY sort for .class constants, for classes whose version is - * 49.0, a {@link Type} of METHOD sort or a {@link Handle} for MethodType and MethodHandle - * constants, for classes whose version is 51.0. - */ - public void visitLdcInsn(final Object value) { - if (api < Opcodes.ASM5 - && (value instanceof Handle - || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitLdcInsn(value); - } - } - - /** - * Visits an IINC instruction. - * - * @param var index of the local variable to be incremented. - * @param increment amount to increment the local variable by. - */ - public void visitIincInsn(final int var, final int increment) { - if (mv != null) { - mv.visitIincInsn(var, increment); - } - } - - /** - * Visits a TABLESWITCH instruction. - * - * @param min the minimum key value. - * @param max the maximum key value. - * @param dflt beginning of the default handler block. - * @param labels beginnings of the handler blocks. labels[i] is the beginning of the - * handler block for the min + i key. - */ - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - if (mv != null) { - mv.visitTableSwitchInsn(min, max, dflt, labels); - } - } - - /** - * Visits a LOOKUPSWITCH instruction. - * - * @param dflt beginning of the default handler block. - * @param keys the values of the keys. - * @param labels beginnings of the handler blocks. labels[i] is the beginning of the - * handler block for the keys[i] key. - */ - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - if (mv != null) { - mv.visitLookupSwitchInsn(dflt, keys, labels); - } - } - - /** - * Visits a MULTIANEWARRAY instruction. - * - * @param descriptor an array type descriptor (see {@link Type}). - * @param numDimensions the number of dimensions of the array to allocate. - */ - public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { - if (mv != null) { - mv.visitMultiANewArrayInsn(descriptor, numDimensions); - } - } - - /** - * Visits an annotation on an instruction. This method must be called just after the - * annotated instruction. It can be called several times for the same instruction. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#INSTANCEOF}, {@link TypeReference#NEW}, {@link - * TypeReference#CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE}, {@link - * TypeReference#CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link - * TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link - * TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitInsnAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitInsnAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - // ----------------------------------------------------------------------------------------------- - // Exceptions table entries, debug information, max stack and max locals - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a try catch block. - * - * @param start the beginning of the exception handler's scope (inclusive). - * @param end the end of the exception handler's scope (exclusive). - * @param handler the beginning of the exception handler's code. - * @param type the internal name of the type of exceptions handled by the handler, or - * null to catch any exceptions (for "finally" blocks). - * @throws IllegalArgumentException if one of the labels has already been visited by this visitor - * (by the {@link #visitLabel} method). - */ - public void visitTryCatchBlock( - final Label start, final Label end, final Label handler, final String type) { - if (mv != null) { - mv.visitTryCatchBlock(start, end, handler, type); - } - } - - /** - * Visits an annotation on an exception handler type. This method must be called after the - * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times - * for the same exception handler. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#EXCEPTION_PARAMETER}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTryCatchAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a local variable declaration. - * - * @param name the name of a local variable. - * @param descriptor the type descriptor of this local variable. - * @param signature the type signature of this local variable. May be null if the local - * variable type does not use generic types. - * @param start the first instruction corresponding to the scope of this local variable - * (inclusive). - * @param end the last instruction corresponding to the scope of this local variable (exclusive). - * @param index the local variable's index. - * @throws IllegalArgumentException if one of the labels has not already been visited by this - * visitor (by the {@link #visitLabel} method). - */ - public void visitLocalVariable( - final String name, - final String descriptor, - final String signature, - final Label start, - final Label end, - final int index) { - if (mv != null) { - mv.visitLocalVariable(name, descriptor, signature, start, end, index); - } - } - - /** - * Visits an annotation on a local variable type. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE}. See {@link - * TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param start the fist instructions corresponding to the continuous ranges that make the scope - * of this local variable (inclusive). - * @param end the last instructions corresponding to the continuous ranges that make the scope of - * this local variable (exclusive). This array must have the same size as the 'start' array. - * @param index the local variable's index in each range. This array must have the same size as - * the 'start' array. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitLocalVariableAnnotation( - final int typeRef, - final TypePath typePath, - final Label[] start, - final Label[] end, - final int[] index, - final String descriptor, - final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitLocalVariableAnnotation( - typeRef, typePath, start, end, index, descriptor, visible); - } - return null; - } - - /** - * Visits a line number declaration. - * - * @param line a line number. This number refers to the source file from which the class was - * compiled. - * @param start the first instruction corresponding to this line number. - * @throws IllegalArgumentException if start has not already been visited by this visitor - * (by the {@link #visitLabel} method). - */ - public void visitLineNumber(final int line, final Label start) { - if (mv != null) { - mv.visitLineNumber(line, start); - } - } - - /** - * Visits the maximum stack size and the maximum number of local variables of the method. - * - * @param maxStack maximum stack size of the method. - * @param maxLocals maximum number of local variables for the method. - */ - public void visitMaxs(final int maxStack, final int maxLocals) { - if (mv != null) { - mv.visitMaxs(maxStack, maxLocals); - } - } - - /** - * Visits the end of the method. This method, which is the last one to be called, is used to - * inform the visitor that all the annotations and attributes of the method have been visited. - */ - public void visitEnd() { - if (mv != null) { - mv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/MethodWriter.java b/src/main/java/org/objectweb/asm/MethodWriter.java deleted file mode 100644 index b8b8ad96..00000000 --- a/src/main/java/org/objectweb/asm/MethodWriter.java +++ /dev/null @@ -1,2378 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the - * Java Virtual Machine Specification (JVMS). - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.6 - */ -final class MethodWriter extends MethodVisitor { - - /** - * Indicates that all the stack map frames must be computed. In this case the maximum stack size - * and the maximum number of local variables is also computed. - */ - static final int COMPUTE_ALL_FRAMES = 3; - - /** - * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not - * computed. They should all be of type F_NEW and should be sufficient to compute the content of - * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT - * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT). - */ - static final int COMPUTE_INSERTED_FRAMES = 2; - - /** - * Indicates that the maximum stack size and the maximum number of local variables must be - * computed. - */ - static final int COMPUTE_MAX_STACK_AND_LOCAL = 1; - - /** - * Indicates that nothing must be computed. - */ - static final int COMPUTE_NOTHING = 0; - - /** - * Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). - */ - private static final int NA = 0; - - /** - * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode - * 'o' is given by the array element at index 'o'. - * - * @see JVMS 6 - */ - private static final int[] STACK_SIZE_DELTA = { - 0, // nop = 0 (0x0) - 1, // aconst_null = 1 (0x1) - 1, // iconst_m1 = 2 (0x2) - 1, // iconst_0 = 3 (0x3) - 1, // iconst_1 = 4 (0x4) - 1, // iconst_2 = 5 (0x5) - 1, // iconst_3 = 6 (0x6) - 1, // iconst_4 = 7 (0x7) - 1, // iconst_5 = 8 (0x8) - 2, // lconst_0 = 9 (0x9) - 2, // lconst_1 = 10 (0xa) - 1, // fconst_0 = 11 (0xb) - 1, // fconst_1 = 12 (0xc) - 1, // fconst_2 = 13 (0xd) - 2, // dconst_0 = 14 (0xe) - 2, // dconst_1 = 15 (0xf) - 1, // bipush = 16 (0x10) - 1, // sipush = 17 (0x11) - 1, // ldc = 18 (0x12) - NA, // ldc_w = 19 (0x13) - NA, // ldc2_w = 20 (0x14) - 1, // iload = 21 (0x15) - 2, // lload = 22 (0x16) - 1, // fload = 23 (0x17) - 2, // dload = 24 (0x18) - 1, // aload = 25 (0x19) - NA, // iload_0 = 26 (0x1a) - NA, // iload_1 = 27 (0x1b) - NA, // iload_2 = 28 (0x1c) - NA, // iload_3 = 29 (0x1d) - NA, // lload_0 = 30 (0x1e) - NA, // lload_1 = 31 (0x1f) - NA, // lload_2 = 32 (0x20) - NA, // lload_3 = 33 (0x21) - NA, // fload_0 = 34 (0x22) - NA, // fload_1 = 35 (0x23) - NA, // fload_2 = 36 (0x24) - NA, // fload_3 = 37 (0x25) - NA, // dload_0 = 38 (0x26) - NA, // dload_1 = 39 (0x27) - NA, // dload_2 = 40 (0x28) - NA, // dload_3 = 41 (0x29) - NA, // aload_0 = 42 (0x2a) - NA, // aload_1 = 43 (0x2b) - NA, // aload_2 = 44 (0x2c) - NA, // aload_3 = 45 (0x2d) - -1, // iaload = 46 (0x2e) - 0, // laload = 47 (0x2f) - -1, // faload = 48 (0x30) - 0, // daload = 49 (0x31) - -1, // aaload = 50 (0x32) - -1, // baload = 51 (0x33) - -1, // caload = 52 (0x34) - -1, // saload = 53 (0x35) - -1, // istore = 54 (0x36) - -2, // lstore = 55 (0x37) - -1, // fstore = 56 (0x38) - -2, // dstore = 57 (0x39) - -1, // astore = 58 (0x3a) - NA, // istore_0 = 59 (0x3b) - NA, // istore_1 = 60 (0x3c) - NA, // istore_2 = 61 (0x3d) - NA, // istore_3 = 62 (0x3e) - NA, // lstore_0 = 63 (0x3f) - NA, // lstore_1 = 64 (0x40) - NA, // lstore_2 = 65 (0x41) - NA, // lstore_3 = 66 (0x42) - NA, // fstore_0 = 67 (0x43) - NA, // fstore_1 = 68 (0x44) - NA, // fstore_2 = 69 (0x45) - NA, // fstore_3 = 70 (0x46) - NA, // dstore_0 = 71 (0x47) - NA, // dstore_1 = 72 (0x48) - NA, // dstore_2 = 73 (0x49) - NA, // dstore_3 = 74 (0x4a) - NA, // astore_0 = 75 (0x4b) - NA, // astore_1 = 76 (0x4c) - NA, // astore_2 = 77 (0x4d) - NA, // astore_3 = 78 (0x4e) - -3, // iastore = 79 (0x4f) - -4, // lastore = 80 (0x50) - -3, // fastore = 81 (0x51) - -4, // dastore = 82 (0x52) - -3, // aastore = 83 (0x53) - -3, // bastore = 84 (0x54) - -3, // castore = 85 (0x55) - -3, // sastore = 86 (0x56) - -1, // pop = 87 (0x57) - -2, // pop2 = 88 (0x58) - 1, // dup = 89 (0x59) - 1, // dup_x1 = 90 (0x5a) - 1, // dup_x2 = 91 (0x5b) - 2, // dup2 = 92 (0x5c) - 2, // dup2_x1 = 93 (0x5d) - 2, // dup2_x2 = 94 (0x5e) - 0, // swap = 95 (0x5f) - -1, // iadd = 96 (0x60) - -2, // ladd = 97 (0x61) - -1, // fadd = 98 (0x62) - -2, // dadd = 99 (0x63) - -1, // isub = 100 (0x64) - -2, // lsub = 101 (0x65) - -1, // fsub = 102 (0x66) - -2, // dsub = 103 (0x67) - -1, // imul = 104 (0x68) - -2, // lmul = 105 (0x69) - -1, // fmul = 106 (0x6a) - -2, // dmul = 107 (0x6b) - -1, // idiv = 108 (0x6c) - -2, // ldiv = 109 (0x6d) - -1, // fdiv = 110 (0x6e) - -2, // ddiv = 111 (0x6f) - -1, // irem = 112 (0x70) - -2, // lrem = 113 (0x71) - -1, // frem = 114 (0x72) - -2, // drem = 115 (0x73) - 0, // ineg = 116 (0x74) - 0, // lneg = 117 (0x75) - 0, // fneg = 118 (0x76) - 0, // dneg = 119 (0x77) - -1, // ishl = 120 (0x78) - -1, // lshl = 121 (0x79) - -1, // ishr = 122 (0x7a) - -1, // lshr = 123 (0x7b) - -1, // iushr = 124 (0x7c) - -1, // lushr = 125 (0x7d) - -1, // iand = 126 (0x7e) - -2, // land = 127 (0x7f) - -1, // ior = 128 (0x80) - -2, // lor = 129 (0x81) - -1, // ixor = 130 (0x82) - -2, // lxor = 131 (0x83) - 0, // iinc = 132 (0x84) - 1, // i2l = 133 (0x85) - 0, // i2f = 134 (0x86) - 1, // i2d = 135 (0x87) - -1, // l2i = 136 (0x88) - -1, // l2f = 137 (0x89) - 0, // l2d = 138 (0x8a) - 0, // f2i = 139 (0x8b) - 1, // f2l = 140 (0x8c) - 1, // f2d = 141 (0x8d) - -1, // d2i = 142 (0x8e) - 0, // d2l = 143 (0x8f) - -1, // d2f = 144 (0x90) - 0, // i2b = 145 (0x91) - 0, // i2c = 146 (0x92) - 0, // i2s = 147 (0x93) - -3, // lcmp = 148 (0x94) - -1, // fcmpl = 149 (0x95) - -1, // fcmpg = 150 (0x96) - -3, // dcmpl = 151 (0x97) - -3, // dcmpg = 152 (0x98) - -1, // ifeq = 153 (0x99) - -1, // ifne = 154 (0x9a) - -1, // iflt = 155 (0x9b) - -1, // ifge = 156 (0x9c) - -1, // ifgt = 157 (0x9d) - -1, // ifle = 158 (0x9e) - -2, // if_icmpeq = 159 (0x9f) - -2, // if_icmpne = 160 (0xa0) - -2, // if_icmplt = 161 (0xa1) - -2, // if_icmpge = 162 (0xa2) - -2, // if_icmpgt = 163 (0xa3) - -2, // if_icmple = 164 (0xa4) - -2, // if_acmpeq = 165 (0xa5) - -2, // if_acmpne = 166 (0xa6) - 0, // goto = 167 (0xa7) - 1, // jsr = 168 (0xa8) - 0, // ret = 169 (0xa9) - -1, // tableswitch = 170 (0xaa) - -1, // lookupswitch = 171 (0xab) - -1, // ireturn = 172 (0xac) - -2, // lreturn = 173 (0xad) - -1, // freturn = 174 (0xae) - -2, // dreturn = 175 (0xaf) - -1, // areturn = 176 (0xb0) - 0, // return = 177 (0xb1) - NA, // getstatic = 178 (0xb2) - NA, // putstatic = 179 (0xb3) - NA, // getfield = 180 (0xb4) - NA, // putfield = 181 (0xb5) - NA, // invokevirtual = 182 (0xb6) - NA, // invokespecial = 183 (0xb7) - NA, // invokestatic = 184 (0xb8) - NA, // invokeinterface = 185 (0xb9) - NA, // invokedynamic = 186 (0xba) - 1, // new = 187 (0xbb) - 0, // newarray = 188 (0xbc) - 0, // anewarray = 189 (0xbd) - 0, // arraylength = 190 (0xbe) - NA, // athrow = 191 (0xbf) - 0, // checkcast = 192 (0xc0) - 0, // instanceof = 193 (0xc1) - -1, // monitorenter = 194 (0xc2) - -1, // monitorexit = 195 (0xc3) - NA, // wide = 196 (0xc4) - NA, // multianewarray = 197 (0xc5) - -1, // ifnull = 198 (0xc6) - -1, // ifnonnull = 199 (0xc7) - NA, // goto_w = 200 (0xc8) - NA // jsr_w = 201 (0xc9) - }; - - /** - * Where the constants used in this MethodWriter must be stored. - */ - private final SymbolTable symbolTable; - - // Note: fields are ordered as in the method_info structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The access_flags field of the method_info JVMS structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private final int accessFlags; - - /** - * The name_index field of the method_info JVMS structure. - */ - private final int nameIndex; - - /** - * The descriptor_index field of the method_info JVMS structure. - */ - private final int descriptorIndex; - - /** - * The descriptor of this method. - */ - private final String descriptor; - - // Code attribute fields and sub attributes: - - /** - * The max_stack field of the Code attribute. - */ - private int maxStack; - - /** - * The max_locals field of the Code attribute. - */ - private int maxLocals; - - /** - * The 'code' field of the Code attribute. - */ - private final ByteVector code = new ByteVector(); - - /** - * The first element in the exception handler list (used to generate the exception_table of the - * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May - * be null. - */ - private Handler firstHandler; - - /** - * The last element in the exception handler list (used to generate the exception_table of the - * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May - * be null. - */ - private Handler lastHandler; - - /** - * The line_number_table_length field of the LineNumberTable code attribute. - */ - private int lineNumberTableLength; - - /** - * The line_number_table array of the LineNumberTable code attribute, or null. - */ - private ByteVector lineNumberTable; - - /** - * The local_variable_table_length field of the LocalVariableTable code attribute. - */ - private int localVariableTableLength; - - /** - * The local_variable_table array of the LocalVariableTable code attribute, or null. - */ - private ByteVector localVariableTable; - - /** - * The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. - */ - private int localVariableTypeTableLength; - - /** - * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or - * null. - */ - private ByteVector localVariableTypeTable; - - /** - * The number_of_entries field of the StackMapTable code attribute. - */ - private int stackMapTableNumberOfEntries; - - /** - * The 'entries' array of the StackMapTable code attribute. - */ - private ByteVector stackMapTableEntries; - - /** - * The last runtime visible type annotation of the Code attribute. The previous ones can be - * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of the Code attribute. The previous ones can be - * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation; - - /** - * The first non standard attribute of the Code attribute. The next ones can be accessed with the - * {@link Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstCodeAttribute; - - // Other method_info attributes: - - /** - * The number_of_exceptions field of the Exceptions attribute. - */ - final int numberOfExceptions; - - /** - * The exception_index_table array of the Exceptions attribute, or null. - */ - final int[] exceptionIndexTable; - - /** - * The signature_index field of the Signature attribute. - */ - final int signatureIndex; - - /** - * The last runtime visible annotation of this method. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this method. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The number of method parameters that can have runtime visible annotations, or 0. - */ - private int visibleAnnotableParameterCount; - - /** - * The runtime visible parameter annotations of this method. Each array element contains the last - * annotation of a parameter (which can be null - the previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field). May be null. - */ - private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations; - - /** - * The number of method parameters that can have runtime visible annotations, or 0. - */ - private int invisibleAnnotableParameterCount; - - /** - * The runtime invisible parameter annotations of this method. Each array element contains the - * last annotation of a parameter (which can be null - the previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field). May be null. - */ - private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations; - - /** - * The last runtime visible type annotation of this method. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this method. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The default_value field of the AnnotationDefault attribute, or null. - */ - private ByteVector defaultValue; - - /** - * The parameters_count field of the MethodParameters attribute. - */ - private int parametersCount; - - /** - * The 'parameters' array of the MethodParameters attribute, or null. - */ - private ByteVector parameters; - - /** - * The first non standard attribute of this method. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - // ----------------------------------------------------------------------------------------------- - // Fields used to compute the maximum stack size and number of locals, and the stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link - * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}. - */ - private final int compute; - - /** - * The first basic block of the method. The next ones (in bytecode offset order) can be accessed - * with the {@link Label#nextBasicBlock} field. - */ - private Label firstBasicBlock; - - /** - * The last basic block of the method (in bytecode offset order). This field is updated each time - * a basic block is encountered, and is used to append it at the end of the basic block list. - */ - private Label lastBasicBlock; - - /** - * The current basic block, i.e. the basic block of the last visited instruction. When {@link - * #compute} is equal to {@link #COMPUTE_ALL_FRAMES}, this field is null for unreachable - * code. When {@link #compute} is equal to {@link #COMPUTE_INSERTED_FRAMES}, this field stays - * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block; - * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame - * without using any control flow graph). - */ - private Label currentBasicBlock; - - /** - * The relative stack size after the last visited instruction. This size is relative to the - * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited - * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link - * #relativeStackSize}. - */ - private int relativeStackSize; - - /** - * The maximum relative stack size after the last visited instruction. This size is relative to - * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last - * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block - * plus {@link #maxRelativeStackSize}. - */ - private int maxRelativeStackSize; - - /** - * The number of local variables in the last visited stack map frame. - */ - private int currentLocals; - - /** - * The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. - */ - private int previousFrameOffset; - - /** - * The last frame that was written in {@link #stackMapTableEntries}. This field has the same - * format as {@link #currentFrame}. - */ - private int[] previousFrame; - - /** - * The current stack map frame. The first element contains the bytecode offset of the instruction - * to which the frame corresponds, the second element is the number of locals and the third one is - * the number of stack elements. The local variables start at index 3 and are followed by the - * operand stack elements. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack, - * frame[3] = nLocal. Local variables and operand stack entries contain abstract types, as defined - * in {@link Frame}, but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} - * or {@link Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array - * entry. - */ - private int[] currentFrame; - - /** - * The number of subroutines in this method. - */ - private int numSubroutines; - - // ----------------------------------------------------------------------------------------------- - // Other miscellaneous status fields - // ----------------------------------------------------------------------------------------------- - - /** - * Whether the bytecode of this method contains ASM specific instructions. - */ - private boolean hasAsmInstructions; - - /** - * The start offset of the last visited instruction. Used to set the offset field of type - * annotations of type 'offset_target' (see JVMS - * 4.7.20.1). - */ - private int lastBytecodeOffset; - - /** - * The offset in bytes in {@link #getSource} from which the method_info for this method (excluding - * its first 6 bytes) must be copied, or 0. - */ - int sourceOffset; - - /** - * The length in bytes in {@link #getSource} which must be copied to get the method_info for this - * method (excluding its first 6 bytes for access_flags, name_index and descriptor_index). - */ - int sourceLength; - - // ----------------------------------------------------------------------------------------------- - // Constructor and accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link MethodWriter}. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be null. - * @param exceptions the internal names of the method's exceptions. May be null. - * @param compute indicates what must be computed (see #compute). - */ - MethodWriter( - final SymbolTable symbolTable, - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions, - final int compute) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.accessFlags = "".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access; - this.nameIndex = symbolTable.addConstantUtf8(name); - this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); - this.descriptor = descriptor; - this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature); - if (exceptions != null && exceptions.length > 0) { - numberOfExceptions = exceptions.length; - this.exceptionIndexTable = new int[numberOfExceptions]; - for (int i = 0; i < numberOfExceptions; ++i) { - this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index; - } - } else { - numberOfExceptions = 0; - this.exceptionIndexTable = null; - } - this.compute = compute; - if (compute != COMPUTE_NOTHING) { - // Update maxLocals and currentLocals. - int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; - if ((access & Opcodes.ACC_STATIC) != 0) { - --argumentsSize; - } - maxLocals = argumentsSize; - currentLocals = argumentsSize; - // Create and visit the label for the first basic block. - firstBasicBlock = new Label(); - visitLabel(firstBasicBlock); - } - } - - ClassReader getSource() { - return symbolTable.getSource(); - } - - boolean hasFrames() { - return stackMapTableNumberOfEntries > 0; - } - - boolean hasAsmInstructions() { - return hasAsmInstructions; - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the MethodVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public void visitParameter(final String name, final int access) { - if (parameters == null) { - parameters = new ByteVector(); - } - ++parametersCount; - parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access); - } - - @Override - public AnnotationVisitor visitAnnotationDefault() { - defaultValue = new ByteVector(); - return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null); - } - - @Override - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { - if (visible) { - visibleAnnotableParameterCount = parameterCount; - } else { - invisibleAnnotableParameterCount = parameterCount; - } - } - - @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, final String annotationDescriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0); - if (visible) { - if (lastRuntimeVisibleParameterAnnotations == null) { - lastRuntimeVisibleParameterAnnotations = - new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - return lastRuntimeVisibleParameterAnnotations[parameter] = - new AnnotationWriter( - symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]); - } else { - if (lastRuntimeInvisibleParameterAnnotations == null) { - lastRuntimeInvisibleParameterAnnotations = - new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - return lastRuntimeInvisibleParameterAnnotations[parameter] = - new AnnotationWriter( - symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]); - } - } - - @Override - public void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - if (attribute.isCodeAttribute()) { - attribute.nextAttribute = firstCodeAttribute; - firstCodeAttribute = attribute; - } else { - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - } - - @Override - public void visitCode() { - // Nothing to do. - } - - @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - if (compute == COMPUTE_ALL_FRAMES) { - return; - } - - if (compute == COMPUTE_INSERTED_FRAMES) { - if (currentBasicBlock.frame == null) { - // This should happen only once, for the implicit first frame (which is explicitly visited - // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES - // can't be set if EXPAND_ASM_INSNS is not used). - currentBasicBlock.frame = new CurrentFrame(currentBasicBlock); - currentBasicBlock.frame.setInputFrameFromDescriptor( - symbolTable, accessFlags, descriptor, nLocal); - currentBasicBlock.frame.accept(this); - } else { - if (type == Opcodes.F_NEW) { - currentBasicBlock.frame.setInputFrameFromApiFormat( - symbolTable, nLocal, local, nStack, stack); - } else { - // In this case type is equal to F_INSERT by hypothesis, and currentBlock.frame contains - // the stack map frame at the current instruction, computed from the last F_NEW frame - // and the bytecode instructions in between (via calls to CurrentFrame#execute). - } - currentBasicBlock.frame.accept(this); - } - } else if (type == Opcodes.F_NEW) { - if (previousFrame == null) { - int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; - Frame implicitFirstFrame = new Frame(new Label()); - implicitFirstFrame.setInputFrameFromDescriptor( - symbolTable, accessFlags, descriptor, argumentsSize); - implicitFirstFrame.accept(this); - } - currentLocals = nLocal; - int frameIndex = visitFrameStart(code.length, nLocal, nStack); - for (int i = 0; i < nLocal; ++i) { - currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); - } - for (int i = 0; i < nStack; ++i) { - currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]); - } - visitFrameEnd(); - } else { - int offsetDelta; - if (stackMapTableEntries == null) { - stackMapTableEntries = new ByteVector(); - offsetDelta = code.length; - } else { - offsetDelta = code.length - previousFrameOffset - 1; - if (offsetDelta < 0) { - if (type == Opcodes.F_SAME) { - return; - } else { - throw new IllegalStateException(); - } - } - } - - switch (type) { - case Opcodes.F_FULL: - currentLocals = nLocal; - stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); - for (int i = 0; i < nLocal; ++i) { - putFrameType(local[i]); - } - stackMapTableEntries.putShort(nStack); - for (int i = 0; i < nStack; ++i) { - putFrameType(stack[i]); - } - break; - case Opcodes.F_APPEND: - currentLocals += nLocal; - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocal).putShort(offsetDelta); - for (int i = 0; i < nLocal; ++i) { - putFrameType(local[i]); - } - break; - case Opcodes.F_CHOP: - currentLocals -= nLocal; - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - nLocal).putShort(offsetDelta); - break; - case Opcodes.F_SAME: - if (offsetDelta < 64) { - stackMapTableEntries.putByte(offsetDelta); - } else { - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); - } - break; - case Opcodes.F_SAME1: - if (offsetDelta < 64) { - stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); - } else { - stackMapTableEntries - .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(offsetDelta); - } - putFrameType(stack[0]); - break; - default: - throw new IllegalArgumentException(); - } - - previousFrameOffset = code.length; - ++stackMapTableNumberOfEntries; - } - - maxStack = Math.max(maxStack, nStack); - maxLocals = Math.max(maxLocals, currentLocals); - } - - @Override - public void visitInsn(final int opcode) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(opcode); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, null, null); - } else { - int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { - endCurrentBasicBlockWithNoSuccessor(); - } - } - } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if (opcode == Opcodes.SIPUSH) { - code.put12(opcode, operand); - } else { // BIPUSH or NEWARRAY - code.put11(opcode, operand); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, operand, null, null); - } else if (opcode != Opcodes.NEWARRAY) { - // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY. - int size = relativeStackSize + 1; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitVarInsn(final int opcode, final int var) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if (var < 4 && opcode != Opcodes.RET) { - int optimizedOpcode; - if (opcode < Opcodes.ISTORE) { - optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var; - } else { - optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var; - } - code.putByte(optimizedOpcode); - } else if (var >= 256) { - code.putByte(Constants.WIDE).put12(opcode, var); - } else { - code.put11(opcode, var); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, var, null, null); - } else { - if (opcode == Opcodes.RET) { - // No stack size delta. - currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END; - currentBasicBlock.outputStackSize = (short) relativeStackSize; - endCurrentBasicBlockWithNoSuccessor(); - } else { // xLOAD or xSTORE - int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - if (compute != COMPUTE_NOTHING) { - int currentMaxLocals; - if (opcode == Opcodes.LLOAD - || opcode == Opcodes.DLOAD - || opcode == Opcodes.LSTORE - || opcode == Opcodes.DSTORE) { - currentMaxLocals = var + 2; - } else { - currentMaxLocals = var + 1; - } - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) { - // If there are exception handler blocks, each instruction within a handler range is, in - // theory, a basic block (since execution can jump from this instruction to the exception - // handler). As a consequence, the local variable types at the beginning of the handler - // block should be the merge of the local variable types at all the instructions within the - // handler range. However, instead of creating a basic block for each instruction, we can - // get the same result in a more efficient way. Namely, by starting a new basic block after - // each xSTORE instruction, which is what we do here. - visitLabel(new Label()); - } - } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol typeSymbol = symbolTable.addConstantClass(type); - code.put12(opcode, typeSymbol.index); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable); - } else if (opcode == Opcodes.NEW) { - // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF. - int size = relativeStackSize + 1; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String descriptor) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor); - code.put12(opcode, fieldrefSymbol.index); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable); - } else { - int size; - char firstDescChar = descriptor.charAt(0); - switch (opcode) { - case Opcodes.GETSTATIC: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1); - break; - case Opcodes.PUTSTATIC: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1); - break; - case Opcodes.GETFIELD: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0); - break; - case Opcodes.PUTFIELD: - default: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2); - break; - } - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface); - if (opcode == Opcodes.INVOKEINTERFACE) { - code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index) - .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0); - } else { - code.put12(opcode, methodrefSymbol.index); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable); - } else { - int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes(); - int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2); - int size; - if (opcode == Opcodes.INVOKESTATIC) { - size = relativeStackSize + stackSizeDelta + 1; - } else { - size = relativeStackSize + stackSizeDelta; - } - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitInvokeDynamicInsn( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol invokeDynamicSymbol = - symbolTable.addConstantInvokeDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); - code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index); - code.putShort(0); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable); - } else { - int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes(); - int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1; - int size = relativeStackSize + stackSizeDelta; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode. - int baseOpcode = - opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode; - boolean nextInsnIsJumpTarget = false; - if ((label.flags & Label.FLAG_RESOLVED) != 0 - && label.bytecodeOffset - code.length < Short.MIN_VALUE) { - // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO - // with GOTO_W, JSR with JSR_W and IFxxx with IFNOTxxx GOTO_W L:..., where - // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where designates - // the instruction just after the GOTO_W. - if (baseOpcode == Opcodes.GOTO) { - code.putByte(Constants.GOTO_W); - } else if (baseOpcode == Opcodes.JSR) { - code.putByte(Constants.JSR_W); - } else { - // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least - // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a - // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W). - code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1); - code.putShort(8); - // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this - // method or another one, and if the class has frames, we will need to insert a frame after - // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM - // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W - // here, which has the unfortunate effect of forcing this additional round trip (which in - // some case would not have been really necessary, but we can't know this at this point). - code.putByte(Constants.ASM_GOTO_W); - hasAsmInstructions = true; - // The instruction after the GOTO_W becomes the target of the IFNOT instruction. - nextInsnIsJumpTarget = true; - } - label.put(code, code.length - 1, true); - } else if (baseOpcode != opcode) { - // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove - // ASM specific instructions). In this case we keep the original instruction. - code.putByte(opcode); - label.put(code, code.length - 1, true); - } else { - // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these - // cases we store the offset in 2 bytes (which will be increased via a ClassReader -> - // ClassWriter round trip if it turns out that 2 bytes are not sufficient). - code.putByte(baseOpcode); - label.put(code, code.length - 1, false); - } - - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - Label nextBasicBlock = null; - if (compute == COMPUTE_ALL_FRAMES) { - currentBasicBlock.frame.execute(baseOpcode, 0, null, null); - // Record the fact that 'label' is the target of a jump instruction. - label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - // Add 'label' as a successor of the current basic block. - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - if (baseOpcode != Opcodes.GOTO) { - // The next instruction starts a new basic block (except for GOTO: by default the code - // following a goto is unreachable - unless there is an explicit label for it - and we - // should not compute stack frame types for its instructions). - nextBasicBlock = new Label(); - } - } else if (compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(baseOpcode, 0, null, null); - } else { - if (baseOpcode == Opcodes.JSR) { - // Record the fact that 'label' designates a subroutine, if not already done. - if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) { - label.flags |= Label.FLAG_SUBROUTINE_START; - ++numSubroutines; - } - currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER; - // Note that, by construction in this method, a block which calls a subroutine has at - // least two successors in the control flow graph: the first one (added below) leads to - // the instruction after the JSR, while the second one (added here) leads to the JSR - // target. Note that the first successor is virtual (it does not correspond to a possible - // execution path): it is only used to compute the successors of the basic blocks ending - // with a ret, in {@link Label#addSubroutineRetSuccessors}. - addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label); - // The instruction after the JSR starts a new basic block. - nextBasicBlock = new Label(); - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - } - // If the next instruction starts a new basic block, call visitLabel to add the label of this - // instruction as a successor of the current block, and to start a new basic block. - if (nextBasicBlock != null) { - if (nextInsnIsJumpTarget) { - nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET; - } - visitLabel(nextBasicBlock); - } - if (baseOpcode == Opcodes.GOTO) { - endCurrentBasicBlockWithNoSuccessor(); - } - } - } - - @Override - public void visitLabel(final Label label) { - // Resolve the forward references to this label, if any. - hasAsmInstructions |= label.resolve(code.data, code.length); - // visitLabel starts a new basic block (except for debug only labels), so we need to update the - // previous and current block references and list of successors. - if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) { - return; - } - if (compute == COMPUTE_ALL_FRAMES) { - if (currentBasicBlock != null) { - if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) { - // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only - // one place, but this does not work for labels which have not been visited yet. - // Therefore, when we detect here two labels having the same bytecode offset, we need to - // - consolidate the state scattered in these two instances into the canonical instance: - currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); - // - make sure the two instances share the same Frame instance (the implementation of - // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be - // null): - label.frame = currentBasicBlock.frame; - // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so - // that they still refer to the canonical instance for this bytecode offset. - return; - } - // End the current basic block (with one new successor). - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - } - // Append 'label' at the end of the basic block list. - if (lastBasicBlock != null) { - if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) { - // Same comment as above. - lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); - // Here label.frame should be null. - label.frame = lastBasicBlock.frame; - currentBasicBlock = lastBasicBlock; - return; - } - lastBasicBlock.nextBasicBlock = label; - } - lastBasicBlock = label; - // Make it the new current basic block. - currentBasicBlock = label; - // Here label.frame should be null. - label.frame = new Frame(label); - } else if (compute == COMPUTE_INSERTED_FRAMES) { - if (currentBasicBlock == null) { - // This case should happen only once, for the visitLabel call in the constructor. Indeed, if - // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged. - currentBasicBlock = label; - } else { - // Update the frame owner so that a correct frame offset is computed in Frame.accept(). - currentBasicBlock.frame.owner = label; - } - } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { - if (currentBasicBlock != null) { - // End the current basic block (with one new successor). - currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - // Start a new current basic block, and reset the current and maximum relative stack sizes. - currentBasicBlock = label; - relativeStackSize = 0; - maxRelativeStackSize = 0; - // Append the new basic block at the end of the basic block list. - if (lastBasicBlock != null) { - lastBasicBlock.nextBasicBlock = label; - } - lastBasicBlock = label; - } - } - - @Override - public void visitLdcInsn(final Object value) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol constantSymbol = symbolTable.addConstant(value); - int constantIndex = constantSymbol.index; - boolean isLongOrDouble = - constantSymbol.tag == Symbol.CONSTANT_LONG_TAG - || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG; - if (isLongOrDouble) { - code.put12(Constants.LDC2_W, constantIndex); - } else if (constantIndex >= 256) { - code.put12(Constants.LDC_W, constantIndex); - } else { - code.put11(Opcodes.LDC, constantIndex); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable); - } else { - int size = relativeStackSize + (isLongOrDouble ? 2 : 1); - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitIincInsn(final int var, final int increment) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if ((var > 255) || (increment > 127) || (increment < -128)) { - code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment); - } else { - code.putByte(Opcodes.IINC).put11(var, increment); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null - && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) { - currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null); - } - if (compute != COMPUTE_NOTHING) { - int currentMaxLocals = var + 1; - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - } - - @Override - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(code, lastBytecodeOffset, true); - code.putInt(min).putInt(max); - for (Label label : labels) { - label.put(code, lastBytecodeOffset, true); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - visitSwitchInsn(dflt, labels); - } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(code, lastBytecodeOffset, true); - code.putInt(labels.length); - for (int i = 0; i < labels.length; ++i) { - code.putInt(keys[i]); - labels[i].put(code, lastBytecodeOffset, true); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - visitSwitchInsn(dflt, labels); - } - - private void visitSwitchInsn(final Label dflt, final Label[] labels) { - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); - // Add all the labels as successors of the current basic block. - addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt); - dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - for (Label label : labels) { - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - } - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - --relativeStackSize; - // Add all the labels as successors of the current basic block. - addSuccessorToCurrentBasicBlock(relativeStackSize, dflt); - for (Label label : labels) { - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - } - // End the current basic block. - endCurrentBasicBlockWithNoSuccessor(); - } - } - - @Override - public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol descSymbol = symbolTable.addConstantClass(descriptor); - code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute( - Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - relativeStackSize += 1 - numDimensions; - } - } - } - - @Override - public AnnotationVisitor visitInsnAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitTryCatchBlock( - final Label start, final Label end, final Label handler, final String type) { - Handler newHandler = - new Handler( - start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type); - if (firstHandler == null) { - firstHandler = newHandler; - } else { - lastHandler.nextHandler = newHandler; - } - lastHandler = newHandler; - } - - @Override - public AnnotationVisitor visitTryCatchAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitLocalVariable( - final String name, - final String descriptor, - final String signature, - final Label start, - final Label end, - final int index) { - if (signature != null) { - if (localVariableTypeTable == null) { - localVariableTypeTable = new ByteVector(); - } - ++localVariableTypeTableLength; - localVariableTypeTable - .putShort(start.bytecodeOffset) - .putShort(end.bytecodeOffset - start.bytecodeOffset) - .putShort(symbolTable.addConstantUtf8(name)) - .putShort(symbolTable.addConstantUtf8(signature)) - .putShort(index); - } - if (localVariableTable == null) { - localVariableTable = new ByteVector(); - } - ++localVariableTableLength; - localVariableTable - .putShort(start.bytecodeOffset) - .putShort(end.bytecodeOffset - start.bytecodeOffset) - .putShort(symbolTable.addConstantUtf8(name)) - .putShort(symbolTable.addConstantUtf8(descriptor)) - .putShort(index); - if (compute != COMPUTE_NOTHING) { - char firstDescChar = descriptor.charAt(0); - int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1); - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - } - - @Override - public AnnotationVisitor visitLocalVariableAnnotation( - final int typeRef, - final TypePath typePath, - final Label[] start, - final Label[] end, - final int[] index, - final String descriptor, - final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - typeAnnotation.putByte(typeRef >>> 24).putShort(start.length); - for (int i = 0; i < start.length; ++i) { - typeAnnotation - .putShort(start[i].bytecodeOffset) - .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset) - .putShort(index[i]); - } - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitLineNumber(final int line, final Label start) { - if (lineNumberTable == null) { - lineNumberTable = new ByteVector(); - } - ++lineNumberTableLength; - lineNumberTable.putShort(start.bytecodeOffset); - lineNumberTable.putShort(line); - } - - @Override - public void visitMaxs(final int maxStack, final int maxLocals) { - if (compute == COMPUTE_ALL_FRAMES) { - computeAllFrames(); - } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { - computeMaxStackAndLocal(); - } else { - this.maxStack = maxStack; - this.maxLocals = maxLocals; - } - } - - /** - * Computes all the stack map frames of the method, from scratch. - */ - private void computeAllFrames() { - // Complete the control flow graph with exception handler blocks. - Handler handler = firstHandler; - while (handler != null) { - String catchTypeDescriptor = - handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor; - int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor); - // Mark handlerBlock as an exception handler. - Label handlerBlock = handler.handlerPc.getCanonicalInstance(); - handlerBlock.flags |= Label.FLAG_JUMP_TARGET; - // Add handlerBlock as a successor of all the basic blocks in the exception handler range. - Label handlerRangeBlock = handler.startPc.getCanonicalInstance(); - Label handlerRangeEnd = handler.endPc.getCanonicalInstance(); - while (handlerRangeBlock != handlerRangeEnd) { - handlerRangeBlock.outgoingEdges = - new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges); - handlerRangeBlock = handlerRangeBlock.nextBasicBlock; - } - handler = handler.nextHandler; - } - - // Create and visit the first (implicit) frame. - Frame firstFrame = firstBasicBlock.frame; - firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals); - firstFrame.accept(this); - - // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks - // whose stack map frame has changed) and, while there are blocks to process, remove one from - // the list and update the stack map frames of its successor blocks in the control flow graph - // (which might change them, in which case these blocks must be processed too, and are thus - // added to the list of blocks to process). Also compute the maximum stack size of the method, - // as a by-product. - Label listOfBlocksToProcess = firstBasicBlock; - listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; - int maxStackSize = 0; - while (listOfBlocksToProcess != Label.EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - basicBlock.nextListElement = null; - // By definition, basicBlock is reachable. - basicBlock.flags |= Label.FLAG_REACHABLE; - // Update the (absolute) maximum stack size. - int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax; - if (maxBlockStackSize > maxStackSize) { - maxStackSize = maxBlockStackSize; - } - // Update the successor blocks of basicBlock in the control flow graph. - Edge outgoingEdge = basicBlock.outgoingEdges; - while (outgoingEdge != null) { - Label successorBlock = outgoingEdge.successor.getCanonicalInstance(); - boolean successorBlockChanged = - basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info); - if (successorBlockChanged && successorBlock.nextListElement == null) { - // If successorBlock has changed it must be processed. Thus, if it is not already in the - // list of blocks to process, add it to this list. - successorBlock.nextListElement = listOfBlocksToProcess; - listOfBlocksToProcess = successorBlock; - } - outgoingEdge = outgoingEdge.nextEdge; - } - } - - // Loop over all the basic blocks and visit the stack map frames that must be stored in the - // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from - // exception handler ranges. - Label basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) - == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) { - basicBlock.frame.accept(this); - } - if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) { - // Find the start and end bytecode offsets of this unreachable block. - Label nextBasicBlock = basicBlock.nextBasicBlock; - int startOffset = basicBlock.bytecodeOffset; - int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1; - if (endOffset >= startOffset) { - // Replace its instructions with NOP ... NOP ATHROW. - for (int i = startOffset; i < endOffset; ++i) { - code.data[i] = Opcodes.NOP; - } - code.data[endOffset] = (byte) Opcodes.ATHROW; - // Emit a frame for this unreachable block, with no local and a Throwable on the stack - // (so that the ATHROW could consume this Throwable if it were reachable). - int frameIndex = visitFrameStart(startOffset, /* nLocal = */ 0, /* nStack = */ 1); - currentFrame[frameIndex] = - Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); - visitFrameEnd(); - // Remove this unreachable basic block from the exception handler ranges. - firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock); - // The maximum stack size is now at least one, because of the Throwable declared above. - maxStackSize = Math.max(maxStackSize, 1); - } - } - basicBlock = basicBlock.nextBasicBlock; - } - - this.maxStack = maxStackSize; - } - - /** - * Computes the maximum stack size of the method. - */ - private void computeMaxStackAndLocal() { - // Complete the control flow graph with exception handler blocks. - Handler handler = firstHandler; - while (handler != null) { - Label handlerBlock = handler.handlerPc; - Label handlerRangeBlock = handler.startPc; - Label handlerRangeEnd = handler.endPc; - // Add handlerBlock as a successor of all the basic blocks in the exception handler range. - while (handlerRangeBlock != handlerRangeEnd) { - if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) { - handlerRangeBlock.outgoingEdges = - new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges); - } else { - // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing - // edges to preserve the hypothesis about JSR block successors order (see - // {@link #visitJumpInsn}). - handlerRangeBlock.outgoingEdges.nextEdge.nextEdge = - new Edge( - Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge); - } - handlerRangeBlock = handlerRangeBlock.nextBasicBlock; - } - handler = handler.nextHandler; - } - - // Complete the control flow graph with the successor blocks of subroutines, if needed. - if (numSubroutines > 0) { - // First step: find the subroutines. This step determines, for each basic block, to which - // subroutine(s) it belongs. Start with the main "subroutine": - int subroutineId = 0; - firstBasicBlock.markSubroutine(subroutineId, numSubroutines); - // Then, loop over all the basic blocks to find those that belong to real subroutines. - Label basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_START) != 0 - && (basicBlock.flags & Label.FLAG_SUBROUTINE_BODY) == 0) { - // If this subroutine has not been marked yet, find its basic blocks. - subroutineId += 1; - basicBlock.markSubroutine(subroutineId, numSubroutines); - } - basicBlock = basicBlock.nextBasicBlock; - } - // Second step: find the successors in the control flow graph of each subroutine basic block - // 'r' ending with a RET instruction. These successors are the virtual successors of the basic - // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'. - basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { - // By construction, jsr targets are stored in the second outgoing edge of basic blocks - // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}). - Label subroutine = basicBlock.outgoingEdges.nextEdge.successor; - subroutine.addSubroutineRetSuccessors(basicBlock); - } - basicBlock = basicBlock.nextBasicBlock; - } - } - - // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks - // whose input stack size has changed) and, while there are blocks to process, remove one - // from the list, update the input stack size of its successor blocks in the control flow - // graph, and add these blocks to the list of blocks to process (if not already done). - Label listOfBlocksToProcess = firstBasicBlock; - listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; - int maxStackSize = 0; - while (listOfBlocksToProcess != Label.EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. Note that we don't reset - // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already - // processed basic blocks. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - // Compute the (absolute) input stack size and maximum stack size of this block. - int inputStackTop = basicBlock.inputStackSize; - int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax; - // Update the absolute maximum stack size of the method. - if (maxBlockStackSize > maxStackSize) { - maxStackSize = maxBlockStackSize; - } - // Update the input stack size of the successor blocks of basicBlock in the control flow - // graph, and add these blocks to the list of blocks to process, if not already done. - Edge outgoingEdge = basicBlock.outgoingEdges; - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { - // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual - // edges which lead to the instruction just after the jsr, and do not correspond to a - // possible execution path (see {@link #visitJumpInsn} and - // {@link Label#FLAG_SUBROUTINE_CALLER}). - outgoingEdge = outgoingEdge.nextEdge; - } - while (outgoingEdge != null) { - Label successorBlock = outgoingEdge.successor; - if (successorBlock.nextListElement == null) { - successorBlock.inputStackSize = - (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info); - successorBlock.nextListElement = listOfBlocksToProcess; - listOfBlocksToProcess = successorBlock; - } - outgoingEdge = outgoingEdge.nextEdge; - } - } - this.maxStack = Math.max(maxStack, maxStackSize); - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: control flow analysis algorithm - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a successor to {@link #currentBasicBlock} in the control flow graph. - * - * @param info information about the control flow edge to be added. - * @param successor the successor block to be added to the current basic block. - */ - private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) { - currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges); - } - - /** - * Ends the current basic block. This method must be used in the case where the current basic - * block does not have any successor. - * - *

WARNING: this method must be called after the currently visited instruction has been put in - * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic - * block after the current instruction). - */ - private void endCurrentBasicBlockWithNoSuccessor() { - if (compute == COMPUTE_ALL_FRAMES) { - Label nextBasicBlock = new Label(); - nextBasicBlock.frame = new Frame(nextBasicBlock); - nextBasicBlock.resolve(code.data, code.length); - lastBasicBlock.nextBasicBlock = nextBasicBlock; - lastBasicBlock = nextBasicBlock; - } else { - currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; - } - if (compute != COMPUTE_INSERTED_FRAMES) { - currentBasicBlock = null; - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Starts the visit of a new stack map frame, stored in {@link #currentFrame}. - * - * @param offset the bytecode offset of the instruction to which the frame corresponds. - * @param nLocal the number of local variables in the frame. - * @param nStack the number of stack elements in the frame. - * @return the index of the next element to be written in this frame. - */ - int visitFrameStart(final int offset, final int nLocal, final int nStack) { - int frameLength = 3 + nLocal + nStack; - if (currentFrame == null || currentFrame.length < frameLength) { - currentFrame = new int[frameLength]; - } - currentFrame[0] = offset; - currentFrame[1] = nLocal; - currentFrame[2] = nStack; - return 3; - } - - /** - * Sets an abstract type in {@link #currentFrame}. - * - * @param frameIndex the index of the element to be set in {@link #currentFrame}. - * @param abstractType an abstract type. - */ - void visitAbstractType(final int frameIndex, final int abstractType) { - currentFrame[frameIndex] = abstractType; - } - - /** - * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by - * updating the StackMapTable number_of_entries (except if the current frame is the first one, - * which is implicit in StackMapTable). Then resets {@link #currentFrame} to null. - */ - void visitFrameEnd() { - if (previousFrame != null) { - if (stackMapTableEntries == null) { - stackMapTableEntries = new ByteVector(); - } - putFrame(); - ++stackMapTableNumberOfEntries; - } - previousFrame = currentFrame; - currentFrame = null; - } - - /** - * Compresses and writes {@link #currentFrame} in a new StackMapTable entry. - */ - private void putFrame() { - final int nLocal = currentFrame[1]; - final int nStack = currentFrame[2]; - if (symbolTable.getMajorVersion() < Opcodes.V1_6) { - // Generate a StackMap attribute entry, which are always uncompressed. - stackMapTableEntries.putShort(currentFrame[0]).putShort(nLocal); - putAbstractTypes(3, 3 + nLocal); - stackMapTableEntries.putShort(nStack); - putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); - return; - } - final int offsetDelta = - stackMapTableNumberOfEntries == 0 - ? currentFrame[0] - : currentFrame[0] - previousFrame[0] - 1; - final int previousNlocal = previousFrame[1]; - final int nLocalDelta = nLocal - previousNlocal; - int type = Frame.FULL_FRAME; - if (nStack == 0) { - switch (nLocalDelta) { - case -3: - case -2: - case -1: - type = Frame.CHOP_FRAME; - break; - case 0: - type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED; - break; - case 1: - case 2: - case 3: - type = Frame.APPEND_FRAME; - break; - default: - // Keep the FULL_FRAME type. - break; - } - } else if (nLocalDelta == 0 && nStack == 1) { - type = - offsetDelta < 63 - ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME - : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; - } - if (type != Frame.FULL_FRAME) { - // Verify if locals are the same as in the previous frame. - int frameIndex = 3; - for (int i = 0; i < previousNlocal && i < nLocal; i++) { - if (currentFrame[frameIndex] != previousFrame[frameIndex]) { - type = Frame.FULL_FRAME; - break; - } - frameIndex++; - } - } - switch (type) { - case Frame.SAME_FRAME: - stackMapTableEntries.putByte(offsetDelta); - break; - case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME: - stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); - putAbstractTypes(3 + nLocal, 4 + nLocal); - break; - case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - stackMapTableEntries - .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(offsetDelta); - putAbstractTypes(3 + nLocal, 4 + nLocal); - break; - case Frame.SAME_FRAME_EXTENDED: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); - break; - case Frame.CHOP_FRAME: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); - break; - case Frame.APPEND_FRAME: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); - putAbstractTypes(3 + previousNlocal, 3 + nLocal); - break; - case Frame.FULL_FRAME: - default: - stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); - putAbstractTypes(3, 3 + nLocal); - stackMapTableEntries.putShort(nStack); - putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); - } - } - - /** - * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the - * JVMS verification_type_info format used in StackMapTable attributes. - * - * @param start index of the first type in {@link #currentFrame} to write. - * @param end index of last type in {@link #currentFrame} to write (exclusive). - */ - private void putAbstractTypes(final int start, final int end) { - for (int i = start; i < end; ++i) { - Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries); - } - } - - /** - * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS - * verification_type_info format used in StackMapTable attributes. - * - * @param type a frame element type described using the same format as in {@link - * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or - * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating - * a NEW instruction (for uninitialized types). - */ - private void putFrameType(final Object type) { - if (type instanceof Integer) { - stackMapTableEntries.putByte(((Integer) type).intValue()); - } else if (type instanceof String) { - stackMapTableEntries - .putByte(Frame.ITEM_OBJECT) - .putShort(symbolTable.addConstantClass((String) type).index); - } else { - stackMapTableEntries - .putByte(Frame.ITEM_UNINITIALIZED) - .putShort(((Label) type).bytecodeOffset); - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the - * names of the attributes of this method in the constant pool. - * - * @return the size in bytes of the method_info JVMS structure. - */ - int computeMethodInfoSize() { - // If this method_info must be copied from an existing one, the size computation is trivial. - if (sourceOffset != 0) { - // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index. - return 6 + sourceLength; - } - // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count. - int size = 8; - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (code.length > 0) { - if (code.length > 65535) { - throw new IndexOutOfBoundsException("Method code too large!"); - } - symbolTable.addConstantUtf8(Constants.CODE); - // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack, - // max_locals, code_length and attributes_count, plus the bytecode and the exception table. - size += 16 + code.length + Handler.getExceptionTableSize(firstHandler); - if (stackMapTableEntries != null) { - boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; - symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"); - // 6 header bytes and 2 bytes for number_of_entries. - size += 8 + stackMapTableEntries.length; - } - if (lineNumberTable != null) { - symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE); - // 6 header bytes and 2 bytes for line_number_table_length. - size += 8 + lineNumberTable.length; - } - if (localVariableTable != null) { - symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE); - // 6 header bytes and 2 bytes for local_variable_table_length. - size += 8 + localVariableTable.length; - } - if (localVariableTypeTable != null) { - symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE); - // 6 header bytes and 2 bytes for local_variable_type_table_length. - size += 8 + localVariableTypeTable.length; - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - size += - lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - size += - lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (firstCodeAttribute != null) { - size += - firstCodeAttribute.computeAttributesSize( - symbolTable, code.data, code.length, maxStack, maxLocals); - } - } - if (numberOfExceptions > 0) { - symbolTable.addConstantUtf8(Constants.EXCEPTIONS); - size += 8 + 2 * numberOfExceptions; - } - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - size += 6; - } - if (signatureIndex != 0) { - symbolTable.addConstantUtf8(Constants.SIGNATURE); - size += 8; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - symbolTable.addConstantUtf8(Constants.DEPRECATED); - size += 6; - } - if (lastRuntimeVisibleAnnotation != null) { - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleParameterAnnotations != null) { - size += - AnnotationWriter.computeParameterAnnotationsSize( - Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, - lastRuntimeVisibleParameterAnnotations, - visibleAnnotableParameterCount == 0 - ? lastRuntimeVisibleParameterAnnotations.length - : visibleAnnotableParameterCount); - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - size += - AnnotationWriter.computeParameterAnnotationsSize( - Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, - lastRuntimeInvisibleParameterAnnotations, - invisibleAnnotableParameterCount == 0 - ? lastRuntimeInvisibleParameterAnnotations.length - : invisibleAnnotableParameterCount); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (defaultValue != null) { - symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT); - size += 6 + defaultValue.length; - } - if (parameters != null) { - symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS); - // 6 header bytes and 1 byte for parameters_count. - size += 7 + parameters.length; - } - if (firstAttribute != null) { - size += firstAttribute.computeAttributesSize(symbolTable); - } - return size; - } - - /** - * Puts the content of the method_info JVMS structure generated by this MethodWriter into the - * given ByteVector. - * - * @param output where the method_info structure must be put. - */ - void putMethodInfo(final ByteVector output) { - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; - output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); - // If this method_info must be copied from an existing one, copy it now and return early. - if (sourceOffset != 0) { - output.putByteArray(getSource().b, sourceOffset, sourceLength); - return; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributeCount = 0; - if (code.length > 0) { - ++attributeCount; - } - if (numberOfExceptions > 0) { - ++attributeCount; - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - ++attributeCount; - } - if (signatureIndex != 0) { - ++attributeCount; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributeCount; - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeVisibleParameterAnnotations != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - ++attributeCount; - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributeCount; - } - if (defaultValue != null) { - ++attributeCount; - } - if (parameters != null) { - ++attributeCount; - } - if (firstAttribute != null) { - attributeCount += firstAttribute.getAttributeCount(); - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - output.putShort(attributeCount); - if (code.length > 0) { - // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and - // attributes_count, plus the bytecode and the exception table. - int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler); - int codeAttributeCount = 0; - if (stackMapTableEntries != null) { - // 6 header bytes and 2 bytes for number_of_entries. - size += 8 + stackMapTableEntries.length; - ++codeAttributeCount; - } - if (lineNumberTable != null) { - // 6 header bytes and 2 bytes for line_number_table_length. - size += 8 + lineNumberTable.length; - ++codeAttributeCount; - } - if (localVariableTable != null) { - // 6 header bytes and 2 bytes for local_variable_table_length. - size += 8 + localVariableTable.length; - ++codeAttributeCount; - } - if (localVariableTypeTable != null) { - // 6 header bytes and 2 bytes for local_variable_type_table_length. - size += 8 + localVariableTypeTable.length; - ++codeAttributeCount; - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - size += - lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - ++codeAttributeCount; - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - size += - lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - ++codeAttributeCount; - } - if (firstCodeAttribute != null) { - size += - firstCodeAttribute.computeAttributesSize( - symbolTable, code.data, code.length, maxStack, maxLocals); - codeAttributeCount += firstCodeAttribute.getAttributeCount(); - } - output - .putShort(symbolTable.addConstantUtf8(Constants.CODE)) - .putInt(size) - .putShort(maxStack) - .putShort(maxLocals) - .putInt(code.length) - .putByteArray(code.data, 0, code.length); - Handler.putExceptionTable(firstHandler, output); - output.putShort(codeAttributeCount); - if (stackMapTableEntries != null) { - boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; - output - .putShort( - symbolTable.addConstantUtf8( - useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap")) - .putInt(2 + stackMapTableEntries.length) - .putShort(stackMapTableNumberOfEntries) - .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length); - } - if (lineNumberTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE)) - .putInt(2 + lineNumberTable.length) - .putShort(lineNumberTableLength) - .putByteArray(lineNumberTable.data, 0, lineNumberTable.length); - } - if (localVariableTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE)) - .putInt(2 + localVariableTable.length) - .putShort(localVariableTableLength) - .putByteArray(localVariableTable.data, 0, localVariableTable.length); - } - if (localVariableTypeTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE)) - .putInt(2 + localVariableTypeTable.length) - .putShort(localVariableTypeTableLength) - .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length); - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - lastCodeRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (firstCodeAttribute != null) { - firstCodeAttribute.putAttributes( - symbolTable, code.data, code.length, maxStack, maxLocals, output); - } - } - if (numberOfExceptions > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS)) - .putInt(2 + 2 * numberOfExceptions) - .putShort(numberOfExceptions); - for (int exceptionIndex : exceptionIndexTable) { - output.putShort(exceptionIndex); - } - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeVisibleParameterAnnotations != null) { - AnnotationWriter.putParameterAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), - lastRuntimeVisibleParameterAnnotations, - visibleAnnotableParameterCount == 0 - ? lastRuntimeVisibleParameterAnnotations.length - : visibleAnnotableParameterCount, - output); - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - AnnotationWriter.putParameterAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS), - lastRuntimeInvisibleParameterAnnotations, - invisibleAnnotableParameterCount == 0 - ? lastRuntimeInvisibleParameterAnnotations.length - : invisibleAnnotableParameterCount, - output); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (defaultValue != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT)) - .putInt(defaultValue.length) - .putByteArray(defaultValue.data, 0, defaultValue.length); - } - if (parameters != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS)) - .putInt(1 + parameters.length) - .putByte(parametersCount) - .putByteArray(parameters.data, 0, parameters.length); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, output); - } - } - - /** - * Collects the attributes of this method into the given set of attribute prototypes. - * - * @param attributePrototypes a set of attribute prototypes. - */ - final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { - attributePrototypes.addAttributes(firstAttribute); - attributePrototypes.addAttributes(firstCodeAttribute); - } -} diff --git a/src/main/java/org/objectweb/asm/ModuleVisitor.java b/src/main/java/org/objectweb/asm/ModuleVisitor.java deleted file mode 100644 index 85cc070f..00000000 --- a/src/main/java/org/objectweb/asm/ModuleVisitor.java +++ /dev/null @@ -1,175 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java module. The methods of this class must be called in the following - * order: visitMainClass | ( visitPackage | visitRequire | - * visitExport | visitOpen | visitUse | visitProvide )* - * visitEnd. - * - * @author Remi Forax - * @author Eric Bruneton - */ -public abstract class ModuleVisitor { - /** - * The ASM API version implemented by this visitor. The value of this field must be {@link - * Opcodes#ASM6}. - */ - protected final int api; - - /** - * The module visitor to which this visitor must delegate method calls. May be null. - */ - protected ModuleVisitor mv; - - /** - * Constructs a new {@link ModuleVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. - */ - public ModuleVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link ModuleVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. - * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May - * be null. - */ - public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) { - if (api != Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.mv = moduleVisitor; - } - - /** - * Visit the main class of the current module. - * - * @param mainClass the internal name of the main class of the current module. - */ - public void visitMainClass(final String mainClass) { - if (mv != null) { - mv.visitMainClass(mainClass); - } - } - - /** - * Visit a package of the current module. - * - * @param packaze the internal name of a package. - */ - public void visitPackage(final String packaze) { - if (mv != null) { - mv.visitPackage(packaze); - } - } - - /** - * Visits a dependence of the current module. - * - * @param module the fully qualified name (using dots) of the dependence. - * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code - * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param version the module version at compile time, or null. - */ - public void visitRequire(final String module, final int access, final String version) { - if (mv != null) { - mv.visitRequire(module, access, version); - } - } - - /** - * Visit an exported package of the current module. - * - * @param packaze the internal name of the exported package. - * @param access the access flag of the exported package, valid values are among {@code - * ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param modules the fully qualified names (using dots) of the modules that can access the public - * classes of the exported package, or null. - */ - public void visitExport(final String packaze, final int access, final String... modules) { - if (mv != null) { - mv.visitExport(packaze, access, modules); - } - } - - /** - * Visit an open package of the current module. - * - * @param packaze the internal name of the opened package. - * @param access the access flag of the opened package, valid values are among {@code - * ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param modules the fully qualified names (using dots) of the modules that can use deep - * reflection to the classes of the open package, or null. - */ - public void visitOpen(final String packaze, final int access, final String... modules) { - if (mv != null) { - mv.visitOpen(packaze, access, modules); - } - } - - /** - * Visit a service used by the current module. The name must be the internal name of an interface - * or a class. - * - * @param service the internal name of the service. - */ - public void visitUse(final String service) { - if (mv != null) { - mv.visitUse(service); - } - } - - /** - * Visit an implementation of a service. - * - * @param service the internal name of the service. - * @param providers the internal names of the implementations of the service (there is at least - * one provider). - */ - public void visitProvide(final String service, final String... providers) { - if (mv != null) { - mv.visitProvide(service, providers); - } - } - - /** - * Visits the end of the module. This method, which is the last one to be called, is used to - * inform the visitor that everything have been visited. - */ - public void visitEnd() { - if (mv != null) { - mv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ModuleWriter.java b/src/main/java/org/objectweb/asm/ModuleWriter.java deleted file mode 100644 index 773de762..00000000 --- a/src/main/java/org/objectweb/asm/ModuleWriter.java +++ /dev/null @@ -1,287 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and - * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS). - * - * @author Remi Forax - * @author Eric Bruneton - * @see JVMS - * 4.7.25 - * @see JVMS - * 4.7.26 - * @see JVMS - * 4.7.27 - */ -final class ModuleWriter extends ModuleVisitor { - - /** - * Where the constants used in this AnnotationWriter must be stored. - */ - private final SymbolTable symbolTable; - - /** - * The module_name_index field of the JVMS Module attribute. - */ - private final int moduleNameIndex; - - /** - * The module_flags field of the JVMS Module attribute. - */ - private final int moduleFlags; - - /** - * The module_version_index field of the JVMS Module attribute. - */ - private final int moduleVersionIndex; - - /** - * The requires_count field of the JVMS Module attribute. - */ - private int requiresCount; - - /** - * The binary content of the 'requires' array of the JVMS Module attribute. - */ - private final ByteVector requires; - - /** - * The exports_count field of the JVMS Module attribute. - */ - private int exportsCount; - - /** - * The binary content of the 'exports' array of the JVMS Module attribute. - */ - private final ByteVector exports; - - /** - * The opens_count field of the JVMS Module attribute. - */ - private int opensCount; - - /** - * The binary content of the 'opens' array of the JVMS Module attribute. - */ - private final ByteVector opens; - - /** - * The uses_count field of the JVMS Module attribute. - */ - private int usesCount; - - /** - * The binary content of the 'uses_index' array of the JVMS Module attribute. - */ - private final ByteVector usesIndex; - - /** - * The provides_count field of the JVMS Module attribute. - */ - private int providesCount; - - /** - * The binary content of the 'provides' array of the JVMS Module attribute. - */ - private final ByteVector provides; - - /** - * The provides_count field of the JVMS ModulePackages attribute. - */ - private int packageCount; - - /** - * The binary content of the 'package_index' array of the JVMS ModulePackages attribute. - */ - private final ByteVector packageIndex; - - /** - * The main_class_index field of the JVMS ModuleMainClass attribute, or 0. - */ - private int mainClassIndex; - - ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.moduleNameIndex = name; - this.moduleFlags = access; - this.moduleVersionIndex = version; - this.requires = new ByteVector(); - this.exports = new ByteVector(); - this.opens = new ByteVector(); - this.usesIndex = new ByteVector(); - this.provides = new ByteVector(); - this.packageIndex = new ByteVector(); - } - - @Override - public void visitMainClass(final String mainClass) { - this.mainClassIndex = symbolTable.addConstantClass(mainClass).index; - } - - @Override - public void visitPackage(final String packaze) { - packageIndex.putShort(symbolTable.addConstantPackage(packaze).index); - packageCount++; - } - - @Override - public void visitRequire(final String module, final int access, final String version) { - requires - .putShort(symbolTable.addConstantModule(module).index) - .putShort(access) - .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); - requiresCount++; - } - - @Override - public void visitExport(final String packaze, final int access, final String... modules) { - exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); - if (modules == null) { - exports.putShort(0); - } else { - exports.putShort(modules.length); - for (String module : modules) { - exports.putShort(symbolTable.addConstantModule(module).index); - } - } - exportsCount++; - } - - @Override - public void visitOpen(final String packaze, final int access, final String... modules) { - opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); - if (modules == null) { - opens.putShort(0); - } else { - opens.putShort(modules.length); - for (String module : modules) { - opens.putShort(symbolTable.addConstantModule(module).index); - } - } - opensCount++; - } - - @Override - public void visitUse(final String service) { - usesIndex.putShort(symbolTable.addConstantClass(service).index); - usesCount++; - } - - @Override - public void visitProvide(final String service, final String... providers) { - provides.putShort(symbolTable.addConstantClass(service).index); - provides.putShort(providers.length); - for (String provider : providers) { - provides.putShort(symbolTable.addConstantClass(provider).index); - } - providesCount++; - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - /** - * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this - * ModuleWriter. - * - * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3). - */ - int getAttributeCount() { - return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0); - } - - /** - * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this - * ModuleWriter. Also add the names of these attributes in the constant pool. - * - * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. - */ - int computeAttributesSize() { - symbolTable.addConstantUtf8(Constants.MODULE); - // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. - int size = - 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; - if (packageCount > 0) { - symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); - // 6 attribute header bytes, and 2 bytes for package_count. - size += 8 + packageIndex.length; - } - if (mainClassIndex > 0) { - symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); - // 6 attribute header bytes, and 2 bytes for main_class_index. - size += 8; - } - return size; - } - - /** - * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter - * in the given ByteVector. - * - * @param output where the attributes must be put. - */ - void putAttributes(final ByteVector output) { - // 6 bytes for name, flags and version, and 5 * 2 bytes for counts. - int moduleAttributeLength = - 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE)) - .putInt(moduleAttributeLength) - .putShort(moduleNameIndex) - .putShort(moduleFlags) - .putShort(moduleVersionIndex) - .putShort(requiresCount) - .putByteArray(requires.data, 0, requires.length) - .putShort(exportsCount) - .putByteArray(exports.data, 0, exports.length) - .putShort(opensCount) - .putByteArray(opens.data, 0, opens.length) - .putShort(usesCount) - .putByteArray(usesIndex.data, 0, usesIndex.length) - .putShort(providesCount) - .putByteArray(provides.data, 0, provides.length); - if (packageCount > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES)) - .putInt(2 + packageIndex.length) - .putShort(packageCount) - .putByteArray(packageIndex.data, 0, packageIndex.length); - } - if (mainClassIndex > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS)) - .putInt(2) - .putShort(mainClassIndex); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Opcodes.java b/src/main/java/org/objectweb/asm/Opcodes.java deleted file mode 100644 index ed3faeb8..00000000 --- a/src/main/java/org/objectweb/asm/Opcodes.java +++ /dev/null @@ -1,331 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM - * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes - * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and - * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically - * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS 6 - */ -public interface Opcodes { - - // ASM API versions. - - int ASM4 = 4 << 16 | 0 << 8; - int ASM5 = 5 << 16 | 0 << 8; - int ASM6 = 6 << 16 | 0 << 8; - - // Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the - // major version in the 16 least significant bits). - - int V1_1 = 3 << 16 | 45; - int V1_2 = 0 << 16 | 46; - int V1_3 = 0 << 16 | 47; - int V1_4 = 0 << 16 | 48; - int V1_5 = 0 << 16 | 49; - int V1_6 = 0 << 16 | 50; - int V1_7 = 0 << 16 | 51; - int V1_8 = 0 << 16 | 52; - int V9 = 0 << 16 | 53; - int V10 = 0 << 16 | 54; - - // Access flags values, defined in - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25 - - int ACC_PUBLIC = 0x0001; // class, field, method - int ACC_PRIVATE = 0x0002; // class, field, method - int ACC_PROTECTED = 0x0004; // class, field, method - int ACC_STATIC = 0x0008; // field, method - int ACC_FINAL = 0x0010; // class, field, method, parameter - int ACC_SUPER = 0x0020; // class - int ACC_SYNCHRONIZED = 0x0020; // method - int ACC_OPEN = 0x0020; // module - int ACC_TRANSITIVE = 0x0020; // module requires - int ACC_VOLATILE = 0x0040; // field - int ACC_BRIDGE = 0x0040; // method - int ACC_STATIC_PHASE = 0x0040; // module requires - int ACC_VARARGS = 0x0080; // method - int ACC_TRANSIENT = 0x0080; // field - int ACC_NATIVE = 0x0100; // method - int ACC_INTERFACE = 0x0200; // class - int ACC_ABSTRACT = 0x0400; // class, method - int ACC_STRICT = 0x0800; // method - int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * - int ACC_ANNOTATION = 0x2000; // class - int ACC_ENUM = 0x4000; // class(?) field inner - int ACC_MANDATED = 0x8000; // parameter, module, module * - int ACC_MODULE = 0x8000; // class - - // ASM specific access flags. - // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard - // access flags, and also to make sure that these flags are automatically filtered out when - // written in class files (because access flags are stored using 16 bits only). - - int ACC_DEPRECATED = 0x20000; // class, field, method - - // Possible values for the type operand of the NEWARRAY instruction. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray. - - int T_BOOLEAN = 4; - int T_CHAR = 5; - int T_FLOAT = 6; - int T_DOUBLE = 7; - int T_BYTE = 8; - int T_SHORT = 9; - int T_INT = 10; - int T_LONG = 11; - - // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8. - - int H_GETFIELD = 1; - int H_GETSTATIC = 2; - int H_PUTFIELD = 3; - int H_PUTSTATIC = 4; - int H_INVOKEVIRTUAL = 5; - int H_INVOKESTATIC = 6; - int H_INVOKESPECIAL = 7; - int H_NEWINVOKESPECIAL = 8; - int H_INVOKEINTERFACE = 9; - - // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. - - /** - * An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. - */ - int F_NEW = -1; - - /** - * A compressed frame with complete frame data. - */ - int F_FULL = 0; - - /** - * A compressed frame where locals are the same as the locals in the previous frame, except that - * additional 1-3 locals are defined, and with an empty stack. - */ - int F_APPEND = 1; - - /** - * A compressed frame where locals are the same as the locals in the previous frame, except that - * the last 1-3 locals are absent and with an empty stack. - */ - int F_CHOP = 2; - - /** - * A compressed frame with exactly the same locals as the previous frame and with an empty stack. - */ - int F_SAME = 3; - - /** - * A compressed frame with exactly the same locals as the previous frame and with a single value - * on the stack. - */ - int F_SAME1 = 4; - - // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}. - - Integer TOP = Frame.ITEM_TOP; - Integer INTEGER = Frame.ITEM_INTEGER; - Integer FLOAT = Frame.ITEM_FLOAT; - Integer DOUBLE = Frame.ITEM_DOUBLE; - Integer LONG = Frame.ITEM_LONG; - Integer NULL = Frame.ITEM_NULL; - Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS; - - // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and - // where '-' means 'same method name as on the previous line'). - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. - - int NOP = 0; // visitInsn - int ACONST_NULL = 1; // - - int ICONST_M1 = 2; // - - int ICONST_0 = 3; // - - int ICONST_1 = 4; // - - int ICONST_2 = 5; // - - int ICONST_3 = 6; // - - int ICONST_4 = 7; // - - int ICONST_5 = 8; // - - int LCONST_0 = 9; // - - int LCONST_1 = 10; // - - int FCONST_0 = 11; // - - int FCONST_1 = 12; // - - int FCONST_2 = 13; // - - int DCONST_0 = 14; // - - int DCONST_1 = 15; // - - int BIPUSH = 16; // visitIntInsn - int SIPUSH = 17; // - - int LDC = 18; // visitLdcInsn - int ILOAD = 21; // visitVarInsn - int LLOAD = 22; // - - int FLOAD = 23; // - - int DLOAD = 24; // - - int ALOAD = 25; // - - int IALOAD = 46; // visitInsn - int LALOAD = 47; // - - int FALOAD = 48; // - - int DALOAD = 49; // - - int AALOAD = 50; // - - int BALOAD = 51; // - - int CALOAD = 52; // - - int SALOAD = 53; // - - int ISTORE = 54; // visitVarInsn - int LSTORE = 55; // - - int FSTORE = 56; // - - int DSTORE = 57; // - - int ASTORE = 58; // - - int IASTORE = 79; // visitInsn - int LASTORE = 80; // - - int FASTORE = 81; // - - int DASTORE = 82; // - - int AASTORE = 83; // - - int BASTORE = 84; // - - int CASTORE = 85; // - - int SASTORE = 86; // - - int POP = 87; // - - int POP2 = 88; // - - int DUP = 89; // - - int DUP_X1 = 90; // - - int DUP_X2 = 91; // - - int DUP2 = 92; // - - int DUP2_X1 = 93; // - - int DUP2_X2 = 94; // - - int SWAP = 95; // - - int IADD = 96; // - - int LADD = 97; // - - int FADD = 98; // - - int DADD = 99; // - - int ISUB = 100; // - - int LSUB = 101; // - - int FSUB = 102; // - - int DSUB = 103; // - - int IMUL = 104; // - - int LMUL = 105; // - - int FMUL = 106; // - - int DMUL = 107; // - - int IDIV = 108; // - - int LDIV = 109; // - - int FDIV = 110; // - - int DDIV = 111; // - - int IREM = 112; // - - int LREM = 113; // - - int FREM = 114; // - - int DREM = 115; // - - int INEG = 116; // - - int LNEG = 117; // - - int FNEG = 118; // - - int DNEG = 119; // - - int ISHL = 120; // - - int LSHL = 121; // - - int ISHR = 122; // - - int LSHR = 123; // - - int IUSHR = 124; // - - int LUSHR = 125; // - - int IAND = 126; // - - int LAND = 127; // - - int IOR = 128; // - - int LOR = 129; // - - int IXOR = 130; // - - int LXOR = 131; // - - int IINC = 132; // visitIincInsn - int I2L = 133; // visitInsn - int I2F = 134; // - - int I2D = 135; // - - int L2I = 136; // - - int L2F = 137; // - - int L2D = 138; // - - int F2I = 139; // - - int F2L = 140; // - - int F2D = 141; // - - int D2I = 142; // - - int D2L = 143; // - - int D2F = 144; // - - int I2B = 145; // - - int I2C = 146; // - - int I2S = 147; // - - int LCMP = 148; // - - int FCMPL = 149; // - - int FCMPG = 150; // - - int DCMPL = 151; // - - int DCMPG = 152; // - - int IFEQ = 153; // visitJumpInsn - int IFNE = 154; // - - int IFLT = 155; // - - int IFGE = 156; // - - int IFGT = 157; // - - int IFLE = 158; // - - int IF_ICMPEQ = 159; // - - int IF_ICMPNE = 160; // - - int IF_ICMPLT = 161; // - - int IF_ICMPGE = 162; // - - int IF_ICMPGT = 163; // - - int IF_ICMPLE = 164; // - - int IF_ACMPEQ = 165; // - - int IF_ACMPNE = 166; // - - int GOTO = 167; // - - int JSR = 168; // - - int RET = 169; // visitVarInsn - int TABLESWITCH = 170; // visiTableSwitchInsn - int LOOKUPSWITCH = 171; // visitLookupSwitch - int IRETURN = 172; // visitInsn - int LRETURN = 173; // - - int FRETURN = 174; // - - int DRETURN = 175; // - - int ARETURN = 176; // - - int RETURN = 177; // - - int GETSTATIC = 178; // visitFieldInsn - int PUTSTATIC = 179; // - - int GETFIELD = 180; // - - int PUTFIELD = 181; // - - int INVOKEVIRTUAL = 182; // visitMethodInsn - int INVOKESPECIAL = 183; // - - int INVOKESTATIC = 184; // - - int INVOKEINTERFACE = 185; // - - int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn - int NEW = 187; // visitTypeInsn - int NEWARRAY = 188; // visitIntInsn - int ANEWARRAY = 189; // visitTypeInsn - int ARRAYLENGTH = 190; // visitInsn - int ATHROW = 191; // - - int CHECKCAST = 192; // visitTypeInsn - int INSTANCEOF = 193; // - - int MONITORENTER = 194; // visitInsn - int MONITOREXIT = 195; // - - int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn - int IFNULL = 198; // visitJumpInsn - int IFNONNULL = 199; // - -} diff --git a/src/main/java/org/objectweb/asm/Symbol.java b/src/main/java/org/objectweb/asm/Symbol.java deleted file mode 100644 index cb9157de..00000000 --- a/src/main/java/org/objectweb/asm/Symbol.java +++ /dev/null @@ -1,273 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type - * table of a class. - * - * @author Eric Bruneton - * @see JVMS - * 4.4 - * @see JVMS - * 4.7.23 - */ -abstract class Symbol { - - // Tag values for the constant pool entries (using the same order as in the JVMS). - - /** - * The tag value of CONSTANT_Class_info JVMS structures. - */ - static final int CONSTANT_CLASS_TAG = 7; - - /** - * The tag value of CONSTANT_Fieldref_info JVMS structures. - */ - static final int CONSTANT_FIELDREF_TAG = 9; - - /** - * The tag value of CONSTANT_Methodref_info JVMS structures. - */ - static final int CONSTANT_METHODREF_TAG = 10; - - /** - * The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. - */ - static final int CONSTANT_INTERFACE_METHODREF_TAG = 11; - - /** - * The tag value of CONSTANT_String_info JVMS structures. - */ - static final int CONSTANT_STRING_TAG = 8; - - /** - * The tag value of CONSTANT_Integer_info JVMS structures. - */ - static final int CONSTANT_INTEGER_TAG = 3; - - /** - * The tag value of CONSTANT_Float_info JVMS structures. - */ - static final int CONSTANT_FLOAT_TAG = 4; - - /** - * The tag value of CONSTANT_Long_info JVMS structures. - */ - static final int CONSTANT_LONG_TAG = 5; - - /** - * The tag value of CONSTANT_Double_info JVMS structures. - */ - static final int CONSTANT_DOUBLE_TAG = 6; - - /** - * The tag value of CONSTANT_NameAndType_info JVMS structures. - */ - static final int CONSTANT_NAME_AND_TYPE_TAG = 12; - - /** - * The tag value of CONSTANT_Utf8_info JVMS structures. - */ - static final int CONSTANT_UTF8_TAG = 1; - - /** - * The tag value of CONSTANT_MethodHandle_info JVMS structures. - */ - static final int CONSTANT_METHOD_HANDLE_TAG = 15; - - /** - * The tag value of CONSTANT_MethodType_info JVMS structures. - */ - static final int CONSTANT_METHOD_TYPE_TAG = 16; - - /** - * The tag value of CONSTANT_InvokeDynamic_info JVMS structures. - */ - static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18; - - /** - * The tag value of CONSTANT_Module_info JVMS structures. - */ - static final int CONSTANT_MODULE_TAG = 19; - - /** - * The tag value of CONSTANT_Package_info JVMS structures. - */ - static final int CONSTANT_PACKAGE_TAG = 20; - - // Tag values for the BootstrapMethods attribute entries (ASM specific tag). - - /** - * The tag value of the BootstrapMethods attribute entries. - */ - static final int BOOTSTRAP_METHOD_TAG = 64; - - // Tag values for the type table entries (ASM specific tags). - - /** - * The tag value of a normal type entry in the (ASM specific) type table of a class. - */ - static final int TYPE_TAG = 128; - - /** - * The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class. - */ - static final int UNINITIALIZED_TYPE_TAG = 129; - - /** - * The tag value of a merged type entry in the (ASM specific) type table of a class. - */ - static final int MERGED_TYPE_TAG = 130; - - // Instance fields. - - /** - * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the - * (ASM specific) type table of a class (depending on the {@link #tag} value). - */ - final int index; - - /** - * A tag indicating the type of this symbol. Must be one of the static tag values defined in this - * class. - */ - final int tag; - - /** - * The internal name of the owner class of this symbol. Only used for {@link - * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link - * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols. - */ - final String owner; - - /** - * The name of the class field or method corresponding to this symbol. Only used for {@link - * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link - * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link - * #CONSTANT_METHOD_HANDLE_TAG} and {@link #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. - */ - final String name; - - /** - * The string value of this symbol. This is: - * - *

    - *
  • a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link - * #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link - * #CONSTANT_METHOD_TYPE_TAG} and {@link #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG} - * symbols, - *
  • an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link - * #UNINITIALIZED_TYPE_TAG} symbols, - *
  • null for the other types of symbol. - *
- */ - final String value; - - /** - * The numeric value of this symbol. This is: - * - *
    - *
  • the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link - * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG}, - *
  • the CONSTANT_MethodHandle_info reference_kind field value for {@link - * #CONSTANT_METHOD_HANDLE_TAG} symbols, - *
  • the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for - * {@link #BOOTSTRAP_METHOD_TAG} symbols, - *
  • the bytecode offset of the NEW instruction that created an {@link - * Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols, - *
  • the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link - * #MERGED_TYPE_TAG} symbols, - *
  • 0 for the other types of symbol. - *
- */ - final long data; - - /** - * Additional information about this symbol, generally computed lazily. Warning: the value of - * this field is ignored when comparing Symbol instances (to avoid duplicate entries in a - * SymbolTable). Therefore, this field should only contain data that can be computed from the - * other fields of this class. It contains: - * - *
    - *
  • the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this - * class, for {@link #CONSTANT_CLASS_TAG} symbols, - *
  • the index (in the class' type table) of the merged type of the two source types for - * {@link #MERGED_TYPE_TAG} symbols, - *
  • 0 for the other types of symbol, or if this field has not been computed yet. - *
- */ - int info; - - /** - * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is - * abstract. Instead, use the factory methods of the {@link SymbolTable} class. - * - * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in - * the (ASM specific) type table of a class (depending on 'tag'). - * @param tag the symbol type. Must be one of the static tag values defined in this class. - * @param owner The internal name of the symbol's owner class. Maybe null. - * @param name The name of the symbol's corresponding class field or method. Maybe null. - * @param value The string value of this symbol. Maybe null. - * @param data The numeric value of this symbol. - */ - Symbol( - final int index, - final int tag, - final String owner, - final String name, - final String value, - final long data) { - this.index = index; - this.tag = tag; - this.owner = owner; - this.name = name; - this.value = value; - this.data = data; - } - - /** - * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in - * {@link #info} for efficiency). This should only be used for {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. - */ - int getArgumentsAndReturnSizes() { - if (info == 0) { - info = Type.getArgumentsAndReturnSizes(value); - } - return info; - } -} diff --git a/src/main/java/org/objectweb/asm/SymbolTable.java b/src/main/java/org/objectweb/asm/SymbolTable.java deleted file mode 100644 index a90fdd2d..00000000 --- a/src/main/java/org/objectweb/asm/SymbolTable.java +++ /dev/null @@ -1,1239 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type - * table entries of a class. - * - * @author Eric Bruneton - * @see JVMS - * 4.4 - * @see JVMS - * 4.7.23 - */ -final class SymbolTable { - - /** - * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields - * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid - * duplicate symbols). See {@link #entries}. - * - * @author Eric Bruneton - */ - private static class Entry extends Symbol { - - /** - * The hash code of this entry. - */ - final int hashCode; - - /** - * Another entry (and so on recursively) having the same hash code (modulo the size of {@link - * #entries}) as this one. - */ - Entry next; - - Entry( - final int index, - final int tag, - final String owner, - final String name, - final String value, - final long data, - final int hashCode) { - super(index, tag, owner, name, value, data); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final String value, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final String value, final long data, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, value, data); - this.hashCode = hashCode; - } - - Entry( - final int index, final int tag, final String name, final String value, final int hashCode) { - super(index, tag, /* owner = */ null, name, value, /* data = */ 0); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final long data, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data); - this.hashCode = hashCode; - } - } - - /** - * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link - * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link - * Attribute#write}. - */ - final ClassWriter classWriter; - - /** - * The ClassReader from which this SymbolTable was constructed, or null if it was - * constructed from scratch. - */ - private final ClassReader sourceClassReader; - - /** - * The major version number of the class to which this symbol table belongs. - */ - private int majorVersion; - - /** - * The internal name of the class to which this symbol table belongs. - */ - private String className; - - /** - * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are - * accessible (recursively) via {@link Entry#next}. - */ - private int entryCount; - - /** - * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the - * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at - * the array index given by its hash code modulo the array size. If several entries must be stored - * at the same array index, they are linked together via their {@link Entry#next} field. The - * factory methods of this class make sure that this table does not contain duplicated entries. - */ - private Entry[] entries; - - /** - * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool - * item has index 1, and long and double items count for two items. - */ - private int constantPoolCount; - - /** - * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable. - * The ClassFile's constant_pool_count field is not included. - */ - private ByteVector constantPool; - - /** - * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the - * BootstrapMethods_attribute's num_bootstrap_methods field value. - */ - private int bootstrapMethodCount; - - /** - * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this - * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its - * num_bootstrap_methods field, are not included. - */ - private ByteVector bootstrapMethods; - - /** - * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to - * typeCount (excluded). The other array entries are empty. - */ - private int typeCount; - - /** - * An ASM specific type table used to temporarily store internal names that will not necessarily - * be stored in the constant pool. This type table is used by the control flow and data flow - * analysis algorithm used to compute stack map frames from scratch. This array stores {@link - * Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index - * i has its {@link Symbol#index} equal to i (and vice versa). - */ - private Entry[] typeTable; - - /** - * Constructs a new, empty SymbolTable for the given ClassWriter. - * - * @param classWriter a ClassWriter. - */ - SymbolTable(final ClassWriter classWriter) { - this.classWriter = classWriter; - this.sourceClassReader = null; - this.entries = new Entry[256]; - this.constantPoolCount = 1; - this.constantPool = new ByteVector(); - } - - /** - * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and - * bootstrap methods of the given ClassReader. - * - * @param classWriter a ClassWriter. - * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to - * initialize the SymbolTable. - */ - SymbolTable(final ClassWriter classWriter, final ClassReader classReader) { - this.classWriter = classWriter; - this.sourceClassReader = classReader; - - // Copy the constant pool binary content. - byte[] inputBytes = classReader.b; - int constantPoolOffset = classReader.getItem(1) - 1; - int constantPoolLength = classReader.header - constantPoolOffset; - constantPoolCount = classReader.getItemCount(); - constantPool = new ByteVector(constantPoolLength); - constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength); - - // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to - // avoid too many hash set collisions (entries is not dynamically resized by the addConstant* - // method calls below), and to account for bootstrap method entries. - entries = new Entry[constantPoolCount * 2]; - char[] charBuffer = new char[classReader.getMaxStringLength()]; - int itemIndex = 1; - while (itemIndex < constantPoolCount) { - int itemOffset = classReader.getItem(itemIndex); - int itemTag = inputBytes[itemOffset - 1]; - int nameAndTypeItemOffset; - switch (itemTag) { - case Symbol.CONSTANT_FIELDREF_TAG: - case Symbol.CONSTANT_METHODREF_TAG: - case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); - addConstantMemberReference( - itemIndex, - itemTag, - classReader.readClass(itemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_INTEGER_TAG: - case Symbol.CONSTANT_FLOAT_TAG: - addConstantInteger(itemIndex, itemTag, classReader.readInt(itemOffset)); - break; - case Symbol.CONSTANT_NAME_AND_TYPE_TAG: - addConstantNameAndType( - itemIndex, - classReader.readUTF8(itemOffset, charBuffer), - classReader.readUTF8(itemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_LONG_TAG: - case Symbol.CONSTANT_DOUBLE_TAG: - addConstantLong(itemIndex, itemTag, classReader.readLong(itemOffset)); - break; - case Symbol.CONSTANT_UTF8_TAG: - addConstantUtf8(itemIndex, classReader.readUTF(itemIndex, charBuffer)); - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - int memberRefItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 1)); - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2)); - addConstantMethodHandle( - itemIndex, - classReader.readByte(itemOffset), - classReader.readClass(memberRefItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); - addConstantInvokeDynamic( - itemIndex, - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer), - classReader.readUnsignedShort(itemOffset)); - break; - case Symbol.CONSTANT_STRING_TAG: - case Symbol.CONSTANT_CLASS_TAG: - case Symbol.CONSTANT_METHOD_TYPE_TAG: - case Symbol.CONSTANT_MODULE_TAG: - case Symbol.CONSTANT_PACKAGE_TAG: - addConstantUtf8Reference( - itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer)); - break; - default: - throw new IllegalArgumentException(); - } - itemIndex += - (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1; - } - - // Copy the BootstrapMethods 'bootstrap_methods' array binary content, if any. - int currentAttributeOffset = classReader.getFirstAttributeOffset(); - for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer); - if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6); - break; - } - currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2); - } - if (bootstrapMethodCount > 0) { - // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array. - int bootstrapMethodsOffset = currentAttributeOffset + 8; - int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2; - bootstrapMethods = new ByteVector(bootstrapMethodsLength); - bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength); - - // Add each bootstrap method in the symbol table entries. - int currentOffset = bootstrapMethodsOffset; - for (int i = 0; i < bootstrapMethodCount; i++) { - int offset = currentOffset - bootstrapMethodsOffset; - int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - int numBootstrapArguments = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode(); - while (numBootstrapArguments-- > 0) { - int bootstrapArgument = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode(); - } - add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF)); - } - } - } - - /** - * @return the ClassReader from which this SymbolTable was constructed, or null if it was - * constructed from scratch. - */ - ClassReader getSource() { - return sourceClassReader; - } - - /** - * @return the major version of the class to which this symbol table belongs. - */ - int getMajorVersion() { - return majorVersion; - } - - /** - * @return the internal name of the class to which this symbol table belongs. - */ - String getClassName() { - return className; - } - - /** - * Sets the major version and the name of the class to which this symbol table belongs. Also adds - * the class name to the constant pool. - * - * @param majorVersion a major ClassFile version number. - * @param className an internal class name. - * @return the constant pool index of a new or already existing Symbol with the given class name. - */ - int setMajorVersionAndClassName(final int majorVersion, final String className) { - this.majorVersion = majorVersion; - this.className = className; - return addConstantClass(className).index; - } - - /** - * @return the number of items in this symbol table's constant_pool array (plus 1). - */ - int getConstantPoolCount() { - return constantPoolCount; - } - - /** - * @return the length in bytes of this symbol table's constant_pool array. - */ - int getConstantPoolLength() { - return constantPool.length; - } - - /** - * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the - * constant_pool_count value. - * - * @param output where the JVMS ClassFile's constant_pool array must be put. - */ - void putConstantPool(final ByteVector output) { - output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length); - } - - /** - * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the - * attribute name in the constant pool. - * - * @return the size in bytes of this symbol table's BootstrapMethods attribute. - */ - int computeBootstrapMethodsSize() { - if (bootstrapMethods != null) { - addConstantUtf8(Constants.BOOTSTRAP_METHODS); - return 8 + bootstrapMethods.length; - } else { - return 0; - } - } - - /** - * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the - * 6 attribute header bytes and the num_bootstrap_methods value. - * - * @param output where the JVMS BootstrapMethods attribute must be put. - */ - void putBootstrapMethods(final ByteVector output) { - if (bootstrapMethods != null) { - output - .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS)) - .putInt(bootstrapMethods.length + 2) - .putShort(bootstrapMethodCount) - .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); - } - } - - // ----------------------------------------------------------------------------------------------- - // Generic symbol table entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * @param hashCode a {@link Entry#hashCode} value. - * @return the list of entries which can potentially have the given hash code. The list is stored - * via the {@link Entry#next} field. - */ - private Entry get(final int hashCode) { - return entries[hashCode % entries.length]; - } - - /** - * Puts the given entry in the {@link #entries} hash set. This method does not check - * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized - * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link - * #entries} array index) as much as possible, with reasonable memory usage. - * - * @param entry an Entry (which must not already be contained in {@link #entries}). - * @return the given entry - */ - private Entry put(final Entry entry) { - if (entryCount > (entries.length * 3) / 4) { - int currentCapacity = entries.length; - int newCapacity = currentCapacity * 2 + 1; - Entry[] newEntries = new Entry[newCapacity]; - for (int i = currentCapacity - 1; i >= 0; --i) { - Entry currentEntry = entries[i]; - while (currentEntry != null) { - int newCurrentEntryIndex = currentEntry.hashCode % newCapacity; - Entry nextEntry = currentEntry.next; - currentEntry.next = newEntries[newCurrentEntryIndex]; - newEntries[newCurrentEntryIndex] = currentEntry; - currentEntry = nextEntry; - } - } - entries = newEntries; - } - entryCount++; - int index = entry.hashCode % entries.length; - entry.next = entries[index]; - return entries[index] = entry; - } - - /** - * Adds the given entry in the {@link #entries} hash set. This method does not check - * whether {@link #entries} already contains a similar entry or not, and does not resize - * {@link #entries} if necessary. - * - * @param entry an Entry (which must not already be contained in {@link #entries}). - */ - private void add(final Entry entry) { - entryCount++; - int index = entry.hashCode % entries.length; - entry.next = entries[index]; - entries[index] = entry; - } - - // ----------------------------------------------------------------------------------------------- - // Constant pool entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value the value of the constant to be added to the constant pool. This parameter must be - * an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link - * Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstant(final Object value) { - if (value instanceof Integer) { - return addConstantInteger(((Integer) value).intValue()); - } else if (value instanceof Byte) { - return addConstantInteger(((Byte) value).intValue()); - } else if (value instanceof Character) { - return addConstantInteger(((Character) value).charValue()); - } else if (value instanceof Short) { - return addConstantInteger(((Short) value).intValue()); - } else if (value instanceof Boolean) { - return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0); - } else if (value instanceof Float) { - return addConstantFloat(((Float) value).floatValue()); - } else if (value instanceof Long) { - return addConstantLong(((Long) value).longValue()); - } else if (value instanceof Double) { - return addConstantDouble(((Double) value).doubleValue()); - } else if (value instanceof String) { - return addConstantString((String) value); - } else if (value instanceof Type) { - Type type = (Type) value; - int typeSort = type.getSort(); - if (typeSort == Type.OBJECT) { - return addConstantClass(type.getInternalName()); - } else if (typeSort == Type.METHOD) { - return addConstantMethodType(type.getDescriptor()); - } else { // type is a primitive or array type. - return addConstantClass(type.getDescriptor()); - } - } else if (value instanceof Handle) { - Handle handle = (Handle) value; - return addConstantMethodHandle( - handle.tag, handle.owner, handle.name, handle.descriptor, handle.isInterface); - } else { - throw new IllegalArgumentException("value " + value); - } - } - - /** - * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value the internal name of a class. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantClass(final String value) { - return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value); - } - - /** - * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param owner the internal name of a class. - * @param name a field name. - * @param descriptor a field descriptor. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantFieldref(final String owner, final String name, final String descriptor) { - return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor); - } - - /** - * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this - * symbol table. Does nothing if the constant pool already contains a similar item. - * - * @param owner the internal name of a class. - * @param name a method name. - * @param descriptor a method descriptor. - * @param isInterface whether owner is an interface or not. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodref( - final String owner, final String name, final String descriptor, final boolean isInterface) { - int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG; - return addConstantMemberReference(tag, owner, name, descriptor); - } - - /** - * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to - * the constant pool of this symbol table. Does nothing if the constant pool already contains a - * similar item. - * - * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} - * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. - * @param owner the internal name of a class. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @return a new or already existing Symbol with the given value. - */ - private Entry addConstantMemberReference( - final int tag, final String owner, final String name, final String descriptor) { - int hashCode = hash(tag, owner, name, descriptor); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.owner.equals(owner) - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - constantPool.put122( - tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor)); - return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode)); - } - - /** - * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info - * to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} - * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. - * @param owner the internal name of a class. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantMemberReference( - final int index, - final int tag, - final String owner, - final String name, - final String descriptor) { - add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor))); - } - - /** - * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a string. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantString(final String value) { - return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value); - } - - /** - * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value an int. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantInteger(final int value) { - return addConstantInteger(Symbol.CONSTANT_INTEGER_TAG, value); - } - - /** - * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a float. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantFloat(final float value) { - return addConstantInteger(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value)); - } - - /** - * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table. - * Does nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. - * @param value an int or float. - * @return a constant pool constant with the given tag and primitive values. - */ - private Symbol addConstantInteger(final int tag, final int value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { - return entry; - } - entry = entry.next; - } - constantPool.putByte(tag).putInt(value); - return put(new Entry(constantPoolCount++, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol - * table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. - * @param value an int or float. - */ - private void addConstantInteger(final int index, final int tag, final int value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - /** - * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a long. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantLong(final long value) { - return addConstantLong(Symbol.CONSTANT_LONG_TAG, value); - } - - /** - * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a double. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantDouble(final double value) { - return addConstantLong(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value)); - } - - /** - * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table. - * Does nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. - * @param value a long or double. - * @return a constant pool constant with the given tag and primitive values. - */ - private Symbol addConstantLong(final int tag, final long value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { - return entry; - } - entry = entry.next; - } - int index = constantPoolCount; - constantPool.putByte(tag).putLong(value); - constantPoolCount += 2; - return put(new Entry(index, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Double_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. - * @param value a long or double. - */ - private void addConstantLong(final int index, final int tag, final long value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - /** - * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @return a new or already existing Symbol with the given value. - */ - int addConstantNameAndType(final String name, final String descriptor) { - final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; - int hashCode = hash(tag, name, descriptor); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry.index; - } - entry = entry.next; - } - constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor)); - return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index; - } - - /** - * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantNameAndType(final int index, final String name, final String descriptor) { - final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; - add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor))); - } - - /** - * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a string. - * @return a new or already existing Symbol with the given value. - */ - int addConstantUtf8(final String value) { - int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.CONSTANT_UTF8_TAG - && entry.hashCode == hashCode - && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value); - return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index; - } - - /** - * Adds a new CONSTANT_String_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param value a string. - */ - private void addConstantUtf8(final int index, final String value) { - add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value))); - } - - /** - * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if - * the constant pool already contains a similar item. - * - * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link - * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of a class of interface. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @param isInterface whether owner is an interface or not. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodHandle( - final int referenceKind, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; - // Note that we don't need to include isInterface in the hash computation, because it is - // redundant with owner (we can't have the same owner with different isInterface values). - int hashCode = hash(tag, owner, name, descriptor, referenceKind); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.data == referenceKind - && entry.owner.equals(owner) - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - if (referenceKind <= Opcodes.H_PUTSTATIC) { - constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index); - } else { - constantPool.put112( - tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index); - } - return put( - new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode)); - } - - /** - * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link - * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of a class of interface. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantMethodHandle( - final int index, - final int referenceKind, - final String owner, - final String name, - final String descriptor) { - final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; - int hashCode = hash(tag, owner, name, descriptor, referenceKind); - add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode)); - } - - /** - * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param methodDescriptor a method descriptor. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodType(final String methodDescriptor) { - return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor); - } - - /** - * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the - * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodHandle a bootstrap method handle. - * @param bootstrapMethodArguments the bootstrap method arguments. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantInvokeDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments); - return addConstantInvokeDynamic(name, descriptor, bootstrapMethod.index); - } - - /** - * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Does nothing if - * the constant pool already contains a similar item. - * - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addConstantInvokeDynamic( - final String name, final String descriptor, final int bootstrapMethodIndex) { - final int tag = Symbol.CONSTANT_INVOKE_DYNAMIC_TAG; - int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.data == bootstrapMethodIndex - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor)); - return put( - new Entry( - constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); - } - - /** - * Adds a new CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. - */ - private void addConstantInvokeDynamic( - final int index, final String name, final String descriptor, final int bootstrapMethodIndex) { - final int tag = Symbol.CONSTANT_INVOKE_DYNAMIC_TAG; - int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); - add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); - } - - /** - * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param moduleName a fully qualified name (using dots) of a module. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantModule(final String moduleName) { - return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName); - } - - /** - * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param packageName the internal name of a package. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantPackage(final String packageName) { - return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName); - } - - /** - * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, - * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does - * nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link - * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link - * Symbol#CONSTANT_PACKAGE_TAG}. - * @param value an internal class name, an arbitrary string, a method descriptor, a module or a - * package name, depending on tag. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addConstantUtf8Reference(final int tag, final String value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) { - return entry; - } - entry = entry.next; - } - constantPool.put12(tag, addConstantUtf8(value)); - return put(new Entry(constantPoolCount++, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, - * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link - * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link - * Symbol#CONSTANT_PACKAGE_TAG}. - * @param value an internal class name, an arbitrary string, a method descriptor, a module or a - * package name, depending on tag. - */ - private void addConstantUtf8Reference(final int index, final int tag, final String value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - // ----------------------------------------------------------------------------------------------- - // Bootstrap method entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if - * the BootstrapMethods already contains a similar bootstrap method. - * - * @param bootstrapMethodHandle a bootstrap method handle. - * @param bootstrapMethodArguments the bootstrap method arguments. - * @return a new or already existing Symbol with the given value. - */ - Symbol addBootstrapMethod( - final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { - ByteVector bootstrapMethodsAttribute = bootstrapMethods; - if (bootstrapMethodsAttribute == null) { - bootstrapMethodsAttribute = bootstrapMethods = new ByteVector(); - } - - // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to - // compare it with existing ones, and will be reverted below if there is already a similar - // bootstrap method. - int bootstrapMethodOffset = bootstrapMethodsAttribute.length; - bootstrapMethodsAttribute.putShort( - addConstantMethodHandle( - bootstrapMethodHandle.tag, - bootstrapMethodHandle.owner, - bootstrapMethodHandle.name, - bootstrapMethodHandle.descriptor, - bootstrapMethodHandle.isInterface()) - .index); - int numBootstrapArguments = bootstrapMethodArguments.length; - bootstrapMethodsAttribute.putShort(numBootstrapArguments); - for (int i = 0; i < numBootstrapArguments; i++) { - bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArguments[i]).index); - } - - // Compute the length and the hash code of the bootstrap method. - int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset; - int hashCode = bootstrapMethodHandle.hashCode(); - for (int i = 0; i < numBootstrapArguments; i++) { - hashCode ^= bootstrapMethodArguments[i].hashCode(); - } - hashCode &= 0x7FFFFFFF; - - // Add the bootstrap method to the symbol table or revert the above changes. - return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode); - } - - /** - * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if - * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the - * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method). - * - * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes. - * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes. - * @param hashCode the hash code of this bootstrap method. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) { - final byte[] bootstrapMethodsData = bootstrapMethods.data; - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) { - int otherOffset = (int) entry.data; - boolean isSameBootstrapMethod = true; - for (int i = 0; i < length; ++i) { - if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) { - isSameBootstrapMethod = false; - break; - } - } - if (isSameBootstrapMethod) { - bootstrapMethods.length = offset; // Revert to old position. - return entry; - } - } - entry = entry.next; - } - return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode)); - } - - // ----------------------------------------------------------------------------------------------- - // Type table entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * @param typeIndex a type table index. - * @return the type table element whose index is given. - */ - Symbol getType(final int typeIndex) { - return typeTable[typeIndex]; - } - - /** - * Adds a type in the type table of this symbol table. Does nothing if the type table already - * contains a similar type. - * - * @param value an internal class name. - * @return the index of a new or already existing type Symbol with the given value. - */ - int addType(final String value) { - int hashCode = hash(Symbol.TYPE_TAG, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - return addType(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode)); - } - - /** - * Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does - * nothing if the type table already contains a similar type. - * - * @param value an internal class name. - * @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link - * Frame#ITEM_UNINITIALIZED} type value. - * @return the index of a new or already existing type Symbol with the given value. - */ - int addUninitializedType(final String value, final int bytecodeOffset) { - int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG - && entry.hashCode == hashCode - && entry.data == bytecodeOffset - && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - return addType( - new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode)); - } - - /** - * Adds a merged type in the type table of this symbol table. Does nothing if the type table - * already contains a similar type. - * - * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type - * table. - * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type - * table. - * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol, - * corresponding to the common super class of the given types. - */ - int addMergedType(final int typeTableIndex1, final int typeTableIndex2) { - // TODO sort the arguments? The merge result should be independent of their order. - long data = typeTableIndex1 | (((long) typeTableIndex2) << 32); - int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) { - return entry.info; - } - entry = entry.next; - } - String type1 = typeTable[typeTableIndex1].value; - String type2 = typeTable[typeTableIndex2].value; - int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2)); - put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex; - return commonSuperTypeIndex; - } - - /** - * Adds the given type Symbol to {@link #typeTable}. - * - * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol. - * The index of this Symbol must be equal to the current value of {@link #typeCount}. - * @return the index in {@link #typeTable} where the given type was added, which is also equal to - * entry's index by hypothesis. - */ - private int addType(final Entry entry) { - if (typeTable == null) { - typeTable = new Entry[16]; - } - if (typeCount == typeTable.length) { - Entry[] newTypeTable = new Entry[2 * typeTable.length]; - System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length); - typeTable = newTypeTable; - } - typeTable[typeCount++] = entry; - return put(entry).index; - } - - // ----------------------------------------------------------------------------------------------- - // Static helper methods to compute hash codes. - // ----------------------------------------------------------------------------------------------- - - private static int hash(final int tag, final int value) { - return 0x7FFFFFFF & (tag + value); - } - - private static int hash(final int tag, final long value) { - return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32)); - } - - private static int hash(final int tag, final String value) { - return 0x7FFFFFFF & (tag + value.hashCode()); - } - - private static int hash(final int tag, final String value1, final int value2) { - return 0x7FFFFFFF & (tag + value1.hashCode() + value2); - } - - private static int hash(final int tag, final String value1, final String value2) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode()); - } - - private static int hash( - final int tag, final String value1, final String value2, final int value3) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1)); - } - - private static int hash( - final int tag, final String value1, final String value2, final String value3) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode()); - } - - private static int hash( - final int tag, - final String value1, - final String value2, - final String value3, - final int value4) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4); - } -} diff --git a/src/main/java/org/objectweb/asm/Type.java b/src/main/java/org/objectweb/asm/Type.java deleted file mode 100644 index 9b204401..00000000 --- a/src/main/java/org/objectweb/asm/Type.java +++ /dev/null @@ -1,953 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -/** - * A Java field or method type. This class can be used to make it easier to manipulate type and - * method descriptors. - * - * @author Eric Bruneton - * @author Chris Nokleberg - */ -public class Type { - - /** - * The sort of the void type. See {@link #getSort}. - */ - public static final int VOID = 0; - - /** - * The sort of the boolean type. See {@link #getSort}. - */ - public static final int BOOLEAN = 1; - - /** - * The sort of the char type. See {@link #getSort}. - */ - public static final int CHAR = 2; - - /** - * The sort of the byte type. See {@link #getSort}. - */ - public static final int BYTE = 3; - - /** - * The sort of the short type. See {@link #getSort}. - */ - public static final int SHORT = 4; - - /** - * The sort of the int type. See {@link #getSort}. - */ - public static final int INT = 5; - - /** - * The sort of the float type. See {@link #getSort}. - */ - public static final int FLOAT = 6; - - /** - * The sort of the long type. See {@link #getSort}. - */ - public static final int LONG = 7; - - /** - * The sort of the double type. See {@link #getSort}. - */ - public static final int DOUBLE = 8; - - /** - * The sort of array reference types. See {@link #getSort}. - */ - public static final int ARRAY = 9; - - /** - * The sort of object reference types. See {@link #getSort}. - */ - public static final int OBJECT = 10; - - /** - * The sort of method types. See {@link #getSort}. - */ - public static final int METHOD = 11; - - /** - * The (private) sort of object reference types represented with an internal name. - */ - private static final int INTERNAL = 12; - - /** - * The descriptors of the primitive types. - */ - private static final char[] PRIMITIVE_DESCRIPTORS = - new char[]{'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D'}; - - /** - * The void type. - */ - public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, 1); - - /** - * The boolean type. - */ - public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, 1); - - /** - * The char type. - */ - public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, 1); - - /** - * The byte type. - */ - public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, 1); - - /** - * The short type. - */ - public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, 1); - - /** - * The int type. - */ - public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, 1); - - /** - * The float type. - */ - public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, 1); - - /** - * The long type. - */ - public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, 1); - - /** - * The double type. - */ - public static final Type DOUBLE_TYPE = new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, 1); - - // ----------------------------------------------------------------------------------------------- - // Fields - // ----------------------------------------------------------------------------------------------- - - /** - * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, - * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, - * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}. - */ - private final int sort; - - /** - * A buffer containing the value of this field or method type. This value is an internal name for - * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other - * cases. - * - *

For {@link #OBJECT} types, this field also contains the descriptor: the {@link #valueLength} - * chars after {@link #valueOffset} contain the internal name, and the {@link #valueLength} + 2 - * chars after {@link #valueOffset} - 1 contain the descriptor. - */ - private final char[] valueBuffer; - - /** - * The offset of the value of this Java field or method type in {@link #valueBuffer}. This value - * is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, and a field or method - * descriptor in the other cases. - */ - private final int valueOffset; - - /** - * The length of the value of this Java field or method type in {@link #valueBuffer}. This value - * is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, and a field or method - * descriptor in the other cases. - */ - private final int valueLength; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a reference type. - * - * @param sort the sort of this type, see {@link #sort}. - * @param valueBuffer a buffer containing the value of this field or method type. - * @param valueOffset the offset of the value of this field or method type in valueBuffer. - * @param valueLength the length of the value of this field or method type. - */ - private Type( - final int sort, final char[] valueBuffer, final int valueOffset, final int valueLength) { - this.sort = sort; - this.valueBuffer = valueBuffer; - this.valueOffset = valueOffset; - this.valueLength = valueLength; - } - - /** - * Returns the {@link Type} corresponding to the given type descriptor. - * - * @param typeDescriptor a field or method type descriptor. - * @return the {@link Type} corresponding to the given type descriptor. - */ - public static Type getType(final String typeDescriptor) { - final char[] valueBuffer = typeDescriptor.toCharArray(); - return getType(valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the {@link Type} corresponding to the given internal name. - * - * @param internalName an internal name. - * @return the {@link Type} corresponding to the given internal name. - */ - public static Type getObjectType(final String internalName) { - final char[] valueBuffer = internalName.toCharArray(); - return new Type(valueBuffer[0] == '[' ? ARRAY : INTERNAL, valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to - * Type.getType(methodDescriptor). - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} corresponding to the given method descriptor. - */ - public static Type getMethodType(final String methodDescriptor) { - final char[] valueBuffer = methodDescriptor.toCharArray(); - return new Type(METHOD, valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the method {@link Type} corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the method {@link Type} corresponding to the given argument and return types. - */ - public static Type getMethodType(final Type returnType, final Type... argumentTypes) { - return getType(getMethodDescriptor(returnType, argumentTypes)); - } - - /** - * Returns the {@link Type} corresponding to the given class. - * - * @param clazz a class. - * @return the {@link Type} corresponding to the given class. - */ - public static Type getType(final Class clazz) { - if (clazz.isPrimitive()) { - if (clazz == Integer.TYPE) { - return INT_TYPE; - } else if (clazz == Void.TYPE) { - return VOID_TYPE; - } else if (clazz == Boolean.TYPE) { - return BOOLEAN_TYPE; - } else if (clazz == Byte.TYPE) { - return BYTE_TYPE; - } else if (clazz == Character.TYPE) { - return CHAR_TYPE; - } else if (clazz == Short.TYPE) { - return SHORT_TYPE; - } else if (clazz == Double.TYPE) { - return DOUBLE_TYPE; - } else if (clazz == Float.TYPE) { - return FLOAT_TYPE; - } else if (clazz == Long.TYPE) { - return LONG_TYPE; - } else { - throw new AssertionError(); - } - } else { - return getType(getDescriptor(clazz)); - } - } - - /** - * Returns the method {@link Type} corresponding to the given constructor. - * - * @param constructor a {@link Constructor} object. - * @return the method {@link Type} corresponding to the given constructor. - */ - public static Type getType(final Constructor constructor) { - return getType(getConstructorDescriptor(constructor)); - } - - /** - * Returns the method {@link Type} corresponding to the given method. - * - * @param method a {@link Method} object. - * @return the method {@link Type} corresponding to the given method. - */ - public static Type getType(final Method method) { - return getType(getMethodDescriptor(method)); - } - - /** - * Returns the {@link Type} values corresponding to the argument types of the given method - * descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} values corresponding to the argument types of the given method - * descriptor. - */ - public static Type[] getArgumentTypes(final String methodDescriptor) { - // First step: compute the number of argument types in methodDescriptor. - final char[] valueBuffer = methodDescriptor.toCharArray(); - int numArgumentTypes = 0; - // Skip the first character, which is always a '('. - int currentOffset = 1; - // Parse the argument types, one at a each loop iteration. - while (valueBuffer[currentOffset] != ')') { - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - ++numArgumentTypes; - } - - // Second step: create a Type instance for each argument type. - Type[] argumentTypes = new Type[numArgumentTypes]; - // Skip the first character, which is always a '('. - currentOffset = 1; - // Parse and create the argument types, one at each loop iteration. - int currentArgumentTypeIndex = 0; - while (valueBuffer[currentOffset] != ')') { - final int currentArgumentTypeOffset = currentOffset; - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - argumentTypes[currentArgumentTypeIndex++] = - getType( - valueBuffer, currentArgumentTypeOffset, currentOffset - currentArgumentTypeOffset); - } - return argumentTypes; - } - - /** - * Returns the {@link Type} values corresponding to the argument types of the given method. - * - * @param method a method. - * @return the {@link Type} values corresponding to the argument types of the given method. - */ - public static Type[] getArgumentTypes(final Method method) { - Class[] classes = method.getParameterTypes(); - Type[] types = new Type[classes.length]; - for (int i = classes.length - 1; i >= 0; --i) { - types[i] = getType(classes[i]); - } - return types; - } - - /** - * Returns the {@link Type} corresponding to the return type of the given method descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} corresponding to the return type of the given method descriptor. - */ - public static Type getReturnType(final String methodDescriptor) { - final char[] valueBuffer = methodDescriptor.toCharArray(); - // Skip the first character, which is always a '('. - int currentOffset = 1; - // Skip the argument types, one at a each loop iteration. - while (valueBuffer[currentOffset] != ')') { - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - } - return getType(valueBuffer, currentOffset + 1, valueBuffer.length - currentOffset - 1); - } - - /** - * Returns the {@link Type} corresponding to the return type of the given method. - * - * @param method a method. - * @return the {@link Type} corresponding to the return type of the given method. - */ - public static Type getReturnType(final Method method) { - return getType(method.getReturnType()); - } - - /** - * Computes the size of the arguments and of the return value of a method. - * - * @param methodDescriptor a method descriptor. - * @return the size of the arguments of the method (plus one for the implicit this argument), - * argumentsSize, and the size of its return value, returnSize, packed into a single int i = - * (argumentsSize << 2) | returnSize (argumentsSize is therefore equal to i - * >> 2, and returnSize to i & 0x03). - */ - public static int getArgumentsAndReturnSizes(final String methodDescriptor) { - int argumentsSize = 1; - // Skip the first character, which is always a '('. - int currentOffset = 1; - int currentChar = methodDescriptor.charAt(currentOffset); - // Parse the argument types and compute their size, one at a each loop iteration. - while (currentChar != ')') { - if (currentChar == 'J' || currentChar == 'D') { - currentOffset++; - argumentsSize += 2; - } else { - while (methodDescriptor.charAt(currentOffset) == '[') { - currentOffset++; - } - if (methodDescriptor.charAt(currentOffset++) == 'L') { - while (methodDescriptor.charAt(currentOffset++) != ';') { - // Skip the argument descriptor content. - } - } - argumentsSize += 1; - } - currentChar = methodDescriptor.charAt(currentOffset); - } - currentChar = methodDescriptor.charAt(currentOffset + 1); - if (currentChar == 'V') { - return argumentsSize << 2; - } else { - int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; - return argumentsSize << 2 | returnSize; - } - } - - /** - * Returns the {@link Type} corresponding to the given field or method descriptor. - * - * @param descriptorBuffer a buffer containing the field or method descriptor. - * @param descriptorOffset the offset of the field or method descriptor in descriptorBuffer. - * @param descriptorLength the length of the field or method descriptor. - * @return the {@link Type} corresponding to the given type descriptor. - */ - private static Type getType( - final char[] descriptorBuffer, final int descriptorOffset, final int descriptorLength) { - switch (descriptorBuffer[descriptorOffset]) { - case 'V': - return VOID_TYPE; - case 'Z': - return BOOLEAN_TYPE; - case 'C': - return CHAR_TYPE; - case 'B': - return BYTE_TYPE; - case 'S': - return SHORT_TYPE; - case 'I': - return INT_TYPE; - case 'F': - return FLOAT_TYPE; - case 'J': - return LONG_TYPE; - case 'D': - return DOUBLE_TYPE; - case '[': - return new Type(ARRAY, descriptorBuffer, descriptorOffset, descriptorLength); - case 'L': - return new Type(OBJECT, descriptorBuffer, descriptorOffset + 1, descriptorLength - 2); - case '(': - return new Type(METHOD, descriptorBuffer, descriptorOffset, descriptorLength); - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the sort of this type. - * - * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link - * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or - * {@link #METHOD}. - */ - public int getSort() { - return sort == INTERNAL ? OBJECT : sort; - } - - /** - * Returns the number of dimensions of this array type. This method should only be used for an - * array type. - * - * @return the number of dimensions of this array type. - */ - public int getDimensions() { - int numDimensions = 1; - while (valueBuffer[valueOffset + numDimensions] == '[') { - numDimensions++; - } - return numDimensions; - } - - /** - * Returns the type of the elements of this array type. This method should only be used for an - * array type. - * - * @return Returns the type of the elements of this array type. - */ - public Type getElementType() { - final int numDimensions = getDimensions(); - return getType(valueBuffer, valueOffset + numDimensions, valueLength - numDimensions); - } - - /** - * Returns the binary name of the class corresponding to this type. This method must not be used - * on method types. - * - * @return the binary name of the class corresponding to this type. - */ - public String getClassName() { - switch (sort) { - case VOID: - return "void"; - case BOOLEAN: - return "boolean"; - case CHAR: - return "char"; - case BYTE: - return "byte"; - case SHORT: - return "short"; - case INT: - return "int"; - case FLOAT: - return "float"; - case LONG: - return "long"; - case DOUBLE: - return "double"; - case ARRAY: - StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); - for (int i = getDimensions(); i > 0; --i) { - stringBuilder.append("[]"); - } - return stringBuilder.toString(); - case OBJECT: - case INTERNAL: - return new String(valueBuffer, valueOffset, valueLength).replace('/', '.'); - default: - throw new AssertionError(); - } - } - - /** - * Returns the internal name of the class corresponding to this object or array type. The internal - * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are - * replaced by '/'). This method should only be used for an object or array type. - * - * @return the internal name of the class corresponding to this object type. - */ - public String getInternalName() { - return new String(valueBuffer, valueOffset, valueLength); - } - - /** - * Returns the argument types of methods of this type. This method should only be used for method - * types. - * - * @return the argument types of methods of this type. - */ - public Type[] getArgumentTypes() { - return getArgumentTypes(getDescriptor()); - } - - /** - * Returns the return type of methods of this type. This method should only be used for method - * types. - * - * @return the return type of methods of this type. - */ - public Type getReturnType() { - return getReturnType(getDescriptor()); - } - - /** - * Returns the size of the arguments and of the return value of methods of this type. This method - * should only be used for method types. - * - * @return the size of the arguments of the method (plus one for the implicit this argument), - * argumentsSize, and the size of its return value, returnSize, packed into a single int i = - * (argumentsSize << 2) | returnSize (argumentsSize is therefore equal to i - * >> 2, and returnSize to i & 0x03). - */ - public int getArgumentsAndReturnSizes() { - return getArgumentsAndReturnSizes(getDescriptor()); - } - - // ----------------------------------------------------------------------------------------------- - // Conversion to type descriptors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the descriptor corresponding to this type. - * - * @return the descriptor corresponding to this type. - */ - public String getDescriptor() { - if (sort == OBJECT) { - return new String(valueBuffer, valueOffset - 1, valueLength + 2); - } else if (sort == INTERNAL) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('L'); - stringBuilder.append(valueBuffer, valueOffset, valueLength); - stringBuilder.append(';'); - return stringBuilder.toString(); - } else { - return new String(valueBuffer, valueOffset, valueLength); - } - } - - /** - * Returns the descriptor corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the descriptor corresponding to the given argument and return types. - */ - public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - for (int i = 0; i < argumentTypes.length; ++i) { - argumentTypes[i].appendDescriptor(stringBuilder); - } - stringBuilder.append(')'); - returnType.appendDescriptor(stringBuilder); - return stringBuilder.toString(); - } - - /** - * Appends the descriptor corresponding to this type to the given string buffer. - * - * @param stringBuilder the string builder to which the descriptor must be appended. - */ - private void appendDescriptor(final StringBuilder stringBuilder) { - if (sort == OBJECT) { - stringBuilder.append(valueBuffer, valueOffset - 1, valueLength + 2); - } else if (sort == INTERNAL) { - stringBuilder.append('L'); - stringBuilder.append(valueBuffer, valueOffset, valueLength); - stringBuilder.append(';'); - } else { - stringBuilder.append(valueBuffer, valueOffset, valueLength); - } - } - - // ----------------------------------------------------------------------------------------------- - // Direct conversion from classes to type descriptors, - // without intermediate Type objects - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the internal name of the given class. The internal name of a class is its fully - * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. - * - * @param clazz an object or array class. - * @return the internal name of the given class. - */ - public static String getInternalName(final Class clazz) { - return clazz.getName().replace('.', '/'); - } - - /** - * Returns the descriptor corresponding to the given class. - * - * @param clazz an object class, a primitive class or an array class. - * @return the descriptor corresponding to the given class. - */ - public static String getDescriptor(final Class clazz) { - StringBuilder stringBuilder = new StringBuilder(); - appendDescriptor(stringBuilder, clazz); - return stringBuilder.toString(); - } - - /** - * Returns the descriptor corresponding to the given constructor. - * - * @param constructor a {@link Constructor} object. - * @return the descriptor of the given constructor. - */ - public static String getConstructorDescriptor(final Constructor constructor) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - Class[] parameters = constructor.getParameterTypes(); - for (int i = 0; i < parameters.length; ++i) { - appendDescriptor(stringBuilder, parameters[i]); - } - return stringBuilder.append(")V").toString(); - } - - /** - * Returns the descriptor corresponding to the given method. - * - * @param method a {@link Method} object. - * @return the descriptor of the given method. - */ - public static String getMethodDescriptor(final Method method) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - Class[] parameters = method.getParameterTypes(); - for (int i = 0; i < parameters.length; ++i) { - appendDescriptor(stringBuilder, parameters[i]); - } - stringBuilder.append(')'); - appendDescriptor(stringBuilder, method.getReturnType()); - return stringBuilder.toString(); - } - - /** - * Appends the descriptor of the given class to the given string builder. - * - * @param stringBuilder the string builder to which the descriptor must be appended. - * @param clazz the class whose descriptor must be computed. - */ - private static void appendDescriptor(final StringBuilder stringBuilder, final Class clazz) { - Class currentClass = clazz; - while (currentClass.isArray()) { - stringBuilder.append('['); - currentClass = currentClass.getComponentType(); - } - if (currentClass.isPrimitive()) { - char descriptor; - if (currentClass == Integer.TYPE) { - descriptor = 'I'; - } else if (currentClass == Void.TYPE) { - descriptor = 'V'; - } else if (currentClass == Boolean.TYPE) { - descriptor = 'Z'; - } else if (currentClass == Byte.TYPE) { - descriptor = 'B'; - } else if (currentClass == Character.TYPE) { - descriptor = 'C'; - } else if (currentClass == Short.TYPE) { - descriptor = 'S'; - } else if (currentClass == Double.TYPE) { - descriptor = 'D'; - } else if (currentClass == Float.TYPE) { - descriptor = 'F'; - } else if (currentClass == Long.TYPE) { - descriptor = 'J'; - } else { - throw new AssertionError(); - } - stringBuilder.append(descriptor); - } else { - stringBuilder.append('L'); - String name = currentClass.getName(); - int nameLength = name.length(); - for (int i = 0; i < nameLength; ++i) { - char car = name.charAt(i); - stringBuilder.append(car == '.' ? '/' : car); - } - stringBuilder.append(';'); - } - } - - // ----------------------------------------------------------------------------------------------- - // Corresponding size and opcodes - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of values of this type. This method must not be used for method types. - * - * @return the size of values of this type, i.e., 2 for long and double, 0 for - * void and 1 otherwise. - */ - public int getSize() { - switch (sort) { - case VOID: - return 0; - case BOOLEAN: - case CHAR: - case BYTE: - case SHORT: - case INT: - case FLOAT: - case ARRAY: - case OBJECT: - case INTERNAL: - return 1; - case LONG: - case DOUBLE: - return 2; - default: - throw new AssertionError(); - } - } - - /** - * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for - * method types. - * - * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, - * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and - * IRETURN. - * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For - * example, if this type is float and opcode is IRETURN, this method returns - * FRETURN. - */ - public int getOpcode(final int opcode) { - if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { - switch (sort) { - case BOOLEAN: - case BYTE: - return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); - case CHAR: - return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); - case SHORT: - return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); - case INT: - return opcode; - case FLOAT: - return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); - case LONG: - return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); - case DOUBLE: - return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); - case ARRAY: - case OBJECT: - case INTERNAL: - return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); - case METHOD: - case VOID: - throw new UnsupportedOperationException(); - default: - throw new AssertionError(); - } - } else { - switch (sort) { - case VOID: - if (opcode != Opcodes.IRETURN) { - throw new UnsupportedOperationException(); - } - return Opcodes.RETURN; - case BOOLEAN: - case BYTE: - case CHAR: - case SHORT: - case INT: - return opcode; - case FLOAT: - return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); - case LONG: - return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); - case DOUBLE: - return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); - case ARRAY: - case OBJECT: - case INTERNAL: - if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { - throw new UnsupportedOperationException(); - } - return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); - case METHOD: - throw new UnsupportedOperationException(); - default: - throw new AssertionError(); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Equals, hashCode and toString - // ----------------------------------------------------------------------------------------------- - - /** - * Tests if the given object is equal to this type. - * - * @param object the object to be compared to this type. - * @return true if the given object is equal to this type. - */ - @Override - public boolean equals(final Object object) { - if (this == object) { - return true; - } - if (!(object instanceof Type)) { - return false; - } - Type other = (Type) object; - if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { - return false; - } - int start = valueOffset; - int end = start + valueLength; - int otherStart = other.valueOffset; - int otherEnd = otherStart + other.valueLength; - // Compare the values. - if (end - start != otherEnd - otherStart) { - return false; - } - for (int i = start, j = otherStart; i < end; i++, j++) { - if (valueBuffer[i] != other.valueBuffer[j]) { - return false; - } - } - return true; - } - - /** - * Returns a hash code value for this type. - * - * @return a hash code value for this type. - */ - @Override - public int hashCode() { - int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); - if (sort >= ARRAY) { - for (int i = valueOffset, end = valueOffset + valueLength; i < end; i++) { - hashCode = 17 * (hashCode + valueBuffer[i]); - } - } - return hashCode; - } - - /** - * Returns a string representation of this type. - * - * @return the descriptor of this type. - */ - @Override - public String toString() { - return getDescriptor(); - } -} diff --git a/src/main/java/org/objectweb/asm/TypePath.java b/src/main/java/org/objectweb/asm/TypePath.java deleted file mode 100644 index 9d6e99fc..00000000 --- a/src/main/java/org/objectweb/asm/TypePath.java +++ /dev/null @@ -1,211 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * The path to a type argument, wildcard bound, array element type, or static inner type within an - * enclosing type. - * - * @author Eric Bruneton - */ -public class TypePath { - - /** - * A type path step that steps into the element type of an array type. See {@link #getStep}. - */ - public static final int ARRAY_ELEMENT = 0; - - /** - * A type path step that steps into the nested type of a class type. See {@link #getStep}. - */ - public static final int INNER_TYPE = 1; - - /** - * A type path step that steps into the bound of a wildcard type. See {@link #getStep}. - */ - public static final int WILDCARD_BOUND = 2; - - /** - * A type path step that steps into a type argument of a generic type. See {@link #getStep}. - */ - public static final int TYPE_ARGUMENT = 3; - - /** - * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine - * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the - * structure in this array is given by {@link #typePathOffset}. - * - * @see JVMS - * 4.7.20.2 - */ - private final byte[] typePathContainer; - - /** - * The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. - */ - private final int typePathOffset; - - /** - * Constructs a new TypePath. - * - * @param typePathContainer a byte array containing a type_path JVMS structure. - * @param typePathOffset the offset of the first byte of the type_path structure in - * typePathContainer. - */ - TypePath(final byte[] typePathContainer, final int typePathOffset) { - this.typePathContainer = typePathContainer; - this.typePathOffset = typePathOffset; - } - - /** - * Returns the length of this path, i.e. its number of steps. - * - * @return the length of this path. - */ - public int getLength() { - // path_length is stored in the first byte of a type_path. - return typePathContainer[typePathOffset]; - } - - /** - * Returns the value of the given step of this path. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link - * #TYPE_ARGUMENT}. - */ - public int getStep(final int index) { - // Returns the type_path_kind of the path element of the given index. - return typePathContainer[typePathOffset + 2 * index + 1]; - } - - /** - * Returns the index of the type argument that the given step is stepping into. This method should - * only be used for steps whose value is {@link #TYPE_ARGUMENT}. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return the index of the type argument that the given step is stepping into. - */ - public int getStepArgument(final int index) { - // Returns the type_argument_index of the path element of the given index. - return typePathContainer[typePathOffset + 2 * index + 2]; - } - - /** - * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath - * object. - * - * @param typePath a type path in string form, in the format used by {@link #toString()}. May be - * null or empty. - * @return the corresponding TypePath object, or null if the path is empty. - */ - public static TypePath fromString(final String typePath) { - if (typePath == null || typePath.length() == 0) { - return null; - } - int typePathLength = typePath.length(); - ByteVector output = new ByteVector(typePathLength); - output.putByte(0); - int typePathIndex = 0; - while (typePathIndex < typePathLength) { - char c = typePath.charAt(typePathIndex++); - if (c == '[') { - output.put11(ARRAY_ELEMENT, 0); - } else if (c == '.') { - output.put11(INNER_TYPE, 0); - } else if (c == '*') { - output.put11(WILDCARD_BOUND, 0); - } else if (c >= '0' && c <= '9') { - int typeArg = c - '0'; - while (typePathIndex < typePathLength) { - c = typePath.charAt(typePathIndex++); - if (c >= '0' && c <= '9') { - typeArg = typeArg * 10 + c - '0'; - } else if (c == ';') { - break; - } else { - throw new IllegalArgumentException(); - } - } - output.put11(TYPE_ARGUMENT, typeArg); - } else { - throw new IllegalArgumentException(); - } - } - output.data[0] = (byte) (output.length / 2); - return new TypePath(output.data, 0); - } - - /** - * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented - * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link - * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. - */ - @Override - public String toString() { - int length = getLength(); - StringBuilder result = new StringBuilder(length * 2); - for (int i = 0; i < length; ++i) { - switch (getStep(i)) { - case ARRAY_ELEMENT: - result.append('['); - break; - case INNER_TYPE: - result.append('.'); - break; - case WILDCARD_BOUND: - result.append('*'); - break; - case TYPE_ARGUMENT: - result.append(getStepArgument(i)).append(';'); - break; - default: - throw new AssertionError(); - } - } - return result.toString(); - } - - /** - * Puts the type_path JVMS structure corresponding to the given TypePath into the given - * ByteVector. - * - * @param typePath a TypePath instance, or null for empty paths. - * @param output where the type path must be put. - */ - static void put(final TypePath typePath, final ByteVector output) { - if (typePath == null) { - output.putByte(0); - } else { - int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1; - output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length); - } - } -} diff --git a/src/main/java/org/objectweb/asm/TypeReference.java b/src/main/java/org/objectweb/asm/TypeReference.java deleted file mode 100644 index 3a11d380..00000000 --- a/src/main/java/org/objectweb/asm/TypeReference.java +++ /dev/null @@ -1,440 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * A reference to a type appearing in a class, field or method declaration, or on an instruction. - * Such a reference designates the part of the class where the referenced type is appearing (e.g. an - * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a - * local variable declaration, etc). - * - * @author Eric Bruneton - */ -public class TypeReference { - - /** - * The sort of type references that target a type parameter of a generic class. See {@link - * #getSort}. - */ - public static final int CLASS_TYPE_PARAMETER = 0x00; - - /** - * The sort of type references that target a type parameter of a generic method. See {@link - * #getSort}. - */ - public static final int METHOD_TYPE_PARAMETER = 0x01; - - /** - * The sort of type references that target the super class of a class or one of the interfaces it - * implements. See {@link #getSort}. - */ - public static final int CLASS_EXTENDS = 0x10; - - /** - * The sort of type references that target a bound of a type parameter of a generic class. See - * {@link #getSort}. - */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** - * The sort of type references that target a bound of a type parameter of a generic method. See - * {@link #getSort}. - */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** - * The sort of type references that target the type of a field. See {@link #getSort}. - */ - public static final int FIELD = 0x13; - - /** - * The sort of type references that target the return type of a method. See {@link #getSort}. - */ - public static final int METHOD_RETURN = 0x14; - - /** - * The sort of type references that target the receiver type of a method. See {@link #getSort}. - */ - public static final int METHOD_RECEIVER = 0x15; - - /** - * The sort of type references that target the type of a formal parameter of a method. See {@link - * #getSort}. - */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; - - /** - * The sort of type references that target the type of an exception declared in the throws clause - * of a method. See {@link #getSort}. - */ - public static final int THROWS = 0x17; - - /** - * The sort of type references that target the type of a local variable in a method. See {@link - * #getSort}. - */ - public static final int LOCAL_VARIABLE = 0x40; - - /** - * The sort of type references that target the type of a resource variable in a method. See {@link - * #getSort}. - */ - public static final int RESOURCE_VARIABLE = 0x41; - - /** - * The sort of type references that target the type of the exception of a 'catch' clause in a - * method. See {@link #getSort}. - */ - public static final int EXCEPTION_PARAMETER = 0x42; - - /** - * The sort of type references that target the type declared in an 'instanceof' instruction. See - * {@link #getSort}. - */ - public static final int INSTANCEOF = 0x43; - - /** - * The sort of type references that target the type of the object created by a 'new' instruction. - * See {@link #getSort}. - */ - public static final int NEW = 0x44; - - /** - * The sort of type references that target the receiver type of a constructor reference. See - * {@link #getSort}. - */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; - - /** - * The sort of type references that target the receiver type of a method reference. See {@link - * #getSort}. - */ - public static final int METHOD_REFERENCE = 0x46; - - /** - * The sort of type references that target the type declared in an explicit or implicit cast - * instruction. See {@link #getSort}. - */ - public static final int CAST = 0x47; - - /** - * The sort of type references that target a type parameter of a generic constructor in a - * constructor call. See {@link #getSort}. - */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** - * The sort of type references that target a type parameter of a generic method in a method call. - * See {@link #getSort}. - */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** - * The sort of type references that target a type parameter of a generic constructor in a - * constructor reference. See {@link #getSort}. - */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** - * The sort of type references that target a type parameter of a generic method in a method - * reference. See {@link #getSort}. - */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - /** - * The target_type and target_info structures - as defined in the Java Virtual Machine - * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all - * the target_info union fields use up to 3 bytes (except localvar_target, handled with the - * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can - * be stored in an int. - * - *

This int field stores target_type (called the TypeReference 'sort' in the public API of this - * class) in its most significant byte, followed by the target_info fields. Depending on - * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info - * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader, - * and recomputed in MethodWriter). - * - * @see JVMS - * 4.7.20 - * @see JVMS - * 4.7.20.1 - */ - private final int targetTypeAndInfo; - - /** - * Constructs a new TypeReference. - * - * @param typeRef the int encoded value of the type reference, as received in a visit method - * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}. - */ - public TypeReference(final int typeRef) { - this.targetTypeAndInfo = typeRef; - } - - /** - * Returns a type reference of the given sort. - * - * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link - * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link - * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}. - * @return a type reference of the given sort. - */ - public static TypeReference newTypeReference(final int sort) { - return new TypeReference(sort << 24); - } - - /** - * Returns a reference to a type parameter of a generic class or method. - * - * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. - * @param paramIndex the type parameter index. - * @return a reference to the given generic class or method type parameter. - */ - public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to a type parameter bound of a generic class or method. - * - * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. - * @param paramIndex the type parameter index. - * @param boundIndex the type bound index within the above type parameters. - * @return a reference to the given generic class or method type parameter bound. - */ - public static TypeReference newTypeParameterBoundReference( - final int sort, final int paramIndex, final int boundIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8)); - } - - /** - * Returns a reference to the super class or to an interface of the 'implements' clause of a - * class. - * - * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to - * reference the super class of the class. - * @return a reference to the given super type of a class. - */ - public static TypeReference newSuperTypeReference(final int itfIndex) { - return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8)); - } - - /** - * Returns a reference to the type of a formal parameter of a method. - * - * @param paramIndex the formal parameter index. - * @return a reference to the type of the given method formal parameter. - */ - public static TypeReference newFormalParameterReference(final int paramIndex) { - return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to the type of an exception, in a 'throws' clause of a method. - * - * @param exceptionIndex the index of an exception in a 'throws' clause of a method. - * @return a reference to the type of the given exception. - */ - public static TypeReference newExceptionReference(final int exceptionIndex) { - return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); - } - - /** - * Returns a reference to the type of the exception declared in a 'catch' clause of a method. - * - * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are - * visited with visitTryCatchBlock). - * @return a reference to the type of the given exception. - */ - public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) { - return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8)); - } - - /** - * Returns a reference to the type of a type argument in a constructor or method call or - * reference. - * - * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link - * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link - * #METHOD_REFERENCE_TYPE_ARGUMENT}. - * @param argIndex the type argument index. - * @return a reference to the type of the given type argument. - */ - public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) { - return new TypeReference((sort << 24) | argIndex); - } - - /** - * Returns the sort of this type reference. - * - * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link - * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND}, - * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link - * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link - * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW}, - * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link - * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. - */ - public int getSort() { - return targetTypeAndInfo >>> 24; - } - - /** - * Returns the index of the type parameter referenced by this type reference. This method must - * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link - * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link - * #METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter index. - */ - public int getTypeParameterIndex() { - return (targetTypeAndInfo & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the type parameter bound, within the type parameter {@link - * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for - * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link - * #METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter bound index. - */ - public int getTypeParameterBoundIndex() { - return (targetTypeAndInfo & 0x0000FF00) >> 8; - } - - /** - * Returns the index of the "super type" of a class that is referenced by this type reference. - * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}. - * - * @return the index of an interface in the 'implements' clause of a class, or -1 if this type - * reference references the type of the super class. - */ - public int getSuperTypeIndex() { - return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8); - } - - /** - * Returns the index of the formal parameter whose type is referenced by this type reference. This - * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}. - * - * @return a formal parameter index. - */ - public int getFormalParameterIndex() { - return (targetTypeAndInfo & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced - * by this type reference. This method must only be used for type references whose sort is {@link - * #THROWS}. - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getExceptionIndex() { - return (targetTypeAndInfo & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the try catch block (using the order in which they are visited with - * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must - * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} . - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getTryCatchBlockIndex() { - return (targetTypeAndInfo & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the type argument referenced by this type reference. This method must only - * be used for type references whose sort is {@link #CAST}, {@link - * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. - * - * @return a type parameter index. - */ - public int getTypeArgumentIndex() { - return targetTypeAndInfo & 0xFF; - } - - /** - * Returns the int encoded value of this type reference, suitable for use in visit methods related - * to type annotations, like visitTypeAnnotation. - * - * @return the int encoded value of this type reference. - */ - public int getValue() { - return targetTypeAndInfo; - } - - /** - * Puts the given target_type and target_info JVMS structures into the given ByteVector. - * - * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link - * #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. - * @param output where the type reference must be put. - */ - static void putTarget(final int targetTypeAndInfo, final ByteVector output) { - switch (targetTypeAndInfo >>> 24) { - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - case METHOD_FORMAL_PARAMETER: - output.putShort(targetTypeAndInfo >>> 16); - break; - case FIELD: - case METHOD_RETURN: - case METHOD_RECEIVER: - output.putByte(targetTypeAndInfo >>> 24); - break; - case CAST: - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - output.putInt(targetTypeAndInfo); - break; - case CLASS_EXTENDS: - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - case THROWS: - case EXCEPTION_PARAMETER: - case INSTANCEOF: - case NEW: - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8); - break; - default: - throw new IllegalArgumentException(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java b/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java deleted file mode 100644 index aa1b1023..00000000 --- a/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java +++ /dev/null @@ -1,633 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm.commons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -/** - * A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around advices in methods - * and constructors. - * - *

The behavior for constructors is like this: - * - *

    - *
  1. as long as the INVOKESPECIAL for the object initialization has not been reached, every - * bytecode instruction is dispatched in the ctor code visitor - *
  2. when this one is reached, it is only added in the ctor code visitor and a JP invoke is - * added - *
  3. after that, only the other code visitor receives the instructions - *
- * - * @author Eugene Kuleshov - * @author Eric Bruneton - */ -public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { - - private static final Object THIS = new Object(); - - private static final Object OTHER = new Object(); - - protected int methodAccess; - - protected String methodDesc; - - private boolean constructor; - - private boolean superInitialized; - - private List stackFrame; - - private Map> branches; - - /** - * Constructs a new {@link AdviceAdapter}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param mv the method visitor to which this adapter delegates calls. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - */ - protected AdviceAdapter( - final int api, - final MethodVisitor mv, - final int access, - final String name, - final String desc) { - super(api, mv, access, name, desc); - methodAccess = access; - methodDesc = desc; - constructor = "".equals(name); - } - - @Override - public void visitCode() { - super.visitCode(); - if (constructor) { - stackFrame = new ArrayList(); - branches = new HashMap>(); - } else { - superInitialized = true; - onMethodEnter(); - } - } - - @Override - public void visitLabel(final Label label) { - super.visitLabel(label); - if (constructor && branches != null) { - List frame = branches.get(label); - if (frame != null) { - stackFrame = frame; - branches.remove(label); - } - } - } - - @Override - public void visitInsn(final int opcode) { - if (constructor) { - int s; - switch (opcode) { - case RETURN: // empty stack - onMethodExit(opcode); - break; - case IRETURN: // 1 before n/a after - case FRETURN: // 1 before n/a after - case ARETURN: // 1 before n/a after - case ATHROW: // 1 before n/a after - popValue(); - onMethodExit(opcode); - break; - case LRETURN: // 2 before n/a after - case DRETURN: // 2 before n/a after - popValue(); - popValue(); - onMethodExit(opcode); - break; - case NOP: - case LALOAD: // remove 2 add 2 - case DALOAD: // remove 2 add 2 - case LNEG: - case DNEG: - case FNEG: - case INEG: - case L2D: - case D2L: - case F2I: - case I2B: - case I2C: - case I2S: - case I2F: - case ARRAYLENGTH: - break; - case ACONST_NULL: - case ICONST_M1: - case ICONST_0: - case ICONST_1: - case ICONST_2: - case ICONST_3: - case ICONST_4: - case ICONST_5: - case FCONST_0: - case FCONST_1: - case FCONST_2: - case F2L: // 1 before 2 after - case F2D: - case I2L: - case I2D: - pushValue(OTHER); - break; - case LCONST_0: - case LCONST_1: - case DCONST_0: - case DCONST_1: - pushValue(OTHER); - pushValue(OTHER); - break; - case IALOAD: // remove 2 add 1 - case FALOAD: // remove 2 add 1 - case AALOAD: // remove 2 add 1 - case BALOAD: // remove 2 add 1 - case CALOAD: // remove 2 add 1 - case SALOAD: // remove 2 add 1 - case POP: - case IADD: - case FADD: - case ISUB: - case LSHL: // 3 before 2 after - case LSHR: // 3 before 2 after - case LUSHR: // 3 before 2 after - case L2I: // 2 before 1 after - case L2F: // 2 before 1 after - case D2I: // 2 before 1 after - case D2F: // 2 before 1 after - case FSUB: - case FMUL: - case FDIV: - case FREM: - case FCMPL: // 2 before 1 after - case FCMPG: // 2 before 1 after - case IMUL: - case IDIV: - case IREM: - case ISHL: - case ISHR: - case IUSHR: - case IAND: - case IOR: - case IXOR: - case MONITORENTER: - case MONITOREXIT: - popValue(); - break; - case POP2: - case LSUB: - case LMUL: - case LDIV: - case LREM: - case LADD: - case LAND: - case LOR: - case LXOR: - case DADD: - case DMUL: - case DSUB: - case DDIV: - case DREM: - popValue(); - popValue(); - break; - case IASTORE: - case FASTORE: - case AASTORE: - case BASTORE: - case CASTORE: - case SASTORE: - case LCMP: // 4 before 1 after - case DCMPL: - case DCMPG: - popValue(); - popValue(); - popValue(); - break; - case LASTORE: - case DASTORE: - popValue(); - popValue(); - popValue(); - popValue(); - break; - case DUP: - pushValue(peekValue()); - break; - case DUP_X1: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP_X2: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP2_X1: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2_X2: - s = stackFrame.size(); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - break; - case SWAP: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.remove(s); - break; - } - } else { - switch (opcode) { - case RETURN: - case IRETURN: - case FRETURN: - case ARETURN: - case LRETURN: - case DRETURN: - case ATHROW: - onMethodExit(opcode); - break; - } - } - super.visitInsn(opcode); - } - - @Override - public void visitVarInsn(final int opcode, final int var) { - super.visitVarInsn(opcode, var); - if (constructor) { - switch (opcode) { - case ILOAD: - case FLOAD: - pushValue(OTHER); - break; - case LLOAD: - case DLOAD: - pushValue(OTHER); - pushValue(OTHER); - break; - case ALOAD: - pushValue(var == 0 ? THIS : OTHER); - break; - case ASTORE: - case ISTORE: - case FSTORE: - popValue(); - break; - case LSTORE: - case DSTORE: - popValue(); - popValue(); - break; - } - } - } - - @Override - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String desc) { - super.visitFieldInsn(opcode, owner, name, desc); - if (constructor) { - char c = desc.charAt(0); - boolean longOrDouble = c == 'J' || c == 'D'; - switch (opcode) { - case GETSTATIC: - pushValue(OTHER); - if (longOrDouble) { - pushValue(OTHER); - } - break; - case PUTSTATIC: - popValue(); - if (longOrDouble) { - popValue(); - } - break; - case PUTFIELD: - popValue(); - popValue(); - if (longOrDouble) { - popValue(); - } - break; - // case GETFIELD: - default: - if (longOrDouble) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - super.visitIntInsn(opcode, operand); - if (constructor && opcode != NEWARRAY) { - pushValue(OTHER); - } - } - - @Override - public void visitLdcInsn(final Object cst) { - super.visitLdcInsn(cst); - if (constructor) { - pushValue(OTHER); - if (cst instanceof Double || cst instanceof Long) { - pushValue(OTHER); - } - } - } - - @Override - public void visitMultiANewArrayInsn(final String desc, final int dims) { - super.visitMultiANewArrayInsn(desc, dims); - if (constructor) { - for (int i = 0; i < dims; i++) { - popValue(); - } - pushValue(OTHER); - } - } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - super.visitTypeInsn(opcode, type); - // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack - if (constructor && opcode == NEW) { - pushValue(OTHER); - } - } - - @Deprecated - @Override - public void visitMethodInsn( - final int opcode, final String owner, final String name, final String desc) { - if (api >= Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE); - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc, - final boolean itf) { - if (api < Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc, itf); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, itf); - } - - private void doVisitMethodInsn( - int opcode, final String owner, final String name, final String desc, final boolean itf) { - mv.visitMethodInsn(opcode, owner, name, desc, itf); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - switch (opcode) { - // case INVOKESTATIC: - // break; - case INVOKEINTERFACE: - case INVOKEVIRTUAL: - popValue(); // objectref - break; - case INVOKESPECIAL: - Object type = popValue(); // objectref - if (type == THIS && !superInitialized) { - onMethodEnter(); - superInitialized = true; - // once super has been initialized it is no longer - // necessary to keep track of stack state - constructor = false; - } - break; - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { - super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - super.visitJumpInsn(opcode, label); - if (constructor) { - switch (opcode) { - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IFNULL: - case IFNONNULL: - popValue(); - break; - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - popValue(); - popValue(); - break; - case JSR: - pushValue(OTHER); - break; - } - addBranch(label); - } - } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - super.visitLookupSwitchInsn(dflt, keys, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); - } - } - - @Override - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - super.visitTableSwitchInsn(min, max, dflt, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - super.visitTryCatchBlock(start, end, handler, type); - if (constructor && !branches.containsKey(handler)) { - List stackFrame = new ArrayList(); - stackFrame.add(OTHER); - branches.put(handler, stackFrame); - } - } - - private void addBranches(final Label dflt, final Label[] labels) { - addBranch(dflt); - for (int i = 0; i < labels.length; i++) { - addBranch(labels[i]); - } - } - - private void addBranch(final Label label) { - if (branches.containsKey(label)) { - return; - } - branches.put(label, new ArrayList(stackFrame)); - } - - private Object popValue() { - return stackFrame.remove(stackFrame.size() - 1); - } - - private Object peekValue() { - return stackFrame.get(stackFrame.size() - 1); - } - - private void pushValue(final Object o) { - stackFrame.add(o); - } - - /** - * Called at the beginning of the method or after super class call in the constructor.
- *
- * Custom code can use or change all the local variables, but should not change state of the - * stack. - */ - protected void onMethodEnter() { - } - - /** - * Called before explicit exit from the method using either return or throw. Top element on the - * stack contains the return value or exception instance. For example: - * - *
-     *   public void onMethodExit(int opcode) {
-     *     if(opcode==RETURN) {
-     *         visitInsn(ACONST_NULL);
-     *     } else if(opcode==ARETURN || opcode==ATHROW) {
-     *         dup();
-     *     } else {
-     *         if(opcode==LRETURN || opcode==DRETURN) {
-     *             dup2();
-     *         } else {
-     *             dup();
-     *         }
-     *         box(Type.getReturnType(this.methodDesc));
-     *     }
-     *     visitIntInsn(SIPUSH, opcode);
-     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
-     *   }
-     *
-     *   // an actual call back method
-     *   public static void onExit(Object param, int opcode) {
-     *     ...
-     * 
- * - *
- *
- * Custom code can use or change all the local variables, but should not change state of the - * stack. - * - * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN or ATHROW - */ - protected void onMethodExit(int opcode) { - } - - // TODO onException, onMethodCall -} diff --git a/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java b/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java deleted file mode 100644 index 48b8807e..00000000 --- a/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java +++ /dev/null @@ -1,920 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm.commons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -/** - * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link - * #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This adapter must be used with - * the {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visitX instruction - * delegates to the next visitor in the chain, if any, and then simulates the effect of this - * instruction on the stack map frame, represented by {@link #locals} and {@link #stack}. The next - * visitor in the chain can get the state of the stack map frame before each instruction by - * reading the value of these fields in its visitX methods (this requires a reference to the - * AnalyzerAdapter that is before it in the chain). If this adapter is used with a class that does - * not contain stack map table attributes (i.e., pre Java 6 classes) then this adapter may not be - * able to compute the stack map frame for each instruction. In this case no exception is thrown but - * the {@link #locals} and {@link #stack} fields will be null for these instructions. - * - * @author Eric Bruneton - */ -public class AnalyzerAdapter extends MethodVisitor { - - /** - * List of the local variable slots for current execution frame. Primitive types are - * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link - * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link - * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one - * being TOP). Reference types are represented by String objects (representing internal names), - * and uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). This field is null for unreachable instructions. - */ - public List locals; - - /** - * List of the operand stack slots for current execution frame. Primitive types are - * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link - * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link - * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one - * being TOP). Reference types are represented by String objects (representing internal names), - * and uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). This field is null for unreachable instructions. - */ - public List stack; - - /** - * The labels that designate the next instruction to be visited. May be null. - */ - private List