Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a...
[WebKit-https.git] / Source / JavaScriptCore / runtime / Executable.h
index 9fc9be7..b506b1c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2010, 2013-2015 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
@@ -36,7 +36,6 @@
 #include "InferredValue.h"
 #include "JITCode.h"
 #include "JSGlobalObject.h"
-#include "SamplingTool.h"
 #include "SourceCode.h"
 #include "TypeSet.h"
 #include "UnlinkedCodeBlock.h"
@@ -76,10 +75,11 @@ 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)
     {
     }
 
@@ -232,7 +232,7 @@ public:
     }
 
     // Intrinsics are only for calls, currently.
-    Intrinsic intrinsic() const;
+    Intrinsic intrinsic() const { return m_intrinsic; }
         
     Intrinsic intrinsicFor(CodeSpecializationKind kind) const
     {
@@ -244,6 +244,7 @@ public:
     void dump(PrintStream&) const;
         
 protected:
+    Intrinsic m_intrinsic;
     RefPtr<JITCode> m_jitCodeForCall;
     RefPtr<JITCode> m_jitCodeForConstruct;
     MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
@@ -257,13 +258,7 @@ 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;
-    }
+    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name);
 
     static void destroy(JSCell*);
 
@@ -288,35 +283,24 @@ public:
         return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
     }
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue proto);
         
     DECLARE_INFO;
 
-    Intrinsic intrinsic() const;
+    const String& name() const { return m_name; }
 
 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;
-    }
+    void finishCreation(VM&, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name);
 
 private:
     friend class ExecutableBase;
 
-    NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
-        : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
-        , m_function(function)
-        , m_constructor(constructor)
-    {
-    }
+    NativeExecutable(VM&, NativeFunction function, NativeFunction constructor, Intrinsic);
 
     NativeFunction m_function;
     NativeFunction m_constructor;
-        
-    Intrinsic m_intrinsic;
+
+    String m_name;
 };
 
 class ScriptExecutable : public ExecutableBase {
@@ -343,15 +327,20 @@ public:
 
     bool usesEval() const { return m_features & EvalFeature; }
     bool usesArguments() const { return m_features & ArgumentsFeature; }
-    bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature); }
+    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(); }
@@ -378,22 +367,24 @@ public:
     void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind);
     CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
     CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
-    
-    JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
-    {
-        if (hasJITCodeFor(kind))
-            return 0;
-        return prepareForExecutionImpl(exec, function, scope, kind);
-    }
+
+    // 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:
     friend class ExecutableBase;
-    JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
+    JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
 
 protected:
-    ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext);
+    ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, EvalContextType, Intrinsic);
 
     void finishCreation(VM& vm)
     {
@@ -406,12 +397,16 @@ protected:
 #endif
     }
 
-    SourceCode m_source;
     CodeFeatures m_features;
-    bool m_hasCapturedVariables;
-    bool m_neverInline;
-    bool m_neverOptimize { false };
     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;
@@ -419,6 +414,7 @@ protected:
     unsigned m_endColumn;
     unsigned m_typeProfilingStartOffset;
     unsigned m_typeProfilingEndOffset;
+    SourceCode m_source;
 };
 
 class EvalExecutable final : public ScriptExecutable {
@@ -434,7 +430,7 @@ public:
         return m_evalCodeBlock.get();
     }
 
-    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, const VariableEnvironment*);
+    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*);
 
     PassRefPtr<JITCode> generatedJITCode()
     {
@@ -448,7 +444,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, 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(); }
@@ -456,7 +452,8 @@ public:
 private:
     friend class ExecutableBase;
     friend class ScriptExecutable;
-    EvalExecutable(ExecState*, const SourceCode&, bool);
+
+    EvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
@@ -501,7 +498,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, 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;
@@ -542,7 +539,8 @@ public:
 
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    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(); }
@@ -569,9 +567,9 @@ public:
 
     static FunctionExecutable* create(
         VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, 
-        unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
+        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, endColumn);
+        FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn, intrinsic);
         executable->finishCreation(vm);
         return executable;
     }
@@ -650,12 +648,18 @@ public:
     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
-    bool isArrowFunction() const { return m_unlinkedExecutable->isArrowFunction(); }
+    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'!
+    SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
+    const SourceCode& classSource() const { return m_unlinkedExecutable->classSource(); }
 
     static void visitChildren(JSCell*, SlotVisitor&);
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
@@ -680,17 +684,17 @@ private:
     friend class ExecutableBase;
     FunctionExecutable(
         VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, 
-        unsigned lastLine, unsigned startColumn, unsigned endColumn);
+        unsigned lastLine, unsigned startColumn, unsigned endColumn, Intrinsic);
     
     void finishCreation(VM&);
 
     friend class ScriptExecutable;
     
+    unsigned m_parametersStartOffset;
     WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
     WriteBarrier<FunctionCodeBlock> m_codeBlockForCall;
     WriteBarrier<FunctionCodeBlock> m_codeBlockForConstruct;
     RefPtr<TypeSet> m_returnStatementTypeSet;
-    unsigned m_parametersStartOffset;
     WriteBarrier<InferredValue> m_singletonFunction;
 };
 
@@ -737,6 +741,25 @@ private:
 };
 #endif
 
+template <typename ExecutableType>
+JSObject* ScriptExecutable::prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
+{
+    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 // Executable_h