/*
- * Copyright (C) 2009 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 "JSFunction.h"
-#include "Interpreter.h"
-#include "Nodes.h"
+#include "ArityCheckMode.h"
+#include "CallData.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 "SourceCode.h"
+#include "TypeSet.h"
+#include "UnlinkedCodeBlock.h"
namespace JSC {
- class CodeBlock;
- class Debugger;
- class EvalCodeBlock;
- 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 RefCounted<ExecutableBase> {
- 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(int numParameters)
- : m_numParameters(numParameters)
- {
- }
+ ExecutableBase(VM& vm, Structure* structure, int numParameters)
+ : JSCell(vm, structure)
+ , m_numParametersForCall(numParameters)
+ , m_numParametersForConstruct(numParameters)
+ {
+ }
- virtual ~ExecutableBase() {}
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ }
- bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
- protected:
- int m_numParameters;
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ CodeBlockHash hashFor(CodeSpecializationKind) const;
-#if ENABLE(JIT)
- public:
- JITCode& generatedJITCode()
- {
- ASSERT(m_jitCode);
- return m_jitCode;
- }
+ bool isEvalExecutable()
+ {
+ return type() == EvalExecutableType;
+ }
+ bool isFunctionExecutable()
+ {
+ return type() == FunctionExecutableType;
+ }
+ bool isProgramExecutable()
+ {
+ return type() == ProgramExecutableType;
+ }
+
+ bool isHostFunction() const
+ {
+ ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+ return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
+ }
+
+ 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:
+ int m_numParametersForCall;
+ int m_numParametersForConstruct;
- ExecutablePool* getExecutablePool()
- {
- return m_jitCode.getExecutablePool();
+public:
+ static void clearCodeVirtual(ExecutableBase*);
+
+ PassRefPtr<JITCode> generatedJITCodeForCall()
+ {
+ ASSERT(m_jitCodeForCall);
+ return m_jitCodeForCall;
+ }
+
+ PassRefPtr<JITCode> generatedJITCodeForConstruct()
+ {
+ ASSERT(m_jitCodeForConstruct);
+ return m_jitCodeForConstruct;
+ }
+
+ PassRefPtr<JITCode> generatedJITCodeFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return generatedJITCodeForCall();
+ ASSERT(kind == CodeForConstruct);
+ return generatedJITCodeForConstruct();
+ }
+
+ 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;
+ }
- protected:
- JITCode m_jitCode;
-#endif
- };
-
-#if ENABLE(JIT)
- class NativeExecutable : public ExecutableBase {
- public:
- NativeExecutable(ExecState* exec)
- : ExecutableBase(NUM_PARAMETERS_IS_HOST)
- {
- m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk()));
+ 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);
+ }
- ~NativeExecutable();
- };
-#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();
+ }
- class VPtrHackExecutable : public ExecutableBase {
- public:
- VPtrHackExecutable()
- : ExecutableBase(NUM_PARAMETERS_IS_HOST)
- {
- }
+ // 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;
+ }
- ~VPtrHackExecutable();
- };
+ static void destroy(JSCell*);
- class ScriptExecutable : public ExecutableBase {
- public:
- ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
- : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
- , m_source(source)
- , m_features(0)
- {
-#if ENABLE(CODEBLOCK_SAMPLING)
- if (SamplingTool* sampler = globalData->interpreter->sampler())
- sampler->notifyOfScope(this);
-#else
- UNUSED_PARAM(globalData);
-#endif
- }
+ CodeBlockHash hashFor(CodeSpecializationKind) const;
+
+ NativeFunction function() { return m_function; }
+ NativeFunction constructor() { return m_constructor; }
+
+ NativeFunction nativeFunctionFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return function();
+ ASSERT(kind == CodeForConstruct);
+ return constructor();
+ }
+
+ static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return OBJECT_OFFSETOF(NativeExecutable, m_function);
+ ASSERT(kind == CodeForConstruct);
+ return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
+
+ DECLARE_INFO;
+
+ Intrinsic intrinsic() const;
+
+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;
+ }
+
+private:
+ NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
+ : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+ , m_function(function)
+ , m_constructor(constructor)
+ {
+ }
+
+ NativeFunction m_function;
+ NativeFunction m_constructor;
+
+ Intrinsic m_intrinsic;
+};
+
+class ScriptExecutable : public ExecutableBase {
+public:
+ typedef ExecutableBase Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ 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; }
+
+ void unlinkCalls();
+
+ CodeFeatures features() const { return m_features; }
+
+ DECLARE_INFO;
+
+ 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*);
+ 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().
- ScriptExecutable(ExecState* exec, const SourceCode& source)
- : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
- , m_source(source)
- , m_features(0)
- {
#if ENABLE(CODEBLOCK_SAMPLING)
- if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
- sampler->notifyOfScope(this);
-#else
- UNUSED_PARAM(exec);
+ if (SamplingTool* sampler = vm.interpreter->sampler())
+ sampler->notifyOfScope(vm, this);
#endif
- }
+ }
- const SourceCode& source() { return m_source; }
- intptr_t sourceID() const { return m_source.provider()->asID(); }
- const UString& sourceURL() const { return m_source.provider()->url(); }
- int lineNo() const { return m_firstLine; }
- int lastLine() const { return m_lastLine; }
+ 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();
+ }
- bool usesEval() const { return m_features & EvalFeature; }
- bool usesArguments() const { return m_features & ArgumentsFeature; }
- bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+ static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode);
- virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
+ PassRefPtr<JITCode> generatedJITCode()
+ {
+ return generatedJITCodeForCall();
+ }
- protected:
- void recordParse(CodeFeatures features, int firstLine, int lastLine)
- {
- m_features = features;
- m_firstLine = firstLine;
- m_lastLine = lastLine;
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
- SourceCode m_source;
- CodeFeatures m_features;
- int m_firstLine;
- int m_lastLine;
- };
+ void unlinkCalls();
- class EvalExecutable : public ScriptExecutable {
- public:
+ void clearCode();
- ~EvalExecutable();
+ ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
- EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- if (!m_evalCodeBlock) {
- JSObject* error = compile(exec, scopeChainNode);
- ASSERT_UNUSED(!error, error);
- }
- return *m_evalCodeBlock;
- }
+ unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
+ unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
- JSObject* compile(ExecState*, ScopeChainNode*);
+private:
+ friend class ScriptExecutable;
+ EvalExecutable(ExecState*, const SourceCode&, bool);
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
- static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
+ static void visitChildren(JSCell*, SlotVisitor&);
- private:
- EvalExecutable(ExecState* exec, const SourceCode& source)
- : ScriptExecutable(exec, source)
- , m_evalCodeBlock(0)
- {
- }
- EvalCodeBlock* m_evalCodeBlock;
-
-#if ENABLE(JIT)
- public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
- }
+ RefPtr<EvalCodeBlock> m_evalCodeBlock;
+ WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
+};
- private:
- void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
- };
+class ProgramExecutable final : public ScriptExecutable {
+ friend class LLIntOffsetsExtractor;
+public:
+ typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- class ProgramExecutable : public ScriptExecutable {
- public:
- static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
- {
- return adoptRef(new ProgramExecutable(exec, source));
- }
+ 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;
+ }
- ~ProgramExecutable();
- ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- if (!m_programCodeBlock) {
- JSObject* error = compile(exec, scopeChainNode);
- ASSERT_UNUSED(!error, error);
- }
- return *m_programCodeBlock;
- }
+ JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*);
- JSObject* checkSyntax(ExecState*);
- JSObject* compile(ExecState*, ScopeChainNode*);
+ static void destroy(JSCell*);
- // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information.
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
+ ProgramCodeBlock* codeBlock()
+ {
+ return m_programCodeBlock.get();
+ }
- private:
- ProgramExecutable(ExecState* exec, const SourceCode& source)
- : ScriptExecutable(exec, source)
- , m_programCodeBlock(0)
- {
- }
- ProgramCodeBlock* m_programCodeBlock;
-
-#if ENABLE(JIT)
- public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
- }
+ JSObject* checkSyntax(ExecState*);
- private:
- void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
- };
-
- class FunctionExecutable : public ScriptExecutable {
- friend class JIT;
- public:
- static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- {
- return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
- }
+ PassRefPtr<JITCode> generatedJITCode()
+ {
+ return generatedJITCodeForCall();
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+ void unlinkCalls();
- static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- {
- return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
- }
+ void clearCode();
- ~FunctionExecutable();
+ ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
- JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
- {
- return new (exec) JSFunction(exec, this, scopeChain);
- }
+private:
+ friend class ScriptExecutable;
- CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- ASSERT(scopeChainNode);
- if (!m_codeBlock)
- compile(exec, scopeChainNode);
- return *m_codeBlock;
- }
+ ProgramExecutable(ExecState*, const SourceCode&);
- bool isGenerated() const
- {
- return m_codeBlock;
- }
+ static void visitChildren(JSCell*, SlotVisitor&);
- CodeBlock& generatedBytecode()
- {
- ASSERT(m_codeBlock);
- return *m_codeBlock;
- }
+ WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
+ RefPtr<ProgramCodeBlock> m_programCodeBlock;
+};
- const Identifier& name() { return m_name; }
- size_t parameterCount() const { return m_parameters->size(); }
- size_t variableCount() const { return m_numVariables; }
- UString paramString() const;
-
- void recompile(ExecState*);
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
- void markAggregate(MarkStack& markStack);
- static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
-
- private:
- FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- : ScriptExecutable(globalData, source)
- , m_forceUsesArguments(forceUsesArguments)
- , m_parameters(parameters)
- , m_codeBlock(0)
- , m_name(name)
- , m_numVariables(0)
- {
- m_firstLine = firstLine;
- m_lastLine = lastLine;
- }
+class FunctionExecutable final : public ScriptExecutable {
+ friend class JIT;
+ friend class LLIntOffsetsExtractor;
+public:
+ typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- : ScriptExecutable(exec, source)
- , m_forceUsesArguments(forceUsesArguments)
- , m_parameters(parameters)
- , m_codeBlock(0)
- , m_name(name)
- , m_numVariables(0)
- {
- m_firstLine = firstLine;
- m_lastLine = lastLine;
- }
+ 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);
- void compile(ExecState*, ScopeChainNode*);
-
- bool m_forceUsesArguments;
- RefPtr<FunctionParameters> m_parameters;
- CodeBlock* m_codeBlock;
- Identifier m_name;
- size_t m_numVariables;
-
-#if ENABLE(JIT)
- public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
- {
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
- }
+ static void destroy(JSCell*);
+
+ UnlinkedFunctionExecutable* unlinkedExecutable()
+ {
+ return m_unlinkedExecutable.get();
+ }
- private:
- void generateJITCode(ExecState*, ScopeChainNode*);
-#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;
+ }
- inline FunctionExecutable* JSFunction::jsExecutable() const
+ FunctionCodeBlock* codeBlockForCall()
{
- ASSERT(!isHostFunctionNonInline());
- return static_cast<FunctionExecutable*>(m_executable.get());
+ return m_codeBlockForCall.get();
}
- inline bool JSFunction::isHostFunction() const
+ bool isGeneratedForConstruct() const
{
- ASSERT(m_executable);
- return m_executable->isHostFunction();
+ return m_codeBlockForConstruct;
}
+ FunctionCodeBlock* codeBlockForConstruct()
+ {
+ return m_codeBlockForConstruct.get();
+ }
+
+ bool isGeneratedFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return isGeneratedForCall();
+ ASSERT(kind == CodeForConstruct);
+ return isGeneratedForConstruct();
+ }
+
+ FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return codeBlockForCall();
+ ASSERT(kind == CodeForConstruct);
+ return codeBlockForConstruct();
+ }
+
+ FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
+
+ FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
+ {
+ 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