📄 bytecodegenerator.h
字号:
/* * 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. */#ifndef BytecodeGenerator_h#define BytecodeGenerator_h#include "CodeBlock.h"#include "HashTraits.h"#include "Instruction.h"#include "Label.h"#include "LabelScope.h"#include "Interpreter.h"#include "RegisterID.h"#include "SegmentedVector.h"#include "SymbolTable.h"#include "Debugger.h"#include "Nodes.h"#include <wtf/PassRefPtr.h>#include <wtf/Vector.h>namespace JSC { class Identifier; class ScopeChain; class ScopeNode; struct FinallyContext { Label* finallyAddr; RegisterID* retAddrDst; }; struct ControlFlowContext { bool isFinallyBlock; FinallyContext finallyContext; }; class BytecodeGenerator { public: typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; static void setDumpsGeneratedCode(bool dumpsGeneratedCode); static bool dumpsGeneratedCode(); BytecodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, ProgramCodeBlock*); BytecodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*); BytecodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*); JSGlobalData* globalData() const { return m_globalData; } const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } void generate(); // Returns the register corresponding to a local variable, or 0 if no // such register exists. Registers returned by registerFor do not // require explicit reference counting. RegisterID* registerFor(const Identifier&); // Behaves as registerFor does, but ignores dynamic scope as // dynamic scope should not interfere with const initialisation RegisterID* constRegisterFor(const Identifier&); // Searches the scope chain in an attempt to statically locate the requested // property. Returns false if for any reason the property cannot be safely // optimised at all. Otherwise it will return the index and depth of the // VariableObject that defines the property. If the property cannot be found // statically, depth will contain the depth of the scope chain where dynamic // lookup must begin. // // NB: depth does _not_ include the local scope. eg. a depth of 0 refers // to the scope containing this codeblock. bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, JSObject*& globalObject); // Returns the register storing "this" RegisterID* thisRegister() { return &m_thisRegister; } bool isLocal(const Identifier&); bool isLocalConstant(const Identifier&); // Returns the next available temporary register. Registers returned by // newTemporary require a modified form of reference counting: any // register with a refcount of 0 is considered "available", meaning that // the next instruction may overwrite it. RegisterID* newTemporary(); RegisterID* highestUsedRegister(); // The same as newTemporary(), but this function returns "suggestion" if // "suggestion" is a temporary. This function is helpful in situations // where you've put "suggestion" in a RefPtr, but you'd like to allow // the next instruction to overwrite it anyway. RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } // Functions for handling of dst register RegisterID* ignoredResult() { return &m_ignoredResultRegister; } // Returns a place to write intermediate values of an operation // which reuses dst if it is safe to do so. RegisterID* tempDestination(RegisterID* dst) { return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); } // Returns the place to write the final output of an operation. RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) { if (originalDst && originalDst != ignoredResult()) return originalDst; ASSERT(tempDst != ignoredResult()); if (tempDst && tempDst->isTemporary()) return tempDst; return newTemporary(); } RegisterID* destinationForAssignResult(RegisterID* dst) { if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) return dst->isTemporary() ? dst : newTemporary(); return 0; } // Moves src to dst if dst is not null and is different from src, otherwise just returns src. RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) { return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; } PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0); PassRefPtr<Label> newLabel(); // The emitNode functions are just syntactic sugar for calling // Node::emitCode. These functions accept a 0 for the register, // meaning that the node should allocate a register, or ignoredResult(), // meaning that the node need not put the result in a register. // Other emit functions do not accept 0 or ignoredResult(). RegisterID* emitNode(RegisterID* dst, Node* n) { // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) { LineInfo info = { instructions().size(), n->lineNo() }; m_codeBlock->addLineInfo(info); } if (m_emitNodeDepth >= s_maxEmitNodeDepth) return emitThrowExpressionTooDeepException(); ++m_emitNodeDepth; RegisterID* r = n->emitBytecode(*this, dst); --m_emitNodeDepth; return r; } RegisterID* emitNode(Node* n) { return emitNode(0, n); } void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) { divot -= m_codeBlock->sourceOffset(); if (divot > ExpressionRangeInfo::MaxDivot) { // Overflow has occurred, we can only give line number info for errors for this region divot = 0; startOffset = 0; endOffset = 0; } else if (startOffset > ExpressionRangeInfo::MaxOffset) { // If the start offset is out of bounds we clear both offsets // so we only get the divot marker. Error message will have to be reduced // to line and column number. startOffset = 0; endOffset = 0; } else if (endOffset > ExpressionRangeInfo::MaxOffset) { // The end offset is only used for additional context, and is much more likely // to overflow (eg. function call arguments) so we are willing to drop it without // dropping the rest of the range. endOffset = 0; } ExpressionRangeInfo info; info.instructionOffset = instructions().size(); info.divotPoint = divot; info.startOffset = startOffset; info.endOffset = endOffset; m_codeBlock->addExpressionInfo(info); } void emitGetByIdExceptionInfo(OpcodeID opcodeID) { // Only op_construct and op_instanceof need exception info for // a preceding op_get_by_id. ASSERT(opcodeID == op_construct || opcodeID == op_instanceof); GetByIdExceptionInfo info; info.bytecodeOffset = instructions().size(); info.isOpConstruct = (opcodeID == op_construct); m_codeBlock->addGetByIdExceptionInfo(info); } ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) { return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; } ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) { if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { PassRefPtr<RegisterID> dst = newTemporary(); emitNode(dst.get(), n); return dst; } return PassRefPtr<RegisterID>(emitNode(n)); } RegisterID* emitLoad(RegisterID* dst, bool); RegisterID* emitLoad(RegisterID* dst, double);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -