2. javascript 引擎Rhino源代码分析 简单代码分析
2015-11-08 21:30
609 查看
1. 简介
本例子通过执行最简单的javascript: var result = 1;
来分析Rhino如何解析,转换,编译,执行。。。
2. 基本测试代码
3. AST抽象语法树转换过程
解析器解析及转换AST:
4. IRFactory将ast语法树转换成为内部表现形式
ast语法树转换成为IR内部表现形式代码:
主要转换核心代码在irf.transformTree(ast);:
最终 转换后的结果存放在Decompiler的sourceBuffer数组:
5. 编译生成byteCode虚拟字节码
主要生成byteCode字节码:
转换后的虚拟字节码:
6. 解释器顺序执行byteCode指令
6.1 代码分析
6.1.1 Context的evaluateString()方法执行上述解析,编译为字节码后,通过script.exec()方法解释执行
itsMaxStack: 当前script最大栈深
itsICode: 存储虚拟指令的字节数组
itsStringTable: 变量表字符串数组,当前例子中 itStringTable[0] = "result"
6.1.2 解释器通过Interpreter.interpret()循环执行指令
6.2 栈桢分析:
接下来详细讲述Rhino如何循环执行上面的指令数组
初始化栈桢前:
初始化栈桢如下所示:
6.2.1 [0] LINE : 1
从指令节中取2个字节,并转为int(行码)
其处理代码:
6.2.2 [3] REG_STR_C0
将变量表第0个数组(result变量名)保存到stringReg字符串中
其处理代码:
6.2.3 [4] BINDNAME
从scope作用域取出名为stringReg的Scriptable,压入栈顶stack[] 如果当前scope找不到,会到当前scope的prototype链上找,可见: ScriptRuntime.bind()方法;
其处理代码:
栈桢示意图:
6.2.4 [5] ONE
将DOUBLE_MARK标记压入栈顶,并将值 1 存入 sDbl数组中
6.2.5 [6] REG_STR_C0
同 6.2.2
6.2.6 [7] SETNAME
包含STRICT与非STRICT模式,弹出并取出栈顶对象,如果为DOUBLE_MARK,取出并转为数值,再从栈顶取一个对象,通过ScriptRuntime.setName()赋值给result.
6.2.7 [8] POP
从栈顶弹出一个对象
6.2.8 [9] RETURN_RESULT
无
作者: 阿钿
本例子通过执行最简单的javascript: var result = 1;
来分析Rhino如何解析,转换,编译,执行。。。
2. 基本测试代码
public static void main(String[] args){ //Context 用来存储对应线程的数据,一个线程只对应唯一的context Context ctx = Context.enter(); //scope表示一组javascript对象,保存执行javascript需要的全部标准对象和全局函数 Scriptable scope = ctx.initSafeStandardObjects(); //设置js优化级别,有-1到9,其中 -1表示直接解释执行; ctx.setOptimizationLevel(-1); try{ //传入并执行javascript代码 ctx.evaluateString(scope, "var result=1;", "", 1, null); }catch(Exception e){ e.printStackTrace(); }finally{ Context.exit(); } }
3. AST抽象语法树转换过程
解析器解析及转换AST:
//具体见Context.compileImpl()方法; Parser p = new Parser(compilerEnv, compilationErrorReporter); AstRoot ast = p.parse(sourceString, sourceName, lineno);
4. IRFactory将ast语法树转换成为内部表现形式
ast语法树转换成为IR内部表现形式代码:
//具体见Context.compileImpl()方法; IRFactory irf = new IRFactory(compilerEnv, compilationErrorReporter); ScriptNode tree = irf.transformTree(ast);
主要转换核心代码在irf.transformTree(ast);:
switch (node.getType()) { case Token.SCRIPT: return transformScript((ScriptNode)node); case Token.NAME: return transformName((Name)node); case Token.NUMBER: return transformNumber((NumberLiteral)node); ... ... }
最终 转换后的结果存放在Decompiler的sourceBuffer数组:
5. 编译生成byteCode虚拟字节码
主要生成byteCode字节码:
//具体见Context.compileImpl()方法; Object bytecode = compiler.compile(compilerEnv,tree, tree.getEncodedSource(),returnFunction);
转换后的虚拟字节码:
MaxStack = 2 [0] LINE : 1 [3] REG_STR_C0 [4] BINDNAME [5] ONE [6] REG_STR_C0 [7] SETNAME [8] POP [9] RETURN_RESULT注: 以上格式为 [pc计数器] 指令码
6. 解释器顺序执行byteCode指令
6.1 代码分析
6.1.1 Context的evaluateString()方法执行上述解析,编译为字节码后,通过script.exec()方法解释执行
Script script = compileString(source, sourceName, lineno,securityDomain); if (script != null) { return script.exec(this, scope); } else { return null; }script实例主要数据有:
itsMaxStack: 当前script最大栈深
itsICode: 存储虚拟指令的字节数组
itsStringTable: 变量表字符串数组,当前例子中 itStringTable[0] = "result"
6.1.2 解释器通过Interpreter.interpret()循环执行指令
private static Object interpretLoop(Context cx, CallFrame frame, Object throwable){ ... for... switch (op) { ... } }
6.2 栈桢分析:
接下来详细讲述Rhino如何循环执行上面的指令数组
初始化栈桢前:
初始化栈桢如下所示:
6.2.1 [0] LINE : 1
从指令节中取2个字节,并转为int(行码)
其处理代码:
case Icode_LINE : frame.pcSourceLineStart = frame.pc; if (frame.debuggerFrame != null) { int line = getIndex(iCode, frame.pc); frame.debuggerFrame.onLineChange(cx, line); } frame.pc += 2; continue Loop;当前栈桢示意图:
6.2.2 [3] REG_STR_C0
将变量表第0个数组(result变量名)保存到stringReg字符串中
其处理代码:
case Icode_REG_STR_C0: stringReg = strings[0]; continue Loop;栈桢示意图:
6.2.3 [4] BINDNAME
从scope作用域取出名为stringReg的Scriptable,压入栈顶stack[] 如果当前scope找不到,会到当前scope的prototype链上找,可见: ScriptRuntime.bind()方法;
其处理代码:
case Token.BINDNAME : stack[++stackTop] = ScriptRuntime.bind(cx, frame.scope, stringReg); continue Loop;
栈桢示意图:
6.2.4 [5] ONE
将DOUBLE_MARK标记压入栈顶,并将值 1 存入 sDbl数组中
6.2.5 [6] REG_STR_C0
同 6.2.2
6.2.6 [7] SETNAME
包含STRICT与非STRICT模式,弹出并取出栈顶对象,如果为DOUBLE_MARK,取出并转为数值,再从栈顶取一个对象,通过ScriptRuntime.setName()赋值给result.
6.2.7 [8] POP
从栈顶弹出一个对象
6.2.8 [9] RETURN_RESULT
无
作者: 阿钿
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android学习笔记(二九):嵌入浏览器
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- JavaScript演示排序算法
- 插入排序
- 冒泡排序