]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved. |
9dae56ea A |
3 | * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * | |
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. | |
81345200 | 14 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
15 | * its contributors may be used to endorse or promote products derived |
16 | * from this software without specific prior written permission. | |
17 | * | |
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. | |
28 | */ | |
29 | ||
30 | #include "config.h" | |
31 | #include "Interpreter.h" | |
32 | ||
33 | #include "Arguments.h" | |
34 | #include "BatchedTransitionOptimizer.h" | |
ba379fdc | 35 | #include "CallFrameClosure.h" |
81345200 | 36 | #include "CallFrameInlines.h" |
9dae56ea | 37 | #include "CodeBlock.h" |
14957cd0 | 38 | #include "Heap.h" |
ba379fdc | 39 | #include "Debugger.h" |
9dae56ea | 40 | #include "DebuggerCallFrame.h" |
14957cd0 | 41 | #include "ErrorInstance.h" |
9dae56ea A |
42 | #include "EvalCodeCache.h" |
43 | #include "ExceptionHelpers.h" | |
4e4e5a6f | 44 | #include "GetterSetter.h" |
9dae56ea A |
45 | #include "JSActivation.h" |
46 | #include "JSArray.h" | |
6fe7ccc8 | 47 | #include "JSBoundFunction.h" |
93a37866 | 48 | #include "JSNameScope.h" |
9dae56ea A |
49 | #include "JSNotAnObject.h" |
50 | #include "JSPropertyNameIterator.h" | |
93a37866 | 51 | #include "JSStackInlines.h" |
9dae56ea | 52 | #include "JSString.h" |
93a37866 A |
53 | #include "JSWithScope.h" |
54 | #include "LLIntCLoop.h" | |
81345200 | 55 | #include "LLIntThunks.h" |
93a37866 A |
56 | #include "LegacyProfiler.h" |
57 | #include "LiteralParser.h" | |
58 | #include "NameInstance.h" | |
9dae56ea | 59 | #include "ObjectPrototype.h" |
81345200 | 60 | #include "JSCInlines.h" |
9dae56ea | 61 | #include "Parser.h" |
81345200 | 62 | #include "ProtoCallFrame.h" |
9dae56ea A |
63 | #include "RegExpObject.h" |
64 | #include "RegExpPrototype.h" | |
65 | #include "Register.h" | |
9dae56ea | 66 | #include "SamplingTool.h" |
81345200 A |
67 | #include "StackAlignment.h" |
68 | #include "StackVisitor.h" | |
14957cd0 | 69 | #include "StrictEvalActivation.h" |
6fe7ccc8 | 70 | #include "StrongInlines.h" |
81345200 A |
71 | #include "VMEntryScope.h" |
72 | #include "VirtualRegister.h" | |
73 | ||
f9bf01c6 | 74 | #include <limits.h> |
9dae56ea | 75 | #include <stdio.h> |
93a37866 | 76 | #include <wtf/StackStats.h> |
81345200 | 77 | #include <wtf/StdLibExtras.h> |
93a37866 | 78 | #include <wtf/StringPrintStream.h> |
ba379fdc | 79 | #include <wtf/Threading.h> |
93a37866 | 80 | #include <wtf/WTFThreadData.h> |
6fe7ccc8 | 81 | #include <wtf/text/StringBuilder.h> |
9dae56ea A |
82 | |
83 | #if ENABLE(JIT) | |
84 | #include "JIT.h" | |
85 | #endif | |
86 | ||
81345200 | 87 | #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (!defined(__llvm__)) |
4e4e5a6f | 88 | |
9dae56ea A |
89 | using namespace std; |
90 | ||
91 | namespace JSC { | |
9dae56ea | 92 | |
6fe7ccc8 | 93 | JSValue eval(CallFrame* callFrame) |
9dae56ea | 94 | { |
6fe7ccc8 | 95 | if (!callFrame->argumentCount()) |
9dae56ea A |
96 | return jsUndefined(); |
97 | ||
6fe7ccc8 | 98 | JSValue program = callFrame->argument(0); |
9dae56ea A |
99 | if (!program.isString()) |
100 | return program; | |
6fe7ccc8 | 101 | |
93a37866 A |
102 | TopCallFrameSetter topCallFrame(callFrame->vm(), callFrame); |
103 | String programSource = asString(program)->value(callFrame); | |
4e4e5a6f A |
104 | if (callFrame->hadException()) |
105 | return JSValue(); | |
14957cd0 | 106 | |
6fe7ccc8 A |
107 | CallFrame* callerFrame = callFrame->callerFrame(); |
108 | CodeBlock* callerCodeBlock = callerFrame->codeBlock(); | |
93a37866 | 109 | JSScope* callerScopeChain = callerFrame->scope(); |
6fe7ccc8 A |
110 | EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain); |
111 | ||
112 | if (!eval) { | |
113 | if (!callerCodeBlock->isStrictMode()) { | |
114 | // FIXME: We can use the preparser in strict mode, we just need additional logic | |
115 | // to prevent duplicates. | |
116 | if (programSource.is8Bit()) { | |
117 | LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON); | |
118 | if (JSValue parsedObject = preparser.tryLiteralParse()) | |
119 | return parsedObject; | |
120 | } else { | |
121 | LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON); | |
122 | if (JSValue parsedObject = preparser.tryLiteralParse()) | |
123 | return parsedObject; | |
124 | } | |
125 | } | |
93a37866 A |
126 | |
127 | // If the literal parser bailed, it should not have thrown exceptions. | |
81345200 | 128 | ASSERT(!callFrame->vm().exception()); |
6fe7ccc8 | 129 | |
81345200 A |
130 | eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain); |
131 | if (!eval) | |
132 | return jsUndefined(); | |
14957cd0 | 133 | } |
f9bf01c6 | 134 | |
6fe7ccc8 | 135 | JSValue thisValue = callerFrame->thisValue(); |
93a37866 A |
136 | Interpreter* interpreter = callFrame->vm().interpreter; |
137 | return interpreter->execute(eval, callFrame, thisValue, callerScopeChain); | |
6fe7ccc8 A |
138 | } |
139 | ||
81345200 | 140 | CallFrame* sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, int firstFreeRegister, uint32_t firstVarArgOffset) |
6fe7ccc8 A |
141 | { |
142 | if (!arguments) { // f.apply(x, arguments), with arguments unmodified. | |
143 | unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); | |
81345200 A |
144 | if (argumentCountIncludingThis > firstVarArgOffset) |
145 | argumentCountIncludingThis -= firstVarArgOffset; | |
146 | else | |
147 | argumentCountIncludingThis = 1; | |
148 | unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1); | |
149 | CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); | |
150 | if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) { | |
151 | throwStackOverflowError(callFrame); | |
6fe7ccc8 A |
152 | return 0; |
153 | } | |
6fe7ccc8 A |
154 | return newCallFrame; |
155 | } | |
156 | ||
157 | if (arguments.isUndefinedOrNull()) { | |
81345200 A |
158 | unsigned argumentCountIncludingThis = 1; |
159 | unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1); | |
160 | CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); | |
161 | if (!stack->ensureCapacityFor(newCallFrame->registers())) { | |
162 | throwStackOverflowError(callFrame); | |
6fe7ccc8 A |
163 | return 0; |
164 | } | |
6fe7ccc8 A |
165 | return newCallFrame; |
166 | } | |
167 | ||
168 | if (!arguments.isObject()) { | |
81345200 | 169 | callFrame->vm().throwException(callFrame, createInvalidParameterError(callFrame, "Function.prototype.apply", arguments)); |
6fe7ccc8 A |
170 | return 0; |
171 | } | |
9dae56ea | 172 | |
81345200 | 173 | if (asObject(arguments)->classInfo() == Arguments::info()) { |
6fe7ccc8 A |
174 | Arguments* argsObject = asArguments(arguments); |
175 | unsigned argCount = argsObject->length(callFrame); | |
40a37d08 | 176 | callFrame->vm().varargsLength = argCount; |
81345200 A |
177 | if (argCount >= firstVarArgOffset) |
178 | argCount -= firstVarArgOffset; | |
179 | else | |
180 | argCount = 0; | |
181 | unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); | |
182 | CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); | |
183 | if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { | |
184 | throwStackOverflowError(callFrame); | |
6fe7ccc8 A |
185 | return 0; |
186 | } | |
6fe7ccc8 A |
187 | return newCallFrame; |
188 | } | |
189 | ||
190 | if (isJSArray(arguments)) { | |
191 | JSArray* array = asArray(arguments); | |
192 | unsigned argCount = array->length(); | |
81345200 A |
193 | if (argCount >= firstVarArgOffset) |
194 | argCount -= firstVarArgOffset; | |
195 | else | |
196 | argCount = 0; | |
197 | unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); | |
198 | CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); | |
199 | if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { | |
200 | throwStackOverflowError(callFrame); | |
6fe7ccc8 A |
201 | return 0; |
202 | } | |
6fe7ccc8 A |
203 | return newCallFrame; |
204 | } | |
9dae56ea | 205 | |
6fe7ccc8 A |
206 | JSObject* argObject = asObject(arguments); |
207 | unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); | |
40a37d08 | 208 | callFrame->vm().varargsLength = argCount; |
81345200 A |
209 | if (argCount >= firstVarArgOffset) |
210 | argCount -= firstVarArgOffset; | |
211 | else | |
212 | argCount = 0; | |
213 | unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1)); | |
214 | CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset); | |
215 | if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) { | |
216 | throwStackOverflowError(callFrame); | |
6fe7ccc8 A |
217 | return 0; |
218 | } | |
81345200 A |
219 | return newCallFrame; |
220 | } | |
221 | ||
222 | void loadVarargs(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset) | |
223 | { | |
224 | if (!arguments) { // f.apply(x, arguments), with arguments unmodified. | |
225 | unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); | |
226 | if (argumentCountIncludingThis > firstVarArgOffset) | |
227 | argumentCountIncludingThis -= firstVarArgOffset; | |
228 | else | |
229 | argumentCountIncludingThis = 1; | |
230 | newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis); | |
231 | newCallFrame->setThisValue(thisValue); | |
232 | for (size_t i = firstVarArgOffset; i < callFrame->argumentCount(); ++i) | |
233 | newCallFrame->setArgument(i - firstVarArgOffset, callFrame->argumentAfterCapture(i)); | |
234 | return; | |
235 | } | |
236 | ||
237 | if (arguments.isUndefinedOrNull()) { | |
238 | newCallFrame->setArgumentCountIncludingThis(1); | |
239 | newCallFrame->setThisValue(thisValue); | |
240 | return; | |
241 | } | |
242 | ||
243 | if (asObject(arguments)->classInfo() == Arguments::info()) { | |
244 | Arguments* argsObject = asArguments(arguments); | |
40a37d08 A |
245 | unsigned argCount = callFrame->vm().varargsLength; |
246 | callFrame->vm().varargsLength = 0; | |
81345200 A |
247 | if (argCount >= firstVarArgOffset) { |
248 | argCount -= firstVarArgOffset; | |
249 | newCallFrame->setArgumentCountIncludingThis(argCount + 1); | |
250 | argsObject->copyToArguments(callFrame, newCallFrame, argCount, firstVarArgOffset); | |
251 | } else | |
252 | newCallFrame->setArgumentCountIncludingThis(1); | |
253 | newCallFrame->setThisValue(thisValue); | |
254 | return; | |
255 | } | |
256 | ||
257 | if (isJSArray(arguments)) { | |
258 | JSArray* array = asArray(arguments); | |
259 | unsigned argCount = array->length(); | |
260 | if (argCount >= firstVarArgOffset) { | |
261 | argCount -= firstVarArgOffset; | |
262 | newCallFrame->setArgumentCountIncludingThis(argCount + 1); | |
263 | array->copyToArguments(callFrame, newCallFrame, argCount, firstVarArgOffset); | |
264 | } else | |
265 | newCallFrame->setArgumentCountIncludingThis(1); | |
266 | newCallFrame->setThisValue(thisValue); | |
267 | return; | |
268 | } | |
269 | ||
40a37d08 | 270 | unsigned argCount = callFrame->vm().varargsLength; |
81345200 A |
271 | if (argCount >= firstVarArgOffset) { |
272 | argCount -= firstVarArgOffset; | |
273 | newCallFrame->setArgumentCountIncludingThis(argCount + 1); | |
274 | } else | |
275 | newCallFrame->setArgumentCountIncludingThis(1); | |
276 | ||
6fe7ccc8 A |
277 | newCallFrame->setThisValue(thisValue); |
278 | for (size_t i = 0; i < argCount; ++i) { | |
81345200 A |
279 | newCallFrame->setArgument(i, asObject(arguments)->get(callFrame, i + firstVarArgOffset)); |
280 | if (UNLIKELY(callFrame->vm().exception())) | |
281 | return; | |
6fe7ccc8 | 282 | } |
9dae56ea A |
283 | } |
284 | ||
93a37866 | 285 | Interpreter::Interpreter(VM& vm) |
f9bf01c6 | 286 | : m_sampleEntryDepth(0) |
81345200 | 287 | , m_vm(vm) |
93a37866 A |
288 | , m_stack(vm) |
289 | , m_errorHandlingModeReentry(0) | |
6fe7ccc8 A |
290 | #if !ASSERT_DISABLED |
291 | , m_initialized(false) | |
292 | #endif | |
9dae56ea | 293 | { |
6fe7ccc8 A |
294 | } |
295 | ||
296 | Interpreter::~Interpreter() | |
297 | { | |
6fe7ccc8 A |
298 | } |
299 | ||
93a37866 | 300 | void Interpreter::initialize(bool canUseJIT) |
6fe7ccc8 | 301 | { |
6fe7ccc8 A |
302 | UNUSED_PARAM(canUseJIT); |
303 | ||
81345200 | 304 | #if ENABLE(COMPUTED_GOTO_OPCODES) |
93a37866 | 305 | m_opcodeTable = LLInt::opcodeMap(); |
ba379fdc A |
306 | for (int i = 0; i < numOpcodeIDs; ++i) |
307 | m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); | |
6fe7ccc8 | 308 | #endif |
93a37866 | 309 | |
6fe7ccc8 A |
310 | #if !ASSERT_DISABLED |
311 | m_initialized = true; | |
312 | #endif | |
f9bf01c6 A |
313 | |
314 | #if ENABLE(OPCODE_SAMPLING) | |
315 | enableSampler(); | |
316 | #endif | |
9dae56ea A |
317 | } |
318 | ||
93a37866 A |
319 | #ifdef NDEBUG |
320 | ||
321 | void Interpreter::dumpCallFrame(CallFrame*) | |
322 | { | |
323 | } | |
324 | ||
325 | #else | |
9dae56ea A |
326 | |
327 | void Interpreter::dumpCallFrame(CallFrame* callFrame) | |
328 | { | |
93a37866 | 329 | callFrame->codeBlock()->dumpBytecode(); |
9dae56ea A |
330 | dumpRegisters(callFrame); |
331 | } | |
332 | ||
81345200 A |
333 | class DumpRegisterFunctor { |
334 | public: | |
335 | DumpRegisterFunctor(const Register*& it) | |
336 | : m_hasSkippedFirstFrame(false) | |
337 | , m_it(it) | |
338 | { | |
339 | } | |
340 | ||
341 | StackVisitor::Status operator()(StackVisitor& visitor) | |
342 | { | |
343 | if (!m_hasSkippedFirstFrame) { | |
344 | m_hasSkippedFirstFrame = true; | |
345 | return StackVisitor::Continue; | |
346 | } | |
347 | ||
348 | unsigned line = 0; | |
349 | unsigned unusedColumn = 0; | |
350 | visitor->computeLineAndColumn(line, unusedColumn); | |
351 | dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", m_it, visitor->bytecodeOffset(), line); | |
352 | --m_it; | |
353 | return StackVisitor::Done; | |
354 | } | |
355 | ||
356 | private: | |
357 | bool m_hasSkippedFirstFrame; | |
358 | const Register*& m_it; | |
359 | }; | |
360 | ||
9dae56ea A |
361 | void Interpreter::dumpRegisters(CallFrame* callFrame) |
362 | { | |
93a37866 A |
363 | dataLogF("Register frame: \n\n"); |
364 | dataLogF("-----------------------------------------------------------------------------\n"); | |
365 | dataLogF(" use | address | value \n"); | |
366 | dataLogF("-----------------------------------------------------------------------------\n"); | |
9dae56ea A |
367 | |
368 | CodeBlock* codeBlock = callFrame->codeBlock(); | |
9dae56ea A |
369 | const Register* it; |
370 | const Register* end; | |
371 | ||
81345200 A |
372 | it = callFrame->registers() + JSStack::ThisArgument + callFrame->argumentCount(); |
373 | end = callFrame->registers() + JSStack::ThisArgument - 1; | |
374 | while (it > end) { | |
93a37866 A |
375 | JSValue v = it->jsValue(); |
376 | int registerNumber = it - callFrame->registers(); | |
81345200 | 377 | String name = codeBlock->nameForRegister(VirtualRegister(registerNumber)); |
93a37866 | 378 | dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v)); |
81345200 | 379 | --it; |
9dae56ea | 380 | } |
93a37866 A |
381 | |
382 | dataLogF("-----------------------------------------------------------------------------\n"); | |
383 | dataLogF("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount()); | |
81345200 | 384 | --it; |
93a37866 | 385 | dataLogF("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame()); |
81345200 | 386 | --it; |
93a37866 | 387 | dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee()); |
81345200 | 388 | --it; |
93a37866 | 389 | dataLogF("[ScopeChain] | %10p | %p \n", it, callFrame->scope()); |
81345200 | 390 | --it; |
93a37866 A |
391 | #if ENABLE(JIT) |
392 | AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm()); | |
393 | if (pc.hasJITReturnAddress()) | |
394 | dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value()); | |
395 | #endif | |
81345200 A |
396 | |
397 | DumpRegisterFunctor functor(it); | |
398 | callFrame->iterate(functor); | |
399 | ||
93a37866 | 400 | dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock()); |
81345200 | 401 | --it; |
93a37866 | 402 | dataLogF("-----------------------------------------------------------------------------\n"); |
9dae56ea | 403 | |
81345200 | 404 | end = it - codeBlock->m_numVars; |
9dae56ea A |
405 | if (it != end) { |
406 | do { | |
93a37866 A |
407 | JSValue v = it->jsValue(); |
408 | int registerNumber = it - callFrame->registers(); | |
81345200 | 409 | String name = codeBlock->nameForRegister(VirtualRegister(registerNumber)); |
93a37866 | 410 | dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v)); |
81345200 | 411 | --it; |
9dae56ea A |
412 | } while (it != end); |
413 | } | |
93a37866 | 414 | dataLogF("-----------------------------------------------------------------------------\n"); |
9dae56ea | 415 | |
81345200 | 416 | end = it - codeBlock->m_numCalleeRegisters + codeBlock->m_numVars; |
9dae56ea A |
417 | if (it != end) { |
418 | do { | |
93a37866 | 419 | JSValue v = (*it).jsValue(); |
81345200 A |
420 | int registerNumber = it - callFrame->registers(); |
421 | dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerNumber, it, toCString(v).data(), (long long)JSValue::encode(v)); | |
422 | --it; | |
9dae56ea A |
423 | } while (it != end); |
424 | } | |
93a37866 | 425 | dataLogF("-----------------------------------------------------------------------------\n"); |
9dae56ea A |
426 | } |
427 | ||
428 | #endif | |
429 | ||
430 | bool Interpreter::isOpcode(Opcode opcode) | |
431 | { | |
93a37866 | 432 | #if ENABLE(COMPUTED_GOTO_OPCODES) |
9dae56ea A |
433 | return opcode != HashTraits<Opcode>::emptyValue() |
434 | && !HashTraits<Opcode>::isDeletedValue(opcode) | |
435 | && m_opcodeIDTable.contains(opcode); | |
436 | #else | |
437 | return opcode >= 0 && opcode <= op_end; | |
438 | #endif | |
439 | } | |
440 | ||
81345200 | 441 | static bool unwindCallFrame(StackVisitor& visitor) |
9dae56ea | 442 | { |
81345200 A |
443 | CallFrame* callFrame = visitor->callFrame(); |
444 | CodeBlock* codeBlock = visitor->codeBlock(); | |
93a37866 | 445 | JSScope* scope = callFrame->scope(); |
9dae56ea | 446 | |
81345200 A |
447 | if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) { |
448 | ClearExceptionScope scope(&callFrame->vm()); | |
9dae56ea | 449 | if (callFrame->callee()) |
81345200 | 450 | debugger->returnEvent(callFrame); |
9dae56ea | 451 | else |
81345200 A |
452 | debugger->didExecuteProgram(callFrame); |
453 | ASSERT(!callFrame->hadException()); | |
93a37866 A |
454 | } |
455 | ||
456 | JSValue activation; | |
81345200 | 457 | if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) { |
6fe7ccc8 | 458 | #if ENABLE(DFG_JIT) |
81345200 | 459 | RELEASE_ASSERT(!visitor->isInlinedFrame()); |
6fe7ccc8 | 460 | #endif |
81345200 A |
461 | activation = callFrame->uncheckedActivation(); |
462 | // Protect against the activation not being created, or the variable still being | |
463 | // initialized to Undefined inside op_enter. | |
464 | if (activation && activation.isCell()) { | |
465 | JSActivation* activationObject = jsCast<JSActivation*>(activation); | |
466 | // Protect against throwing exceptions after tear-off. | |
467 | if (!activationObject->isTornOff()) | |
468 | activationObject->tearOff(*scope->vm()); | |
469 | } | |
93a37866 | 470 | } |
6fe7ccc8 | 471 | |
81345200 A |
472 | if (codeBlock->codeType() == FunctionCode && codeBlock->usesArguments()) { |
473 | if (Arguments* arguments = visitor->existingArguments()) { | |
474 | if (activation && activation.isCell()) | |
475 | arguments->didTearOffActivation(callFrame, jsCast<JSActivation*>(activation)); | |
6fe7ccc8 | 476 | #if ENABLE(DFG_JIT) |
81345200 A |
477 | else if (visitor->isInlinedFrame()) |
478 | arguments->tearOff(callFrame, visitor->inlineCallFrame()); | |
6fe7ccc8 | 479 | #endif |
81345200 A |
480 | else |
481 | arguments->tearOff(callFrame); | |
93a37866 | 482 | } |
6fe7ccc8 A |
483 | } |
484 | ||
81345200 A |
485 | CallFrame* callerFrame = callFrame->callerFrame(); |
486 | return !callerFrame->isVMEntrySentinel(); | |
6fe7ccc8 A |
487 | } |
488 | ||
81345200 | 489 | static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor) |
6fe7ccc8 | 490 | { |
81345200 A |
491 | switch (visitor->codeType()) { |
492 | case StackVisitor::Frame::Eval: | |
6fe7ccc8 | 493 | return StackFrameEvalCode; |
81345200 | 494 | case StackVisitor::Frame::Function: |
6fe7ccc8 | 495 | return StackFrameFunctionCode; |
81345200 | 496 | case StackVisitor::Frame::Global: |
6fe7ccc8 | 497 | return StackFrameGlobalCode; |
81345200 A |
498 | case StackVisitor::Frame::Native: |
499 | ASSERT_NOT_REACHED(); | |
500 | return StackFrameNativeCode; | |
6fe7ccc8 | 501 | } |
93a37866 | 502 | RELEASE_ASSERT_NOT_REACHED(); |
6fe7ccc8 A |
503 | return StackFrameGlobalCode; |
504 | } | |
505 | ||
93a37866 | 506 | void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column) |
6fe7ccc8 | 507 | { |
93a37866 A |
508 | if (!codeBlock) { |
509 | line = 0; | |
510 | column = 0; | |
6fe7ccc8 | 511 | return; |
93a37866 A |
512 | } |
513 | ||
514 | int divot = 0; | |
515 | int unusedStartOffset = 0; | |
516 | int unusedEndOffset = 0; | |
517 | unsigned divotLine = 0; | |
518 | unsigned divotColumn = 0; | |
519 | expressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn); | |
520 | ||
521 | line = divotLine + lineOffset; | |
522 | column = divotColumn + (divotLine ? 1 : firstLineColumnOffset); | |
523 | } | |
524 | ||
525 | void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) | |
526 | { | |
527 | codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column); | |
528 | divot += characterOffset; | |
529 | } | |
530 | ||
531 | String StackFrame::toString(CallFrame* callFrame) | |
532 | { | |
533 | StringBuilder traceBuild; | |
534 | String functionName = friendlyFunctionName(callFrame); | |
535 | String sourceURL = friendlySourceURL(); | |
536 | traceBuild.append(functionName); | |
537 | if (!sourceURL.isEmpty()) { | |
538 | if (!functionName.isEmpty()) | |
539 | traceBuild.append('@'); | |
540 | traceBuild.append(sourceURL); | |
541 | if (codeType != StackFrameNativeCode) { | |
542 | unsigned line; | |
543 | unsigned column; | |
544 | computeLineAndColumn(line, column); | |
545 | ||
546 | traceBuild.append(':'); | |
547 | traceBuild.appendNumber(line); | |
548 | traceBuild.append(':'); | |
549 | traceBuild.appendNumber(column); | |
550 | } | |
551 | } | |
552 | return traceBuild.toString().impl(); | |
553 | } | |
6fe7ccc8 | 554 | |
81345200 A |
555 | class GetStackTraceFunctor { |
556 | public: | |
557 | GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity) | |
558 | : m_vm(vm) | |
559 | , m_results(results) | |
560 | , m_remainingCapacityForFrameCapture(remainingCapacity) | |
561 | { | |
562 | } | |
563 | ||
564 | StackVisitor::Status operator()(StackVisitor& visitor) | |
565 | { | |
566 | VM& vm = m_vm; | |
567 | if (m_remainingCapacityForFrameCapture) { | |
568 | if (visitor->isJSFrame() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { | |
569 | CodeBlock* codeBlock = visitor->codeBlock(); | |
570 | StackFrame s = { | |
571 | Strong<JSObject>(vm, visitor->callee()), | |
572 | getStackFrameCodeType(visitor), | |
573 | Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()), | |
574 | Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()), | |
575 | codeBlock->source(), | |
576 | codeBlock->ownerExecutable()->lineNo(), | |
577 | codeBlock->firstLineColumnOffset(), | |
578 | codeBlock->sourceOffset(), | |
579 | visitor->bytecodeOffset(), | |
580 | visitor->sourceURL() | |
581 | }; | |
582 | m_results.append(s); | |
583 | } else { | |
584 | StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()}; | |
585 | m_results.append(s); | |
586 | } | |
587 | ||
588 | m_remainingCapacityForFrameCapture--; | |
589 | return StackVisitor::Continue; | |
6fe7ccc8 | 590 | } |
81345200 | 591 | return StackVisitor::Done; |
6fe7ccc8 | 592 | } |
6fe7ccc8 | 593 | |
81345200 A |
594 | private: |
595 | VM& m_vm; | |
596 | Vector<StackFrame>& m_results; | |
597 | size_t m_remainingCapacityForFrameCapture; | |
598 | }; | |
6fe7ccc8 | 599 | |
81345200 A |
600 | void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize) |
601 | { | |
602 | VM& vm = m_vm; | |
603 | ASSERT(!vm.topCallFrame->isVMEntrySentinel()); | |
604 | CallFrame* callFrame = vm.topCallFrame; | |
605 | if (!callFrame) | |
6fe7ccc8 | 606 | return; |
93a37866 | 607 | |
81345200 A |
608 | GetStackTraceFunctor functor(vm, results, maxStackSize); |
609 | callFrame->iterate(functor); | |
610 | } | |
93a37866 | 611 | |
81345200 A |
612 | JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace) |
613 | { | |
93a37866 | 614 | // FIXME: JSStringJoiner could be more efficient than StringBuilder here. |
6fe7ccc8 A |
615 | StringBuilder builder; |
616 | for (unsigned i = 0; i < stackTrace.size(); i++) { | |
81345200 | 617 | builder.append(String(stackTrace[i].toString(exec))); |
6fe7ccc8 A |
618 | if (i != stackTrace.size() - 1) |
619 | builder.append('\n'); | |
620 | } | |
81345200 | 621 | return jsString(&exec->vm(), builder.toString()); |
6fe7ccc8 A |
622 | } |
623 | ||
81345200 A |
624 | class GetExceptionHandlerFunctor { |
625 | public: | |
626 | GetExceptionHandlerFunctor() | |
627 | : m_handler(0) | |
628 | { | |
629 | } | |
630 | ||
631 | HandlerInfo* handler() { return m_handler; } | |
632 | ||
633 | StackVisitor::Status operator()(StackVisitor& visitor) | |
634 | { | |
635 | CodeBlock* codeBlock = visitor->codeBlock(); | |
636 | if (!codeBlock) | |
637 | return StackVisitor::Continue; | |
638 | ||
639 | unsigned bytecodeOffset = visitor->bytecodeOffset(); | |
640 | m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); | |
641 | if (m_handler) | |
642 | return StackVisitor::Done; | |
643 | ||
644 | return StackVisitor::Continue; | |
645 | } | |
646 | ||
647 | private: | |
648 | HandlerInfo* m_handler; | |
649 | }; | |
650 | ||
651 | class UnwindFunctor { | |
652 | public: | |
653 | UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) | |
654 | : m_callFrame(callFrame) | |
655 | , m_isTermination(isTermination) | |
656 | , m_codeBlock(codeBlock) | |
657 | , m_handler(handler) | |
658 | { | |
659 | } | |
660 | ||
661 | StackVisitor::Status operator()(StackVisitor& visitor) | |
662 | { | |
663 | VM& vm = m_callFrame->vm(); | |
664 | m_callFrame = visitor->callFrame(); | |
665 | m_codeBlock = visitor->codeBlock(); | |
666 | unsigned bytecodeOffset = visitor->bytecodeOffset(); | |
667 | ||
668 | if (m_isTermination || !(m_handler = m_codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { | |
669 | if (!unwindCallFrame(visitor)) { | |
670 | if (LegacyProfiler* profiler = vm.enabledProfiler()) | |
671 | profiler->exceptionUnwind(m_callFrame); | |
672 | return StackVisitor::Done; | |
673 | } | |
674 | } else | |
675 | return StackVisitor::Done; | |
676 | ||
677 | return StackVisitor::Continue; | |
678 | } | |
679 | ||
680 | private: | |
681 | CallFrame*& m_callFrame; | |
682 | bool m_isTermination; | |
683 | CodeBlock*& m_codeBlock; | |
684 | HandlerInfo*& m_handler; | |
685 | }; | |
686 | ||
687 | NEVER_INLINE HandlerInfo* Interpreter::unwind(CallFrame*& callFrame, JSValue& exceptionValue) | |
14957cd0 | 688 | { |
81345200 A |
689 | if (callFrame->isVMEntrySentinel()) { |
690 | // This happens when we throw stack overflow in a function that is called | |
691 | // directly from callToJavaScript. Stack overflow throws the exception in the | |
692 | // context of the caller. In that case the caller is the sentinel frame. The | |
693 | // right thing to do is to pretend that the exception is uncaught so that we | |
694 | // go to the uncaught exception handler, which returns through callToJavaScript. | |
695 | return 0; | |
696 | } | |
697 | ||
9dae56ea | 698 | CodeBlock* codeBlock = callFrame->codeBlock(); |
81345200 | 699 | ASSERT(codeBlock); |
93a37866 | 700 | bool isTermination = false; |
14957cd0 | 701 | |
6fe7ccc8 A |
702 | ASSERT(!exceptionValue.isEmpty()); |
703 | ASSERT(!exceptionValue.isCell() || exceptionValue.asCell()); | |
704 | // This shouldn't be possible (hence the assertions), but we're already in the slowest of | |
705 | // slow cases, so let's harden against it anyway to be safe. | |
706 | if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell())) | |
707 | exceptionValue = jsNull(); | |
708 | ||
81345200 A |
709 | if (exceptionValue.isObject()) |
710 | isTermination = isTerminatedExecutionException(asObject(exceptionValue)); | |
711 | ||
712 | ASSERT(callFrame->vm().exceptionStack().size()); | |
713 | ||
714 | Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); | |
715 | if (debugger && debugger->needsExceptionCallbacks()) { | |
716 | // We need to clear the exception and the exception stack here in order to see if a new exception happens. | |
717 | // Afterwards, the values are put back to continue processing this error. | |
718 | ClearExceptionScope scope(&callFrame->vm()); | |
719 | // This code assumes that if the debugger is enabled then there is no inlining. | |
720 | // If that assumption turns out to be false then we'll ignore the inlined call | |
721 | // frames. | |
722 | // https://bugs.webkit.org/show_bug.cgi?id=121754 | |
723 | ||
724 | bool hasHandler; | |
725 | if (isTermination) | |
726 | hasHandler = false; | |
727 | else { | |
728 | GetExceptionHandlerFunctor functor; | |
729 | callFrame->iterate(functor); | |
730 | hasHandler = !!functor.handler(); | |
93a37866 | 731 | } |
9dae56ea | 732 | |
81345200 A |
733 | debugger->exception(callFrame, exceptionValue, hasHandler); |
734 | ASSERT(!callFrame->hadException()); | |
9dae56ea A |
735 | } |
736 | ||
737 | // Calculate an exception handler vPC, unwinding call frames as necessary. | |
9dae56ea | 738 | HandlerInfo* handler = 0; |
81345200 A |
739 | VM& vm = callFrame->vm(); |
740 | ASSERT(callFrame == vm.topCallFrame); | |
741 | UnwindFunctor functor(callFrame, isTermination, codeBlock, handler); | |
742 | callFrame->iterate(functor); | |
743 | if (!handler) | |
744 | return 0; | |
9dae56ea | 745 | |
81345200 | 746 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
14957cd0 | 747 | profiler->exceptionUnwind(callFrame); |
9dae56ea | 748 | |
14957cd0 | 749 | // Unwind the scope chain within the exception handler's call frame. |
81345200 A |
750 | int targetScopeDepth = handler->scopeDepth; |
751 | if (codeBlock->needsActivation() && callFrame->hasActivation()) | |
752 | ++targetScopeDepth; | |
753 | ||
93a37866 | 754 | JSScope* scope = callFrame->scope(); |
81345200 A |
755 | int scopeDelta = scope->depth() - targetScopeDepth; |
756 | RELEASE_ASSERT(scopeDelta >= 0); | |
757 | ||
9dae56ea | 758 | while (scopeDelta--) |
93a37866 A |
759 | scope = scope->next(); |
760 | callFrame->setScope(scope); | |
9dae56ea A |
761 | |
762 | return handler; | |
763 | } | |
764 | ||
14957cd0 A |
765 | static inline JSValue checkedReturn(JSValue returnValue) |
766 | { | |
767 | ASSERT(returnValue); | |
768 | return returnValue; | |
769 | } | |
770 | ||
771 | static inline JSObject* checkedReturn(JSObject* returnValue) | |
772 | { | |
773 | ASSERT(returnValue); | |
774 | return returnValue; | |
775 | } | |
776 | ||
93a37866 A |
777 | class SamplingScope { |
778 | public: | |
779 | SamplingScope(Interpreter* interpreter) | |
780 | : m_interpreter(interpreter) | |
781 | { | |
782 | interpreter->startSampling(); | |
783 | } | |
784 | ~SamplingScope() | |
785 | { | |
786 | m_interpreter->stopSampling(); | |
787 | } | |
788 | private: | |
789 | Interpreter* m_interpreter; | |
790 | }; | |
791 | ||
792 | JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj) | |
9dae56ea | 793 | { |
93a37866 A |
794 | SamplingScope samplingScope(this); |
795 | ||
796 | JSScope* scope = callFrame->scope(); | |
797 | VM& vm = *scope->vm(); | |
798 | ||
81345200 | 799 | ASSERT(!vm.exception()); |
93a37866 | 800 | ASSERT(!vm.isCollectorBusy()); |
81345200 | 801 | RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); |
93a37866 A |
802 | if (vm.isCollectorBusy()) |
803 | return jsNull(); | |
9dae56ea | 804 | |
81345200 | 805 | if (!vm.isSafeToRecurse()) |
14957cd0 A |
806 | return checkedReturn(throwStackOverflowError(callFrame)); |
807 | ||
93a37866 A |
808 | // First check if the "program" is actually just a JSON object. If so, |
809 | // we'll handle the JSON object here. Else, we'll handle real JS code | |
810 | // below at failedJSONP. | |
81345200 | 811 | |
6fe7ccc8 A |
812 | Vector<JSONPData> JSONPData; |
813 | bool parseResult; | |
93a37866 | 814 | const String programSource = program->source().toString(); |
6fe7ccc8 A |
815 | if (programSource.isNull()) |
816 | return jsUndefined(); | |
817 | if (programSource.is8Bit()) { | |
818 | LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP); | |
93a37866 | 819 | parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject())); |
6fe7ccc8 A |
820 | } else { |
821 | LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP); | |
93a37866 | 822 | parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject())); |
6fe7ccc8 A |
823 | } |
824 | ||
825 | if (parseResult) { | |
93a37866 | 826 | JSGlobalObject* globalObject = scope->globalObject(); |
14957cd0 A |
827 | JSValue result; |
828 | for (unsigned entry = 0; entry < JSONPData.size(); entry++) { | |
6fe7ccc8 | 829 | Vector<JSONPPathEntry> JSONPPath; |
14957cd0 A |
830 | JSONPPath.swap(JSONPData[entry].m_path); |
831 | JSValue JSONPValue = JSONPData[entry].m_value.get(); | |
6fe7ccc8 | 832 | if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclare) { |
81345200 A |
833 | globalObject->addVar(callFrame, JSONPPath[0].m_pathEntryName); |
834 | PutPropertySlot slot(globalObject); | |
835 | globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot); | |
14957cd0 A |
836 | result = jsUndefined(); |
837 | continue; | |
838 | } | |
839 | JSValue baseObject(globalObject); | |
840 | for (unsigned i = 0; i < JSONPPath.size() - 1; i++) { | |
6fe7ccc8 | 841 | ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclare); |
14957cd0 | 842 | switch (JSONPPath[i].m_type) { |
6fe7ccc8 | 843 | case JSONPPathEntryTypeDot: { |
14957cd0 A |
844 | if (i == 0) { |
845 | PropertySlot slot(globalObject); | |
846 | if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) { | |
847 | if (entry) | |
81345200 | 848 | return callFrame->vm().throwException(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName)); |
14957cd0 A |
849 | goto failedJSONP; |
850 | } | |
851 | baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName); | |
852 | } else | |
853 | baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName); | |
854 | if (callFrame->hadException()) | |
855 | return jsUndefined(); | |
856 | continue; | |
857 | } | |
6fe7ccc8 | 858 | case JSONPPathEntryTypeLookup: { |
14957cd0 A |
859 | baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex); |
860 | if (callFrame->hadException()) | |
861 | return jsUndefined(); | |
862 | continue; | |
863 | } | |
864 | default: | |
93a37866 | 865 | RELEASE_ASSERT_NOT_REACHED(); |
14957cd0 A |
866 | return jsUndefined(); |
867 | } | |
868 | } | |
81345200 | 869 | PutPropertySlot slot(baseObject); |
14957cd0 | 870 | switch (JSONPPath.last().m_type) { |
6fe7ccc8 | 871 | case JSONPPathEntryTypeCall: { |
14957cd0 A |
872 | JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName); |
873 | if (callFrame->hadException()) | |
874 | return jsUndefined(); | |
875 | CallData callData; | |
876 | CallType callType = getCallData(function, callData); | |
877 | if (callType == CallTypeNone) | |
81345200 | 878 | return callFrame->vm().throwException(callFrame, createNotAFunctionError(callFrame, function)); |
14957cd0 A |
879 | MarkedArgumentBuffer jsonArg; |
880 | jsonArg.append(JSONPValue); | |
881 | JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject; | |
882 | JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg); | |
883 | if (callFrame->hadException()) | |
884 | return jsUndefined(); | |
885 | break; | |
886 | } | |
6fe7ccc8 | 887 | case JSONPPathEntryTypeDot: { |
14957cd0 A |
888 | baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot); |
889 | if (callFrame->hadException()) | |
890 | return jsUndefined(); | |
891 | break; | |
892 | } | |
6fe7ccc8 A |
893 | case JSONPPathEntryTypeLookup: { |
894 | baseObject.putByIndex(callFrame, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode()); | |
14957cd0 A |
895 | if (callFrame->hadException()) |
896 | return jsUndefined(); | |
897 | break; | |
898 | } | |
899 | default: | |
93a37866 | 900 | RELEASE_ASSERT_NOT_REACHED(); |
14957cd0 A |
901 | return jsUndefined(); |
902 | } | |
903 | result = JSONPValue; | |
ba379fdc | 904 | } |
14957cd0 | 905 | return result; |
9dae56ea | 906 | } |
14957cd0 | 907 | failedJSONP: |
93a37866 A |
908 | // If we get here, then we have already proven that the script is not a JSON |
909 | // object. | |
910 | ||
81345200 A |
911 | VMEntryScope entryScope(vm, scope->globalObject()); |
912 | ||
93a37866 A |
913 | // Compile source to bytecode if necessary: |
914 | if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope)) | |
81345200 | 915 | return checkedReturn(callFrame->vm().throwException(callFrame, error)); |
9dae56ea | 916 | |
81345200 A |
917 | if (JSObject* error = program->prepareForExecution(callFrame, nullptr, &scope, CodeForCall)) |
918 | return checkedReturn(callFrame->vm().throwException(callFrame, error)); | |
93a37866 | 919 | |
81345200 | 920 | ProgramCodeBlock* codeBlock = program->codeBlock(); |
93a37866 | 921 | |
81345200 | 922 | if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(callFrame))) |
93a37866 | 923 | return throwTerminatedExecutionException(callFrame); |
9dae56ea | 924 | |
6fe7ccc8 | 925 | ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. |
93a37866 | 926 | |
81345200 A |
927 | ProtoCallFrame protoCallFrame; |
928 | protoCallFrame.init(codeBlock, scope, 0, thisObj, 1); | |
9dae56ea | 929 | |
93a37866 | 930 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
81345200 | 931 | profiler->willExecute(callFrame, program->sourceURL(), program->lineNo(), program->startColumn()); |
9dae56ea | 932 | |
93a37866 | 933 | // Execute the code: |
ba379fdc | 934 | JSValue result; |
9dae56ea | 935 | { |
f9bf01c6 | 936 | SamplingTool::CallRecord callRecord(m_sampler.get()); |
81345200 | 937 | Watchdog::Scope watchdogScope(vm.watchdog.get()); |
9dae56ea | 938 | |
81345200 | 939 | result = program->generatedJITCode()->execute(&vm, &protoCallFrame); |
9dae56ea A |
940 | } |
941 | ||
93a37866 | 942 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
81345200 | 943 | profiler->didExecute(callFrame, program->sourceURL(), program->lineNo(), program->startColumn()); |
9dae56ea | 944 | |
14957cd0 | 945 | return checkedReturn(result); |
9dae56ea A |
946 | } |
947 | ||
14957cd0 | 948 | JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) |
9dae56ea | 949 | { |
93a37866 | 950 | VM& vm = callFrame->vm(); |
14957cd0 | 951 | ASSERT(!callFrame->hadException()); |
93a37866 A |
952 | ASSERT(!vm.isCollectorBusy()); |
953 | if (vm.isCollectorBusy()) | |
14957cd0 | 954 | return jsNull(); |
9dae56ea | 955 | |
93a37866 A |
956 | bool isJSCall = (callType == CallTypeJS); |
957 | JSScope* scope; | |
958 | CodeBlock* newCodeBlock; | |
959 | size_t argsCount = 1 + args.size(); // implicit "this" parameter | |
14957cd0 | 960 | |
93a37866 A |
961 | if (isJSCall) |
962 | scope = callData.js.scope; | |
963 | else { | |
964 | ASSERT(callType == CallTypeHost); | |
965 | scope = callFrame->scope(); | |
966 | } | |
81345200 A |
967 | |
968 | VMEntryScope entryScope(vm, scope->globalObject()); | |
969 | if (!vm.isSafeToRecurse()) | |
970 | return checkedReturn(throwStackOverflowError(callFrame)); | |
14957cd0 | 971 | |
93a37866 A |
972 | if (isJSCall) { |
973 | // Compile the callee: | |
81345200 | 974 | JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), &scope, CodeForCall); |
14957cd0 | 975 | if (UNLIKELY(!!compileError)) { |
81345200 | 976 | return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); |
14957cd0 | 977 | } |
81345200 | 978 | newCodeBlock = callData.js.functionExecutable->codeBlockForCall(); |
93a37866 | 979 | ASSERT(!!newCodeBlock); |
81345200 | 980 | newCodeBlock->m_shouldAlwaysBeInlined = false; |
93a37866 A |
981 | } else |
982 | newCodeBlock = 0; | |
14957cd0 | 983 | |
81345200 | 984 | if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(callFrame))) |
93a37866 | 985 | return throwTerminatedExecutionException(callFrame); |
14957cd0 | 986 | |
81345200 A |
987 | ProtoCallFrame protoCallFrame; |
988 | protoCallFrame.init(newCodeBlock, scope, function, thisValue, argsCount, args.data()); | |
9dae56ea | 989 | |
93a37866 A |
990 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
991 | profiler->willExecute(callFrame, function); | |
9dae56ea | 992 | |
ba379fdc | 993 | JSValue result; |
9dae56ea | 994 | { |
93a37866 | 995 | SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall); |
81345200 | 996 | Watchdog::Scope watchdogScope(vm.watchdog.get()); |
93a37866 A |
997 | |
998 | // Execute the code: | |
81345200 A |
999 | if (isJSCall) |
1000 | result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame); | |
1001 | else { | |
1002 | result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame)); | |
1003 | if (callFrame->hadException()) | |
1004 | result = jsNull(); | |
1005 | } | |
14957cd0 | 1006 | } |
9dae56ea | 1007 | |
93a37866 A |
1008 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1009 | profiler->didExecute(callFrame, function); | |
14957cd0 | 1010 | |
14957cd0 A |
1011 | return checkedReturn(result); |
1012 | } | |
1013 | ||
1014 | JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args) | |
1015 | { | |
93a37866 | 1016 | VM& vm = callFrame->vm(); |
14957cd0 | 1017 | ASSERT(!callFrame->hadException()); |
93a37866 | 1018 | ASSERT(!vm.isCollectorBusy()); |
14957cd0 A |
1019 | // We throw in this case because we have to return something "valid" but we're |
1020 | // already in an invalid state. | |
93a37866 | 1021 | if (vm.isCollectorBusy()) |
14957cd0 A |
1022 | return checkedReturn(throwStackOverflowError(callFrame)); |
1023 | ||
93a37866 A |
1024 | bool isJSConstruct = (constructType == ConstructTypeJS); |
1025 | JSScope* scope; | |
1026 | CodeBlock* newCodeBlock; | |
1027 | size_t argsCount = 1 + args.size(); // implicit "this" parameter | |
14957cd0 | 1028 | |
93a37866 A |
1029 | if (isJSConstruct) |
1030 | scope = constructData.js.scope; | |
1031 | else { | |
1032 | ASSERT(constructType == ConstructTypeHost); | |
1033 | scope = callFrame->scope(); | |
1034 | } | |
14957cd0 | 1035 | |
81345200 A |
1036 | VMEntryScope entryScope(vm, scope->globalObject()); |
1037 | if (!vm.isSafeToRecurse()) | |
1038 | return checkedReturn(throwStackOverflowError(callFrame)); | |
14957cd0 | 1039 | |
93a37866 A |
1040 | if (isJSConstruct) { |
1041 | // Compile the callee: | |
81345200 | 1042 | JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), &scope, CodeForConstruct); |
14957cd0 | 1043 | if (UNLIKELY(!!compileError)) { |
81345200 | 1044 | return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); |
14957cd0 | 1045 | } |
81345200 | 1046 | newCodeBlock = constructData.js.functionExecutable->codeBlockForConstruct(); |
93a37866 | 1047 | ASSERT(!!newCodeBlock); |
81345200 | 1048 | newCodeBlock->m_shouldAlwaysBeInlined = false; |
93a37866 A |
1049 | } else |
1050 | newCodeBlock = 0; | |
14957cd0 | 1051 | |
81345200 | 1052 | if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(callFrame))) |
93a37866 | 1053 | return throwTerminatedExecutionException(callFrame); |
14957cd0 | 1054 | |
81345200 A |
1055 | ProtoCallFrame protoCallFrame; |
1056 | protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data()); | |
14957cd0 | 1057 | |
93a37866 A |
1058 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1059 | profiler->willExecute(callFrame, constructor); | |
14957cd0 A |
1060 | |
1061 | JSValue result; | |
1062 | { | |
93a37866 | 1063 | SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct); |
81345200 | 1064 | Watchdog::Scope watchdogScope(vm.watchdog.get()); |
93a37866 A |
1065 | |
1066 | // Execute the code. | |
81345200 A |
1067 | if (isJSConstruct) |
1068 | result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame); | |
1069 | else { | |
1070 | result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame)); | |
1071 | ||
1072 | if (!callFrame->hadException()) | |
1073 | RELEASE_ASSERT(result.isObject()); | |
1074 | } | |
14957cd0 A |
1075 | } |
1076 | ||
93a37866 A |
1077 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1078 | profiler->didExecute(callFrame, constructor); | |
1079 | ||
14957cd0 A |
1080 | if (callFrame->hadException()) |
1081 | return 0; | |
1082 | ASSERT(result.isObject()); | |
1083 | return checkedReturn(asObject(result)); | |
9dae56ea A |
1084 | } |
1085 | ||
81345200 | 1086 | CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, JSValue* args) |
ba379fdc | 1087 | { |
93a37866 | 1088 | VM& vm = *scope->vm(); |
81345200 | 1089 | ASSERT(!vm.exception()); |
ba379fdc | 1090 | |
93a37866 | 1091 | if (vm.isCollectorBusy()) |
6fe7ccc8 A |
1092 | return CallFrameClosure(); |
1093 | ||
93a37866 | 1094 | // Compile the callee: |
81345200 | 1095 | JSObject* error = functionExecutable->prepareForExecution(callFrame, function, &scope, CodeForCall); |
93a37866 | 1096 | if (error) { |
81345200 | 1097 | callFrame->vm().throwException(callFrame, error); |
ba379fdc A |
1098 | return CallFrameClosure(); |
1099 | } | |
81345200 A |
1100 | CodeBlock* newCodeBlock = functionExecutable->codeBlockForCall(); |
1101 | newCodeBlock->m_shouldAlwaysBeInlined = false; | |
ba379fdc | 1102 | |
93a37866 A |
1103 | size_t argsCount = argumentCountIncludingThis; |
1104 | ||
81345200 | 1105 | protoCallFrame->init(newCodeBlock, scope, function, jsUndefined(), argsCount, args); |
93a37866 | 1106 | // Return the successful closure: |
81345200 | 1107 | CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; |
ba379fdc A |
1108 | return result; |
1109 | } | |
1110 | ||
14957cd0 | 1111 | JSValue Interpreter::execute(CallFrameClosure& closure) |
ba379fdc | 1112 | { |
93a37866 A |
1113 | VM& vm = *closure.vm; |
1114 | SamplingScope samplingScope(this); | |
1115 | ||
1116 | ASSERT(!vm.isCollectorBusy()); | |
81345200 | 1117 | RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); |
93a37866 | 1118 | if (vm.isCollectorBusy()) |
14957cd0 | 1119 | return jsNull(); |
93a37866 A |
1120 | |
1121 | StackStats::CheckPoint stackCheckPoint; | |
ba379fdc | 1122 | closure.resetCallFrame(); |
93a37866 A |
1123 | |
1124 | if (LegacyProfiler* profiler = vm.enabledProfiler()) | |
1125 | profiler->willExecute(closure.oldCallFrame, closure.function); | |
1126 | ||
81345200 | 1127 | if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(closure.oldCallFrame))) |
93a37866 | 1128 | return throwTerminatedExecutionException(closure.oldCallFrame); |
6fe7ccc8 | 1129 | |
93a37866 | 1130 | // Execute the code: |
ba379fdc A |
1131 | JSValue result; |
1132 | { | |
f9bf01c6 | 1133 | SamplingTool::CallRecord callRecord(m_sampler.get()); |
81345200 | 1134 | Watchdog::Scope watchdogScope(vm.watchdog.get()); |
93a37866 | 1135 | |
81345200 | 1136 | result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame); |
ba379fdc | 1137 | } |
6fe7ccc8 | 1138 | |
93a37866 A |
1139 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1140 | profiler->didExecute(closure.oldCallFrame, closure.function); | |
1141 | ||
14957cd0 | 1142 | return checkedReturn(result); |
ba379fdc A |
1143 | } |
1144 | ||
93a37866 | 1145 | JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope) |
9dae56ea | 1146 | { |
93a37866 A |
1147 | VM& vm = *scope->vm(); |
1148 | SamplingScope samplingScope(this); | |
1149 | ||
1150 | ASSERT(scope->vm() == &callFrame->vm()); | |
81345200 | 1151 | ASSERT(!vm.exception()); |
93a37866 | 1152 | ASSERT(!vm.isCollectorBusy()); |
81345200 | 1153 | RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); |
93a37866 | 1154 | if (vm.isCollectorBusy()) |
14957cd0 | 1155 | return jsNull(); |
9dae56ea | 1156 | |
81345200 A |
1157 | VMEntryScope entryScope(vm, scope->globalObject()); |
1158 | if (!vm.isSafeToRecurse()) | |
1159 | return checkedReturn(throwStackOverflowError(callFrame)); | |
9dae56ea | 1160 | |
81345200 A |
1161 | unsigned numVariables = eval->numVariables(); |
1162 | int numFunctions = eval->numberOfFunctionDecls(); | |
9dae56ea | 1163 | |
81345200 A |
1164 | JSScope* variableObject; |
1165 | if ((numVariables || numFunctions) && eval->isStrictMode()) { | |
1166 | scope = StrictEvalActivation::create(callFrame); | |
1167 | variableObject = scope; | |
1168 | } else { | |
1169 | for (JSScope* node = scope; ; node = node->next()) { | |
1170 | RELEASE_ASSERT(node); | |
1171 | if (node->isVariableObject() && !node->isNameScopeObject()) { | |
1172 | variableObject = node; | |
1173 | break; | |
1174 | } | |
9dae56ea A |
1175 | } |
1176 | } | |
1177 | ||
81345200 A |
1178 | JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, &scope, CodeForCall); |
1179 | if (UNLIKELY(!!compileError)) | |
1180 | return checkedReturn(callFrame->vm().throwException(callFrame, compileError)); | |
1181 | EvalCodeBlock* codeBlock = eval->codeBlock(); | |
1182 | ||
4e4e5a6f | 1183 | if (numVariables || numFunctions) { |
93a37866 | 1184 | BatchedTransitionOptimizer optimizer(vm, variableObject); |
81345200 A |
1185 | if (variableObject->next()) |
1186 | variableObject->globalObject()->varInjectionWatchpoint()->fireAll(); | |
9dae56ea | 1187 | |
f9bf01c6 A |
1188 | for (unsigned i = 0; i < numVariables; ++i) { |
1189 | const Identifier& ident = codeBlock->variable(i); | |
9dae56ea | 1190 | if (!variableObject->hasProperty(callFrame, ident)) { |
81345200 | 1191 | PutPropertySlot slot(variableObject); |
6fe7ccc8 | 1192 | variableObject->methodTable()->put(variableObject, callFrame, ident, jsUndefined(), slot); |
9dae56ea A |
1193 | } |
1194 | } | |
1195 | ||
f9bf01c6 A |
1196 | for (int i = 0; i < numFunctions; ++i) { |
1197 | FunctionExecutable* function = codeBlock->functionDecl(i); | |
81345200 A |
1198 | PutPropertySlot slot(variableObject); |
1199 | variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot); | |
9dae56ea | 1200 | } |
9dae56ea A |
1201 | } |
1202 | ||
81345200 | 1203 | if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(callFrame))) |
93a37866 | 1204 | return throwTerminatedExecutionException(callFrame); |
6fe7ccc8 A |
1205 | |
1206 | ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. | |
9dae56ea | 1207 | |
81345200 A |
1208 | ProtoCallFrame protoCallFrame; |
1209 | protoCallFrame.init(codeBlock, scope, 0, thisValue, 1); | |
9dae56ea | 1210 | |
93a37866 | 1211 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
81345200 | 1212 | profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo(), eval->startColumn()); |
9dae56ea | 1213 | |
93a37866 | 1214 | // Execute the code: |
ba379fdc | 1215 | JSValue result; |
9dae56ea | 1216 | { |
f9bf01c6 | 1217 | SamplingTool::CallRecord callRecord(m_sampler.get()); |
81345200 | 1218 | Watchdog::Scope watchdogScope(vm.watchdog.get()); |
9dae56ea | 1219 | |
81345200 | 1220 | result = eval->generatedJITCode()->execute(&vm, &protoCallFrame); |
9dae56ea A |
1221 | } |
1222 | ||
93a37866 | 1223 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
81345200 | 1224 | profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo(), eval->startColumn()); |
9dae56ea | 1225 | |
14957cd0 | 1226 | return checkedReturn(result); |
9dae56ea A |
1227 | } |
1228 | ||
81345200 | 1229 | NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID) |
9dae56ea | 1230 | { |
81345200 | 1231 | Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger(); |
9dae56ea A |
1232 | if (!debugger) |
1233 | return; | |
1234 | ||
81345200 A |
1235 | ASSERT(callFrame->codeBlock()->hasDebuggerRequests()); |
1236 | ASSERT(!callFrame->hadException()); | |
1237 | ||
9dae56ea A |
1238 | switch (debugHookID) { |
1239 | case DidEnterCallFrame: | |
81345200 A |
1240 | debugger->callEvent(callFrame); |
1241 | break; | |
9dae56ea | 1242 | case WillLeaveCallFrame: |
81345200 A |
1243 | debugger->returnEvent(callFrame); |
1244 | break; | |
9dae56ea | 1245 | case WillExecuteStatement: |
81345200 A |
1246 | debugger->atStatement(callFrame); |
1247 | break; | |
9dae56ea | 1248 | case WillExecuteProgram: |
81345200 A |
1249 | debugger->willExecuteProgram(callFrame); |
1250 | break; | |
9dae56ea | 1251 | case DidExecuteProgram: |
81345200 A |
1252 | debugger->didExecuteProgram(callFrame); |
1253 | break; | |
9dae56ea | 1254 | case DidReachBreakpoint: |
81345200 A |
1255 | debugger->didReachBreakpoint(callFrame); |
1256 | break; | |
9dae56ea | 1257 | } |
81345200 A |
1258 | ASSERT(!callFrame->hadException()); |
1259 | } | |
9dae56ea | 1260 | |
f9bf01c6 A |
1261 | void Interpreter::enableSampler() |
1262 | { | |
1263 | #if ENABLE(OPCODE_SAMPLING) | |
1264 | if (!m_sampler) { | |
6fe7ccc8 | 1265 | m_sampler = adoptPtr(new SamplingTool(this)); |
f9bf01c6 A |
1266 | m_sampler->setup(); |
1267 | } | |
1268 | #endif | |
1269 | } | |
1270 | void Interpreter::dumpSampleData(ExecState* exec) | |
1271 | { | |
1272 | #if ENABLE(OPCODE_SAMPLING) | |
1273 | if (m_sampler) | |
1274 | m_sampler->dump(exec); | |
1275 | #else | |
1276 | UNUSED_PARAM(exec); | |
1277 | #endif | |
1278 | } | |
1279 | void Interpreter::startSampling() | |
1280 | { | |
1281 | #if ENABLE(SAMPLING_THREAD) | |
1282 | if (!m_sampleEntryDepth) | |
1283 | SamplingThread::start(); | |
1284 | ||
1285 | m_sampleEntryDepth++; | |
1286 | #endif | |
1287 | } | |
1288 | void Interpreter::stopSampling() | |
1289 | { | |
1290 | #if ENABLE(SAMPLING_THREAD) | |
1291 | m_sampleEntryDepth--; | |
1292 | if (!m_sampleEntryDepth) | |
1293 | SamplingThread::stop(); | |
1294 | #endif | |
1295 | } | |
1296 | ||
9dae56ea | 1297 | } // namespace JSC |