Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a...
[WebKit-https.git] / Source / JavaScriptCore / runtime / Executable.h
index 0cb3bb9..b506b1c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013-2016 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 "CodeBlockHash.h"
 #include "CodeSpecializationKind.h"
 #include "CompilationResult.h"
-#include "DFGPlan.h"
+#include "ExecutableInfo.h"
 #include "HandlerInfo.h"
-#include "JSFunction.h"
-#include "Interpreter.h"
+#include "InferredValue.h"
 #include "JITCode.h"
 #include "JSGlobalObject.h"
-#include "LLIntCLoop.h"
-#include "SamplingTool.h"
 #include "SourceCode.h"
+#include "TypeSet.h"
 #include "UnlinkedCodeBlock.h"
-#include <wtf/PassOwnPtr.h>
+#include "UnlinkedFunctionExecutable.h"
 
 namespace JSC {
 
@@ -48,10 +47,17 @@ class CodeBlock;
 class Debugger;
 class EvalCodeBlock;
 class FunctionCodeBlock;
+class JSScope;
+class JSWASMModule;
 class LLIntOffsetsExtractor;
 class ProgramCodeBlock;
+class ModuleProgramCodeBlock;
 class JSScope;
-    
+class WebAssemblyCodeBlock;
+class ModuleProgramCodeBlock;
+class JSModuleRecord;
+class JSScope;
+
 enum CompilationKind { FirstCompilation, OptimizingCompilation };
 
 inline bool isCall(CodeSpecializationKind kind)
@@ -62,18 +68,18 @@ inline bool isCall(CodeSpecializationKind kind)
     return false;
 }
 
-class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
-    friend class WTF::DoublyLinkedListNode<ExecutableBase>;
+class ExecutableBase : public JSCell {
     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)
+    ExecutableBase(VM& vm, Structure* structure, int numParameters, Intrinsic intrinsic)
         : JSCell(vm, structure)
         , m_numParametersForCall(numParameters)
         , m_numParametersForConstruct(numParameters)
+        , m_intrinsic(intrinsic)
     {
     }
 
@@ -84,19 +90,30 @@ protected:
 
 public:
     typedef JSCell Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
 
-#if ENABLE(JIT)
     static const bool needsDestruction = true;
-    static const bool hasImmortalStructure = true;
     static void destroy(JSCell*);
-#endif
         
     CodeBlockHash hashFor(CodeSpecializationKind) const;
 
-    bool isFunctionExecutable()
+    bool isEvalExecutable() const
+    {
+        return type() == EvalExecutableType;
+    }
+    bool isFunctionExecutable() const
     {
-        return structure()->typeInfo().type() == FunctionExecutableType;
+        return type() == FunctionExecutableType;
     }
+    bool isProgramExecutable() const
+    {
+        return type() == ProgramExecutableType;
+    }
+    bool isModuleProgramExecutable()
+    {
+        return type() == ModuleProgramExecutableType;
+    }
+
 
     bool isHostFunction() const
     {
@@ -104,21 +121,24 @@ public:
         return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
     }
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), info()); }
+#if ENABLE(WEBASSEMBLY)
+    bool isWebAssemblyExecutable() const
+    {
+        return type() == WebAssemblyExecutableType;
+    }
+#endif
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
         
     void clearCode();
 
     DECLARE_EXPORT_INFO;
 
 protected:
-    static const unsigned StructureFlags = 0;
     int m_numParametersForCall;
     int m_numParametersForConstruct;
 
 public:
-    static void clearCodeVirtual(ExecutableBase*);
-
-#if ENABLE(JIT)
     PassRefPtr<JITCode> generatedJITCodeForCall()
     {
         ASSERT(m_jitCodeForCall);
@@ -138,37 +158,53 @@ public:
         ASSERT(kind == CodeForConstruct);
         return generatedJITCodeForConstruct();
     }
-
-    MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
-    {
-        ASSERT(m_jitCodeForCall);
-        ASSERT(m_jitCodeForCallWithArityCheck);
-        return m_jitCodeForCallWithArityCheck;
+    
+    MacroAssemblerCodePtr entrypointFor(CodeSpecializationKind kind, ArityCheckMode arity)
+    {
+        // 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:
+                if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck)
+                    return result;
+                break;
+            case CodeForConstruct:
+                if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck)
+                    return result;
+                break;
+            }
+        }
+        MacroAssemblerCodePtr result =
+            generatedJITCodeFor(kind)->addressForCall(arity);
+        if (arity == MustCheckArity) {
+            // Cache the result; this is necessary for the JIT's virtual call optimizations.
+            switch (kind) {
+            case CodeForCall:
+                m_jitCodeForCallWithArityCheck = result;
+                break;
+            case CodeForConstruct:
+                m_jitCodeForConstructWithArityCheck = result;
+                break;
+            }
+        }
+        return result;
     }
 
