]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Executable.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / Executable.h
index e795fbfc3123e3f72b25f7aa320832b5d2a22520..1c7c80003d2a32bd6a311dac0de53901a8ad781f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013-2015 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 "ArityCheckMode.h"
 #include "CallData.h"
-#include "JSFunction.h"
-#include "Interpreter.h"
-#include "Nodes.h"
+#include "CodeBlockHash.h"
+#include "CodeSpecializationKind.h"
+#include "CompilationResult.h"
+#include "DFGPlan.h"
+#include "HandlerInfo.h"
+#include "InferredValue.h"
+#include "JITCode.h"
+#include "JSGlobalObject.h"
+#include "RegisterPreservationMode.h"
 #include "SamplingTool.h"
-#include <wtf/PassOwnPtr.h>
+#include "SourceCode.h"
+#include "TypeSet.h"
+#include "UnlinkedCodeBlock.h"
 
 namespace JSC {
 
-    class CodeBlock;
-    class Debugger;
-    class EvalCodeBlock;
-    class FunctionCodeBlock;
-    class ProgramCodeBlock;
-    class ScopeChainNode;
+class CodeBlock;
+class Debugger;
+class EvalCodeBlock;
+class FunctionCodeBlock;
+class LLIntOffsetsExtractor;
+class ProgramCodeBlock;
+class JSScope;
+    
+enum CompilationKind { FirstCompilation, OptimizingCompilation };
+
+inline bool isCall(CodeSpecializationKind kind)
+{
+    if (kind == CodeForCall)
+        return true;
+    ASSERT(kind == CodeForConstruct);
+    return false;
+}
 
-    struct ExceptionInfo;
+class ExecutableBase : public JSCell {
+    friend class JIT;
 
-    class ExecutableBase : public JSCell {
-        friend class JIT;
+protected:
+    static const int NUM_PARAMETERS_IS_HOST = 0;
+    static const int NUM_PARAMETERS_NOT_COMPILED = -1;
 
-    protected:
-        static const int NUM_PARAMETERS_IS_HOST = 0;
-        static const int NUM_PARAMETERS_NOT_COMPILED = -1;
-    
-    public:
-        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
-        }
+    ExecutableBase(VM& vm, Structure* structure, int numParameters)
+        : JSCell(vm, structure)
+        , m_numParametersForCall(numParameters)
+        , m_numParametersForConstruct(numParameters)
+    {
+    }
 
-        bool isHostFunction() const
-        {
-            ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
-            return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
-        }
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+    }
 
-        static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); }
+public:
+    typedef JSCell Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
+
+    static const bool needsDestruction = true;
+    static void destroy(JSCell*);
         
-        static const ClassInfo s_info;
-
-    protected:
-        static const unsigned StructureFlags = 0;
-        int m_numParametersForCall;
-        int m_numParametersForConstruct;
-
-#if ENABLE(JIT)
-    public:
-        JITCode& generatedJITCodeForCall()
-        {
-            ASSERT(m_jitCodeForCall);
-            return m_jitCodeForCall;
-        }
+    CodeBlockHash hashFor(CodeSpecializationKind) const;
 
-        JITCode& generatedJITCodeForConstruct()
-        {
-            ASSERT(m_jitCodeForConstruct);
-            return m_jitCodeForConstruct;
-        }
+    bool isEvalExecutable()
+    {
+        return type() == EvalExecutableType;
+    }
+    bool isFunctionExecutable()
+    {
+        return type() == FunctionExecutableType;
+    }
+    bool isProgramExecutable()
+    {
+        return type() == ProgramExecutableType;
+    }
 
-        void clearExecutableCode()
-        {
-            m_jitCodeForCall.clear();
-            m_jitCodeForConstruct.clear();
-        }
+    bool isHostFunction() const
+    {
+        ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+        return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
+    }
 
-    protected:
-        JITCode m_jitCodeForCall;
-        JITCode m_jitCodeForConstruct;
-        MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
-        MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
         
