/* | |
* Copyright (C) 2009 Apple Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
#ifndef Executable_h | |
#define Executable_h | |
#include "JSFunction.h" | |
#include "Interpreter.h" | |
#include "Nodes.h" | |
#include "SamplingTool.h" | |
namespace JSC { | |
class CodeBlock; | |
class Debugger; | |
class EvalCodeBlock; | |
class ProgramCodeBlock; | |
class ScopeChainNode; | |
struct ExceptionInfo; | |
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; | |
public: | |
ExecutableBase(int numParameters) | |
: m_numParameters(numParameters) | |
{ | |
} | |
virtual ~ExecutableBase() {} | |
bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } | |
protected: | |
int m_numParameters; | |
#if ENABLE(JIT) | |
public: | |
JITCode& generatedJITCode() | |
{ | |
ASSERT(m_jitCode); | |
return m_jitCode; | |
} | |
ExecutablePool* getExecutablePool() | |
{ | |
return m_jitCode.getExecutablePool(); | |
} | |
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())); | |
} | |
~NativeExecutable(); | |
}; | |
#endif | |
class VPtrHackExecutable : public ExecutableBase { | |
public: | |
VPtrHackExecutable() | |
: ExecutableBase(NUM_PARAMETERS_IS_HOST) | |
{ | |
} | |
~VPtrHackExecutable(); | |
}; | |
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 | |
} | |
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); | |
#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; } | |
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; | |
protected: | |
void recordParse(CodeFeatures features, int firstLine, int lastLine) | |
{ | |
m_features = features; | |
m_firstLine = firstLine; | |
m_lastLine = lastLine; | |
} | |
SourceCode m_source; | |
CodeFeatures m_features; | |
int m_firstLine; | |
int m_lastLine; | |
}; | |
class EvalExecutable : public ScriptExecutable { | |
public: | |
~EvalExecutable(); | |
EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) | |
{ | |
if (!m_evalCodeBlock) { | |
JSObject* error = compile(exec, scopeChainNode); | |
ASSERT_UNUSED(!error, error); | |
} | |
return *m_evalCodeBlock; | |
} | |
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* m_evalCodeBlock; | |
#if ENABLE(JIT) | |
public: | |
JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) | |
{ | |
if (!m_jitCode) | |
generateJITCode(exec, scopeChainNode); | |
return m_jitCode; | |
} | |
private: | |
void generateJITCode(ExecState*, ScopeChainNode*); | |
#endif | |
}; | |
class ProgramExecutable : public ScriptExecutable { | |
public: | |
static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) | |
{ | |
return adoptRef(new ProgramExecutable(exec, source)); | |
} | |
~ProgramExecutable(); | |
ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) | |
{ | |
if (!m_programCodeBlock) { | |
JSObject* error = compile(exec, scopeChainNode); | |
ASSERT_UNUSED(!error, error); | |
} | |
return *m_programCodeBlock; | |
} | |
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* m_programCodeBlock; | |
#if ENABLE(JIT) | |
public: | |
JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) | |
{ | |
if (!m_jitCode) | |
generateJITCode(exec, scopeChainNode); | |
return m_jitCode; | |
} | |
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)); | |
} | |
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)); | |
} | |
~FunctionExecutable(); | |
JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) | |
{ | |
return new (exec) JSFunction(exec, this, scopeChain); | |
} | |
CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) | |
{ | |
ASSERT(scopeChainNode); | |
if (!m_codeBlock) | |
compile(exec, scopeChainNode); | |
return *m_codeBlock; | |
} | |
bool isGenerated() const | |
{ | |
return m_codeBlock; | |
} | |
CodeBlock& generatedBytecode() | |
{ | |
ASSERT(m_codeBlock); | |
return *m_codeBlock; | |
} | |
const Identifier& name() { return m_name; } | |
size_t parameterCount() const { return m_parameters->size(); } | |
size_t variableCount() const { return m_numVariables; } | |
UString paramString() const; | |
#ifdef QT_BUILD_SCRIPT_LIB | |
UString parameterName(int i) const { return (*m_parameters)[i].ustring(); } | |
#endif | |
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; | |
} | |
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; | |
} | |
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; | |
} | |
private: | |
void generateJITCode(ExecState*, ScopeChainNode*); | |
#endif | |
}; | |
inline FunctionExecutable* JSFunction::jsExecutable() const | |
{ | |
ASSERT(!isHostFunctionNonInline()); | |
return static_cast<FunctionExecutable*>(m_executable.get()); | |
} | |
inline bool JSFunction::isHostFunction() const | |
{ | |
ASSERT(m_executable); | |
return m_executable->isHostFunction(); | |
} | |
} | |
#endif |