-    MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
-    {
-        ASSERT(m_jitCodeForConstruct);
-        ASSERT(m_jitCodeForConstructWithArityCheck);
-        return m_jitCodeForConstructWithArityCheck;
-    }
-        
-    MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
+    static ptrdiff_t offsetOfJITCodeWithArityCheckFor(
+        CodeSpecializationKind kind)
     {
-        if (kind == CodeForCall)
-            return generatedJITCodeForCallWithArityCheck();
-        ASSERT(kind == CodeForConstruct);
-        return generatedJITCodeForConstructWithArityCheck();
-    }
-        
-    static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind)
-    {
-        if (kind == CodeForCall)
+        switch (kind) {
+        case CodeForCall:
             return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
-        ASSERT(kind == CodeForConstruct);
-        return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+        case CodeForConstruct:
+            return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
     }
-        
+    
     static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
     {
         if (kind == CodeForCall)
@@ -176,7 +212,6 @@ public:
         ASSERT(kind == CodeForConstruct);
         return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct);
     }
-#endif // ENABLE(JIT)
 
     bool hasJITCodeForCall() const
     {
@@ -197,7 +232,7 @@ public:
     }
 
     // Intrinsics are only for calls, currently.
-    Intrinsic intrinsic() const;
+    Intrinsic intrinsic() const { return m_intrinsic; }
         
     Intrinsic intrinsicFor(CodeSpecializationKind kind) const
     {
@@ -205,92 +240,27 @@ public:
             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)
-
+    void dump(PrintStream&) const;
+        
 protected:
-    ExecutableBase* m_prev;
-    ExecutableBase* m_next;
-
+    Intrinsic m_intrinsic;
     RefPtr<JITCode> m_jitCodeForCall;
     RefPtr<JITCode> m_jitCodeForConstruct;
     MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
     MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
 };
 
-class NativeExecutable : public ExecutableBase {
+class NativeExecutable final : public ExecutableBase {
     friend class JIT;
     friend class LLIntOffsetsExtractor;
 public:
     typedef ExecutableBase Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-#if ENABLE(JIT)
-    static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
-    {
-        NativeExecutable* executable;
-        if (!callThunk) {
-            executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
-            executable->finishCreation(vm, 0, 0, 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
-
-#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
+    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name);
 
-#if ENABLE(JIT)
     static void destroy(JSCell*);
-#endif
 
     CodeBlockHash hashFor(CodeSpecializationKind) const;
 
@@ -313,115 +283,113 @@ public:
         return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
     }
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), info()); }
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue proto);
         
     DECLARE_INFO;
 
-    Intrinsic intrinsic() const;
+    const String& name() const { return m_name; }
 
 protected:
-#if ENABLE(JIT)
-    void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic)
-    {
-        Base::finishCreation(vm);
-        m_jitCodeForCallWithArityCheck = callThunk ? callThunk->addressForCall() : MacroAssemblerCodePtr();
-        m_jitCodeForConstructWithArityCheck = constructThunk ? constructThunk->addressForCall() : MacroAssemblerCodePtr();
-        m_jitCodeForCall = callThunk;
-        m_jitCodeForConstruct = constructThunk;
-        m_intrinsic = intrinsic;
-    }
-#endif
+    void finishCreation(VM&, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name);
 
 private:
-    NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
-        : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
-        , m_function(function)
-        , m_constructor(constructor)
-    {
-    }
+    friend class ExecutableBase;
+
+    NativeExecutable(VM&, NativeFunction function, NativeFunction constructor, Intrinsic);
 
     NativeFunction m_function;
     NativeFunction m_constructor;
-        
-    Intrinsic m_intrinsic;
+
+    String m_name;
 };
 
 class ScriptExecutable : public ExecutableBase {
 public:
     typedef ExecutableBase Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
 
-    ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext)
-        : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
-        , m_source(source)
-        , m_features(isInStrictContext ? StrictModeFeature : 0)
-        , m_neverInline(false)
-    {
-    }
-
-    ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
-        : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED)
-        , m_source(source)
-        , m_features(isInStrictContext ? StrictModeFeature : 0)
-        , m_neverInline(false)
-    {
-    }
-
-#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 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 isArrowFunctionContext() const { return m_isArrowFunctionContext; }
     bool isStrictMode() const { return m_features & StrictModeFeature; }
