]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Executable.h
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / runtime / Executable.h
index f74abe93d4721b39d831e767dd385093cd481012..bf774e3e960333766ec23ff964c1a208cbac442e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013 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 "CodeBlockHash.h"
+#include "CodeSpecializationKind.h"
+#include "HandlerInfo.h"
 #include "JSFunction.h"
 #include "Interpreter.h"
-#include "Nodes.h"
+#include "JITCode.h"
+#include "JSGlobalObject.h"
+#include "LLIntCLoop.h"
 #include "SamplingTool.h"
+#include "SourceCode.h"
+#include "UnlinkedCodeBlock.h"
+#include <wtf/PassOwnPtr.h>
 
 namespace JSC {
 
     class CodeBlock;
     class Debugger;
     class EvalCodeBlock;
+    class FunctionCodeBlock;
+    class LLIntOffsetsExtractor;
     class ProgramCodeBlock;
-    class ScopeChainNode;
+    class JSScope;
+    
+    enum CompilationKind { FirstCompilation, OptimizingCompilation };
 
-    struct ExceptionInfo;
+    inline bool isCall(CodeSpecializationKind kind)
+    {
+        if (kind == CodeForCall)
+            return true;
+        ASSERT(kind == CodeForConstruct);
+        return false;
+    }
 
-    class ExecutableBase : public RefCounted<ExecutableBase> {
+    class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
+        friend class WTF::DoublyLinkedListNode<ExecutableBase>;
         friend class JIT;
 
     protected:
         static const int NUM_PARAMETERS_IS_HOST = 0;
         static const int NUM_PARAMETERS_NOT_COMPILED = -1;
-    
+
+        ExecutableBase(VM& vm, Structure* structure, int numParameters)
+            : JSCell(vm, structure)
+            , m_numParametersForCall(numParameters)
+            , m_numParametersForConstruct(numParameters)
+        {
+        }
+
+        void finishCreation(VM& vm)
+        {
+            Base::finishCreation(vm);
+        }
+
     public:
-        ExecutableBase(int numParameters)
-            : m_numParameters(numParameters)
+        typedef JSCell Base;
+
+#if ENABLE(JIT)
+        static const bool needsDestruction = true;
+        static const bool hasImmortalStructure = true;
+        static void destroy(JSCell*);
+#endif
+        
+        CodeBlockHash hashFor(CodeSpecializationKind) const;
+
+        bool isFunctionExecutable()
+        {
+            return structure()->typeInfo().type() == FunctionExecutableType;
+        }
+
+        bool isHostFunction() const
         {
+            ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+            return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
         }
 
-        virtual ~ExecutableBase() {}
+        static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
+        
+        void clearCode();
 
-        bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
+        static JS_EXPORTDATA 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()
+        static void clearCodeVirtual(ExecutableBase*);
+
+#if ENABLE(JIT)
+        JITCode& generatedJITCodeForCall()
+        {
+            ASSERT(m_jitCodeForCall);
+            return m_jitCodeForCall;
+        }
+
+        JITCode& generatedJITCodeForConstruct()
+        {
+            ASSERT(m_jitCodeForConstruct);
+            return m_jitCodeForConstruct;
+        }
+        
+        JITCode& generatedJITCodeFor(CodeSpecializationKind kind)
         {
-            ASSERT(m_jitCode);
-            return m_jitCode;
+            if (kind == CodeForCall)
+                return generatedJITCodeForCall();
+            ASSERT(kind == CodeForConstruct);
+            return generatedJITCodeForConstruct();
         }
 
-        ExecutablePool* getExecutablePool()
+        MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
         {
-            return m_jitCode.getExecutablePool();
+            ASSERT(m_jitCodeForCall);
+            ASSERT(m_jitCodeForCallWithArityCheck);
+            return m_jitCodeForCallWithArityCheck;
         }
 
+        MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+        {
+            ASSERT(m_jitCodeForConstruct);
+            ASSERT(m_jitCodeForConstructWithArityCheck);
+            return m_jitCodeForConstructWithArityCheck;
+        }
+        
+        MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return generatedJITCodeForCallWithArityCheck();
+            ASSERT(kind == CodeForConstruct);
+            return generatedJITCodeForConstructWithArityCheck();
+        }
+        
+        bool hasJITCodeForCall() const
+        {
+            return m_numParametersForCall >= 0;
+        }
+        
+        bool hasJITCodeForConstruct() const
+        {
+            return m_numParametersForConstruct >= 0;
+        }
+        
+        bool hasJITCodeFor(CodeSpecializationKind kind) const
+        {
+            if (kind == CodeForCall)
+                return hasJITCodeForCall();
+            ASSERT(kind == CodeForConstruct);
+            return hasJITCodeForConstruct();
+        }
+
+        static ptrdiff_t offsetOfJITCodeFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCall);
+            ASSERT(kind == CodeForConstruct);
+            return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstruct);
+        }
+        
+        static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
+            ASSERT(kind == CodeForConstruct);
+            return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+        }
+        
+        static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall);
+            ASSERT(kind == CodeForConstruct);
+            return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct);
+        }
+#endif // ENABLE(JIT)
+
+        // Intrinsics are only for calls, currently.
+        Intrinsic intrinsic() const;
+        
+        Intrinsic intrinsicFor(CodeSpecializationKind kind) const
+        {
+            if (isCall(kind))
+                return intrinsic();
+            return NoIntrinsic;
+        }
+        
+#if ENABLE(JIT) || ENABLE(LLINT_C_LOOP)
+        MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind)
+        {
+            #if ENABLE(JIT)
+            return generatedJITCodeFor(kind).addressForCall();
+            #else
+            return LLInt::CLoop::hostCodeEntryFor(kind);
+            #endif
+        }
+
+        MacroAssemblerCodePtr jsCodeEntryFor(CodeSpecializationKind kind)
+        {
+            #if ENABLE(JIT)
+            return generatedJITCodeFor(kind).addressForCall();
+            #else
+            return LLInt::CLoop::jsCodeEntryFor(kind);
+            #endif
+        }
+
+        MacroAssemblerCodePtr jsCodeWithArityCheckEntryFor(CodeSpecializationKind kind)
+        {
+            #if ENABLE(JIT)
+            return generatedJITCodeWithArityCheckFor(kind);
+            #else
+            return LLInt::CLoop::jsCodeEntryWithArityCheckFor(kind);
+            #endif
+        }
+
+        static void* catchRoutineFor(HandlerInfo* handler, Instruction* catchPCForInterpreter)
+        {
+            #if ENABLE(JIT)
+            UNUSED_PARAM(catchPCForInterpreter);
+            return handler->nativeCode.executableAddress();
+            #else
+            UNUSED_PARAM(handler);
+            return LLInt::CLoop::catchRoutineFor(catchPCForInterpreter);
+            #endif
+        }
+#endif // ENABLE(JIT || ENABLE(LLINT_C_LOOP)
+
     protected:
-        JITCode m_jitCode;
+        ExecutableBase* m_prev;
+        ExecutableBase* m_next;
+
+#if ENABLE(JIT)
+        JITCode m_jitCodeForCall;
+        JITCode m_jitCodeForConstruct;
+        MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+        MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
 #endif
     };
 
-#if ENABLE(JIT)
     class NativeExecutable : public ExecutableBase {
+        friend class JIT;
+        friend class LLIntOffsetsExtractor;
     public:
-        NativeExecutable(ExecState* exec)
-            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+        typedef ExecutableBase Base;
+
+#if ENABLE(JIT)
+        static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
         {
-            m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk()));
+            NativeExecutable* executable;
+            if (!callThunk) {
+                executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
+                executable->finishCreation(vm, JITCode(), JITCode(), intrinsic);
+            } else {
+                executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
+                executable->finishCreation(vm, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
+            }
+            return executable;
         }
+#endif
 
-        ~NativeExecutable();
-    };
+#if ENABLE(LLINT_C_LOOP)
+        static NativeExecutable* create(VM& vm, NativeFunction function, NativeFunction constructor)
+        {
+            ASSERT(!vm.canUseJIT());
+            NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
+            executable->finishCreation(vm);
+            return executable;
+        }
 #endif
 
-    class VPtrHackExecutable : public ExecutableBase {
-    public:
-        VPtrHackExecutable()
-            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+#if ENABLE(JIT)
+        static void destroy(JSCell*);
+#endif
+
+        CodeBlockHash hashFor(CodeSpecializationKind) const;
+
+        NativeFunction function() { return m_function; }
+        NativeFunction constructor() { return m_constructor; }
+        
+        NativeFunction nativeFunctionFor(CodeSpecializationKind kind)
         {
+            if (kind == CodeForCall)
+                return function();
+            ASSERT(kind == CodeForConstruct);
+            return constructor();
         }
+        
+        static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return OBJECT_OFFSETOF(NativeExecutable, m_function);
+            ASSERT(kind == CodeForConstruct);
+            return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
+        }
+
+        static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); }
+        
+        static const ClassInfo s_info;
 
