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