开发基于JVM的声明式编程语言
PreRequisites antlr4 asm-plugin: https://github.com/kamiiel/asm-intellij-plugin/releases Intellij IDEA Install plugin from disk
排错记录 编译过程没问题,执行时报错: Exception in thread “main” java.lang.ClassFormatError: Field “out” in class test has illegal signature “Ljava/io/PrintStream”
错误原因:在产生字节码的过程中,调用PrintStream忘记加分号
1 2 methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream");
应为:
1 2 methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
JVM结构 1.类加载器 2.运行时数据区 3.执行引擎 4.本地方法库
double和long需要占据2个slot,其余基本类型和引用都是1个slot。 slot可以重复利用
垃圾回收(Garbage Collection) 查看Java进程使用的垃圾回收器:
查看默认垃圾回收器
JVM字节码 解析一个接口 接口定义:
1 2 3 4 package edu.ustb.spesc.element;public interface InterfaceLook {}
javap -v 结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Classfile /home/wsd/STEM/Experiments/SPESC-Java-Compiler/compiler/target/test-classes/edu/ustb/spesc/element/InterfaceLook.class Last modified Apr 1, 2021; size 130 bytes MD5 checksum 849d09ca95f1ed5733cca527dce9ed9c Compiled from "InterfaceLook.java" public interface edu.ustb.spesc.element.InterfaceLook minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT Constant pool: #1 = Class #5 // edu/ustb/spesc/element/InterfaceLook #2 = Class #6 // java/lang/Object #3 = Utf8 SourceFile #4 = Utf8 InterfaceLook.java #5 = Utf8 edu/ustb/spesc/element/InterfaceLook #6 = Utf8 java/lang/Object { } SourceFile: "InterfaceLook.java"
一些操作码助记符:除了比较容易记住的 i=int, l=long, s=short, b=byte, c=char, f=float, d=double, 还有 z=boolean, a=reference
DUP 这是一条直接操作操作数栈的指令,表示复制操作数栈栈顶的值,并插入到栈顶 比如最常见的:
1 2 3 Object create () { return new Object(); }
编译后字节码如下:
1 2 3 4 5 Method java.lang.Object create() 0 new #1 // Class java.lang.Object 3 dup 4 invokespecial #4 // Method java.lang.Object.<init>()V 7 areturn
第0行通过new创建了一个Object类型的对象,并将其引用压入栈顶 第3行复制栈顶的引用一份 第4行调用invokespecial为Object的构造函数,这里会消耗一个引用 所以第3行需要复制一份,不然调用invokespecial后会导致无法返回实例引用
解析一个类 类定义:
1 2 3 4 package edu.ustb.spesc;public class bytecodeTest {}
javap -v 结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Classfile /home/wsd/STEM/Experiments/SPESC-Java-Compiler/compiler/target/test-classes/edu/ustb/spesc/bytecodeTest.class Last modified Apr 1, 2021; size 291 bytes MD5 checksum 58439c875ed1b27cf7a5a68507efbf13 Compiled from "bytecodeTest.java" public class edu.ustb.spesc.bytecodeTest minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#13 // java/lang/Object."<init>":()V #2 = Class #14 // edu/ustb/spesc/bytecodeTest #3 = Class #15 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 Ledu/ustb/spesc/bytecodeTest; #11 = Utf8 SourceFile #12 = Utf8 bytecodeTest.java #13 = NameAndType #4:#5 // "<init>":()V #14 = Utf8 edu/ustb/spesc/bytecodeTest #15 = Utf8 java/lang/Object { public edu.ustb.spesc.bytecodeTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Ledu/ustb/spesc/bytecodeTest; } SourceFile: "bytecodeTest.java"
由于JVM解析Java文件是按照行来解析的,一行Java代码可能对应多行字节码,所以设置 LineNumberTable 这个属性就是表示java文件的某行与字节码某行的对应关系。 比如上面的显示 line 3: 0 就表示bytecodeTest.java的第3行对应解析到jvm字节码的第0行即 aload_0 Slot是字节码中的存储单位,1个Slot大小为32bit(4 bytes)
使用ASM操作字节码 methodVisitor.visitMethodInsn五个参数
INVOKE
调用函数的内部全类名
函数名
返回类型
是否接口调用
一些与标准文档的出入之处 3.1 .用作结构体访问的操作符,用做结束符会冲突 6.3 当事人描述中的 field 不止属于当事人,还可以作为合约的全局变量 另外,在filed定义中 attribute : (constant | type) 实际匹配过程应该是先匹配type,再匹配constant。否则如果出现类似 name : String 会将其匹配到constant 所以程序中使用 name : (type | value) 的方式匹配 name : IDENTIFIER type : BOOLEAN (‘[‘ ‘]’) | INTEGER (‘[‘ ‘]’) ; value : NUMBER | STRING ; 其中,(‘[‘ ‘]’)*用于匹配数组
6.8 有关系符号,但缺少关系表达式 关系表达式属于谓词,可返回Yes,No,Unknown 关系表达式中可再分所属关系和比较关系,所属关系的关键词是belongsTo,比较关系的关键词有 > >= < <= == != 所以在规则中添加了relationalExpression
实验探究 invokespecial 和 invokevirtual 的区别 1 2 3 4 5 public class LibSayHello { public void sayHello () { System.out.println("Hello" ); } }
bytecode如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 public sayHello()V L0 LINENUMBER 5 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "Hello" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L1 LINENUMBER 6 L1 RETURN L2 LOCALVARIABLE this Ledu/ustb/spesc/LibSayHello; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1
1 2 3 4 5 6 public class MainTest { public static void main (String[] args) { LibSayHello testObj = new LibSayHello(); testObj.sayHello(); } }
bytecode如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static main([Ljava/lang/String;)V L0 LINENUMBER 5 L0 NEW edu/ustb/spesc/LibSayHello DUP INVOKESPECIAL edu/ustb/spesc/LibSayHello.<init> ()V ASTORE 1 L1 LINENUMBER 6 L1 ALOAD 1 INVOKEVIRTUAL edu/ustb/spesc/LibSayHello.sayHello ()V L2 LINENUMBER 7 L2 RETURN L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 LOCALVARIABLE testObj Ledu/ustb/spesc/LibSayHello; L1 L3 1 MAXSTACK = 2 MAXLOCALS = 2
可以看到,init构造函数使用的是INVOKESPECIAL,普通方法sayHello使用的是INVOKEVIRTUAL
再来进行一层抽象,将LibHello写成接口的形式,类LibHelloImpl用于实现,此时测试main函数的bytecode变为如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static main([Ljava/lang/String;)V L0 LINENUMBER 5 L0 NEW edu/ustb/spesc/LibHelloImpl DUP INVOKESPECIAL edu/ustb/spesc/LibHelloImpl.<init> ()V ASTORE 1 L1 LINENUMBER 6 L1 ALOAD 1 INVOKEINTERFACE edu/ustb/spesc/LibHello.sayHello ()V (itf) L2 LINENUMBER 7 L2 RETURN L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 LOCALVARIABLE testObj Ledu/ustb/spesc/LibHello; L1 L3 1 MAXSTACK = 2 MAXLOCALS = 2
可以看到对sayHello的调用由原来的invokespecial变成了invokeinterface
假如LibHello是abstract类呢? 实验后可以发现,不管LibHelloImpl是否重写hello方法,对sayHello的调用都变回了invokevirtual 并且只要LibHello不变,即使改变了LibHelloImpl,也不会触发对于MainTest的字节码重新编译
FunctionalInterface底层实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ││ [Verified Entry Point] 1.54% ↘│ 0x00007f6db5299a80: mov %eax,-0x14000(%rsp) 2.23% │ 0x00007f6db5299a87: push %rbp 0.80% │ 0x00007f6db5299a88: sub $0x30,%rsp ;*aload_1 │ ; - cn.wsd.benchmark.functionalinterface.TestMain::lambda$dynamicMethodCall$0@0 (line 30) 2.00% ││ 0x00007f6db5299a8c: mov 0xc(%rdx),%eax ;*arraylength ││ ; - cn.wsd.benchmark.functionalinterface.TestMain::lambda$dynamicMethodCall$0@1 (line 30) ││ ; implicit exception: dispatches to 0x00007f6db5299aa0 0.94% ││ 0x00007f6db5299a8f: mov 0xc(%rsi),%esi ;*getfield offset ││ ; - cn.wsd.benchmark.functionalinterface.TestMain::lambda$dynamicMethodCall$0@3 (line 30) 0.78% ││ 0x00007f6db5299a92: add %esi,%eax 0.85% ││ 0x00007f6db5299a94: add $0x30,%rsp 1.21% ││ 0x00007f6db5299a98: pop %rbp 0.95% ││ 0x00007f6db5299a99: test %eax,0x177c7661(%rip) # 0x00007f6dcca61100 ││ ; {poll_return} 0.74% ││╭ 0x00007f6db5299a9f: retq │││ 0x00007f6db5299aa0: callq 0x00007f6db5100a80 ; OopMap{rsi=Oop off=69} │││ ;*arraylength │││ ; - cn.wsd.benchmark.functionalinterface.TestMain::lambda$dynamicMethodCall$0@1 (line 30) │││ ; {runtime_call} │ │ 0x00007f6db5299aa5: nop │ │ 0x00007f6db5299aa6: nop
先看下总得分:
1 2 3 4 5 Benchmark Mode Cnt Score Error Units FunctionalInterfaceTest.dynamicMethodCall avgt 5 7.902 ± 0.807 ns/op FunctionalInterfaceTest.dynamicMethodCall:·asm avgt NaN --- FunctionalInterfaceTest.normalMethodCall avgt 5 4.139 ± 0.081 ns/op FunctionalInterfaceTest.normalMethodCall:·asm avgt NaN ---
函数式调用方式较差,但没有数量级上的差距。这比较符合预期。
normalMethod的汇编实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 c2, level 4, cn.wsd.benchmark.functionalinterface.CounterImpl::work, version 2, compile id 6875 # parm0: rdx:rdx = '[B' # [sp+0x20] (sp of caller) 0x00007fef9c3c9320: mov 0x8(%rsi),%r10d 0x00007fef9c3c9324: movabs $0x800000000,%r12 0x00007fef9c3c932e: add %r12,%r10 0x00007fef9c3c9331: xor %r12,%r12 0x00007fef9c3c9334: cmp %r10,%rax 0x00007fef9c3c9337: jne 0x00007fef9464b080 ; {runtime_call ic_miss_stub} 0x00007fef9c3c933d: data16 xchg %ax,%ax [Verified Entry Point] 1.51% 0x00007fef9c3c9340: mov %eax,-0x14000(%rsp) 5.94% 0x00007fef9c3c9347: push %rbp 0.04% 0x00007fef9c3c9348: sub $0x10,%rsp ;*synchronization entry ; - cn.wsd.benchmark.functionalinterface.CounterImpl::work@-1 (line 17) 1.49% ╭ 0x00007fef9c3c934c: mov 0xc(%rdx),%eax ; implicit exception: dispatches to 0x00007fef9c3c9362 5.46% │ 0x00007fef9c3c934f: add 0xc(%rsi),%eax ;*iadd {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.CounterImpl::work@6 (line 17) 0.30% │ 0x00007fef9c3c9352: add $0x10,%rsp 1.39% │ 0x00007fef9c3c9356: pop %rbp 0.15% │ 0x00007fef9c3c9357: mov 0x108(%r15),%r10 5.24% │ 0x00007fef9c3c935e: test %eax,(%r10) ; {poll_return} 0.28% │ 0x00007fef9c3c9361: retq ↘ 0x00007fef9c3c9362: mov $0xfffffff6,%esi 0x00007fef9c3c9367: callq 0x00007fef94649e00 ; ImmutableOopMap{} ;*arraylength {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.CounterImpl::work@1 (line 17) ; {runtime_call UncommonTrapBlob} 0x00007fef9c3c936c: hlt
调用它的地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 c2, level 4, cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub, version 4, compile id 6989 0x00007fef9c3d41e4: mov 0x40(%rsp),%r10 0x00007fef9c3d41e9: movzbl 0x94(%r10),%r11d ;*getfield isDone {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@30 (line 192) ; implicit exception: dispatches to 0x00007fef9c3d4318 0x00007fef9c3d41f1: mov $0x1,%ebp 0x00007fef9c3d41f6: test %r11d,%r11d ╭ 0x00007fef9c3d41f9: jne 0x00007fef9c3d4258 ;*ifeq {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@33 (line 192) │ 0x00007fef9c3d41fb: nopl 0x0(%rax,%rax,1) ;*aload_1 {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@36 (line 193) 0.31% │↗ 0x00007fef9c3d4200: mov 0x50(%rsp),%r10 1.44% ││ 0x00007fef9c3d4205: mov 0x14(%r10),%r11d ;*getfield coder {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::normalMethodCall@1 (line 29) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@17 (line 190) 0.17% ││ 0x00007fef9c3d4209: mov 0x10(%r10),%r10d ;*getfield inBytes {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::normalMethodCall@5 (line 29) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@17 (line 190) 5.39% ││ 0x00007fef9c3d420d: mov 0x8(%r12,%r11,8),%r9d ; implicit exception: dispatches to 0x00007fef9c3d42d4 7.70% ││ 0x00007fef9c3d4212: cmp $0xfa768,%r9d ; {metadata('cn/wsd/benchmark/functionalinterface/CounterImpl')} ││ 0x00007fef9c3d4219: jne 0x00007fef9c3d4291 5.56% ││ 0x00007fef9c3d421b: lea (%r12,%r11,8),%rsi ;*invokeinterface work {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::normalMethodCall@8 (line 29) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@17 (line 190) 0.05% ││ 0x00007fef9c3d421f: mov %r10,%rdx 1.49% ││ 0x00007fef9c3d4222: shl $0x3,%rdx ;*getfield inBytes {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::normalMethodCall@5 (line 29) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@17 (line 190) 0.11% ││ 0x00007fef9c3d4226: nop 5.45% ││ 0x00007fef9c3d4227: callq 0x00007fef9464ad80 ; ImmutableOopMap{[64]=Oop [72]=Oop [80]=Oop [8]=Oop } ││ ;*invokeinterface work {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::normalMethodCall@8 (line 29) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@17 (line 190) ││ ; {optimized virtual_call} 1.63% ││ 0x00007fef9c3d422c: mov 0x8(%rsp),%rsi 5.43% ││ 0x00007fef9c3d4231: mov %eax,%edx 0.28% ││ 0x00007fef9c3d4233: callq 0x00007fef9464ad80 ; ImmutableOopMap{[64]=Oop [72]=Oop [80]=Oop [8]=Oop } ││ ;*invokespecial consumeFull {reexecute=0 rethrow=0 return_oop=0} ││ ; - org.openjdk.jmh.infra.Blackhole::consume@15 (line 382) ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@20 (line 190) ││ ; {optimized virtual_call} 1.67% ││ 0x00007fef9c3d4238: mov 0x40(%rsp),%r10 5.12% ││ 0x00007fef9c3d423d: movzbl 0x94(%r10),%r11d ;*ifeq {reexecute=0 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@33 (line 192) 0.30% ││ 0x00007fef9c3d4245: mov 0x108(%r15),%r10 1.49% ││ 0x00007fef9c3d424c: add $0x1,%rbp ; ImmutableOopMap{[64]=Oop [72]=Oop [80]=Oop [8]=Oop } ││ ;*ifeq {reexecute=1 rethrow=0 return_oop=0} ││ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@33 (line 192) 0.16% ││ 0x00007fef9c3d4250: test %eax,(%r10) ; {poll} 5.16% ││ 0x00007fef9c3d4253: test %r11d,%r11d │╰ 0x00007fef9c3d4256: je 0x00007fef9c3d4200 ;*aload_1 {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@36 (line 193) ↘ 0x00007fef9c3d4258: movabs $0x7fefb409bc20,%r10 0x00007fef9c3d4262: callq *%r10 ;*invokestatic nanoTime {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@37 (line 193) 0x00007fef9c3d4265: mov 0x48(%rsp),%r10 0x00007fef9c3d426a: mov %rax,0x30(%r10) ;*putfield stopTime {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@40 (line 193) 0x00007fef9c3d426e: movq $0x0,0x20(%r10) ;*putfield realTime {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.jmh_generated.FunctionalInterfaceTest_normalMethodCall_jmhTest::normalMethodCall_avgt_jmhStub@46 (line 194)
lambda函数的汇编实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 c2, level 4, cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49.0x00000008000d3840::work, version 2, compile id 6885 dependencies [0x00007ff0e03ca928,0x00007ff0e03ca930] = 8 handler table [0x00007ff0e03ca930,0x00007ff0e03ca948] = 24 ---------------------------------------------------------------------- cn/wsd/benchmark/functionalinterface/FunctionalInterfaceTest$$Lambda$49.work([B)I [0x00007ff0e03ca7c0, 0x00007ff0e03ca868] 168 bytes [Entry Point] [Constants] # {method} {0x00007ff08fcf8ba0} 'work' '([B)I' in 'cn/wsd/benchmark/functionalinterface/FunctionalInterfaceTest$$Lambda$49' # this: rsi:rsi = 'cn/wsd/benchmark/functionalinterface/FunctionalInterfaceTest$$Lambda$49' # parm0: rdx:rdx = '[B' # [sp+0x20] (sp of caller) 0.05% 0x00007ff0e03ca7c0: mov 0x8(%rsi),%r10d 3.30% 0x00007ff0e03ca7c4: movabs $0x800000000,%r12 0.07% 0x00007ff0e03ca7ce: add %r12,%r10 0.05% 0x00007ff0e03ca7d1: xor %r12,%r12 0.03% 0x00007ff0e03ca7d4: cmp %r10,%rax 0x00007ff0e03ca7d7: jne 0x00007ff0d864b080 ; {runtime_call ic_miss_stub} 3.08% 0x00007ff0e03ca7dd: data16 xchg %ax,%ax [Verified Entry Point] 0.05% 0x00007ff0e03ca7e0: mov %eax,-0x14000(%rsp) 0.10% 0x00007ff0e03ca7e7: push %rbp 3.07% 0x00007ff0e03ca7e8: sub $0x10,%rsp ;*synchronization entry ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@-1 0.06% 0x00007ff0e03ca7ec: mov 0xc(%rsi),%r10d ;*getfield arg$1 {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@1 0.07% 0x00007ff0e03ca7f0: test %r10d,%r10d ╭ 0x00007ff0e03ca7f3: je 0x00007ff0e03ca810 ;*invokespecial lambda$dynamicMethodCall$0 {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@5 3.11% │ 0x00007ff0e03ca7f5: lea (%r12,%r10,8),%rsi ;*getfield arg$1 {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@1 0.05% │ 0x00007ff0e03ca7f9: xchg %ax,%ax 0.02% │ 0x00007ff0e03ca7fb: callq 0x00007ff0d864ad80 ; ImmutableOopMap{} │ ;*invokespecial lambda$dynamicMethodCall$0 {reexecute=0 rethrow=0 return_oop=0} │ ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@5 │ ; {optimized virtual_call} 6.98% │ 0x00007ff0e03ca800: add $0x10,%rsp 0.04% │ 0x00007ff0e03ca804: pop %rbp 0.06% │ 0x00007ff0e03ca805: mov 0x108(%r15),%r10 3.10% │ 0x00007ff0e03ca80c: test %eax,(%r10) ; {poll_return} 0.04% │ 0x00007ff0e03ca80f: retq ↘ 0x00007ff0e03ca810: mov $0xfffffff6,%esi 0x00007ff0e03ca815: mov %rdx,%rbp 0x00007ff0e03ca818: data16 xchg %ax,%ax 0x00007ff0e03ca81b: callq 0x00007ff0d8649e00 ; ImmutableOopMap{rbp=Oop } ;*invokespecial lambda$dynamicMethodCall$0 {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest$$Lambda$49/0x00000008000d3840::work@5 ; {runtime_call UncommonTrapBlob} 0x00007ff0e03ca820: mov %rax,%rsi 0x00007ff0e03ca823: add $0x10,%rsp 0x00007ff0e03ca827: pop %rbp
调用它的地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 c2, level 4, cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::bynamicMethod, version 2, compile id 6881 # parm1: rcx:rcx = '[B' # [sp+0x20] (sp of caller) 0x00007ff0e03c99a0: mov 0x8(%rsi),%r10d 0x00007ff0e03c99a4: movabs $0x800000000,%r12 0x00007ff0e03c99ae: add %r12,%r10 0x00007ff0e03c99b1: xor %r12,%r12 0x00007ff0e03c99b4: cmp %r10,%rax 0x00007ff0e03c99b7: jne 0x00007ff0d864b080 ; {runtime_call ic_miss_stub} 0x00007ff0e03c99bd: data16 xchg %ax,%ax [Verified Entry Point] 3.14% 0x00007ff0e03c99c0: mov %eax,-0x14000(%rsp) 0.08% 0x00007ff0e03c99c7: push %rbp 0.04% 0x00007ff0e03c99c8: sub $0x10,%rsp ;*synchronization entry ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::bynamicMethod@-1 (line 19) 3.19% 0x00007ff0e03c99cc: mov %rdx,%rsi 0.03% 0x00007ff0e03c99cf: mov %rcx,%rdx 0.05% 0x00007ff0e03c99d2: data16 xchg %ax,%ax 3.35% 0x00007ff0e03c99d5: movabs $0xffffffffffffffff,%rax 0.06% 0x00007ff0e03c99df: callq 0x00007ff0d864aa80 ; ImmutableOopMap{} ;*invokeinterface work {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::bynamicMethod@2 (line 19) ; {virtual_call} 0.06% 0x00007ff0e03c99e4: add $0x10,%rsp 2.95% 0x00007ff0e03c99e8: pop %rbp 0.06% 0x00007ff0e03c99e9: mov 0x108(%r15),%r10 0.05% 0x00007ff0e03c99f0: test %eax,(%r10) ; {poll_return} 0.06% 0x00007ff0e03c99f3: retq ;*invokeinterface work {reexecute=0 rethrow=0 return_oop=0} ; - cn.wsd.benchmark.functionalinterface.FunctionalInterfaceTest::bynamicMethod@2 (line 19) 0x00007ff0e03c99f4: mov %rax,%rsi 0x00007ff0e03c99f7: add $0x10,%rsp 0x00007ff0e03c99fb: pop %rbp 0x00007ff0e03c99fc: jmpq 0x00007ff0d86f9900 ; {runtime_call _rethrow_Java}
reexperiment 0x00007f95a864ad80
一些思考 条款对应实现的Java数据结构是怎样的?一个函数、多个函数还是一个类 一个函数表达不出条款的意思 多个函数方案可以将when,while,where分别对应到一个函数,不过难以统一判断条款的参与方party,需要每个函数前面都加一个判断。 一个类的方案目前还没遇到问题。
条款中的动作参数是形参还是实参 使用形参parametersList。因为条款里的动作相当于AOP中的PointCut,定义为ActionSignature 与此区分,test函数里的action调用定义为 functionCall,使用实参argumentList
关于不支持函数重载 一般说来,虽然Action中支持定义参数,但是我们一般不使用同名不同参来进行函数重载(即不支持函数重载) 原因是我们使用的是方法名作为唯一标示去查找和判定的。为什么不用Method? 因为 Method 不支持 Berkeley DB持久化存储。
ContractEngine 的设计 根据Action是由自主触发还是AOP外部触发将工作模式分为自实现和AOP两种。
自实现
AOP
handleAction触发,内部调用method.invoke执行动作
Spring Bean中方法执行动作,@Pointcut拦截触发
两种模式对于duty的处理:
Duty
自实现
AOP
can
通过调用handleAction触发
拦截外部调用后检查termObj, termObj.when 通过后执行
must
runMustActions 中触发调用must动作
和can对待是一样的。所以需要另写breach term处理must动作如果一直不触发的情况
cannot
handleAction中检查出来,则不发生动作执行
termObj.when 通过后,则不执行pjp.proceed
两种模式对于条件的处理:
Condition
自实现
AOP
when
termObj.when
和自实现一样
while
termObj.while,和method.invoke 并列执行
termObj.while,和 pjp.proceed 并列执行
where
termObj.where
和自实现一样
Comments
shortname
for Disqus. Please set it in_config.yml
.