从 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**两个值,对应相应的两种模式

我们来创建一个解释器并尝试打开跟踪执行(生产环境不建议打开跟踪执行):

  1. package com.googlecode.aviator.example;
  2. import com.googlecode.aviator.AviatorEvaluator;
  3. import com.googlecode.aviator.AviatorEvaluatorInstance;
  4. import com.googlecode.aviator.EvalMode;
  5. import com.googlecode.aviator.Expression;
  6. import com.googlecode.aviator.Options;
  7. /**
  8. * Interpreter example
  9. *
  10. * @since 5.3
  11. * @author dennis(killme2008@gmail.com)
  12. *
  13. */
  14. public class InterpreterExample {
  15. public static void main(final String[] args) {
  16. // 创建解释器
  17. AviatorEvaluatorInstance engine = AviatorEvaluator.newInstance(EvalMode.INTERPRETER);
  18. // 打开跟踪执行
  19. engine.setOption(Options.TRACE_EVAL, true);
  20. Expression exp = engine.compile("score > 80 ? 'good' : 'bad'");
  21. System.out.println(exp.execute(exp.newEnv("score", 100)));
  22. System.out.println(exp.execute(exp.newEnv("score", 50)));
  23. }
  24. }

当 score 大于 50 ,返回 good,其他情况返回 bad。执行输出:

  1. [Aviator TRACE] null instruments:
  2. [Aviator TRACE] 0 load score [Variable] (null:1)
  3. [Aviator TRACE] 1 load 80 [Number] (null:1)
  4. [Aviator TRACE] 2 gt
  5. [Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
  6. [Aviator TRACE] 4 pop
  7. [Aviator TRACE] 5 load good [String] (null:1)
  8. [Aviator TRACE] 6 goto 10 [L1] (null: 1)
  9. [Aviator TRACE] 7 pop
  10. [Aviator TRACE] 8 pop
  11. [Aviator TRACE] 9 load bad [String] (null:1)
  12. [Aviator TRACE] 10 return
  13. [Aviator TRACE] Execute instruments:
  14. [Aviator TRACE] load score [Variable] (null:1) <Stack, []>
  15. [Aviator TRACE] load 80 [Number] (null:1) <Stack, [<JavaType, score, 100, java.lang.Integer>]>
  16. [Aviator TRACE] gt <Stack, [<Long, 80>, <JavaType, score, 100, java.lang.Integer>]>
  17. [Aviator TRACE] branch_unless 8 [L0] (null: 1) <Stack, [<Boolean, true>]>
  18. [Aviator TRACE] pop <Stack, [<Boolean, true>]>
  19. [Aviator TRACE] load good [String] (null:1) <Stack, []>
  20. [Aviator TRACE] goto 10 [L1] (null: 1) <Stack, [<String, good>]>
  21. [Aviator TRACE] return <Stack, [<String, good>]>
  22. good
  23. [Aviator TRACE] null instruments:
  24. [Aviator TRACE] 0 load score [Variable] (null:1)
  25. [Aviator TRACE] 1 load 80 [Number] (null:1)
  26. [Aviator TRACE] 2 gt
  27. [Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
  28. [Aviator TRACE] 4 pop
  29. [Aviator TRACE] 5 load good [String] (null:1)
  30. [Aviator TRACE] 6 goto 10 [L1] (null: 1)
  31. [Aviator TRACE] 7 pop
  32. [Aviator TRACE] 8 pop
  33. [Aviator TRACE] 9 load bad [String] (null:1)
  34. [Aviator TRACE] 10 return
  35. [Aviator TRACE] Execute instruments:
  36. [Aviator TRACE] load score [Variable] (null:1) <Stack, []>
  37. [Aviator TRACE] load 80 [Number] (null:1) <Stack, [<JavaType, score, 50, java.lang.Integer>]>
  38. [Aviator TRACE] gt <Stack, [<Long, 80>, <JavaType, score, 50, java.lang.Integer>]>
  39. [Aviator TRACE] branch_unless 8 [L0] (null: 1) <Stack, [<Boolean, false>]>
  40. [Aviator TRACE] pop <Stack, [<Boolean, false>]>
  41. [Aviator TRACE] load bad [String] (null:1) <Stack, []>
  42. [Aviator TRACE] return <Stack, [<String, bad>]>
  43. bad

这个表达式的指令就是

  1. [Aviator TRACE] 0 load score [Variable] (null:1)
  2. [Aviator TRACE] 1 load 80 [Number] (null:1)
  3. [Aviator TRACE] 2 gt
  4. [Aviator TRACE] 3 branch_unless 8 [L0] (null: 1)
  5. [Aviator TRACE] 4 pop
  6. [Aviator TRACE] 5 load good [String] (null:1)
  7. [Aviator TRACE] 6 goto 10 [L1] (null: 1)
  8. [Aviator TRACE] 7 pop
  9. [Aviator TRACE] 8 pop
  10. [Aviator TRACE] 9 load bad [String] (null:1)
  11. [Aviator TRACE] 10 return

这里不过多解释,有兴趣的可以自行研究。Execute instruments:部分是实际的执行过程,会打印栈里的信息。

注意事项

在解释器模式下,从测试来看,性能会有明显的下降,这是需要用户注意的。功能上是完备支持所有的功能集。

性能测试对比,解释模式下性能下降 30%~60% 之间。

  1. Benchmark Mode Cnt Score Error Units
  2. PerfBenchmark.testArithByAviator thrpt 5 2307.900 ± 20.074 ops/ms
  3. PerfBenchmark.testArithByAviatorInterpretMode thrpt 5 1591.425 ± 82.611 ops/ms
  4. PerfBenchmark.testCondByAviator thrpt 5 1794.663 ± 45.618 ops/ms
  5. PerfBenchmark.testCondByAviatorInterpretMode thrpt 5 702.236 ± 43.204 ops/ms
  6. PerfBenchmark.testObjectByAviator thrpt 5 928.572 ± 61.004 ops/ms
  7. PerfBenchmark.testObjectByAviatorInterpretMode thrpt 5 626.764 ± 53.991 ops/ms