-    private:
-        static WeakHandleOwner* executableFinalizer();
-#endif
-    };
-
-    class NativeExecutable : public ExecutableBase {
-        friend class JIT;
-    public:
-#if ENABLE(JIT)
-        static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor)
-        {
-            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
+    void clearCode();
+
+    DECLARE_EXPORT_INFO;
 
-        ~NativeExecutable();
+protected:
+    int m_numParametersForCall;
+    int m_numParametersForConstruct;
 
-        NativeFunction function() { return m_function; }
+public:
+    static void clearCodeVirtual(ExecutableBase*);
 
-        static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(LeafType, StructureFlags), AnonymousSlotCount, &s_info); }
+    PassRefPtr<JITCode> generatedJITCodeForCall()
+    {
+        ASSERT(m_jitCodeForCall);
+        return m_jitCodeForCall;
+    }
+
+    PassRefPtr<JITCode> generatedJITCodeForConstruct()
+    {
+        ASSERT(m_jitCodeForConstruct);
+        return m_jitCodeForConstruct;
+    }
         
-        static const ClassInfo s_info;
+    PassRefPtr<JITCode> generatedJITCodeFor(CodeSpecializationKind kind)
+    {
+        if (kind == CodeForCall)
+            return generatedJITCodeForCall();
+        ASSERT(kind == CodeForConstruct);
+        return generatedJITCodeForConstruct();
+    }
     
-    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
+    MacroAssemblerCodePtr entrypointFor(
+        VM& vm, CodeSpecializationKind kind, ArityCheckMode arity, RegisterPreservationMode registers)
+    {
+        // Check if we have a cached result. We only have it for arity check because we use the
+        // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in
+        // machine code.
+        if (arity == MustCheckArity) {
+            switch (kind) {
+            case CodeForCall:
+                switch (registers) {
+                case RegisterPreservationNotRequired:
+                    if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck)
+                        return result;
+                    break;
+                case MustPreserveRegisters:
+                    if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheckAndPreserveRegs)
+                        return result;
+                    break;
+                }
+                break;
+            case CodeForConstruct:
+                switch (registers) {
+                case RegisterPreservationNotRequired:
+                    if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck)
+                        return result;
+                    break;
+                case MustPreserveRegisters:
+                    if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheckAndPreserveRegs)
+                        return result;
+                    break;
+                }
+                break;
+            }
+        }
+        MacroAssemblerCodePtr result =
+            generatedJITCodeFor(kind)->addressForCall(vm, this, arity, registers);
+        if (arity == MustCheckArity) {
+            // Cache the result; this is necessary for the JIT's virtual call optimizations.
+            switch (kind) {
+            case CodeForCall:
+                switch (registers) {
+                case RegisterPreservationNotRequired:
+                    m_jitCodeForCallWithArityCheck = result;
+                    break;
+                case MustPreserveRegisters:
+                    m_jitCodeForCallWithArityCheckAndPreserveRegs = result;
+                    break;
+                }
+                break;
+            case CodeForConstruct:
+                switch (registers) {
+                case RegisterPreservationNotRequired:
+                    m_jitCodeForConstructWithArityCheck = result;
+                    break;
+                case MustPreserveRegisters:
+                    m_jitCodeForConstructWithArityCheckAndPreserveRegs = result;
+                    break;
+                }
+                break;
+            }
+        }
+        return result;
+    }
 
