从 5.3 版本开始, AviatorScript 还支持了解释执行模式,这种模式下,将生成 AviatorScript 自身设计的指令并解释执行,这样就不依赖 asm,也不会生成字节码,在 Android 等非标准 Java 平台上就可以运行。
创建解释器
可以通过 AviatorEvaluator.newInstance(EvalMode)
来创建一个特定执行模式的脚本引擎, EvalMode
包括:
EvalMode.ASM
原有的默认的基于 asm 生成 jvm 字节码的运行模式。EvalMode.INTERPRETER
解释器模式,将生成 aviatorscript IR 并解释执行。
默认模式(也就是全局引擎 AviatorEvaluator.getInstance()
的执行模式)取决于运行的平台,如果检测到是在 android 系统,会自动启用解释模式,否则还是 asm 模式。默认模式还可以通过指定的系统环境变量 **aviator.eval.mode**
来控制,该变量支持 **asm**
和 **interpreter**
两个值,对应相应的两种模式。
我们来创建一个解释器并尝试打开跟踪执行(生产环境不建议打开跟踪执行):
package com.googlecode.aviator.example;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.EvalMode;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.Options;
/**
* Interpreter example
*
* @since 5.3
* @author dennis(killme2008@gmail.com)
*
*/
public class InterpreterExample {
public static void main(final String[] args) {
// 创建解释器
AviatorEvaluatorInstance engine = AviatorEvaluator.newInstance(EvalMode.INTERPRETER);
// 打开跟踪执行
engine.setOption(Options.TRACE_EVAL, true);
Expression exp = engine.compile("score > 80 ? 'good' : 'bad'");
System.out.println(exp.execute(exp.newEnv("score", 100)));
System.out.println(exp.execute(exp.newEnv("score", 50)));
}
}
当 score 大于 50 ,返回 good,其他情况返回 bad。执行输出:
[Aviator TRACE] null instruments:
[Aviator TRACE] 0 load score [Variable] (null:1)
[Aviator TRACE] 1 load 80 [Number] (null:1)
[Aviator TRACE] 2 gt
[Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
[Aviator TRACE] 4 pop
[Aviator TRACE] 5 load good [String] (null:1)
[Aviator TRACE] 6 goto 10 [L1] (null: 1)
[Aviator TRACE] 7 pop
[Aviator TRACE] 8 pop
[Aviator TRACE] 9 load bad [String] (null:1)
[Aviator TRACE] 10 return
[Aviator TRACE] Execute instruments:
[Aviator TRACE] load score [Variable] (null:1) <Stack, []>
[Aviator TRACE] load 80 [Number] (null:1) <Stack, [<JavaType, score, 100, java.lang.Integer>]>
[Aviator TRACE] gt <Stack, [<Long, 80>, <JavaType, score, 100, java.lang.Integer>]>
[Aviator TRACE] branch_unless 8 [L0] (null: 1) <Stack, [<Boolean, true>]>
[Aviator TRACE] pop <Stack, [<Boolean, true>]>
[Aviator TRACE] load good [String] (null:1) <Stack, []>
[Aviator TRACE] goto 10 [L1] (null: 1) <Stack, [<String, good>]>
[Aviator TRACE] return <Stack, [<String, good>]>
good
[Aviator TRACE] null instruments:
[Aviator TRACE] 0 load score [Variable] (null:1)
[Aviator TRACE] 1 load 80 [Number] (null:1)
[Aviator TRACE] 2 gt
[Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
[Aviator TRACE] 4 pop
[Aviator TRACE] 5 load good [String] (null:1)
[Aviator TRACE] 6 goto 10 [L1] (null: 1)
[Aviator TRACE] 7 pop
[Aviator TRACE] 8 pop
[Aviator TRACE] 9 load bad [String] (null:1)
[Aviator TRACE] 10 return
[Aviator TRACE] Execute instruments:
[Aviator TRACE] load score [Variable] (null:1) <Stack, []>
[Aviator TRACE] load 80 [Number] (null:1) <Stack, [<JavaType, score, 50, java.lang.Integer>]>
[Aviator TRACE] gt <Stack, [<Long, 80>, <JavaType, score, 50, java.lang.Integer>]>
[Aviator TRACE] branch_unless 8 [L0] (null: 1) <Stack, [<Boolean, false>]>
[Aviator TRACE] pop <Stack, [<Boolean, false>]>
[Aviator TRACE] load bad [String] (null:1) <Stack, []>
[Aviator TRACE] return <Stack, [<String, bad>]>
bad
这个表达式的指令就是
[Aviator TRACE] 0 load score [Variable] (null:1)
[Aviator TRACE] 1 load 80 [Number] (null:1)
[Aviator TRACE] 2 gt
[Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
[Aviator TRACE] 4 pop
[Aviator TRACE] 5 load good [String] (null:1)
[Aviator TRACE] 6 goto 10 [L1] (null: 1)
[Aviator TRACE] 7 pop
[Aviator TRACE] 8 pop
[Aviator TRACE] 9 load bad [String] (null:1)
[Aviator TRACE] 10 return
这里不过多解释,有兴趣的可以自行研究。Execute instruments:
部分是实际的执行过程,会打印栈里的信息。
注意事项
在解释器模式下,从测试来看,性能会有明显的下降,这是需要用户注意的。功能上是完备支持所有的功能集。
性能测试对比,解释模式下性能下降 30%~60% 之间。
Benchmark Mode Cnt Score Error Units
PerfBenchmark.testArithByAviator thrpt 5 2307.900 ± 20.074 ops/ms
PerfBenchmark.testArithByAviatorInterpretMode thrpt 5 1591.425 ± 82.611 ops/ms
PerfBenchmark.testCondByAviator thrpt 5 1794.663 ± 45.618 ops/ms
PerfBenchmark.testCondByAviatorInterpretMode thrpt 5 702.236 ± 43.204 ops/ms
PerfBenchmark.testObjectByAviator thrpt 5 928.572 ± 61.004 ops/ms
PerfBenchmark.testObjectByAviatorInterpretMode thrpt 5 626.764 ± 53.991 ops/ms