+    DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
+    EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
+
+    ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
         
     void setNeverInline(bool value) { m_neverInline = value; }
+    void setNeverOptimize(bool value) { m_neverOptimize = value; }
+    void setNeverFTLOptimize(bool value) { m_neverFTLOptimize = value; }
+    void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; }
     bool neverInline() const { return m_neverInline; }
+    bool neverOptimize() const { return m_neverOptimize; }
+    bool neverFTLOptimize() const { return m_neverFTLOptimize; }
+    bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; }
     bool isInliningCandidate() const { return !neverInline(); }
+    bool isOkToOptimize() const { return !neverOptimize(); }
+    
+    bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; }
 
-    void unlinkCalls();
-        
     CodeFeatures features() const { return m_features; }
         
-    DECLARE_INFO;
+    DECLARE_EXPORT_INFO;
 
-    void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn)
+    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;
     }
 
     void installCode(CodeBlock*);
-    PassRefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSScope*, JSObject*& exception);
-    PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind);
-    
-    JSObject* prepareForExecution(ExecState* exec, JSScope* scope, CodeSpecializationKind kind)
-    {
-        if (hasJITCodeFor(kind))
-            return 0;
-        return prepareForExecutionImpl(exec, scope, kind);
-    }
+    void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind);
+    CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
+    CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
+
+    // This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock
+    // that is not jettisoned before this function returns. Callers are essentially asking for a strong reference
+    // to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in
+    // their CodeBlock*& reference because it's safe for CodeBlock to be jettisoned if Executable is the only thing
+    // to point to it. This forces callers to have a CodeBlock* in a register or on the stack that will be marked
+    // by conservative GC if a GC happens after we create the CodeBlock.
+    template <typename ExecutableType>
+    JSObject* prepareForExecution(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock);
+
+    template <typename Functor> void forEachCodeBlock(Functor&&);
 
 private:
-    JSObject* prepareForExecutionImpl(ExecState*, JSScope*, CodeSpecializationKind);
+    friend class ExecutableBase;
+    JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
 
 protected:
+    ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, EvalContextType, Intrinsic);
+
     void finishCreation(VM& vm)
     {
         Base::finishCreation(vm);
-        vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
+        vm.heap.addExecutable(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
 
 #if ENABLE(CODEBLOCK_SAMPLING)
         if (SamplingTool* sampler = vm.interpreter->sampler())
@@ -429,39 +397,46 @@ protected:
 #endif
     }
 
-    SourceCode m_source;
     CodeFeatures m_features;
-    bool m_hasCapturedVariables;
-    bool m_neverInline;
+    bool m_didTryToEnterInLoop;
+    bool m_hasCapturedVariables : 1;
+    bool m_neverInline : 1;
+    bool m_neverOptimize : 1;
+    bool m_neverFTLOptimize : 1;
+    bool m_isArrowFunctionContext : 1;
+    unsigned m_derivedContextType : 2; // DerivedContextType
+    unsigned m_evalContextType : 2; // EvalContextType
+
+    int m_overrideLineNumber;
     int m_firstLine;
     int m_lastLine;
     unsigned m_startColumn;
+    unsigned m_endColumn;
+    unsigned m_typeProfilingStartOffset;
+    unsigned m_typeProfilingEndOffset;
+    SourceCode m_source;
 };
 
-class EvalExecutable : public ScriptExecutable {
+class EvalExecutable final : public ScriptExecutable {
     friend class LLIntOffsetsExtractor;
 public:
     typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
     static void destroy(JSCell*);
 
-#if ENABLE(JIT)
-    void jettisonOptimizedCode(VM&);
-#endif
-
     EvalCodeBlock* codeBlock()
     {
         return m_evalCodeBlock.get();
     }
 
-    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext);
+    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*);
 
-#if ENABLE(JIT)
     PassRefPtr<JITCode> generatedJITCode()
     {
         return generatedJITCodeForCall();
     }
-#endif
+
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
     {
         return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), info());
@@ -469,30 +444,28 @@ public:
         
     DECLARE_INFO;
 
-    void unlinkCalls();
-
-    void clearCode();
-
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext(), false, evalContextType()); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
 
 private:
+    friend class ExecutableBase;
     friend class ScriptExecutable;
-    static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
-    EvalExecutable(ExecState*, const SourceCode&, bool);
+
+    EvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    RefPtr<EvalCodeBlock> m_evalCodeBlock;
+    WriteBarrier<EvalCodeBlock> m_evalCodeBlock;
     WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
 };
 