-        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(Structure* structure, JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext)
-            : ExecutableBase(*globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
-            , m_source(source)
-            , m_features(isInStrictContext ? StrictModeFeature : 0)
-        {
-#if ENABLE(CODEBLOCK_SAMPLING)
-            relaxAdoptionRequirement();
-            if (SamplingTool* sampler = globalData->interpreter->sampler())
-                sampler->notifyOfScope(this);
-#else
-            UNUSED_PARAM(globalData);
-#endif
-        }
+    static ptrdiff_t offsetOfJITCodeWithArityCheckFor(
+        CodeSpecializationKind kind, RegisterPreservationMode registers)
+    {
+        switch (kind) {
+        case CodeForCall:
+            switch (registers) {
+            case RegisterPreservationNotRequired:
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
+            case MustPreserveRegisters:
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheckAndPreserveRegs);
+            }
+        case CodeForConstruct:
+            switch (registers) {
+            case RegisterPreservationNotRequired:
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+            case MustPreserveRegisters:
+                return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheckAndPreserveRegs);
+            }
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+    
+    static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
+    {
+        if (kind == CodeForCall)
+            return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall);
+        ASSERT(kind == CodeForConstruct);
+        return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct);
+    }
 
-        ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
-            : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
-            , m_source(source)
-            , m_features(isInStrictContext ? StrictModeFeature : 0)
-        {
-#if ENABLE(CODEBLOCK_SAMPLING)
-            relaxAdoptionRequirement();
-            if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
-                sampler->notifyOfScope(this);
-#else
-            UNUSED_PARAM(exec);
-#endif
-        }
+    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();
+    }
 
-        const SourceCode& source() { return m_source; }
-        intptr_t sourceID() const { return m_source.provider()->asID(); }
-        const UString& sourceURL() const { return m_source.provider()->url(); }
-        int lineNo() const { return m_firstLine; }
-        int lastLine() const { return m_lastLine; }
+    // Intrinsics are only for calls, currently.
+    Intrinsic intrinsic() const;
+        
+    Intrinsic intrinsicFor(CodeSpecializationKind kind) const
+    {
+        if (isCall(kind))
+            return intrinsic();
+        return NoIntrinsic;
+    }
+    
+    void dump(PrintStream&) const;
+        
+protected:
+    RefPtr<JITCode> m_jitCodeForCall;
+    RefPtr<JITCode> m_jitCodeForConstruct;
+    MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+    MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
+    MacroAssemblerCodePtr m_jitCodeForCallWithArityCheckAndPreserveRegs;
+    MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheckAndPreserveRegs;
+};
+
+class NativeExecutable final : public ExecutableBase {
+    friend class JIT;
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ExecutableBase Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic)
+    {
+        NativeExecutable* executable;
+        executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
+        executable->finishCreation(vm, callThunk, constructThunk, intrinsic);
+        return executable;
+    }
 
-        bool usesEval() const { return m_features & EvalFeature; }
-        bool usesArguments() const { return m_features & ArgumentsFeature; }
-        bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
-        bool isStrictMode() const { return m_features & StrictModeFeature; }
+    static void destroy(JSCell*);
 
-        virtual void unlinkCalls() = 0;
+    CodeBlockHash hashFor(CodeSpecializationKind) const;
+
+    NativeFunction function() { return m_function; }
+    NativeFunction constructor() { return m_constructor; }
         
-        static const ClassInfo s_info;
-    protected:
-        void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
-        {
-            m_features = features;
-            m_hasCapturedVariables = hasCapturedVariables;
-            m_firstLine = firstLine;
-            m_lastLine = lastLine;
-        }
+    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);
+    }
 
-        SourceCode m_source;
-        CodeFeatures m_features;
-        bool m_hasCapturedVariables;
-        int m_firstLine;
-        int m_lastLine;
-    };
-
-    class EvalExecutable : public ScriptExecutable {
-    public:
-
-        ~EvalExecutable();
-
-        JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
-        {
-            ASSERT(exec->globalData().dynamicGlobalObject);
-            JSObject* error = 0;
-            if (!m_evalCodeBlock)
-                error = compileInternal(exec, scopeChainNode);
-            ASSERT(!error == !!m_evalCodeBlock);
-            return error;
-        }
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
+        
+    DECLARE_INFO;
 
-        EvalCodeBlock& generatedBytecode()
-        {
-            ASSERT(m_evalCodeBlock);
-            return *m_evalCodeBlock;
-        }
+    Intrinsic intrinsic() const;
 
-        static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); }
+protected:
+    void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic)
+    {
+        Base::finishCreation(vm);
+        m_jitCodeForCall = callThunk;
+        m_jitCodeForConstruct = constructThunk;
+        m_intrinsic = intrinsic;
+    }
 
