从 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 UnitsPerfBenchmark.testArithByAviator thrpt 5 2307.900 ± 20.074 ops/msPerfBenchmark.testArithByAviatorInterpretMode thrpt 5 1591.425 ± 82.611 ops/msPerfBenchmark.testCondByAviator thrpt 5 1794.663 ± 45.618 ops/msPerfBenchmark.testCondByAviatorInterpretMode thrpt 5 702.236 ± 43.204 ops/msPerfBenchmark.testObjectByAviator thrpt 5 928.572 ± 61.004 ops/msPerfBenchmark.testObjectByAviatorInterpretMode thrpt 5 626.764 ± 53.991 ops/ms