-        ~VPtrHackExecutable();
+        Intrinsic intrinsic() const;
+
+    protected:
+#if ENABLE(JIT)
+        void finishCreation(VM& vm, JITCode callThunk, JITCode constructThunk, Intrinsic intrinsic)
+        {
+            Base::finishCreation(vm);
+            m_jitCodeForCall = callThunk;
+            m_jitCodeForConstruct = constructThunk;
+            m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+            m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
+            m_intrinsic = intrinsic;
+        }
+#endif
+
+    private:
+        NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
+            : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+            , m_function(function)
+            , m_constructor(constructor)
+        {
+        }
+
+        NativeFunction m_function;
+        NativeFunction m_constructor;
+        
+        Intrinsic m_intrinsic;
     };
 
     class ScriptExecutable : public ExecutableBase {
     public:
-        ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
-            : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+        typedef ExecutableBase Base;
+
+        ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext)
+            : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
-#if ENABLE(CODEBLOCK_SAMPLING)
-            if (SamplingTool* sampler = globalData->interpreter->sampler())
-                sampler->notifyOfScope(this);
-#else
-            UNUSED_PARAM(globalData);
-#endif
         }
 
-        ScriptExecutable(ExecState* exec, const SourceCode& source)
-            : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+        ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
+            : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
-#if ENABLE(CODEBLOCK_SAMPLING)
-            if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
-                sampler->notifyOfScope(this);
-#else
-            UNUSED_PARAM(exec);
-#endif
         }
 
-        const SourceCode& source() { return m_source; }
-        intptr_t sourceID() const { return m_source.provider()->asID(); }
-        const UString& sourceURL() const { return m_source.provider()->url(); }
+#if ENABLE(JIT)
+        static void destroy(JSCell*);
+#endif
+        
+        CodeBlockHash hashFor(CodeSpecializationKind) const;
+
+        const SourceCode& source() const { return m_source; }
+        intptr_t sourceID() const { return m_source.providerID(); }
+        const String& sourceURL() const { return m_source.provider()->url(); }
         int lineNo() const { return m_firstLine; }
         int lastLine() const { return m_lastLine; }
+        unsigned startColumn() const { return m_startColumn; }
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
-        bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+        bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+        bool isStrictMode() const { return m_features & StrictModeFeature; }
 
-        virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
+        void unlinkCalls();
 
-    protected:
-        void recordParse(CodeFeatures features, int firstLine, int lastLine)
+        CodeFeatures features() const { return m_features; }
+        
+        static const ClassInfo s_info;
+
+        void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn)
         {
             m_features = features;
+            m_hasCapturedVariables = hasCapturedVariables;
             m_firstLine = firstLine;
             m_lastLine = lastLine;
+            m_startColumn = startColumn;
+        }
+
+    protected:
+        void finishCreation(VM& vm)
+        {
+            Base::finishCreation(vm);
+            vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
+
+#if ENABLE(CODEBLOCK_SAMPLING)
+            if (SamplingTool* sampler = vm.interpreter->sampler())
+                sampler->notifyOfScope(vm, this);
+#endif
         }
 
         SourceCode m_source;
         CodeFeatures m_features;
+        bool m_hasCapturedVariables;
         int m_firstLine;
         int m_lastLine;
+        unsigned m_startColumn;
     };
 
     class EvalExecutable : public ScriptExecutable {
+        friend class LLIntOffsetsExtractor;
     public:
+        typedef ScriptExecutable Base;
 
-        ~EvalExecutable();
+        static void destroy(JSCell*);
 
-        EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JSObject* compile(ExecState* exec, JSScope* scope)
         {
-            if (!m_evalCodeBlock) {
-                JSObject* error = compile(exec, scopeChainNode);
-                ASSERT_UNUSED(!error, error);
-            }
-            return *m_evalCodeBlock;
+            RELEASE_ASSERT(exec->vm().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_evalCodeBlock)
+                error = compileInternal(exec, scope, JITCode::bottomTierJIT());
+            ASSERT(!error == !!m_evalCodeBlock);
+            return error;
         }
+        
+        JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex);
+        
+#if ENABLE(JIT)
+        void jettisonOptimizedCode(VM&);
+        bool jitCompile(ExecState*);
+#endif
 
