2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "JSFunction.h"
38 #include "LLIntData.h"
40 #include "RegisterFile.h"
42 #include <wtf/HashMap.h>
43 #include <wtf/text/StringBuilder.h>
50 class FunctionExecutable;
52 class LLIntOffsetsExtractor;
53 class ProgramExecutable;
57 struct CallFrameClosure;
70 enum StackFrameCodeType {
73 StackFrameFunctionCode,
78 Strong<JSObject> callee;
79 StackFrameCodeType codeType;
80 Strong<ExecutableBase> executable;
83 UString toString(CallFrame* callFrame) const
85 StringBuilder traceBuild;
86 String functionName = friendlyFunctionName(callFrame);
87 String sourceURL = friendlySourceURL();
88 traceBuild.append(functionName);
89 if (!sourceURL.isEmpty()) {
90 if (!functionName.isEmpty())
91 traceBuild.append('@');
92 traceBuild.append(sourceURL);
94 traceBuild.append(':');
95 traceBuild.append(String::number(line));
98 return traceBuild.toString().impl();
100 String friendlySourceURL() const
105 case StackFrameEvalCode:
106 case StackFrameFunctionCode:
107 case StackFrameGlobalCode:
108 if (!sourceURL.isEmpty())
109 traceLine = sourceURL.impl();
111 case StackFrameNativeCode:
112 traceLine = "[native code]";
115 return traceLine.isNull() ? emptyString() : traceLine;
117 String friendlyFunctionName(CallFrame* callFrame) const
120 JSObject* stackFrameCallee = callee.get();
123 case StackFrameEvalCode:
124 traceLine = "eval code";
126 case StackFrameNativeCode:
128 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
130 case StackFrameFunctionCode:
131 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
133 case StackFrameGlobalCode:
134 traceLine = "global code";
137 return traceLine.isNull() ? emptyString() : traceLine;
139 unsigned friendlyLineNumber() const
141 return line > -1 ? line : 0;
145 class TopCallFrameSetter {
147 TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame)
149 , oldCallFrame(global.topCallFrame)
151 global.topCallFrame = callFrame;
154 ~TopCallFrameSetter()
156 globalData.topCallFrame = oldCallFrame;
159 JSGlobalData& globalData;
160 CallFrame* oldCallFrame;
163 class NativeCallFrameTracer {
165 ALWAYS_INLINE NativeCallFrameTracer(JSGlobalData* global, CallFrame* callFrame)
169 global->topCallFrame = callFrame;
173 // We use a smaller reentrancy limit on iPhone because of the high amount of
174 // stack space required on the web thread.
176 enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 };
178 enum { MaxLargeThreadReentryDepth = 256, MaxSmallThreadReentryDepth = 16 };
179 #endif // PLATFORM(IOS)
182 WTF_MAKE_FAST_ALLOCATED;
183 friend class CachedCall;
184 friend class LLIntOffsetsExtractor;
190 void initialize(LLInt::Data*, bool canUseJIT);
192 RegisterFile& registerFile() { return m_registerFile; }
194 Opcode getOpcode(OpcodeID id)
196 ASSERT(m_initialized);
197 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
198 return m_opcodeTable[id];
204 OpcodeID getOpcodeID(Opcode opcode)
206 ASSERT(m_initialized);
208 ASSERT(isOpcode(opcode));
209 return m_opcodeIDTable.get(opcode);
210 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
211 ASSERT(isOpcode(opcode));
212 if (!m_classicEnabled)
213 return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode));
215 return m_opcodeIDTable.get(opcode);
221 bool classicEnabled()
223 return m_classicEnabled;
226 bool isOpcode(Opcode);
228 JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj);
229 JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
230 JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
231 JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*);
232 JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, ScopeChainNode*, int globalRegisterOffset);
234 JSValue retrieveArgumentsFromVMCode(CallFrame*, JSFunction*) const;
235 JSValue retrieveCallerFromVMCode(CallFrame*, JSFunction*) const;
236 JS_EXPORT_PRIVATE void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const;
238 void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
240 SamplingTool* sampler() { return m_sampler.get(); }
242 NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
243 NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
244 static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int);
245 JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results);
246 static void addStackTraceIfNecessary(CallFrame*, JSObject* error);
248 void dumpSampleData(ExecState* exec);
249 void startSampling();
252 enum ExecutionFlag { Normal, InitializeAndReturn };
254 CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, ScopeChainNode*);
255 void endRepeatCall(CallFrameClosure&);
256 JSValue execute(CallFrameClosure&);
258 #if ENABLE(CLASSIC_INTERPRETER)
259 NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue);
260 NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue& exceptionValue);
261 NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue);
262 NEVER_INLINE bool resolveGlobalDynamic(CallFrame*, Instruction*, JSValue& exceptionValue);
263 NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC);
264 NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue);
265 NEVER_INLINE bool resolveThisAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue);
266 NEVER_INLINE ScopeChainNode* createExceptionScope(CallFrame*, const Instruction* vPC);
268 void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const Identifier& propertyName, const PropertySlot&);
269 void uncacheGetByID(CodeBlock*, Instruction* vPC);
270 void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const PutPropertySlot&);
271 void uncachePutByID(CodeBlock*, Instruction* vPC);
272 #endif // ENABLE(CLASSIC_INTERPRETER)
274 NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&);
276 static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc);
278 static CallFrame* findFunctionCallFrameFromVMCode(CallFrame*, JSFunction*);
280 JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*);
282 void dumpCallFrame(CallFrame*);
283 void dumpRegisters(CallFrame*);
285 bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
287 void enableSampler();
288 int m_sampleEntryDepth;
289 OwnPtr<SamplingTool> m_sampler;
293 RegisterFile m_registerFile;
296 Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
297 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
298 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
299 Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
300 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
306 bool m_classicEnabled;
309 // This value must not be an object that would require this conversion (WebCore's global object).
310 inline bool isValidThisObject(JSValue thisValue, ExecState* exec)
312 return !thisValue.isObject() || thisValue.toThisObject(exec) == thisValue;
315 inline JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain)
317 return execute(eval, callFrame, thisValue, scopeChain, m_registerFile.size() + 1 + RegisterFile::CallFrameHeaderSize);
320 JSValue eval(CallFrame*);
321 CallFrame* loadVarargs(CallFrame*, RegisterFile*, JSValue thisValue, JSValue arguments, int firstFreeRegister);
325 #endif // Interpreter_h