|
25 | 25 | package java.lang.classfile.snippets;
|
26 | 26 |
|
27 | 27 | import java.lang.classfile.*;
|
28 |
| -import java.lang.classfile.components.ClassRemapper; |
29 |
| -import java.lang.classfile.components.CodeLocalsShifter; |
30 |
| -import java.lang.classfile.components.CodeRelabeler; |
31 | 28 | import java.lang.classfile.instruction.*;
|
32 | 29 | import java.lang.constant.ClassDesc;
|
33 | 30 | import java.lang.constant.ConstantDescs;
|
34 | 31 | import java.lang.constant.MethodTypeDesc;
|
35 | 32 | import java.lang.invoke.MethodHandles;
|
36 |
| -import java.lang.reflect.AccessFlag; |
37 |
| -import java.util.ArrayDeque; |
38 | 33 | import java.util.HashSet;
|
39 |
| -import java.util.Map; |
40 | 34 | import java.util.Set;
|
41 |
| -import java.util.function.Predicate; |
42 |
| -import java.util.stream.Collectors; |
43 | 35 | import java.util.stream.Stream;
|
44 | 36 |
|
45 | 37 | import static java.util.stream.Collectors.toSet;
|
@@ -326,82 +318,6 @@ void fooToBarUnrolled(ClassModel classModel) {
|
326 | 318 | // @end
|
327 | 319 | }
|
328 | 320 |
|
329 |
| - void codeRelabeling(ClassModel classModel) { |
330 |
| - // @start region="codeRelabeling" |
331 |
| - byte[] newBytes = ClassFile.of().transformClass(classModel, |
332 |
| - ClassTransform.transformingMethodBodies( |
333 |
| - CodeTransform.ofStateful(CodeRelabeler::of))); |
334 |
| - // @end |
335 |
| - } |
336 |
| - |
337 |
| - // @start region="classInstrumentation" |
338 |
| - byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicate<MethodModel> instrumentedMethodsFilter) { |
339 |
| - var instrumentorCodeMap = instrumentor.methods().stream() |
340 |
| - .filter(instrumentedMethodsFilter) |
341 |
| - .collect(Collectors.toMap(mm -> mm.methodName().stringValue() + mm.methodType().stringValue(), mm -> mm.code().orElseThrow())); |
342 |
| - var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); |
343 |
| - var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); |
344 |
| - var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); |
345 |
| - return ClassFile.of().transformClass(target, |
346 |
| - ClassTransform.transformingMethods( |
347 |
| - instrumentedMethodsFilter, |
348 |
| - (mb, me) -> { |
349 |
| - if (me instanceof CodeModel targetCodeModel) { |
350 |
| - var mm = targetCodeModel.parent().get(); |
351 |
| - //instrumented methods code is taken from instrumentor |
352 |
| - mb.transformCode(instrumentorCodeMap.get(mm.methodName().stringValue() + mm.methodType().stringValue()), |
353 |
| - //all references to the instrumentor class are remapped to target class |
354 |
| - instrumentorClassRemapper.asCodeTransform() |
355 |
| - .andThen((codeBuilder, instrumentorCodeElement) -> { |
356 |
| - //all invocations of target methods from instrumentor are inlined |
357 |
| - if (instrumentorCodeElement instanceof InvokeInstruction inv |
358 |
| - && target.thisClass().asInternalName().equals(inv.owner().asInternalName()) |
359 |
| - && mm.methodName().stringValue().equals(inv.name().stringValue()) |
360 |
| - && mm.methodType().stringValue().equals(inv.type().stringValue())) { |
361 |
| - |
362 |
| - //store stacked method parameters into locals |
363 |
| - var storeStack = new ArrayDeque<StoreInstruction>(); |
364 |
| - int slot = 0; |
365 |
| - if (!mm.flags().has(AccessFlag.STATIC)) |
366 |
| - storeStack.push(StoreInstruction.of(TypeKind.REFERENCE, slot++)); |
367 |
| - for (var pt : mm.methodTypeSymbol().parameterList()) { |
368 |
| - var tk = TypeKind.from(pt); |
369 |
| - storeStack.push(StoreInstruction.of(tk, slot)); |
370 |
| - slot += tk.slotSize(); |
371 |
| - } |
372 |
| - storeStack.forEach(codeBuilder::with); |
373 |
| - |
374 |
| - //inlined target locals must be shifted based on the actual instrumentor locals |
375 |
| - codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder |
376 |
| - .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) |
377 |
| - .andThen(CodeRelabeler.of()) |
378 |
| - .andThen((innerBuilder, shiftedTargetCode) -> { |
379 |
| - //returns must be replaced with jump to the end of the inlined method |
380 |
| - if (shiftedTargetCode instanceof ReturnInstruction) |
381 |
| - innerBuilder.goto_(inlinedBlockBuilder.breakLabel()); |
382 |
| - else |
383 |
| - innerBuilder.with(shiftedTargetCode); |
384 |
| - }))); |
385 |
| - } else |
386 |
| - codeBuilder.with(instrumentorCodeElement); |
387 |
| - })); |
388 |
| - } else |
389 |
| - mb.with(me); |
390 |
| - }) |
391 |
| - .andThen(ClassTransform.endHandler(clb -> |
392 |
| - //remaining instrumentor fields and methods are injected at the end |
393 |
| - clb.transform(instrumentor, |
394 |
| - ClassTransform.dropping(cle -> |
395 |
| - !(cle instanceof FieldModel fm |
396 |
| - && !targetFieldNames.contains(fm.fieldName().stringValue())) |
397 |
| - && !(cle instanceof MethodModel mm |
398 |
| - && !ConstantDescs.INIT_NAME.equals(mm.methodName().stringValue()) |
399 |
| - && !targetMethods.contains(mm.methodName().stringValue() + mm.methodType().stringValue()))) |
400 |
| - //and instrumentor class references remapped to target class |
401 |
| - .andThen(instrumentorClassRemapper))))); |
402 |
| - } |
403 |
| - // @end |
404 |
| - |
405 | 321 | void resolverExample() {
|
406 | 322 | // @start region="lookup-class-hierarchy-resolver"
|
407 | 323 | MethodHandles.Lookup lookup = MethodHandles.lookup(); // @replace regex="MethodHandles\.lookup\(\)" replacement="..."
|
|
0 commit comments