-        JSObject* compile(ExecState*, ScopeChainNode*);
-
-        ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
-        static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
+        EvalCodeBlock& generatedBytecode()
+        {
+            ASSERT(m_evalCodeBlock);
+            return *m_evalCodeBlock;
+        }
 
-    private:
-        EvalExecutable(ExecState* exec, const SourceCode& source)
-            : ScriptExecutable(exec, source)
-            , m_evalCodeBlock(0)
+        static EvalExecutable* create(ExecState* exec, PassRefPtr<CodeCache> cache, const SourceCode& source, bool isInStrictContext)
         {
+            EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, cache, source, isInStrictContext);
+            executable->finishCreation(exec->vm());
+            return executable;
         }
-        EvalCodeBlock* m_evalCodeBlock;
 
 #if ENABLE(JIT)
-    public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JITCode& generatedJITCode()
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            return generatedJITCodeForCall();
         }
+#endif
+        static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+        {
+            return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info);
+        }
+        
+        static const ClassInfo s_info;
+
+        void unlinkCalls();
+
+        void clearCode();
+
+        ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
 
     private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+        EvalExecutable(ExecState*, PassRefPtr<CodeCache>, const SourceCode&, bool);
+
+        JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
+        static void visitChildren(JSCell*, SlotVisitor&);
+
+        OwnPtr<EvalCodeBlock> m_evalCodeBlock;
+        WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
+        RefPtr<CodeCache> m_codeCache;
     };
 
     class ProgramExecutable : public ScriptExecutable {
+        friend class LLIntOffsetsExtractor;
     public:
-        static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
+        typedef ScriptExecutable Base;
+
+        static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
         {
-            return adoptRef(new ProgramExecutable(exec, source));
+            ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
+            executable->finishCreation(exec->vm());
+            return executable;
         }
 
-        ~ProgramExecutable();
 
-        ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*);
+
+        static void destroy(JSCell*);
+
+        JSObject* compile(ExecState* exec, JSScope* scope)
         {
-            if (!m_programCodeBlock) {
-                JSObject* error = compile(exec, scopeChainNode);
-                ASSERT_UNUSED(!error, error);
-            }
-            return *m_programCodeBlock;
+            RELEASE_ASSERT(exec->vm().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_programCodeBlock)
+                error = compileInternal(exec, scope, JITCode::bottomTierJIT());
+            ASSERT(!error == !!m_programCodeBlock);
+            return error;
         }
 
-        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; }
+        JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex);
+        
+#if ENABLE(JIT)
+        void jettisonOptimizedCode(VM&);
+        bool jitCompile(ExecState*);
+#endif
 
-    private:
-        ProgramExecutable(ExecState* exec, const SourceCode& source)
-            : ScriptExecutable(exec, source)
-            , m_programCodeBlock(0)
+        ProgramCodeBlock& generatedBytecode()
         {
+            ASSERT(m_programCodeBlock);
+            return *m_programCodeBlock;
         }
-        ProgramCodeBlock* m_programCodeBlock;
+
+        JSObject* checkSyntax(ExecState*);
 
 #if ENABLE(JIT)
-    public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        JITCode& generatedJITCode()
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            return generatedJITCodeForCall();
         }
+#endif
+        
+        static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+        {
+            return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info);
+        }
+        
+        static const ClassInfo s_info;
+        
+        void unlinkCalls();
+
+        void clearCode();
+
+        ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
 
     private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+
+        ProgramExecutable(ExecState*, const SourceCode&);
+
+        enum ConstantMode { IsConstant, IsVariable };
+        enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable };
+        int addGlobalVar(JSGlobalObject*, const Identifier&, ConstantMode, FunctionMode);
+
+        JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
+        static void visitChildren(JSCell*, SlotVisitor&);
+
+        WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
+        OwnPtr<ProgramCodeBlock> m_programCodeBlock;
     };
 
     class FunctionExecutable : public ScriptExecutable {
         friend class JIT;
+        friend class LLIntOffsetsExtractor;
     public:
-        static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        typedef ScriptExecutable Base;
+
+        static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn)
         {
-            return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn);
+            executable->finishCreation(vm);
+            return executable;
         }
+        static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
 
-        static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        static void destroy(JSCell*);
+        
+        UnlinkedFunctionExecutable* unlinkedExecutable()
         {
-            return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            return m_unlinkedExecutable.get();
         }
 