-class ProgramExecutable : public ScriptExecutable {
+class ProgramExecutable final : public ScriptExecutable {
     friend class LLIntOffsetsExtractor;
 public:
     typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
     static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
     {
@@ -506,10 +479,6 @@ public:
 
     static void destroy(JSCell*);
 
-#if ENABLE(JIT)
-    void jettisonOptimizedCode(VM&);
-#endif
-
     ProgramCodeBlock* codeBlock()
     {
         return m_programCodeBlock.get();
@@ -517,12 +486,10 @@ public:
 
     JSObject* checkSyntax(ExecState*);
 
-#if ENABLE(JIT)
     PassRefPtr<JITCode> generatedJITCode()
     {
         return generatedJITCodeForCall();
     }
-#endif
         
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
     {
@@ -530,43 +497,89 @@ public:
     }
         
     DECLARE_INFO;
-        
-    void unlinkCalls();
-
-    void clearCode();
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext(), false, EvalContextType::None); }
 
 private:
+    friend class ExecutableBase;
     friend class ScriptExecutable;
-    
-    static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
 
     ProgramExecutable(ExecState*, const SourceCode&);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
     WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
-    RefPtr<ProgramCodeBlock> m_programCodeBlock;
+    WriteBarrier<ProgramCodeBlock> m_programCodeBlock;
+};
+
+class ModuleProgramExecutable final : public ScriptExecutable {
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static ModuleProgramExecutable* create(ExecState*, const SourceCode&);
+
+    static void destroy(JSCell*);
+
+    ModuleProgramCodeBlock* codeBlock()
+    {
+        return m_moduleProgramCodeBlock.get();
+    }
+
+    PassRefPtr<JITCode> generatedJITCode()
+    {
+        return generatedJITCodeForCall();
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(ModuleProgramExecutableType, StructureFlags), info());
+    }
+
+    DECLARE_INFO;
+
+    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), isArrowFunctionContext(), false, EvalContextType::None); }
+
+    UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
+
+    SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
+
+private:
+    friend class ExecutableBase;
+    friend class ScriptExecutable;
+
+    ModuleProgramExecutable(ExecState*, const SourceCode&);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    WriteBarrier<UnlinkedModuleProgramCodeBlock> m_unlinkedModuleProgramCodeBlock;
+    WriteBarrier<SymbolTable> m_moduleEnvironmentSymbolTable;
+    WriteBarrier<ModuleProgramCodeBlock> m_moduleProgramCodeBlock;
 };
 
-class FunctionExecutable : public ScriptExecutable {
+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)
+    static FunctionExecutable* create(
+        VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, 
+        unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, Intrinsic intrinsic)
     {
-        FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn);
+        FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn, intrinsic);
         executable->finishCreation(vm);
         return executable;
     }
-    static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
+    static FunctionExecutable* fromGlobalCode(
+        const Identifier& name, ExecState&, const SourceCode&, 
+        JSObject*& exception, int overrideLineNumber);
 
     static void destroy(JSCell*);
         
-    UnlinkedFunctionExecutable* unlinkedExecutable()
+    UnlinkedFunctionExecutable* unlinkedExecutable() const
     {
         return m_unlinkedExecutable.get();
     }
@@ -581,13 +594,9 @@ public:
         return m_codeBlockForConstruct.get();
     }
         
-#if ENABLE(JIT)
-    void jettisonOptimizedCodeForCall(VM&);
-#endif
-
     bool isGeneratedForCall() const
     {
-        return m_codeBlockForCall;
+        return !!m_codeBlockForCall;
     }
 
     FunctionCodeBlock* codeBlockForCall()
@@ -595,13 +604,9 @@ public:
         return m_codeBlockForCall.get();
     }
 
-#if ENABLE(JIT)
-    void jettisonOptimizedCodeForConstruct(VM&);
-#endif
-
     bool isGeneratedForConstruct() const
     {
-        return m_codeBlockForConstruct;
+        return m_codeBlockForConstruct.get();
     }
 
     FunctionCodeBlock* codeBlockForConstruct()
@@ -609,18 +614,6 @@ public:
         return m_codeBlockForConstruct.get();
     }
         