-#if ENABLE(JIT)
-        JITCode& generatedJITCode()
-        {
-            return generatedJITCodeForCall();
-        }
-#endif
-        static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
-        {
-            return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
-        }
+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;
         
-        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 ProgramExecutable* create(ExecState* exec, const SourceCode& source)
-        {
-            return new (exec) ProgramExecutable(exec, source);
-        }
+    Intrinsic m_intrinsic;
+};
 
-        ~ProgramExecutable();
+class ScriptExecutable : public ExecutableBase {
+public:
+    typedef ExecutableBase Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
 
-        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;
-        }
+    static void destroy(JSCell*);
+        
+    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 firstLine() const { return m_firstLine; }
+    void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; }
+    bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; }
+    int overrideLineNumber() const { return m_overrideLineNumber; }
+    int lastLine() const { return m_lastLine; }
+    unsigned startColumn() const { return m_startColumn; }
+    unsigned endColumn() const { return m_endColumn; }
+    unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; }
+    unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
+
+    bool usesEval() const { return m_features & EvalFeature; }
+    bool usesArguments() const { return m_features & ArgumentsFeature; }
+    bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+    bool isStrictMode() const { return m_features & StrictModeFeature; }
+    ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
+        
+    void setNeverInline(bool value) { m_neverInline = value; }
+    void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; }
+    bool neverInline() const { return m_neverInline; }
+    bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; }
+    bool isInliningCandidate() const { return !neverInline(); }
+    
+    bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; }
 
-        ProgramCodeBlock& generatedBytecode()
-        {
-            ASSERT(m_programCodeBlock);
-            return *m_programCodeBlock;
-        }
+    void unlinkCalls();
+        
+    CodeFeatures features() const { return m_features; }
+        
+    DECLARE_INFO;
 
-        JSObject* checkSyntax(ExecState*);
+    void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn, unsigned endColumn)
+    {
+        m_features = features;
+        m_hasCapturedVariables = hasCapturedVariables;
+        m_firstLine = firstLine;
+        m_lastLine = lastLine;
+        ASSERT(startColumn != UINT_MAX);
+        m_startColumn = startColumn;
+        ASSERT(endColumn != UINT_MAX);
+        m_endColumn = endColumn;
+    }
 
-#if ENABLE(JIT)
-        JITCode& generatedJITCode()
-        {
-            return generatedJITCodeForCall();
-        }
+    void installCode(CodeBlock*);
+    RefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
+    PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind);
+    
+    JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
+    {
+        if (hasJITCodeFor(kind))
+            return 0;
+        return prepareForExecutionImpl(exec, function, scope, kind);
+    }
+
+    template <typename Functor> void forEachCodeBlock(Functor&&);
+
+private:
+    JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
+
+protected:
+    ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext);
+
+    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;
+    bool m_neverInline;
+    bool m_didTryToEnterInLoop;
+    int m_overrideLineNumber;
+    int m_firstLine;
+    int m_lastLine;
+    unsigned m_startColumn;
+    unsigned m_endColumn;
+    unsigned m_typeProfilingStartOffset;
+    unsigned m_typeProfilingEndOffset;
+};
+
+class EvalExecutable final : public ScriptExecutable {
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static void destroy(JSCell*);
+
+    EvalCodeBlock* codeBlock()
+    {
+        return m_evalCodeBlock.get();
+    }
+
+    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode);
+
+    PassRefPtr<JITCode> generatedJITCode()
+    {
+        return generatedJITCodeForCall();
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), info());
+    }
         
-        static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
-        {
-            return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
-        }
-        
-        static const ClassInfo s_info;
+    DECLARE_INFO;
 
-    private:
-        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
-        ProgramExecutable(ExecState*, const SourceCode&);
+    void unlinkCalls();
 
