]> git.saurik.com Git - apple/javascriptcore.git/blame - interpreter/Interpreter.cpp
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / interpreter / Interpreter.cpp
CommitLineData
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
89using namespace std;
90
91namespace JSC {
9dae56ea 92
6fe7ccc8 93JSValue 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 140CallFrame* 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
222void 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 285Interpreter::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
296Interpreter::~Interpreter()
297{
6fe7ccc8
A
298}
299
93a37866 300void 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
321void Interpreter::dumpCallFrame(CallFrame*)
322{
323}
324
325#else
9dae56ea
A
326
327void Interpreter::dumpCallFrame(CallFrame* callFrame)
328{
93a37866 329 callFrame->codeBlock()->dumpBytecode();
9dae56ea
A
330 dumpRegisters(callFrame);
331}
332
81345200
A
333class DumpRegisterFunctor {
334public:
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
356private:
357 bool m_hasSkippedFirstFrame;
358 const Register*& m_it;
359};
360
9dae56ea
A
361void 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
430bool 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 441static 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 489static 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 506void 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
525void 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
531String 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
555class GetStackTraceFunctor {
556public:
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
594private:
595 VM& m_vm;
596 Vector<StackFrame>& m_results;
597 size_t m_remainingCapacityForFrameCapture;
598};
6fe7ccc8 599
81345200
A
600void 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
612JSString* 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
624class GetExceptionHandlerFunctor {
625public:
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
647private:
648 HandlerInfo* m_handler;
649};
650
651class UnwindFunctor {
652public:
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
680private:
681 CallFrame*& m_callFrame;
682 bool m_isTermination;
683 CodeBlock*& m_codeBlock;
684 HandlerInfo*& m_handler;
685};
686
687NEVER_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
765static inline JSValue checkedReturn(JSValue returnValue)
766{
767 ASSERT(returnValue);
768 return returnValue;
769}
770
771static inline JSObject* checkedReturn(JSObject* returnValue)
772{
773 ASSERT(returnValue);
774 return returnValue;
775}
776
93a37866
A
777class SamplingScope {
778public:
779 SamplingScope(Interpreter* interpreter)
780 : m_interpreter(interpreter)
781 {
782 interpreter->startSampling();
783 }
784 ~SamplingScope()
785 {
786 m_interpreter->stopSampling();
787 }
788private:
789 Interpreter* m_interpreter;
790};
791
792JSValue 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 907failedJSONP:
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 948JSValue 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
1014JSObject* 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 1086CallFrameClosure 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 1111JSValue 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 1145JSValue 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 1229NEVER_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
1261void 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}
1270void 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}
1279void Interpreter::startSampling()
1280{
1281#if ENABLE(SAMPLING_THREAD)
1282 if (!m_sampleEntryDepth)
1283 SamplingThread::start();
1284
1285 m_sampleEntryDepth++;
1286#endif
1287}
1288void 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