/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * * 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 "SymbolTable.h" #include "Debugger.h" #include "Nodes.h" #include #include #include namespace JSC { class Identifier; class ScopeChainNode; class CallArguments { public: CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode); RegisterID* thisRegister() { return m_argv[0].get(); } RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } unsigned callFrame() { return thisRegister()->index() + count() + RegisterFile::CallFrameHeaderSize; } unsigned count() { return m_argv.size(); } RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } ArgumentsNode* argumentsNode() { return m_argumentsNode; } private: RefPtr m_profileHookRegister; ArgumentsNode* m_argumentsNode; Vector, 16> m_argv; }; struct FinallyContext { Label* finallyAddr; RegisterID* retAddrDst; }; struct ControlFlowContext { bool isFinallyBlock; FinallyContext finallyContext; }; struct ForInContext { RefPtr expectedSubscriptRegister; RefPtr iterRegister; RefPtr indexRegister; RefPtr propertyRegister; }; class BytecodeGenerator { WTF_MAKE_FAST_ALLOCATED; public: typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; static void setDumpsGeneratedCode(bool dumpsGeneratedCode); static bool dumpsGeneratedCode(); BytecodeGenerator(ProgramNode*, ScopeChainNode*, SymbolTable*, ProgramCodeBlock*); BytecodeGenerator(FunctionBodyNode*, ScopeChainNode*, SymbolTable*, CodeBlock*); BytecodeGenerator(EvalNode*, ScopeChainNode*, SymbolTable*, EvalCodeBlock*); JSGlobalData* globalData() const { return m_globalData; } const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } bool isConstructor() { return m_codeBlock->m_isConstructor; } JSObject* 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&); // Returns the agument number if this is an argument, or 0 if not. int argumentNumberFor(const Identifier&); void setIsNumericCompareFunction(bool isNumericCompareFunction); bool willResolveToArguments(const Identifier&); RegisterID* uncheckedRegisterForArguments(); // 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. bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, 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(); } // Returns the place to write the final output of an operation. RegisterID* finalDestinationOrIgnored(RegisterID* originalDst, RegisterID* tempDst = 0) { if (originalDst) 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 newLabelScope(LabelScope::Type, const Identifier* = 0); PassRefPtr