]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Executable.h
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / runtime / Executable.h
index dec841a0ef4b28cf1ab7ae55544eb3421748997d..e795fbfc3123e3f72b25f7aa320832b5d2a22520 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #ifndef Executable_h
 #define Executable_h
 
+#include "CallData.h"
 #include "JSFunction.h"
 #include "Interpreter.h"
 #include "Nodes.h"
 #include "SamplingTool.h"
+#include <wtf/PassOwnPtr.h>
 
 namespace JSC {
 
     class CodeBlock;
     class Debugger;
     class EvalCodeBlock;
+    class FunctionCodeBlock;
     class ProgramCodeBlock;
     class ScopeChainNode;
 
     struct ExceptionInfo;
 
-    class ExecutableBase : public RefCounted<ExecutableBase> {
+    class ExecutableBase : public JSCell {
         friend class JIT;
 
     protected:
@@ -49,67 +52,124 @@ namespace JSC {
         static const int NUM_PARAMETERS_NOT_COMPILED = -1;
     
     public:
-        ExecutableBase(int numParameters)
-            : m_numParameters(numParameters)
+        ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
+            : JSCell(globalData, structure)
+            , m_numParametersForCall(numParameters)
+            , m_numParametersForConstruct(numParameters)
         {
+#if ENABLE(JIT)
+            Weak<ExecutableBase> finalizer(globalData, this, executableFinalizer());
+            finalizer.leakHandle();
+#endif
         }
 
-        virtual ~ExecutableBase() {}
+        bool isHostFunction() const
+        {
+            ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+            return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
+        }
 
-        bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
+        static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); }
+        
+        static const ClassInfo s_info;
 
     protected:
-        int m_numParameters;
+        static const unsigned StructureFlags = 0;
+        int m_numParametersForCall;
+        int m_numParametersForConstruct;
 
 #if ENABLE(JIT)
     public:
-        JITCode& generatedJITCode()
+        JITCode& generatedJITCodeForCall()
         {
-            ASSERT(m_jitCode);
-            return m_jitCode;
+            ASSERT(m_jitCodeForCall);
+            return m_jitCodeForCall;
         }
 
-        ExecutablePool* getExecutablePool()
+        JITCode& generatedJITCodeForConstruct()
         {
-            return m_jitCode.getExecutablePool();
+            ASSERT(m_jitCodeForConstruct);
+            return m_jitCodeForConstruct;
+        }
+
+        void clearExecutableCode()
+        {
+            m_jitCodeForCall.clear();
+            m_jitCodeForConstruct.clear();
         }
 
     protected:
-        JITCode m_jitCode;
+        JITCode m_jitCodeForCall;
+        JITCode m_jitCodeForConstruct;
+        MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+        MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
+        
+    private:
+        static WeakHandleOwner* executableFinalizer();
 #endif
     };
 
-#if ENABLE(JIT)
     class NativeExecutable : public ExecutableBase {
+        friend class JIT;
     public:
-        NativeExecutable(JITCode thunk)
-            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+#if ENABLE(JIT)
+        static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor)
         {
-            m_jitCode = thunk;
+            if (!callThunk)
+                return new (&globalData) NativeExecutable(globalData, JITCode(), function, JITCode(), constructor);
+            return new (&globalData) NativeExecutable(globalData, JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor);
         }
+#else
+        static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+        {
+            return new (&globalData) NativeExecutable(globalData, function, constructor);
+        }
+#endif
 
         ~NativeExecutable();
-    };
-#endif
 
-    class VPtrHackExecutable : public ExecutableBase {
-    public:
-        VPtrHackExecutable()
-            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+        NativeFunction function() { return m_function; }
+
+        static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(LeafType, StructureFlags), AnonymousSlotCount, &s_info); }
+        
+        static const ClassInfo s_info;
+    
+    private:
+#if ENABLE(JIT)
+        NativeExecutable(JSGlobalData& globalData, JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor)
+            : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+            , m_function(function)
+            , m_constructor(constructor)
+        {
+            m_jitCodeForCall = callThunk;
+            m_jitCodeForConstruct = constructThunk;
+            m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+            m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
+        }
+#else
+        NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+            : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+            , m_function(function)
+            , m_constructor(constructor)
         {
         }
+#endif
 
