2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "JSFunction.h"
37 #include "LLIntData.h"
39 #include "RegisterFile.h"
41 #include <wtf/HashMap.h>
48 class FunctionExecutable
;
50 class LLIntOffsetsExtractor
;
51 class ProgramExecutable
;
55 struct CallFrameClosure
;
68 enum StackFrameCodeType
{
71 StackFrameFunctionCode
,
76 Strong
<JSObject
> callee
;
77 StackFrameCodeType codeType
;
78 Strong
<ExecutableBase
> executable
;
81 UString
toString(CallFrame
* callFrame
) const
83 bool hasSourceURLInfo
= !sourceURL
.isNull() && !sourceURL
.isEmpty();
84 bool hasLineInfo
= line
> -1;
86 JSObject
* stackFrameCallee
= callee
.get();
89 case StackFrameEvalCode
:
90 if (hasSourceURLInfo
) {
91 traceLine
= hasLineInfo
? String::format("eval code@%s:%d", sourceURL
.ascii().data(), line
)
92 : String::format("eval code@%s", sourceURL
.ascii().data());
94 traceLine
= String::format("eval code");
96 case StackFrameNativeCode
: {
98 UString functionName
= getCalculatedDisplayName(callFrame
, stackFrameCallee
);
99 traceLine
= String::format("%s@[native code]", functionName
.ascii().data());
101 traceLine
= "[native code]";
104 case StackFrameFunctionCode
: {
105 UString functionName
= getCalculatedDisplayName(callFrame
, stackFrameCallee
);
106 if (hasSourceURLInfo
) {
107 traceLine
= hasLineInfo
? String::format("%s@%s:%d", functionName
.ascii().data(), sourceURL
.ascii().data(), line
)
108 : String::format("%s@%s", functionName
.ascii().data(), sourceURL
.ascii().data());
110 traceLine
= String::format("%s\n", functionName
.ascii().data());
113 case StackFrameGlobalCode
:
114 if (hasSourceURLInfo
) {
115 traceLine
= hasLineInfo
? String::format("global code@%s:%d", sourceURL
.ascii().data(), line
)
116 : String::format("global code@%s", sourceURL
.ascii().data());
118 traceLine
= String::format("global code");
121 return traceLine
.impl();
125 class TopCallFrameSetter
{
127 TopCallFrameSetter(JSGlobalData
& global
, CallFrame
* callFrame
)
129 , oldCallFrame(global
.topCallFrame
)
131 global
.topCallFrame
= callFrame
;
134 ~TopCallFrameSetter()
136 globalData
.topCallFrame
= oldCallFrame
;
139 JSGlobalData
& globalData
;
140 CallFrame
* oldCallFrame
;
143 class NativeCallFrameTracer
{
145 ALWAYS_INLINE
NativeCallFrameTracer(JSGlobalData
* global
, CallFrame
* callFrame
)
149 global
->topCallFrame
= callFrame
;
153 // We use a smaller reentrancy limit on iPhone because of the high amount of
154 // stack space required on the web thread.
155 enum { MaxLargeThreadReentryDepth
= 64, MaxSmallThreadReentryDepth
= 16 };
158 WTF_MAKE_FAST_ALLOCATED
;
159 friend class CachedCall
;
160 friend class LLIntOffsetsExtractor
;
166 void initialize(LLInt::Data
*, bool canUseJIT
);
168 RegisterFile
& registerFile() { return m_registerFile
; }
170 Opcode
getOpcode(OpcodeID id
)
172 ASSERT(m_initialized
);
173 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
174 return m_opcodeTable
[id
];
180 OpcodeID
getOpcodeID(Opcode opcode
)
182 ASSERT(m_initialized
);
184 ASSERT(isOpcode(opcode
));
185 return m_opcodeIDTable
.get(opcode
);
186 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
187 ASSERT(isOpcode(opcode
));
188 if (!m_classicEnabled
)
189 return static_cast<OpcodeID
>(bitwise_cast
<uintptr_t>(opcode
));
191 return m_opcodeIDTable
.get(opcode
);
197 bool classicEnabled()
199 return m_classicEnabled
;
202 bool isOpcode(Opcode
);
204 JSValue
execute(ProgramExecutable
*, CallFrame
*, ScopeChainNode
*, JSObject
* thisObj
);
205 JSValue
executeCall(CallFrame
*, JSObject
* function
, CallType
, const CallData
&, JSValue thisValue
, const ArgList
&);
206 JSObject
* executeConstruct(CallFrame
*, JSObject
* function
, ConstructType
, const ConstructData
&, const ArgList
&);
207 JSValue
execute(EvalExecutable
*, CallFrame
*, JSValue thisValue
, ScopeChainNode
*);
208 JSValue
execute(EvalExecutable
*, CallFrame
*, JSValue thisValue
, ScopeChainNode
*, int globalRegisterOffset
);
210 JSValue
retrieveArgumentsFromVMCode(CallFrame
*, JSFunction
*) const;
211 JSValue
retrieveCallerFromVMCode(CallFrame
*, JSFunction
*) const;
212 JS_EXPORT_PRIVATE
void retrieveLastCaller(CallFrame
*, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const;
214 void getArgumentsData(CallFrame
*, JSFunction
*&, ptrdiff_t& firstParameterIndex
, Register
*& argv
, int& argc
);
216 SamplingTool
* sampler() { return m_sampler
.get(); }
218 NEVER_INLINE HandlerInfo
* throwException(CallFrame
*&, JSValue
&, unsigned bytecodeOffset
);
219 NEVER_INLINE
void debug(CallFrame
*, DebugHookID
, int firstLine
, int lastLine
);
220 static const UString
getTraceLine(CallFrame
*, StackFrameCodeType
, const UString
&, int);
221 JS_EXPORT_PRIVATE
static void getStackTrace(JSGlobalData
*, Vector
<StackFrame
>& results
);
222 static void addStackTraceIfNecessary(CallFrame
*, JSObject
* error
);
224 void dumpSampleData(ExecState
* exec
);
225 void startSampling();
228 enum ExecutionFlag
{ Normal
, InitializeAndReturn
};
230 CallFrameClosure
prepareForRepeatCall(FunctionExecutable
*, CallFrame
*, JSFunction
*, int argumentCountIncludingThis
, ScopeChainNode
*);
231 void endRepeatCall(CallFrameClosure
&);
232 JSValue
execute(CallFrameClosure
&);
234 #if ENABLE(CLASSIC_INTERPRETER)
235 NEVER_INLINE
bool resolve(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
236 NEVER_INLINE
bool resolveSkip(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
237 NEVER_INLINE
bool resolveGlobal(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
238 NEVER_INLINE
bool resolveGlobalDynamic(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
239 NEVER_INLINE
void resolveBase(CallFrame
*, Instruction
* vPC
);
240 NEVER_INLINE
bool resolveBaseAndProperty(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
241 NEVER_INLINE
bool resolveThisAndProperty(CallFrame
*, Instruction
*, JSValue
& exceptionValue
);
242 NEVER_INLINE ScopeChainNode
* createExceptionScope(CallFrame
*, const Instruction
* vPC
);
244 void tryCacheGetByID(CallFrame
*, CodeBlock
*, Instruction
*, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
&);
245 void uncacheGetByID(CodeBlock
*, Instruction
* vPC
);
246 void tryCachePutByID(CallFrame
*, CodeBlock
*, Instruction
*, JSValue baseValue
, const PutPropertySlot
&);
247 void uncachePutByID(CodeBlock
*, Instruction
* vPC
);
248 #endif // ENABLE(CLASSIC_INTERPRETER)
250 NEVER_INLINE
bool unwindCallFrame(CallFrame
*&, JSValue
, unsigned& bytecodeOffset
, CodeBlock
*&);
252 static ALWAYS_INLINE CallFrame
* slideRegisterWindowForCall(CodeBlock
*, RegisterFile
*, CallFrame
*, size_t registerOffset
, int argc
);
254 static CallFrame
* findFunctionCallFrameFromVMCode(CallFrame
*, JSFunction
*);
256 JSValue
privateExecute(ExecutionFlag
, RegisterFile
*, CallFrame
*);
258 void dumpCallFrame(CallFrame
*);
259 void dumpRegisters(CallFrame
*);
261 bool isCallBytecode(Opcode opcode
) { return opcode
== getOpcode(op_call
) || opcode
== getOpcode(op_construct
) || opcode
== getOpcode(op_call_eval
); }
263 void enableSampler();
264 int m_sampleEntryDepth
;
265 OwnPtr
<SamplingTool
> m_sampler
;
269 RegisterFile m_registerFile
;
272 Opcode
* m_opcodeTable
; // Maps OpcodeID => Opcode for compiling
273 HashMap
<Opcode
, OpcodeID
> m_opcodeIDTable
; // Maps Opcode => OpcodeID for decompiling
274 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
275 Opcode m_opcodeTable
[numOpcodeIDs
]; // Maps OpcodeID => Opcode for compiling
276 HashMap
<Opcode
, OpcodeID
> m_opcodeIDTable
; // Maps Opcode => OpcodeID for decompiling
282 bool m_classicEnabled
;
285 // This value must not be an object that would require this conversion (WebCore's global object).
286 inline bool isValidThisObject(JSValue thisValue
, ExecState
* exec
)
288 return !thisValue
.isObject() || thisValue
.toThisObject(exec
) == thisValue
;
291 inline JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSValue thisValue
, ScopeChainNode
* scopeChain
)
293 return execute(eval
, callFrame
, thisValue
, scopeChain
, m_registerFile
.size() + 1 + RegisterFile::CallFrameHeaderSize
);
296 JSValue
eval(CallFrame
*);
297 CallFrame
* loadVarargs(CallFrame
*, RegisterFile
*, JSValue thisValue
, JSValue arguments
, int firstFreeRegister
);
301 #endif // Interpreter_h