{"id":19569546,"url":"https://github.com/3arthqu4ke/handlewrapper","last_synced_at":"2025-04-27T03:30:47.416Z","repository":{"id":107426867,"uuid":"344537299","full_name":"3arthqu4ke/HandleWrapper","owner":"3arthqu4ke","description":"Dynamically inline MethodHandles","archived":false,"fork":false,"pushed_at":"2022-08-26T12:01:52.000Z","size":18,"stargazers_count":21,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T20:36:10.789Z","etag":null,"topics":["bytecode"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/3arthqu4ke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-04T16:24:46.000Z","updated_at":"2024-10-22T11:05:59.000Z","dependencies_parsed_at":"2023-08-27T19:04:25.139Z","dependency_job_id":null,"html_url":"https://github.com/3arthqu4ke/HandleWrapper","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3arthqu4ke%2FHandleWrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3arthqu4ke%2FHandleWrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3arthqu4ke%2FHandleWrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3arthqu4ke%2FHandleWrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/3arthqu4ke","download_url":"https://codeload.github.com/3arthqu4ke/HandleWrapper/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251085147,"owners_count":21533821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bytecode"],"created_at":"2024-11-11T06:10:46.887Z","updated_at":"2025-04-27T03:30:47.409Z","avatar_url":"https://github.com/3arthqu4ke.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HandleWrapper\n\n[MethodHandles](https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html) can be as fast as \ndirect invocation, as long as they are static final fields. Then they can be \ninlined. But what if we want to use them dynamically? I wanted to learn a thing or 2 about bytecode, so here I use [ASM](https://asm.ow2.io/) to create classes at runtime that contain the MethodHandle as a static final field. These \"HandleWrappers\" are almost as fast as direct invocation.\n\n```text\nBenchmark                                        Mode  Cnt  Score   Error  Units\nQuickBenchmark.benchmarkDirect                   avgt   10  3,592 ± 0,004  ns/op\nQuickBenchmark.benchmarkStaticFinalMethodHandle  avgt   10  3,638 ± 0,032  ns/op\nQuickBenchmark.benchmarkWrapper                  avgt   10  3,876 ± 0,049  ns/op\nQuickBenchmark.benchmarkNonStaticHandle          avgt   10  7,456 ± 0,460  ns/op\nQuickBenchmark.benchmarkNonFinalHandle           avgt   10  7,460 ± 0,189  ns/op\n```\n\n## Usage\nAssume we want to call following method:\n\n```java\npublic class SomeClass {\n    private int someMethod(Object someArg, String someOtherArg) { ... }\n}\n```\nFirst we need to obtain a MethodHandle for the method:\n\n```java\nMethod method = SomeClass.class.getDeclaredMethod(\"someMethod\", Object.class, String.class);\nmethod.setAccessible(true);\nMethodHandle handle = MethodHandles.lookup().unreflect(method);\n```\nNow we can use the WrapperFactory to wrap the Handle and use it:\n\n```java\nHandleWrapper wrapper = WrapperFactory.wrap(handle, SomeClass.class, false, int.class, Object.class, String.class);\nint result = (int) wrapper.invoke(objectOfSomeClass, someArg, \"someOtherArg\");\n```\nYou can also wrap your MethodHandle in an interface, the interfaces methods \ncan target all public methods of the MethodHandle class, they just need to have the same signature, and if they target a SignaturePolymorphic method like invoke or\ninvokeExact they need to have the same Signature as the target method (If the method is not static the first argument needs to be an Object of the targeted class).\n```java\npublic interface CustomInterface {\n    int accessSomeMethod(SomeClass target, Object someArg, String someOtherArg);\n}\n```\nNow declare which methods from the interface link to which MethodHandle method and call the WrapperFactory.\n```java\nMethod from = CustomInterface.class.getDeclaredMethod(accessSomeMethod ...);\nMethod to   = MethodHandle.class.getDeclaredMethod(\"invoke\", Object[].class);\nMap\u003cMethod, Method\u003e links = new HashMap\u003c\u003e();\nlinks.put(from, to);\n\nCustomInterface customWrapper = WrapperFactory.wrap(CustomInterface.class, links, handle);\nint result = customWrapper.accessSomeMethod(target, someArg, \"someOtherArg\");\n```\n\n## License\nThe contents of this project are licensed under the [MIT license](LICENSE).\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3arthqu4ke%2Fhandlewrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F3arthqu4ke%2Fhandlewrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3arthqu4ke%2Fhandlewrapper/lists"}