Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304884
  • 博文数量: 174
  • 博客积分: 3061
  • 博客等级: 中校
  • 技术积分: 1740
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-04 22:43
文章分类

全部博文(174)

文章存档

2011年(54)

2010年(14)

2009年(30)

2008年(26)

2007年(27)

2006年(23)

我的朋友

分类: WINDOWS

2011-08-11 17:29:58

ecma 262 js标准文档。


js的标准要求,15节,即在一个js程序能够运行前,需要首先初始化一些内部对象。
"There are certain built-in objects available whenever an ECMAScript program begins execution. One, the global object, is in the scope chain of the executing program. Others are accessible as initial properties of the global object."


就是说有一个特殊的globalobject需要被首先初始化,它是程序的执行链; 


1.  globalexec
  ExecState* JSGlobalObject::globalExec()
{
    return CallFrame::create(d()->globalCallFrame + RegisterFile::CallFrameHeaderSize);
}

JSGlobalObject 存在一个寄存器数组,这个数组构成了全局执行环境,就是
 Register globalCallFrame[RegisterFile::CallFrameHeaderSize];


enum CallFrameHeaderEntry {
            CallFrameHeaderSize = 8,

            CodeBlock = -8,
            ScopeChain = -7,
            CallerFrame = -6,
            ReturnPC = -5, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
            ReturnValueRegister = -4,
            ArgumentCount = -3,
            Callee = -2,
            OptionalCalleeArguments = -1
        };

这个globalexec 是按照数组的倒序进行的,即负值。

 class ExecState : private Register 
...


注意,这儿的Register 含有一个8byte的
union {
            int32_t i;
            EncodedJSValue value;

            JSActivation* activation;
            CallFrame* callFrame;
            CodeBlock* codeBlock;
            JSObject* object;
            JSPropertyNameIterator* propertyNameIterator;
            ScopeChainNode* scopeChain;
            Instruction* vPC;
        } u;

而ExecState 则是一个空类,它没有成员只有方法,所以...

ALWAYS_INLINE void ExecState::init(CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain,
            CallFrame* callerFrame, int returnValueRegister, int argc, JSObject* callee)
        {
            setCodeBlock(codeBlock);
            setScopeChain(scopeChain);
            setCallerFrame(callerFrame);
            static_cast(this)[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
            static_cast(this)[RegisterFile::ReturnValueRegister] = Register::withInt(returnValueRegister);
            setArgumentCount(argc); // original argument count (for the sake of the "arguments" object)
            setCallee(callee);
            setCalleeArguments(JSValue());
        }


实际上就是修改了这个Register 数组的各个成员。

init实际上就是初始化了 codeblock,scopechain,callerframe,returnpc,returnvalueregister,argumentcount,callee,calleearguments,共计8个。



2. qscriptengine 这个类相当于是qt实现的对javascriptcore的包装。它能够提供类型的互相转化,执行js,gc等。


这个结构关系图大致描述了qt包装的scriptengine 以及qscriptvalue , jsvalue 之间的互相转换以及访问关系,对了还有globalobject/globaldata 这个体系。

void JSGlobalObject::reset(JSValue prototype)  这个方法内初始化了很多js规定的内置类型的属性,比如看下图:



  void JSObject::putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }

这个方法维护了内置的或者以后用户设置近来的属性列表。
FunctionPrototype
ObjectPrototype
ArrayPrototype
StringPrototype
BooleanPrototype
NumberPrototype
DatePrototype
RegExpPrototype
ErrorPrototype


  void JSGlobalObject::reset(JSValue prototype)
这个方法就是重点。

如第一张图,globalobject对象通过globalobjectdata对象的一些prototype成员完成了function,object,string,bool等内置对象的原型装备,然后初始化了一些全局函数,比如:

putDirectFunctionWithoutTransition(Identifier(exec, "Object"), objectConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Function"), functionConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Array"), arrayConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Boolean"), booleanConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "String"), stringConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Number"), numberConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Date"), dateConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "RegExp"), d()->regExpConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "Error"), d()->errorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "EvalError"), d()->evalErrorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "RangeError"), d()->rangeErrorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "TypeError"), d()->typeErrorConstructor, DontEnum);
    putDirectFunctionWithoutTransition(Identifier(exec, "URIError"), d()->URIErrorConstructor, DontEnum);

    // Set global values.
    GlobalPropertyInfo staticGlobals[] = {
        GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete),
        GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete),
        GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete),
        GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete),
        GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete)
    };

    addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));

    // Set global functions.

    d()->evalFunction = new (exec) GlobalEvalFunction(exec, GlobalEvalFunction::createStructure(d()->functionPrototype), 1, exec->propertyNames().eval, globalFuncEval, this);
    putDirectFunctionWithoutTransition(exec, d()->evalFunction, DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum);
    putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum);






