diff options
Diffstat (limited to 'JavaScriptCore/runtime/Executable.h')
| -rw-r--r-- | JavaScriptCore/runtime/Executable.h | 290 |
1 files changed, 172 insertions, 118 deletions
diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index f74abe9..14ed927 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,16 +26,19 @@ #ifndef Executable_h #define Executable_h +#include "CallData.h" #include "JSFunction.h" #include "Interpreter.h" #include "Nodes.h" #include "SamplingTool.h" +#include <wtf/PassOwnPtr.h> namespace JSC { class CodeBlock; class Debugger; class EvalCodeBlock; + class FunctionCodeBlock; class ProgramCodeBlock; class ScopeChainNode; @@ -50,45 +53,76 @@ namespace JSC { public: ExecutableBase(int numParameters) - : m_numParameters(numParameters) + : m_numParametersForCall(numParameters) + , m_numParametersForConstruct(numParameters) { } virtual ~ExecutableBase() {} - bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } + bool isHostFunction() const + { + ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); + return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; + } protected: - int m_numParameters; + int m_numParametersForCall; + int m_numParametersForConstruct; #if ENABLE(JIT) public: - JITCode& generatedJITCode() + JITCode& generatedJITCodeForCall() { - ASSERT(m_jitCode); - return m_jitCode; + ASSERT(m_jitCodeForCall); + return m_jitCodeForCall; } - ExecutablePool* getExecutablePool() + JITCode& generatedJITCodeForConstruct() { - return m_jitCode.getExecutablePool(); + ASSERT(m_jitCodeForConstruct); + return m_jitCodeForConstruct; } protected: - JITCode m_jitCode; + JITCode m_jitCodeForCall; + JITCode m_jitCodeForConstruct; + MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; + MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; #endif }; #if ENABLE(JIT) class NativeExecutable : public ExecutableBase { + friend class JIT; public: - NativeExecutable(ExecState* exec) - : ExecutableBase(NUM_PARAMETERS_IS_HOST) + static PassRefPtr<NativeExecutable> create(MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor) { - m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk())); + if (!callThunk) + return adoptRef(new NativeExecutable(JITCode(), function, JITCode(), constructor)); + return adoptRef(new NativeExecutable(JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor)); } ~NativeExecutable(); + + NativeFunction function() { return m_function; } + + private: + NativeExecutable(JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + , m_function(function) + , m_constructor(constructor) + { + m_jitCodeForCall = callThunk; + m_jitCodeForConstruct = constructThunk; + m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); + m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); + } + + NativeFunction m_function; + // Probably should be a NativeConstructor, but this will currently require rewriting the JIT + // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList. + NativeFunction m_constructor; }; #endif @@ -104,12 +138,13 @@ namespace JSC { class ScriptExecutable : public ExecutableBase { public: - ScriptExecutable(JSGlobalData* globalData, const SourceCode& source) + ScriptExecutable(JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext) : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) , m_source(source) - , m_features(0) + , m_features(isInStrictContext ? StrictModeFeature : 0) { #if ENABLE(CODEBLOCK_SAMPLING) + relaxAdoptionRequirement(); if (SamplingTool* sampler = globalData->interpreter->sampler()) sampler->notifyOfScope(this); #else @@ -117,12 +152,13 @@ namespace JSC { #endif } - ScriptExecutable(ExecState* exec, const SourceCode& source) + ScriptExecutable(ExecState* exec, const SourceCode& source, bool isInStrictContext) : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) , m_source(source) - , m_features(0) + , m_features(isInStrictContext ? StrictModeFeature : 0) { #if ENABLE(CODEBLOCK_SAMPLING) + relaxAdoptionRequirement(); if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) sampler->notifyOfScope(this); #else @@ -138,20 +174,21 @@ namespace JSC { bool usesEval() const { return m_features & EvalFeature; } bool usesArguments() const { return m_features & ArgumentsFeature; } - bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } - - virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; + bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } + bool isStrictMode() const { return m_features & StrictModeFeature; } protected: - void recordParse(CodeFeatures features, int firstLine, int lastLine) + void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) { m_features = features; + m_hasCapturedVariables = hasCapturedVariables; m_firstLine = firstLine; m_lastLine = lastLine; } SourceCode m_source; CodeFeatures m_features; + bool m_hasCapturedVariables; int m_firstLine; int m_lastLine; }; @@ -161,40 +198,36 @@ namespace JSC { ~EvalExecutable(); - EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) { - if (!m_evalCodeBlock) { - JSObject* error = compile(exec, scopeChainNode); - ASSERT_UNUSED(!error, error); - } - return *m_evalCodeBlock; + JSObject* error = 0; + if (!m_evalCodeBlock) + error = compileInternal(exec, scopeChainNode); + ASSERT(!error == !!m_evalCodeBlock); + return error; } - JSObject* compile(ExecState*, ScopeChainNode*); - - ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); - static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } - - private: - EvalExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec, source) - , m_evalCodeBlock(0) + EvalCodeBlock& generatedBytecode() { + ASSERT(m_evalCodeBlock); + return *m_evalCodeBlock; } - EvalCodeBlock* m_evalCodeBlock; + + static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return adoptRef(new EvalExecutable(exec, source, isInStrictContext)); } #if ENABLE(JIT) - public: - JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + JITCode& generatedJITCode() { - if (!m_jitCode) - generateJITCode(exec, scopeChainNode); - return m_jitCode; + return generatedJITCodeForCall(); } +#endif private: - void generateJITCode(ExecState*, ScopeChainNode*); -#endif + EvalExecutable(ExecState*, const SourceCode&, bool); + + JSObject* compileInternal(ExecState*, ScopeChainNode*); + + OwnPtr<EvalCodeBlock> m_evalCodeBlock; }; class ProgramExecutable : public ScriptExecutable { @@ -206,54 +239,49 @@ namespace JSC { ~ProgramExecutable(); - ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) { - if (!m_programCodeBlock) { - JSObject* error = compile(exec, scopeChainNode); - ASSERT_UNUSED(!error, error); - } - return *m_programCodeBlock; + JSObject* error = 0; + if (!m_programCodeBlock) + error = compileInternal(exec, scopeChainNode); + 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; } - - 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 private: - void generateJITCode(ExecState*, ScopeChainNode*); -#endif + ProgramExecutable(ExecState*, const SourceCode&); + + JSObject* compileInternal(ExecState*, ScopeChainNode*); + + OwnPtr<ProgramCodeBlock> m_programCodeBlock; }; 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) + static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine)); + return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine)); } - static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) + static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine)); + return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine)); } ~FunctionExecutable(); @@ -262,80 +290,99 @@ namespace JSC { { return new (exec) JSFunction(exec, this, scopeChain); } + + // Returns either call or construct bytecode. This can be appropriate + // for answering questions that that don't vary between call and construct -- + // for example, argumentsRegister(). + FunctionCodeBlock& generatedBytecode() + { + if (m_codeBlockForCall) + return *m_codeBlockForCall; + ASSERT(m_codeBlockForConstruct); + return *m_codeBlockForConstruct; + } + + JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode) + { + JSObject* error = 0; + if (!m_codeBlockForCall) + error = compileForCallInternal(exec, scopeChainNode); + ASSERT(!error == !!m_codeBlockForCall); + return error; + } + + bool isGeneratedForCall() const + { + return m_codeBlockForCall; + } + + FunctionCodeBlock& generatedBytecodeForCall() + { + ASSERT(m_codeBlockForCall); + return *m_codeBlockForCall; + } - CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { - ASSERT(scopeChainNode); - if (!m_codeBlock) - compile(exec, scopeChainNode); - return *m_codeBlock; + JSObject* error = 0; + if (!m_codeBlockForConstruct) + error = compileForConstructInternal(exec, scopeChainNode); + ASSERT(!error == !!m_codeBlockForConstruct); + return error; } - bool isGenerated() const + bool isGeneratedForConstruct() const { - return m_codeBlock; + return m_codeBlockForConstruct; } - CodeBlock& generatedBytecode() + FunctionCodeBlock& generatedBytecodeForConstruct() { - ASSERT(m_codeBlock); - return *m_codeBlock; + ASSERT(m_codeBlockForConstruct); + return *m_codeBlockForConstruct; } const Identifier& name() { return m_name; } size_t parameterCount() const { return m_parameters->size(); } - size_t variableCount() const { return m_numVariables; } + unsigned capturedVariableCount() const { return m_numCapturedVariables; } UString paramString() const; + SharedSymbolTable* symbolTable() const { return m_symbolTable; } 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); + void markAggregate(MarkStack&); + static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); 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; - } + FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); + FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); - 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; - } + JSObject* compileForCallInternal(ExecState*, ScopeChainNode*); + JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*); - void compile(ExecState*, ScopeChainNode*); + unsigned m_numCapturedVariables : 31; + bool m_forceUsesArguments : 1; - bool m_forceUsesArguments; RefPtr<FunctionParameters> m_parameters; - CodeBlock* m_codeBlock; + OwnPtr<FunctionCodeBlock> m_codeBlockForCall; + OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; Identifier m_name; - size_t m_numVariables; + SharedSymbolTable* m_symbolTable; #if ENABLE(JIT) public: - JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() { - if (!m_jitCode) - generateJITCode(exec, scopeChainNode); - return m_jitCode; + ASSERT(m_jitCodeForCall); + ASSERT(m_jitCodeForCallWithArityCheck); + return m_jitCodeForCallWithArityCheck; } - private: - void generateJITCode(ExecState*, ScopeChainNode*); + MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() + { + ASSERT(m_jitCodeForConstruct); + ASSERT(m_jitCodeForConstructWithArityCheck); + return m_jitCodeForConstructWithArityCheck; + } #endif }; @@ -351,6 +398,13 @@ namespace JSC { return m_executable->isHostFunction(); } +#if ENABLE(JIT) + inline NativeFunction JSFunction::nativeFunction() + { + ASSERT(isHostFunction()); + return static_cast<NativeExecutable*>(m_executable.get())->function(); + } +#endif } #endif |