-#if ENABLE(JIT)
-    void jettisonOptimizedCodeFor(VM& vm, CodeSpecializationKind kind)
-    {
-        if (kind == CodeForCall) 
-            jettisonOptimizedCodeForCall(vm);
-        else {
-            ASSERT(kind == CodeForConstruct);
-            jettisonOptimizedCodeForConstruct(vm);
-        }
-    }
-#endif
-        
     bool isGeneratedFor(CodeSpecializationKind kind)
     {
         if (kind == CodeForCall)
@@ -643,86 +636,130 @@ public:
     {
         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(); }
+    ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
+    bool isClass() const { return !classSource().isNull(); }
+    bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+    bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
+    bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
+    DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
+    bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
     const Identifier& name() { return m_unlinkedExecutable->name(); }
+    const Identifier& ecmaName() { return m_unlinkedExecutable->ecmaName(); }
     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); }
+    SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
+    const SourceCode& classSource() const { return m_unlinkedExecutable->classSource(); }
 
-    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), 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);
+    friend class ExecutableBase;
+    FunctionExecutable(
+        VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, 
+        unsigned lastLine, unsigned startColumn, unsigned endColumn, Intrinsic);
+    
+    void finishCreation(VM&);
 
-    bool isCompiling()
+    friend class ScriptExecutable;
+    
+    unsigned m_parametersStartOffset;
+    WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
+    WriteBarrier<FunctionCodeBlock> m_codeBlockForCall;
+    WriteBarrier<FunctionCodeBlock> m_codeBlockForConstruct;
+    RefPtr<TypeSet> m_returnStatementTypeSet;
+    WriteBarrier<InferredValue> m_singletonFunction;
+};
+
+#if ENABLE(WEBASSEMBLY)
+class WebAssemblyExecutable final : public ExecutableBase {
+public:
+    typedef ExecutableBase Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static WebAssemblyExecutable* create(VM& vm, const SourceCode& source, JSWASMModule* module, unsigned functionIndex)
     {
-#if ENABLE(JIT)
-        if (!m_jitCodeForCall && m_codeBlockForCall)
-            return true;
-        if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
-            return true;
-#endif
-        return false;
+        WebAssemblyExecutable* executable = new (NotNull, allocateCell<WebAssemblyExecutable>(vm.heap)) WebAssemblyExecutable(vm, source, module, functionIndex);
+        executable->finishCreation(vm);
+        return executable;
     }
 
-    friend class ScriptExecutable;
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(WebAssemblyExecutableType, StructureFlags), info());
+    }
 
-    static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
-    WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
-    RefPtr<FunctionCodeBlock> m_codeBlockForCall;
-    RefPtr<FunctionCodeBlock> m_codeBlockForConstruct;
-};
+    static void destroy(JSCell*);
 
-inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
-{
-    JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
-    if (!function || !function->isHostFunction())
-        return false;
-    return function->nativeFunction() == nativeFunction;
-}
+    DECLARE_INFO;
 
-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();
+    void prepareForExecution(ExecState*);
+
+    WebAssemblyCodeBlock* codeBlockForCall()
+    {
+        return m_codeBlockForCall.get();
     }
-}
 
-inline void ScriptExecutable::unlinkCalls()
+private:
+    friend class ExecutableBase;
+    WebAssemblyExecutable(VM&, const SourceCode&, JSWASMModule*, unsigned functionIndex);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    SourceCode m_source;
+    WriteBarrier<JSWASMModule> m_module;
+    unsigned m_functionIndex;
+
+    WriteBarrier<WebAssemblyCodeBlock> m_codeBlockForCall;
+};
+#endif
+
+template <typename ExecutableType>
+JSObject* ScriptExecutable::prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
 {
-    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();
-    }
+    if (hasJITCodeFor(kind)) {
+        if (std::is_same<ExecutableType, EvalExecutable>::value)
+            resultCodeBlock = jsCast<CodeBlock*>(jsCast<EvalExecutable*>(this)->codeBlock());
+        else if (std::is_same<ExecutableType, ProgramExecutable>::value)
+            resultCodeBlock = jsCast<CodeBlock*>(jsCast<ProgramExecutable*>(this)->codeBlock());
+        else if (std::is_same<ExecutableType, ModuleProgramExecutable>::value)
+            resultCodeBlock = jsCast<CodeBlock*>(jsCast<ModuleProgramExecutable*>(this)->codeBlock());
+        else if (std::is_same<ExecutableType, FunctionExecutable>::value)
+            resultCodeBlock = jsCast<CodeBlock*>(jsCast<FunctionExecutable*>(this)->codeBlockFor(kind));
+        else
+            RELEASE_ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+    return prepareForExecutionImpl(exec, function, scope, kind, resultCodeBlock);
 }
 
-}
+} // namespace JSC
 
-#endif
+#endif // Executable_h