-        JSObject* compileInternal(ExecState*, ScopeChainNode*);
-        virtual void visitChildren(SlotVisitor&);
-        void unlinkCalls();
+    void clearCode();
 
-        OwnPtr<ProgramCodeBlock> m_programCodeBlock;
-    };
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
 
-    class FunctionExecutable : public ScriptExecutable {
-        friend class JIT;
-    public:
-        static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
-        {
-            return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
-        }
+    unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
+    unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
 
-        static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
-        {
-            return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
-        }
+private:
+    friend class ScriptExecutable;
+    EvalExecutable(ExecState*, const SourceCode&, bool);
 
-        JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
-        {
-            return new (exec) JSFunction(exec, this, 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()
-        {
-            if (m_codeBlockForCall)
-                return *m_codeBlockForCall;
-            ASSERT(m_codeBlockForConstruct);
-            return *m_codeBlockForConstruct;
-        }
+    static void visitChildren(JSCell*, SlotVisitor&);
 
-        JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
-        {
-            ASSERT(exec->globalData().dynamicGlobalObject);
-            JSObject* error = 0;
-            if (!m_codeBlockForCall)
-                error = compileForCallInternal(exec, scopeChainNode);
-            ASSERT(!error == !!m_codeBlockForCall);
-            return error;
-        }
+    RefPtr<EvalCodeBlock> m_evalCodeBlock;
+    WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
+};
 
-        bool isGeneratedForCall() const
-        {
-            return m_codeBlockForCall;
-        }
+class ProgramExecutable final : public ScriptExecutable {
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-        FunctionCodeBlock& generatedBytecodeForCall()
-        {
-            ASSERT(m_codeBlockForCall);
-            return *m_codeBlockForCall;
-        }
+    static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
+    {
+        ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
+        executable->finishCreation(exec->vm());
+        return executable;
+    }
 
-        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;
-        }
 
-        bool isGeneratedForConstruct() const
-        {
-            return m_codeBlockForConstruct;
-        }
+    JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*);
 
-        FunctionCodeBlock& generatedBytecodeForConstruct()
-        {
-            ASSERT(m_codeBlockForConstruct);
-            return *m_codeBlockForConstruct;
-        }
+    static void destroy(JSCell*);
 
-        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);
-        }
+    ProgramCodeBlock* codeBlock()
+    {
+        return m_programCodeBlock.get();
+    }
+
+    JSObject* checkSyntax(ExecState*);
+
+    PassRefPtr<JITCode> generatedJITCode()
+    {
+        return generatedJITCodeForCall();
+    }
+        
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info());
+    }
         
-        static const ClassInfo s_info;
+    DECLARE_INFO;
+        
+    void unlinkCalls();
+
+    void clearCode();
+
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
+
+private:
+    friend class ScriptExecutable;
+
+    ProgramExecutable(ExecState*, const SourceCode&);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
 
-    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);
+    WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
+    RefPtr<ProgramCodeBlock> m_programCodeBlock;
+};
 
