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