]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - bytecompiler/BytecodeGenerator.h
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / bytecompiler / BytecodeGenerator.h
index 194aabd6d4f94e3566eb472d0402f61416c8f141..3667198dad5466e20548747449b5fa7925cc6c8c 100644 (file)
 #include "LabelScope.h"
 #include "Interpreter.h"
 #include "RegisterID.h"
-#include "SegmentedVector.h"
 #include "SymbolTable.h"
 #include "Debugger.h"
 #include "Nodes.h"
+#include <wtf/FastAllocBase.h>
 #include <wtf/PassRefPtr.h>
+#include <wtf/SegmentedVector.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
@@ -60,7 +61,14 @@ namespace JSC {
         FinallyContext finallyContext;
     };
 
-    class BytecodeGenerator {
+    struct ForInContext {
+        RefPtr<RegisterID> expectedSubscriptRegister;
+        RefPtr<RegisterID> iterRegister;
+        RefPtr<RegisterID> indexRegister;
+        RefPtr<RegisterID> propertyRegister;
+    };
+
+    class BytecodeGenerator : public FastAllocBase {
     public:
         typedef DeclarationStacks::VarStack VarStack;
         typedef DeclarationStacks::FunctionStack FunctionStack;
@@ -81,6 +89,9 @@ namespace JSC {
         // such register exists. Registers returned by registerFor do not
         // require explicit reference counting.
         RegisterID* registerFor(const Identifier&);
+        
+        bool willResolveToArguments(const Identifier&);
+        RegisterID* uncheckedRegisterForArguments();
 
         // Behaves as registerFor does, but ignores dynamic scope as
         // dynamic scope should not interfere with const initialisation
@@ -95,7 +106,7 @@ namespace JSC {
         //
         // 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);
+        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; }
@@ -181,6 +192,19 @@ namespace JSC {
             return emitNode(0, n);
         }
 
+        void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
+        {
+            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)
+                emitThrowExpressionTooDeepException();
+            ++m_emitNodeDepth;
+            n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
+            --m_emitNodeDepth;
+        }
+
         void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset)
         { 
             divot -= m_codeBlock->sourceOffset();
@@ -240,9 +264,7 @@ namespace JSC {
         RegisterID* emitLoad(RegisterID* dst, bool);
         RegisterID* emitLoad(RegisterID* dst, double);
         RegisterID* emitLoad(RegisterID* dst, const Identifier&);
-        RegisterID* emitLoad(RegisterID* dst, JSValuePtr);
-        RegisterID* emitUnexpectedLoad(RegisterID* dst, bool);
-        RegisterID* emitUnexpectedLoad(RegisterID* dst, double);
+        RegisterID* emitLoad(RegisterID* dst, JSValue);
 
         RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
         RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
@@ -252,7 +274,7 @@ namespace JSC {
         RegisterID* emitNewObject(RegisterID* dst);
         RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision
 
-        RegisterID* emitNewFunction(RegisterID* dst, FuncDeclNode* func);
+        RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body);
         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp);
 
@@ -269,15 +291,17 @@ namespace JSC {
         RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
 
         RegisterID* emitResolve(RegisterID* dst, const Identifier& property);
-        RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValuePtr globalObject);
-        RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValuePtr globalObject);
+        RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject);
+        RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject);
 
         RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);
         RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
-        RegisterID* emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property);
+
+        void emitMethodCheck();
 
         RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
         RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
+        RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
         RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
         RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
         RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
@@ -288,28 +312,34 @@ namespace JSC {
 
         RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
         RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCount, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* args);
 
         RegisterID* emitReturn(RegisterID* src);
         RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
 
         RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
+        void emitToPrimitive(RegisterID* dst, RegisterID* src);
 
         PassRefPtr<Label> emitLabel(Label*);
         PassRefPtr<Label> emitJump(Label* target);
         PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target);
         PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target);
+        PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
+        PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
         PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth);
 
         PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*);
         void emitSubroutineReturn(RegisterID* retAddrSrc);
 
-        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); }
-        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target);
+        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
+        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
 
         RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
         void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); }
-        RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValuePtr message);
-        void emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value);
+        RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValue message);
+        void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value);
 
         RegisterID* emitPushScope(RegisterID* scope);
         void emitPopScope();