-        ~FunctionExecutable();
-
-        JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
+        // 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()
         {
-            return new (exec) JSFunction(exec, this, scopeChain);
+            if (m_codeBlockForCall)
+                return *m_codeBlockForCall;
+            ASSERT(m_codeBlockForConstruct);
+            return *m_codeBlockForConstruct;
         }
+        
+        PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(JSScope*, CodeSpecializationKind, JSObject*& exception);
 
-        CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) 
+        JSObject* compileForCall(ExecState* exec, JSScope* scope)
         {
-            ASSERT(scopeChainNode);
-            if (!m_codeBlock)
-                compile(exec, scopeChainNode);
-            return *m_codeBlock;
+            RELEASE_ASSERT(exec->vm().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_codeBlockForCall)
+                error = compileForCallInternal(exec, scope, JITCode::bottomTierJIT());
+            ASSERT(!error == !!m_codeBlockForCall);
+            return error;
         }
 
-        bool isGenerated() const
+        JSObject* compileOptimizedForCall(ExecState*, JSScope*, unsigned bytecodeIndex);
+        
+#if ENABLE(JIT)
+        void jettisonOptimizedCodeForCall(VM&);
+        bool jitCompileForCall(ExecState*);
+#endif
+
+        bool isGeneratedForCall() const
         {
-            return m_codeBlock;
+            return m_codeBlockForCall;
         }
 
-        CodeBlock& generatedBytecode()
+        FunctionCodeBlock& generatedBytecodeForCall()
         {
-            ASSERT(m_codeBlock);
-            return *m_codeBlock;
+            ASSERT(m_codeBlockForCall);
+            return *m_codeBlockForCall;
         }
 
-        const Identifier& name() { return m_name; }
-        size_t parameterCount() const { return m_parameters->size(); }
-        size_t variableCount() const { return m_numVariables; }
-        UString paramString() const;
+        JSObject* compileForConstruct(ExecState* exec, JSScope* scope)
+        {
+            RELEASE_ASSERT(exec->vm().dynamicGlobalObject);
+            JSObject* error = 0;
+            if (!m_codeBlockForConstruct)
+                error = compileForConstructInternal(exec, scope, JITCode::bottomTierJIT());
+            ASSERT(!error == !!m_codeBlockForConstruct);
+            return error;
+        }
 
-        void recompile(ExecState*);
-        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* compileOptimizedForConstruct(ExecState*, JSScope*, unsigned bytecodeIndex);
+        
+#if ENABLE(JIT)
+        void jettisonOptimizedCodeForConstruct(VM&);
+        bool jitCompileForConstruct(ExecState*);
+#endif
 
-    private:
-        FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
-            : ScriptExecutable(globalData, source)
-            , m_forceUsesArguments(forceUsesArguments)
-            , m_parameters(parameters)
-            , m_codeBlock(0)
-            , m_name(name)
-            , m_numVariables(0)
+        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_forceUsesArguments(forceUsesArguments)
-            , m_parameters(parameters)
-            , m_codeBlock(0)
-            , m_name(name)
-            , m_numVariables(0)
+        FunctionCodeBlock& generatedBytecodeForConstruct()
         {
-            m_firstLine = firstLine;
-            m_lastLine = lastLine;
+            ASSERT(m_codeBlockForConstruct);
+            return *m_codeBlockForConstruct;
+        }
+        
+        JSObject* compileFor(ExecState* exec, JSScope* scope, CodeSpecializationKind kind)
+        {
+            ASSERT(exec->callee());
+            ASSERT(exec->callee()->inherits(&JSFunction::s_info));
+            ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this);
+
+            if (kind == CodeForCall)
+                return compileForCall(exec, scope);
+            ASSERT(kind == CodeForConstruct);
+            return compileForConstruct(exec, scope);
+        }
+        
+        JSObject* compileOptimizedFor(ExecState* exec, JSScope* scope, unsigned bytecodeIndex, CodeSpecializationKind kind)
+        {
+            ASSERT(exec->callee());
+            ASSERT(exec->callee()->inherits(&JSFunction::s_info));
+            ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this);
+            
+            if (kind == CodeForCall)
+                return compileOptimizedForCall(exec, scope, bytecodeIndex);
+            ASSERT(kind == CodeForConstruct);
+            return compileOptimizedForConstruct(exec, scope, bytecodeIndex);
         }
 
-        void compile(ExecState*, ScopeChainNode*);
-
-        bool m_forceUsesArguments;
-        RefPtr<FunctionParameters> m_parameters;
-        CodeBlock* m_codeBlock;
-        Identifier m_name;
-        size_t m_numVariables;
-
+        
 #if ENABLE(JIT)