3. js代码的预处理以及执行

这块内容我没有继续理解,感觉有困难。

关闭jit之后,对于js的内部理解似乎又可以进行了,关闭jit 可http://blogold.chinaunix.net/u/18544/showart_2622370.html 


我们那一段简单代码来验证下

button.text = qsTr('Hello World!');
button.styleSheet = 'font-style: italic';
button.show();


qtwebkit 执行后,大致流程如下

1. QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
  将sourcecode交给执行引擎进行执行

2. EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode)
  编译脚本

   这个过程讲起来其实有点复杂,需要一定的编译器基础,lex,yacc的知识。

   然后用BytecodeGenerator::generate() 来产生字节码,这些字节码之后将交给引擎进行解释执行,注意由于关闭了jit所以这儿看到的是解释执行。

3. Interpreter::execute
   由解释器开始执行。 解释器执行的时候是有点类似于8031,8051那样的按照opcode执行的,js的opcode大致有这些。

     opcode 后面的数字实际上是指令的长度。

     #define FOR_EACH_OPCODE_ID(macro) \
        macro(op_enter, 1) \
        macro(op_enter_with_activation, 2) \
        macro(op_init_arguments, 1) \
        macro(op_create_arguments, 1) \
        macro(op_convert_this, 2) \
        \
        macro(op_new_object, 2) \
        macro(op_new_array, 4) \
        macro(op_new_regexp, 3) \
        macro(op_mov, 3) \
        \
        macro(op_not, 3) \
        macro(op_eq, 4) \
        macro(op_eq_null, 3) \
        macro(op_neq, 4) \
        macro(op_neq_null, 3) \
        macro(op_stricteq, 4) \
        macro(op_nstricteq, 4) \
        macro(op_less, 4) \
        macro(op_lesseq, 4) \
        \
        macro(op_pre_inc, 2) \
        macro(op_pre_dec, 2) \
        macro(op_post_inc, 3) \
        macro(op_post_dec, 3) \
        macro(op_to_jsnumber, 3) \
        macro(op_negate, 3) \
        macro(op_add, 5) \
        macro(op_mul, 5) \
        macro(op_div, 5) \
        macro(op_mod, 4) \
        macro(op_sub, 5) \
        \
        macro(op_lshift, 4) \
        macro(op_rshift, 4) \
        macro(op_urshift, 4) \
        macro(op_bitand, 5) \
        macro(op_bitxor, 5) \
        macro(op_bitor, 5) \
        macro(op_bitnot, 3) \
        \
        macro(op_instanceof, 5) \
        macro(op_typeof, 3) \
        macro(op_is_undefined, 3) \
        macro(op_is_boolean, 3) \
        macro(op_is_number, 3) \
        macro(op_is_string, 3) \
        macro(op_is_object, 3) \
        macro(op_is_function, 3) \
        macro(op_in, 4) \
        \
        macro(op_resolve, 3) \
        macro(op_resolve_skip, 4) \
        macro(op_resolve_global, 6) \
        macro(op_get_scoped_var, 4) \
        macro(op_put_scoped_var, 4) \
        macro(op_get_global_var, 4) \
        macro(op_put_global_var, 4) \
        macro(op_resolve_base, 3) \
        macro(op_resolve_with_base, 4) \
        macro(op_get_by_id, 8) \
        macro(op_get_by_id_self, 8) \
        macro(op_get_by_id_self_list, 8) \
        macro(op_get_by_id_proto, 8) \
        macro(op_get_by_id_proto_list, 8) \
        macro(op_get_by_id_chain, 8) \
        macro(op_get_by_id_generic, 8) \
        macro(op_get_array_length, 8) \
        macro(op_get_string_length, 8) \
        macro(op_put_by_id, 8) \
        macro(op_put_by_id_transition, 8) \
        macro(op_put_by_id_replace, 8) \
        macro(op_put_by_id_generic, 8) \
        macro(op_del_by_id, 4) \
        macro(op_get_by_val, 4) \
        macro(op_get_by_pname, 7) \
        macro(op_put_by_val, 4) \
        macro(op_del_by_val, 4) \
        macro(op_put_by_index, 4) \
        macro(op_put_getter, 4) \
        macro(op_put_setter, 4) \
        \
        macro(op_jmp, 2) \
        macro(op_jtrue, 3) \
        macro(op_jfalse, 3) \
        macro(op_jeq_null, 3) \
        macro(op_jneq_null, 3) \
        macro(op_jneq_ptr, 4) \
        macro(op_jnless, 4) \
        macro(op_jnlesseq, 4) \
        macro(op_jless, 4) \
        macro(op_jmp_scopes, 3) \
        macro(op_loop, 2) \
        macro(op_loop_if_true, 3) \
        macro(op_loop_if_false, 3) \
        macro(op_loop_if_less, 4) \
        macro(op_loop_if_lesseq, 4) \
        macro(op_switch_imm, 4) \
        macro(op_switch_char, 4) \
        macro(op_switch_string, 4) \
        \
        macro(op_new_func, 3) \
        macro(op_new_func_exp, 3) \
        macro(op_call, 5) \
        macro(op_call_eval, 5) \
        macro(op_call_varargs, 5) \
        macro(op_load_varargs, 3) \
        macro(op_tear_off_activation, 2) \
        macro(op_tear_off_arguments, 1) \
        macro(op_ret, 2) \
        macro(op_method_check, 1) \
        \
        macro(op_construct, 7) \
        macro(op_construct_verify, 3) \
        macro(op_strcat, 4) \
        macro(op_to_primitive, 3) \
        \
        macro(op_get_pnames, 6) \
        macro(op_next_pname, 7) \
        \
        macro(op_push_scope, 2) \
        macro(op_pop_scope, 1) \
        macro(op_push_new_scope, 4) \
        \
        macro(op_catch, 2) \
        macro(op_throw, 2) \
        macro(op_new_error, 4) \
        \
        macro(op_jsr, 3) \
        macro(op_sret, 2) \
        \
        macro(op_debug, 4) \
        macro(op_profile_will_call, 2) \
        macro(op_profile_did_call, 2) \
        \
        macro(op_end, 2) // end must be the last opcode in the list