-        JSObject* compileForCallInternal(ExecState*, ScopeChainNode*);
-        JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*);
+class FunctionExecutable final : public ScriptExecutable {
+    friend class JIT;
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static FunctionExecutable* create(
+        VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, 
+        unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
+    {
+        FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn);
+        executable->finishCreation(vm);
+        return executable;
+    }
+    static FunctionExecutable* fromGlobalCode(
+        const Identifier& name, ExecState&, const SourceCode&, 
+        JSObject*& exception, int overrideLineNumber);
+
+    static void destroy(JSCell*);
         
-        static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
-        unsigned m_numCapturedVariables : 31;
-        bool m_forceUsesArguments : 1;
-        void unlinkCalls();
-
-        RefPtr<FunctionParameters> m_parameters;
-        OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
-        OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
-        Identifier m_name;
-        SharedSymbolTable* m_symbolTable;
-
-#if ENABLE(JIT)
-    public:
-        MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
-        {
-            ASSERT(m_jitCodeForCall);
-            ASSERT(m_jitCodeForCallWithArityCheck);
-            return m_jitCodeForCallWithArityCheck;
-        }
+    UnlinkedFunctionExecutable* unlinkedExecutable()
+    {
+        return m_unlinkedExecutable.get();
+    }
 
-        MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
-        {
-            ASSERT(m_jitCodeForConstruct);
-            ASSERT(m_jitCodeForConstructWithArityCheck);
-            return m_jitCodeForConstructWithArityCheck;
-        }
-#endif
-    };
+    // 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* eitherCodeBlock()
+    {
+        if (m_codeBlockForCall)
+            return m_codeBlockForCall.get();
+        return m_codeBlockForConstruct.get();
+    }
+        
+    bool isGeneratedForCall() const
+    {
+        return m_codeBlockForCall;
+    }
+
+    FunctionCodeBlock* codeBlockForCall()
+    {
+        return m_codeBlockForCall.get();
+    }
 
-    inline FunctionExecutable* JSFunction::jsExecutable() const
+    bool isGeneratedForConstruct() const
     {
-        ASSERT(!isHostFunctionNonInline());
-        return static_cast<FunctionExecutable*>(m_executable.get());
+        return m_codeBlockForConstruct;
     }
 
-    inline bool JSFunction::isHostFunction() const
+    FunctionCodeBlock* codeBlockForConstruct()
+    {
+        return m_codeBlockForConstruct.get();
+    }
+        
+    bool isGeneratedFor(CodeSpecializationKind kind)
+    {
+        if (kind == CodeForCall)
+            return isGeneratedForCall();
+        ASSERT(kind == CodeForConstruct);
+        return isGeneratedForConstruct();
+    }
+        
+    FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind)
     {
-        ASSERT(m_executable);
-        return m_executable->isHostFunction();
+        if (kind == CodeForCall)
+            return codeBlockForCall();
+        ASSERT(kind == CodeForConstruct);
+        return codeBlockForConstruct();
     }
 
-    inline NativeFunction JSFunction::nativeFunction()
+    FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
+        
+    FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
     {
-        ASSERT(isHostFunction());
-        return static_cast<NativeExecutable*>(m_executable.get())->function();
+        return baselineCodeBlockFor(kind);
     }
+
+    RefPtr<TypeSet> returnStatementTypeSet() 
+    {
+        if (!m_returnStatementTypeSet)
+            m_returnStatementTypeSet = TypeSet::create();
+
+        return m_returnStatementTypeSet;
+    }
+        
+    FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
+    bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
+    bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
+    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'!
+    SymbolTable* symbolTable(CodeSpecializationKind);
+
+    void clearUnlinkedCodeForRecompilation();
+    static void visitChildren(JSCell*, SlotVisitor&);
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
+    }
+
+    unsigned parametersStartOffset() const { return m_parametersStartOffset; }
+
+    void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
+    {
+        m_parametersStartOffset = parametersStartOffset;
+        m_typeProfilingStartOffset = typeProfilingStartOffset;
+        m_typeProfilingEndOffset = typeProfilingEndOffset;
+    }
+
+    DECLARE_INFO;
+        
+    void unlinkCalls();
+
+    void clearCode();
+    
+    InferredValue* singletonFunction() { return m_singletonFunction.get(); }
+
+private:
+    FunctionExecutable(
+        VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, 
+        unsigned lastLine, unsigned startColumn, unsigned endColumn);
+    
+    void finishCreation(VM&);
+
+    friend class ScriptExecutable;
+    
+    WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
+    RefPtr<FunctionCodeBlock> m_codeBlockForCall;
+    RefPtr<FunctionCodeBlock> m_codeBlockForConstruct;
+    RefPtr<TypeSet> m_returnStatementTypeSet;
+    unsigned m_parametersStartOffset;
+    WriteBarrier<InferredValue> m_singletonFunction;
+};
+
+inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
+{
+    switch (executable->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 (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