@@ -322,6 +352,17 @@ namespace JSC {
         void pushFinallyContext(Label* target, RegisterID* returnAddrDst);
         void popFinallyContext();
 
+        void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
+        {
+            ForInContext context = { expectedBase, iter, index, propertyRegister };
+            m_forInContextStack.append(context);
+        }
+
+        void popOptimisedForIn()
+        {
+            m_forInContextStack.removeLast();
+        }
+
         LabelScope* breakTarget(const Identifier&);
         LabelScope* continueTarget(const Identifier&);
 
@@ -340,17 +381,12 @@ namespace JSC {
         void emitOpcode(OpcodeID);
         void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
         void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
-        void rewindBinaryOp();
-        void rewindUnaryOp();
+        ALWAYS_INLINE void rewindBinaryOp();
+        ALWAYS_INLINE void rewindUnaryOp();
 
         PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
 
-        struct JSValueHashTraits : HashTraits<JSValueEncodedAsPointer*> {
-            static void constructDeletedValue(JSValueEncodedAsPointer*& slot) { slot = JSValuePtr::encode(jsImpossibleValue()); }
-            static bool isDeletedValue(JSValueEncodedAsPointer* value) { return value == JSValuePtr::encode(jsImpossibleValue()); }
-        };
-
-        typedef HashMap<JSValueEncodedAsPointer*, unsigned, PtrHash<JSValueEncodedAsPointer*>, JSValueHashTraits> JSValueMap;
+        typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap;
 
         struct IdentifierMapIndexHashTraits {
             typedef int TraitType;
@@ -362,9 +398,9 @@ namespace JSC {
         };
 
         typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
-        typedef HashMap<double, JSValuePtr> NumberMap;
+        typedef HashMap<double, JSValue> NumberMap;
         typedef HashMap<UString::Rep*, JSString*, IdentifierRepHash> IdentifierStringMap;
-
+        
         RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
         
         RegisterID* newRegister();
@@ -391,7 +427,7 @@ namespace JSC {
 
         RegisterID* addParameter(const Identifier&);
         
-        void allocateConstants(size_t);
+        void preserveLastVar();
 
         RegisterID& registerFor(int index)
         {
@@ -409,13 +445,20 @@ namespace JSC {
             return m_globals[-index - 1];
         }
 
-        unsigned addConstant(FuncDeclNode*);
-        unsigned addConstant(FuncExprNode*);
         unsigned addConstant(const Identifier&);
-        RegisterID* addConstant(JSValuePtr);
-        unsigned addUnexpectedConstant(JSValuePtr);
+        RegisterID* addConstantValue(JSValue);
         unsigned addRegExp(RegExp*);
 
+        PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body)
+        {
+            return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+        }
+
+        PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
+        {
+            return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+        }
+
         Vector<Instruction>& instructions() { return m_codeBlock->instructions(); }
         SymbolTable& symbolTable() { return *m_symbolTable; }
 
@@ -424,6 +467,8 @@ namespace JSC {
 
         RegisterID* emitThrowExpressionTooDeepException();
 
+        void createArgumentsIfNecessary();
+
         bool m_shouldEmitDebugHooks;
         bool m_shouldEmitProfileHooks;
 
@@ -433,17 +478,20 @@ namespace JSC {
         ScopeNode* m_scopeNode;
         CodeBlock* m_codeBlock;
 
+        // Some of these objects keep pointers to one another. They are arranged
+        // to ensure a sane destruction order that avoids references to freed memory.
         HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions;
         RegisterID m_ignoredResultRegister;
         RegisterID m_thisRegister;
         RegisterID m_argumentsRegister;
         int m_activationRegisterIndex;
-        SegmentedVector<RegisterID, 512> m_calleeRegisters;
-        SegmentedVector<RegisterID, 512> m_parameters;
-        SegmentedVector<RegisterID, 512> m_globals;
-        SegmentedVector<LabelScope, 256> m_labelScopes;
-        SegmentedVector<Label, 256> m_labels;
-        RefPtr<RegisterID> m_lastConstant;
+        SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
+        SegmentedVector<RegisterID, 32> m_calleeRegisters;
+        SegmentedVector<RegisterID, 32> m_parameters;
+        SegmentedVector<RegisterID, 32> m_globals;
+        SegmentedVector<Label, 32> m_labels;
+        SegmentedVector<LabelScope, 8> m_labelScopes;
+        RefPtr<RegisterID> m_lastVar;
         int m_finallyDepth;
         int m_dynamicScopeDepth;
         int m_baseScopeDepth;
@@ -451,10 +499,13 @@ namespace JSC {
 
         Vector<ControlFlowContext> m_scopeContextStack;
         Vector<SwitchInfo> m_switchContextStack;
+        Vector<ForInContext> m_forInContextStack;
 
         int m_nextGlobalIndex;
         int m_nextParameterIndex;
-        int m_nextConstantIndex;
+        int m_firstConstantIndex;
+        int m_nextConstantOffset;
+        unsigned m_globalConstantIndex;
 
         int m_globalVarStorageOffset;
 
@@ -473,9 +524,29 @@ namespace JSC {
         bool m_regeneratingForExceptionInfo;
         CodeBlock* m_codeBlockBeingRegeneratedFrom;
 
-        static const unsigned s_maxEmitNodeDepth = 10000;
+        static const unsigned s_maxEmitNodeDepth = 3000;
+
+        friend class IncreaseEmitNodeDepth;
     };
 
+    class IncreaseEmitNodeDepth {
+    public:
+        IncreaseEmitNodeDepth(BytecodeGenerator& generator, unsigned count = 1)
+            : m_generator(generator)
+            , m_count(count)
+        {
+            m_generator.m_emitNodeDepth += count;
+        }
+
+        ~IncreaseEmitNodeDepth()
+        {
+            m_generator.m_emitNodeDepth -= m_count;
+        }
+
+    private:
+        BytecodeGenerator& m_generator;
+        unsigned m_count;
+    };
 }
 
 #endif // BytecodeGenerator_h