由于js的字节码生成的一些要求,所以第一个指令是op_enter , 这些本文不做分析,下面主要是看看名称解析这个过程。 比如第一行代码 button.text = ...  这个指令中button是如何解析的,而button是我们用qt注入的一个对象。


js 的具体执行体现为一个op_resolve 指令, 表示它要解释一个名称。

我们来看下面的代码,以及注释。。。


NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
    int dst = vPC[1].u.operand;
    int property = vPC[2].u.operand;

    // 这个过程就是很多js书籍中所说的,对于一个名称的查找js是从当前的frame,也就是自己所在的那个     // frame开始向上查找的
    ScopeChainNode* scopeChain = callFrame->scopeChain();
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);

    CodeBlock* codeBlock = callFrame->codeBlock();
    Identifier& ident = codeBlock->identifier(property);
    do {
        JSObject* o = *iter;
        PropertySlot slot(o);
        // 在每个scopechainnode上查找是否存在这个属性
        if (o->getPropertySlot(callFrame, ident, slot)) {
            JSValue result = slot.getValue(callFrame, ident);
            exceptionValue = callFrame->globalData().exception;
            if (exceptionValue)
                return false;
        // 将得到的jsvalue 存储到dst,相当于一次赋值从左
            callFrame->r(dst) = JSValue(result);
            return true;
        }
    } while (++iter != end);
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
    return false;
}


ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    JSObject* object = this;
    while (true) {
        // 先看看自己是否存在这个属性
        if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
            return true;
        // 再看看自己的原型对象,相当于父对象
        JSValue prototype = object->prototype();
        if (!prototype.isObject())
            return false;
        object = asObject(prototype);
    }
}


这个resovle的细节如果要理解还需要自己阅读,不过这样一个qt的button 就从一个jsvalue 最后到了 js执行中的dst 变量。



下面一个opcode 是op_putbyid, 它解释了 button.text 这个.text 的执行

 DEFINE_OPCODE(op_put_by_id) {
        /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)

           Generic property access: Sets the property named by identifier
           property, belonging to register base, to register value.

           Unlike many opcodes, this one does not write any output to
           the register file.
        */

        int base = vPC[1].u.operand;
        int property = vPC[2].u.operand;
        int value = vPC[3].u.operand;

        CodeBlock* codeBlock = callFrame->codeBlock();
        JSValue baseValue = callFrame->r(base).jsValue();
        Identifier& ident = codeBlock->identifier(property);
        PutPropertySlot slot;
        // 下面这个代码最终将能够解释vsd所画的那张从一个jsvalue-->qscriptobject-->qobjectdelete 最后用到qt自由的metaobject,细节过程还是比较复杂的,我也不是且安全理解,不过过程比较清晰了
        baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
        CHECK_FOR_EXCEPTION();

        tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);

        vPC += OPCODE_LENGTH(op_put_by_id);
        NEXT_INSTRUCTION();
    }

       callstack可以看看下面这个。

    


      对实例的js代码反复执行,会看到运用到最多的opcode就是
op_enter  

op_move , 即赋值
op_resolve* 解释名称,这个非常常用
           qsTr , op_resolve_with_base
           button, op_resolve
op_putbyid , 根据某个属性名称赋值
           .text , op_putbyid
           .stylesheet, op_putbyid
op_getbyid , 比如获取show这个属性/方法名称
op_methodcheck , 
           .show()
op_call , 函数调用

op_end
阅读(1362) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~