-        ~VPtrHackExecutable();
+        NativeFunction m_function;
+        // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
+        // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
+        NativeFunction m_constructor;
     };
 
     class ScriptExecutable : public ExecutableBase {
     public:
-        ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
-            : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+        ScriptExecutable(Structure* structure, JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext)
+            : ExecutableBase(*globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
 #if ENABLE(CODEBLOCK_SAMPLING)
+            relaxAdoptionRequirement();
             if (SamplingTool* sampler = globalData->interpreter->sampler())
                 sampler->notifyOfScope(this);
 #else
@@ -117,12 +177,13 @@ namespace JSC {
 #endif
         }
 
-        ScriptExecutable(ExecState* exec, const SourceCode& source)
-            : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+        ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
+            : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
 #if ENABLE(CODEBLOCK_SAMPLING)
+            relaxAdoptionRequirement();
             if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
                 sampler->notifyOfScope(this);
 #else
@@ -138,20 +199,24 @@ namespace JSC {
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
-        bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
-
-        virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
+        bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+        bool isStrictMode() const { return m_features & StrictModeFeature; }
 
+        virtual void unlinkCalls() = 0;
+        
+        static const ClassInfo s_info;
     protected:
-        void recordParse(CodeFeatures features, int firstLine, int lastLine)
+        void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
         {
             m_features = features;
+            m_hasCapturedVariables = hasCapturedVariables;
             m_firstLine = firstLine;
             m_lastLine = lastLine;
         }
 
         SourceCode m_source;
         CodeFeatures m_features;
+        bool m_hasCapturedVariables;
         int m_firstLine;
         int m_lastLine;
     };
@@ -161,182 +226,219 @@ namespace JSC {
 
         ~EvalExecutable();
 
-        EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
         {
-            if (!m_evalCodeBlock) {
-                JSObject* error = compile(exec, scopeChainNode);
-                ASSERT_UNUSED(!error, error);
-            }
-            return *m_evalCodeBlock;
+            ASSERT(exec->globalData().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_evalCodeBlock)
+                error = compileInternal(exec, scopeChainNode);
+            ASSERT(!error == !!m_evalCodeBlock);
+            return error;
         }
 
-        JSObject* compile(ExecState*, ScopeChainNode*);
-
-        ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
-        static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
-
-    private:
-        EvalExecutable(ExecState* exec, const SourceCode& source)
-            : ScriptExecutable(exec, source)
-            , m_evalCodeBlock(0)
+        EvalCodeBlock& generatedBytecode()
         {
+            ASSERT(m_evalCodeBlock);
+            return *m_evalCodeBlock;
         }
-        EvalCodeBlock* m_evalCodeBlock;
+
+        static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); }
 
 #if ENABLE(JIT)
-    public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JITCode& generatedJITCode()
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            return generatedJITCodeForCall();
         }
-
-    private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
 #endif
+        static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+        {
+            return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
+        }
+        
+        static const ClassInfo s_info;
+    private:
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+        EvalExecutable(ExecState*, const SourceCode&, bool);
+
+        JSObject* compileInternal(ExecState*, ScopeChainNode*);
+        virtual void visitChildren(SlotVisitor&);
+        void unlinkCalls();
+
+        OwnPtr<EvalCodeBlock> m_evalCodeBlock;
     };
 
     class ProgramExecutable : public ScriptExecutable {
     public:
-        static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
+        static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
         {
-            return adoptRef(new ProgramExecutable(exec, source));
+            return new (exec) ProgramExecutable(exec, source);
         }
 
         ~ProgramExecutable();
 
-        ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+        {
+            ASSERT(exec->globalData().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_programCodeBlock)
+                error = compileInternal(exec, scopeChainNode);
+            ASSERT(!error == !!m_programCodeBlock);
+            return error;
+        }
+
+        ProgramCodeBlock& generatedBytecode()
         {
-            if (!m_programCodeBlock) {
-                JSObject* error = compile(exec, scopeChainNode);
-                ASSERT_UNUSED(!error, error);
-            }
+            ASSERT(m_programCodeBlock);
             return *m_programCodeBlock;
         }
 
         JSObject* checkSyntax(ExecState*);
-        JSObject* compile(ExecState*, ScopeChainNode*);
-
-        // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information.
-        ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
 
-    private:
-        ProgramExecutable(ExecState* exec, const SourceCode& source)
-            : ScriptExecutable(exec, source)
-            , m_programCodeBlock(0)
+#if ENABLE(JIT)
+        JITCode& generatedJITCode()
         {
+            return generatedJITCodeForCall();
         }
-        ProgramCodeBlock* m_programCodeBlock;
-
-#if ENABLE(JIT)
-    public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+#endif
+        
+        static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
         }
+        
+        static const ClassInfo s_info;
 
     private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+        ProgramExecutable(ExecState*, const SourceCode&);
+
+        JSObject* compileInternal(ExecState*, ScopeChainNode*);
+        virtual void visitChildren(SlotVisitor&);
+        void unlinkCalls();
+
+        OwnPtr<ProgramCodeBlock> m_programCodeBlock;
     };
 
     class FunctionExecutable : public ScriptExecutable {
         friend class JIT;
     public:
-        static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
         {
-            return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
         }
 
-        static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
         {
-            return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
         }
 
-        ~FunctionExecutable();
-
         JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
         {
             return new (exec) JSFunction(exec, this, scopeChain);
         }
-
-        CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) 
+        
+        // Returns either call or construct bytecode. This can be appropriate
+        // for answering questions that that don't vary between call and construct --
+        // for example, argumentsRegister().
+        FunctionCodeBlock& generatedBytecode()
         {
-            ASSERT(scopeChainNode);
-            if (!m_codeBlock)
-                compile(exec, scopeChainNode);
-            return *m_codeBlock;
+            if (m_codeBlockForCall)
+                return *m_codeBlockForCall;
+            ASSERT(m_codeBlockForConstruct);
+            return *m_codeBlockForConstruct;
         }
 
-        bool isGenerated() const
+        JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
         {
-            return m_codeBlock;
+            ASSERT(exec->globalData().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_codeBlockForCall)
+                error = compileForCallInternal(exec, scopeChainNode);
+            ASSERT(!error == !!m_codeBlockForCall);
+            return error;
         }
 
-        CodeBlock& generatedBytecode()
+        bool isGeneratedForCall() const
         {
-            ASSERT(m_codeBlock);
-            return *m_codeBlock;
+            return m_codeBlockForCall;
         }
 
-        const Identifier& name() { return m_name; }
-        size_t parameterCount() const { return m_parameters->size(); }
-        unsigned variableCount() const { return m_numVariables; }
-        UString paramString() const;
+        FunctionCodeBlock& generatedBytecodeForCall()
+        {
+            ASSERT(m_codeBlockForCall);
+            return *m_codeBlockForCall;
+        }
 
-        void recompile();
-        ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
-        void markAggregate(MarkStack& markStack);
-        static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
+        JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
+        {
+            ASSERT(exec->globalData().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_codeBlockForConstruct)
+                error = compileForConstructInternal(exec, scopeChainNode);
+            ASSERT(!error == !!m_codeBlockForConstruct);
+            return error;
+        }
 
-    private:
-        FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
-            : ScriptExecutable(globalData, source)
-            , m_numVariables(0)
-            , m_forceUsesArguments(forceUsesArguments)
-            , m_parameters(parameters)
-            , m_codeBlock(0)
-            , m_name(name)
+        bool isGeneratedForConstruct() const
         {
-            m_firstLine = firstLine;
-            m_lastLine = lastLine;
+            return m_codeBlockForConstruct;
         }
 
-        FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
-            : ScriptExecutable(exec, source)
-            , m_numVariables(0)
-            , m_forceUsesArguments(forceUsesArguments)
-            , m_parameters(parameters)
-            , m_codeBlock(0)
-            , m_name(name)
+        FunctionCodeBlock& generatedBytecodeForConstruct()
         {
-            m_firstLine = firstLine;
-            m_lastLine = lastLine;
+            ASSERT(m_codeBlockForConstruct);
+            return *m_codeBlockForConstruct;
         }
 
-        void compile(ExecState*, ScopeChainNode*);
+        const Identifier& name() { return m_name; }
+        size_t parameterCount() const { return m_parameters->size(); }
+        unsigned capturedVariableCount() const { return m_numCapturedVariables; }
+        UString paramString() const;
+        SharedSymbolTable* symbolTable() const { return m_symbolTable; }
+
+        void discardCode();
+        void visitChildren(SlotVisitor&);
+        static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
+        static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+        {
+            return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
+        }
+        
+        static const ClassInfo s_info;
 
-        unsigned m_numVariables : 31;
+    private:
+        FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
+        FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
+
+        JSObject* compileForCallInternal(ExecState*, ScopeChainNode*);
+        JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*);
+        
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+        unsigned m_numCapturedVariables : 31;
         bool m_forceUsesArguments : 1;
+        void unlinkCalls();
 
         RefPtr<FunctionParameters> m_parameters;
-        CodeBlock* m_codeBlock;
+        OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
+        OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
         Identifier m_name;
+        SharedSymbolTable* m_symbolTable;
 
 #if ENABLE(JIT)
     public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            ASSERT(m_jitCodeForCall);
+            ASSERT(m_jitCodeForCallWithArityCheck);
+            return m_jitCodeForCallWithArityCheck;
         }
 
-    private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
+        MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+        {
+            ASSERT(m_jitCodeForConstruct);
+            ASSERT(m_jitCodeForConstructWithArityCheck);
+            return m_jitCodeForConstructWithArityCheck;
+        }
 #endif
     };
 
@@ -352,6 +454,11 @@ namespace JSC {
         return m_executable->isHostFunction();
     }
 
+    inline NativeFunction JSFunction::nativeFunction()
+    {
+        ASSERT(isHostFunction());
+        return static_cast<NativeExecutable*>(m_executable.get())->function();
+    }
 }
 
 #endif