-    public:
-        JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+        void jettisonOptimizedCodeFor(VM& vm, CodeSpecializationKind kind)
         {
-            if (!m_jitCode)
-                generateJITCode(exec, scopeChainNode);
-            return m_jitCode;
+            if (kind == CodeForCall) 
+                jettisonOptimizedCodeForCall(vm);
+            else {
+                ASSERT(kind == CodeForConstruct);
+                jettisonOptimizedCodeForConstruct(vm);
+            }
+        }
+        
+        bool jitCompileFor(ExecState* exec, CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return jitCompileForCall(exec);
+            ASSERT(kind == CodeForConstruct);
+            return jitCompileForConstruct(exec);
+        }
+#endif
+        
+        bool isGeneratedFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return isGeneratedForCall();
+            ASSERT(kind == CodeForConstruct);
+            return isGeneratedForConstruct();
+        }
+        
+        FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return generatedBytecodeForCall();
+            ASSERT(kind == CodeForConstruct);
+            return generatedBytecodeForConstruct();
         }
 
+        FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
+        
+        FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
+        {
+            return baselineCodeBlockFor(kind);
+        }
+        
+        const Identifier& name() { return m_unlinkedExecutable->name(); }
+        const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
+        JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
+        size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
+        String paramString() const;
+        SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); }
+
+        void clearCodeIfNotCompiling();
+        void clearUnlinkedCodeForRecompilationIfNotCompiling();
+        static void visitChildren(JSCell*, SlotVisitor&);
+        static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+        {
+            return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info);
+        }
+        
+        static const ClassInfo s_info;
+        
+        void unlinkCalls();
+
+        void clearCode();
+
     private:
-        void generateJITCode(ExecState*, ScopeChainNode*);
+        FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn);
+
+        JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
+        JSObject* compileForConstructInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
+        
+        OwnPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind)
+        {
+            if (kind == CodeForCall)
+                return m_codeBlockForCall;
+            ASSERT(kind == CodeForConstruct);
+            return m_codeBlockForConstruct;
+        }
+        bool isCompiling()
+        {
+#if ENABLE(JIT)
+            if (!m_jitCodeForCall && m_codeBlockForCall)
+                return true;
+            if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
+                return true;
 #endif
+            return false;
+        }
+
+        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+        WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
+        OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
+        OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
     };
 
+    inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
+        : Base(vm, scope->globalObject()->functionStructure())
+        , m_executable(vm, this, executable)
+        , m_scope(vm, this, scope)
+        , m_allocationProfileWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
+    {
+    }
+
     inline FunctionExecutable* JSFunction::jsExecutable() const
     {
         ASSERT(!isHostFunctionNonInline());
@@ -351,6 +800,54 @@ namespace JSC {
         return m_executable->isHostFunction();
     }
 
+    inline NativeFunction JSFunction::nativeFunction()
+    {
+        ASSERT(isHostFunction());
+        return static_cast<NativeExecutable*>(m_executable.get())->function();
+    }
+
+    inline NativeFunction JSFunction::nativeConstructor()
+    {
+        ASSERT(isHostFunction());
+        return static_cast<NativeExecutable*>(m_executable.get())->constructor();
+    }
+
+    inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
+    {
+        JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
+        if (!function || !function->isHostFunction())
+            return false;
+        return function->nativeFunction() == nativeFunction;
+    }
+
+    inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
+    {
+        switch (executable->structure()->typeInfo().type()) {
+        case EvalExecutableType:
+            return jsCast<EvalExecutable*>(executable)->clearCode();
+        case ProgramExecutableType:
+            return jsCast<ProgramExecutable*>(executable)->clearCode();
+        case FunctionExecutableType:
+            return jsCast<FunctionExecutable*>(executable)->clearCode();
+        default:
+            return jsCast<NativeExecutable*>(executable)->clearCode();
+        }
+    }
+
+    inline void ScriptExecutable::unlinkCalls()
+    {
+        switch (structure()->typeInfo().type()) {
+        case EvalExecutableType:
+            return jsCast<EvalExecutable*>(this)->unlinkCalls();
+        case ProgramExecutableType:
+            return jsCast<ProgramExecutable*>(this)->unlinkCalls();
+        case FunctionExecutableType:
+            return jsCast<FunctionExecutable*>(this)->unlinkCalls();
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+
 }
 
 #endif