⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bytecodegenerator.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1.  Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. * 2.  Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of *     its contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "BytecodeGenerator.h"#include "BatchedTransitionOptimizer.h"#include "JSFunction.h"#include "Interpreter.h"#include "UString.h"using namespace std;namespace JSC {/*    The layout of a register frame looks like this:    For    function f(x, y) {        var v1;        function g() { }        var v2;        return (x) * (y);    }    assuming (x) and (y) generated temporaries t1 and t2, you would have    ------------------------------------    |  x |  y |  g | v2 | v1 | t1 | t2 | <-- value held    ------------------------------------    | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index    ------------------------------------    | params->|<-locals      | temps->    Because temporary registers are allocated in a stack-like fashion, we    can reclaim them with a simple popping algorithm. The same goes for labels.    (We never reclaim parameter or local registers, because parameters and    locals are DontDelete.)    The register layout before a function call looks like this:    For    function f(x, y)    {    }    f(1);    >                        <------------------------------    <                        >  reserved: call frame  |  1 | <-- value held    >         >snip<         <------------------------------    <                        > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index    >                        <------------------------------    | params->|<-locals      | temps->    The call instruction fills in the "call frame" registers. It also pads    missing arguments at the end of the call:    >                        <-----------------------------------    <                        >  reserved: call frame  |  1 |  ? | <-- value held ("?" stands for "undefined")    >         >snip<         <-----------------------------------    <                        > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index    >                        <-----------------------------------    | params->|<-locals      | temps->    After filling in missing arguments, the call instruction sets up the new    stack frame to overlap the end of the old stack frame:                             |---------------------------------->                        <                             |  reserved: call frame  |  1 |  ? <                        > <-- value held ("?" stands for "undefined")                             |---------------------------------->         >snip<         <                             | -7 | -6 | -5 | -4 | -3 | -2 | -1 <                        > <-- register index                             |---------------------------------->                        <                             |                        | params->|<-locals       | temps->    That way, arguments are "copied" into the callee's stack frame for free.    If the caller supplies too many arguments, this trick doesn't work. The    extra arguments protrude into space reserved for locals and temporaries.    In that case, the call instruction makes a real copy of the call frame header,    along with just the arguments expected by the callee, leaving the original    call frame header and arguments behind. (The call instruction can't just discard    extra arguments, because the "arguments" object may access them later.)    This copying strategy ensures that all named values will be at the indices    expected by the callee.*/#ifndef NDEBUGstatic bool s_dumpsGeneratedCode = false;#endifvoid BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode){#ifndef NDEBUG    s_dumpsGeneratedCode = dumpsGeneratedCode;#else    UNUSED_PARAM(dumpsGeneratedCode);#endif}bool BytecodeGenerator::dumpsGeneratedCode(){#ifndef NDEBUG    return s_dumpsGeneratedCode;#else    return false;#endif}void BytecodeGenerator::generate(){    m_codeBlock->setThisRegister(m_thisRegister.index());    m_scopeNode->emitBytecode(*this);#ifndef NDEBUG    m_codeBlock->setInstructionCount(m_codeBlock->instructions().size());    if (s_dumpsGeneratedCode)        m_codeBlock->dump(m_scopeChain->globalObject()->globalExec());#endif    if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)        symbolTable().clear();            m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec()));#if !ENABLE(OPCODE_SAMPLING)    if (!m_regeneratingForExceptionInfo && (m_codeType == FunctionCode || m_codeType == EvalCode))        m_codeBlock->clearExceptionInfo();#endif    m_codeBlock->shrinkToFit();}bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0){    int index = m_calleeRegisters.size();    SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);    pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);    if (!result.second) {        r0 = &registerFor(result.first->second.getIndex());        return false;    }    ++m_codeBlock->m_numVars;    r0 = newRegister();    return true;}bool BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0){    int index = m_nextGlobalIndex;    SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);    pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);    if (!result.second)        index = result.first->second.getIndex();    else {        --m_nextGlobalIndex;        m_globals.append(index + m_globalVarStorageOffset);    }    r0 = &registerFor(index);    return result.second;}void BytecodeGenerator::allocateConstants(size_t count){    m_codeBlock->m_numConstants = count;    if (!count)        return;        m_nextConstantIndex = m_calleeRegisters.size();    for (size_t i = 0; i < count; ++i)        newRegister();    m_lastConstant = &m_calleeRegisters.last();}BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock)    : m_shouldEmitDebugHooks(!!debugger)    , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling())    , m_scopeChain(&scopeChain)    , m_symbolTable(symbolTable)    , m_scopeNode(programNode)    , m_codeBlock(codeBlock)    , m_thisRegister(RegisterFile::ProgramCodeThisRegister)    , m_finallyDepth(0)    , m_dynamicScopeDepth(0)    , m_baseScopeDepth(0)    , m_codeType(GlobalCode)    , m_nextGlobalIndex(-1)    , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())    , m_lastOpcodeID(op_end)    , m_emitNodeDepth(0)    , m_regeneratingForExceptionInfo(false)    , m_codeBlockBeingRegeneratedFrom(0){    if (m_shouldEmitDebugHooks)        m_codeBlock->setNeedsFullScopeChain(true);    emitOpcode(op_enter);    codeBlock->setGlobalData(m_globalData);    // FIXME: Move code that modifies the global object to Interpreter::execute.        m_codeBlock->m_numParameters = 1; // Allocate space for "this"    JSGlobalObject* globalObject = scopeChain.globalObject();    ExecState* exec = globalObject->globalExec();    RegisterFile* registerFile = &exec->globalData().interpreter->registerFile();        // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.    m_globalVarStorageOffset = -RegisterFile::CallFrameHeaderSize - m_codeBlock->m_numParameters - registerFile->size();    // Add previously defined symbols to bookkeeping.    m_globals.grow(symbolTable->size());    SymbolTable::iterator end = symbolTable->end();    for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)        registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset);            BatchedTransitionOptimizer optimizer(globalObject);    const VarStack& varStack = programNode->varStack();    const FunctionStack& functionStack = programNode->functionStack();    bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();    if (canOptimizeNewGlobals) {        // Shift new symbols so they get stored prior to existing symbols.        m_nextGlobalIndex -= symbolTable->size();        for (size_t i = 0; i < functionStack.size(); ++i) {            FuncDeclNode* funcDecl = functionStack[i].get();            globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.            emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);        }        Vector<RegisterID*, 32> newVars;        for (size_t i = 0; i < varStack.size(); ++i)            if (!globalObject->hasProperty(exec, varStack[i].first))                newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));        allocateConstants(programNode->neededConstants());        for (size_t i = 0; i < newVars.size(); ++i)            emitLoad(newVars[i], jsUndefined());    } else {        for (size_t i = 0; i < functionStack.size(); ++i) {            FuncDeclNode* funcDecl = functionStack[i].get();            globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);        }        for (size_t i = 0; i < varStack.size(); ++i) {            if (globalObject->hasProperty(exec, varStack[i].first))                continue;            int attributes = DontDelete;            if (varStack[i].second & DeclarationStacks::IsConstant)                attributes |= ReadOnly;            globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);        }        allocateConstants(programNode->neededConstants());    }}BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)    : m_shouldEmitDebugHooks(!!debugger)    , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling())    , m_scopeChain(&scopeChain)    , m_symbolTable(symbolTable)    , m_scopeNode(functionBody)    , m_codeBlock(codeBlock)    , m_finallyDepth(0)    , m_dynamicScopeDepth(0)    , m_baseScopeDepth(0)    , m_codeType(FunctionCode)    , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())    , m_lastOpcodeID(op_end)    , m_emitNodeDepth(0)    , m_regeneratingForExceptionInfo(false)    , m_codeBlockBeingRegeneratedFrom(0){    if (m_shouldEmitDebugHooks)        m_codeBlock->setNeedsFullScopeChain(true);    codeBlock->setGlobalData(m_globalData);    bool usesArguments = functionBody->usesArguments();    codeBlock->setUsesArguments(usesArguments);    if (usesArguments) {        m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);        addVar(propertyNames().arguments, false);    }    if (m_codeBlock->needsFullScopeChain()) {        ++m_codeBlock->m_numVars;        m_activationRegisterIndex = newRegister()->index();        emitOpcode(op_enter_with_activation);        instructions().append(m_activationRegisterIndex);    } else        emitOpcode(op_enter);    if (usesArguments)        emitOpcode(op_create_arguments);    const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();    for (size_t i = 0; i < functionStack.size(); ++i) {        FuncDeclNode* funcDecl = functionStack[i].get();        const Identifier& ident = funcDecl->m_ident;        m_functions.add(ident.ustring().rep());        emitNewFunction(addVar(ident, false), funcDecl);    }    const DeclarationStacks::VarStack& varStack = functionBody->varStack();    for (size_t i = 0; i < varStack.size(); ++i)        addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);    const Identifier* parameters = functionBody->parameters();    size_t parameterCount = functionBody->parameterCount();    m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;    m_parameters.grow(1 + parameterCount); // reserve space for "this"    // Add "this" as a parameter    m_thisRegister.setIndex(m_nextParameterIndex);    ++m_nextParameterIndex;    ++m_codeBlock->m_numParameters;    if (functionBody->usesThis() || m_shouldEmitDebugHooks) {        emitOpcode(op_convert_this);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -