/ interpreter / Interpreter.cpp
Interpreter.cpp
1 /* 2 * Copyright (C) 2008-2020 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 "BatchedTransitionOptimizer.h" 34 #include "Bytecodes.h" 35 #include "CallFrameClosure.h" 36 #include "CatchScope.h" 37 #include "CheckpointOSRExitSideState.h" 38 #include "CodeBlock.h" 39 #include "DirectArguments.h" 40 #include "Debugger.h" 41 #include "DirectEvalCodeCache.h" 42 #include "EvalCodeBlock.h" 43 #include "ExecutableBaseInlines.h" 44 #include "FrameTracers.h" 45 #include "InterpreterInlines.h" 46 #include "JITCodeInlines.h" 47 #include "JSArrayInlines.h" 48 #include "JSCInlines.h" 49 #include "JSImmutableButterfly.h" 50 #include "JSLexicalEnvironment.h" 51 #include "JSModuleEnvironment.h" 52 #include "JSString.h" 53 #include "LLIntThunks.h" 54 #include "LiteralParser.h" 55 #include "ModuleProgramCodeBlock.h" 56 #include "ProgramCodeBlock.h" 57 #include "ProtoCallFrameInlines.h" 58 #include "Register.h" 59 #include "RegisterAtOffsetList.h" 60 #include "ScopedArguments.h" 61 #include "StackFrame.h" 62 #include "StackVisitor.h" 63 #include "StrictEvalActivation.h" 64 #include "VMEntryScope.h" 65 #include "VMInlines.h" 66 #include "VirtualRegister.h" 67 #include <stdio.h> 68 #include <wtf/NeverDestroyed.h> 69 #include <wtf/Scope.h> 70 #include <wtf/StdLibExtras.h> 71 #include <wtf/text/StringBuilder.h> 72 73 #if ENABLE(WEBASSEMBLY) 74 #include "WasmContextInlines.h" 75 #include "WebAssemblyFunction.h" 76 #endif 77 78 namespace JSC { 79 80 JSValue eval(JSGlobalObject* globalObject, CallFrame* callFrame, ECMAMode ecmaMode) 81 { 82 VM& vm = globalObject->vm(); 83 auto scope = DECLARE_THROW_SCOPE(vm); 84 85 auto clobberizeValidator = makeScopeExit([&] { 86 vm.didEnterVM = true; 87 }); 88 89 if (!callFrame->argumentCount()) 90 return jsUndefined(); 91 92 JSValue program = callFrame->argument(0); 93 if (!program.isString()) 94 return program; 95 96 TopCallFrameSetter topCallFrame(vm, callFrame); 97 if (!globalObject->evalEnabled()) { 98 throwException(globalObject, scope, createEvalError(globalObject, globalObject->evalDisabledErrorMessage())); 99 return jsUndefined(); 100 } 101 String programSource = asString(program)->value(globalObject); 102 RETURN_IF_EXCEPTION(scope, JSValue()); 103 104 CallFrame* callerFrame = callFrame->callerFrame(); 105 CallSiteIndex callerCallSiteIndex = callerFrame->callSiteIndex(); 106 CodeBlock* callerCodeBlock = callerFrame->codeBlock(); 107 JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister()).Register::scope(); 108 UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock(); 109 110 bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext(); 111 112 DerivedContextType derivedContextType = callerUnlinkedCodeBlock->derivedContextType(); 113 if (!isArrowFunctionContext && callerUnlinkedCodeBlock->isClassContext()) { 114 derivedContextType = callerUnlinkedCodeBlock->isConstructor() 115 ? DerivedContextType::DerivedConstructorContext 116 : DerivedContextType::DerivedMethodContext; 117 } 118 119 EvalContextType evalContextType; 120 if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::ClassFieldInitializerMode) 121 evalContextType = EvalContextType::InstanceFieldEvalContext; 122 else if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode())) 123 evalContextType = EvalContextType::FunctionEvalContext; 124 else if (callerUnlinkedCodeBlock->codeType() == EvalCode) 125 evalContextType = callerUnlinkedCodeBlock->evalContextType(); 126 else 127 evalContextType = EvalContextType::None; 128 129 DirectEvalExecutable* eval = callerCodeBlock->directEvalCodeCache().tryGet(programSource, callerCallSiteIndex); 130 if (!eval) { 131 if (!ecmaMode.isStrict()) { 132 if (programSource.is8Bit()) { 133 LiteralParser<LChar> preparser(globalObject, programSource.characters8(), programSource.length(), NonStrictJSON, callerCodeBlock); 134 if (JSValue parsedObject = preparser.tryLiteralParse()) 135 RELEASE_AND_RETURN(scope, parsedObject); 136 137 } else { 138 LiteralParser<UChar> preparser(globalObject, programSource.characters16(), programSource.length(), NonStrictJSON, callerCodeBlock); 139 if (JSValue parsedObject = preparser.tryLiteralParse()) 140 RELEASE_AND_RETURN(scope, parsedObject); 141 142 } 143 RETURN_IF_EXCEPTION(scope, JSValue()); 144 } 145 146 TDZEnvironment variablesUnderTDZ; 147 VariableEnvironment privateNames; 148 JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ, privateNames); 149 eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), derivedContextType, callerUnlinkedCodeBlock->needsClassFieldInitializer(), isArrowFunctionContext, callerCodeBlock->ownerExecutable()->isInsideOrdinaryFunction(), evalContextType, &variablesUnderTDZ, &privateNames, ecmaMode); 150 EXCEPTION_ASSERT(!!scope.exception() == !eval); 151 if (!eval) 152 return jsUndefined(); 153 154 callerCodeBlock->directEvalCodeCache().set(globalObject, callerCodeBlock, programSource, callerCallSiteIndex, eval); 155 } 156 157 JSValue thisValue = callerFrame->thisValue(); 158 Interpreter* interpreter = vm.interpreter; 159 RELEASE_AND_RETURN(scope, interpreter->execute(eval, globalObject, thisValue, callerScopeChain)); 160 } 161 162 unsigned sizeOfVarargs(JSGlobalObject* globalObject, JSValue arguments, uint32_t firstVarArgOffset) 163 { 164 VM& vm = globalObject->vm(); 165 auto scope = DECLARE_THROW_SCOPE(vm); 166 167 if (UNLIKELY(!arguments.isCell())) { 168 if (arguments.isUndefinedOrNull()) 169 return 0; 170 171 throwException(globalObject, scope, createInvalidFunctionApplyParameterError(globalObject, arguments)); 172 return 0; 173 } 174 175 JSCell* cell = arguments.asCell(); 176 unsigned length; 177 switch (cell->type()) { 178 case DirectArgumentsType: 179 length = jsCast<DirectArguments*>(cell)->length(globalObject); 180 break; 181 case ScopedArgumentsType: 182 length = jsCast<ScopedArguments*>(cell)->length(globalObject); 183 break; 184 case JSImmutableButterflyType: 185 length = jsCast<JSImmutableButterfly*>(cell)->length(); 186 break; 187 case StringType: 188 case SymbolType: 189 case HeapBigIntType: 190 throwException(globalObject, scope, createInvalidFunctionApplyParameterError(globalObject, arguments)); 191 return 0; 192 193 default: 194 RELEASE_ASSERT(arguments.isObject()); 195 length = clampToUnsigned(toLength(globalObject, jsCast<JSObject*>(cell))); 196 break; 197 } 198 RETURN_IF_EXCEPTION(scope, 0); 199 200 if (length > maxArguments) 201 throwStackOverflowError(globalObject, scope); 202 203 if (length >= firstVarArgOffset) 204 length -= firstVarArgOffset; 205 else 206 length = 0; 207 208 return length; 209 } 210 211 unsigned sizeFrameForForwardArguments(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, unsigned numUsedStackSlots) 212 { 213 auto scope = DECLARE_THROW_SCOPE(vm); 214 215 unsigned length = callFrame->argumentCount(); 216 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1); 217 if (UNLIKELY(!vm.ensureStackCapacityFor(calleeFrame->registers()))) 218 throwStackOverflowError(globalObject, scope); 219 220 return length; 221 } 222 223 unsigned sizeFrameForVarargs(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset) 224 { 225 auto scope = DECLARE_THROW_SCOPE(vm); 226 227 unsigned length = sizeOfVarargs(globalObject, arguments, firstVarArgOffset); 228 RETURN_IF_EXCEPTION(scope, 0); 229 230 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1); 231 if (UNLIKELY(length > maxArguments || !vm.ensureStackCapacityFor(calleeFrame->registers()))) { 232 throwStackOverflowError(globalObject, scope); 233 return 0; 234 } 235 236 return length; 237 } 238 239 void loadVarargs(JSGlobalObject* globalObject, JSValue* firstElementDest, JSValue arguments, uint32_t offset, uint32_t length) 240 { 241 if (UNLIKELY(!arguments.isCell()) || !length) 242 return; 243 244 VM& vm = globalObject->vm(); 245 auto scope = DECLARE_THROW_SCOPE(vm); 246 JSCell* cell = arguments.asCell(); 247 248 switch (cell->type()) { 249 case DirectArgumentsType: 250 scope.release(); 251 jsCast<DirectArguments*>(cell)->copyToArguments(globalObject, firstElementDest, offset, length); 252 return; 253 case ScopedArgumentsType: 254 scope.release(); 255 jsCast<ScopedArguments*>(cell)->copyToArguments(globalObject, firstElementDest, offset, length); 256 return; 257 case JSImmutableButterflyType: 258 scope.release(); 259 jsCast<JSImmutableButterfly*>(cell)->copyToArguments(globalObject, firstElementDest, offset, length); 260 return; 261 default: { 262 ASSERT(arguments.isObject()); 263 JSObject* object = jsCast<JSObject*>(cell); 264 if (isJSArray(object)) { 265 scope.release(); 266 jsCast<JSArray*>(object)->copyToArguments(globalObject, firstElementDest, offset, length); 267 return; 268 } 269 unsigned i; 270 for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i) 271 firstElementDest[i] = object->getIndexQuickly(i + offset); 272 for (; i < length; ++i) { 273 JSValue value = object->get(globalObject, i + offset); 274 RETURN_IF_EXCEPTION(scope, void()); 275 firstElementDest[i] = value; 276 } 277 return; 278 } } 279 } 280 281 void setupVarargsFrame(JSGlobalObject* globalObject, CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length) 282 { 283 VirtualRegister calleeFrameOffset(newCallFrame - callFrame); 284 285 loadVarargs( 286 globalObject, 287 bitwise_cast<JSValue*>(&callFrame->r(calleeFrameOffset + CallFrame::argumentOffset(0))), 288 arguments, offset, length); 289 290 newCallFrame->setArgumentCountIncludingThis(length + 1); 291 } 292 293 void setupVarargsFrameAndSetThis(JSGlobalObject* globalObject, CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length) 294 { 295 setupVarargsFrame(globalObject, callFrame, newCallFrame, arguments, firstVarArgOffset, length); 296 newCallFrame->setThisValue(thisValue); 297 } 298 299 void setupForwardArgumentsFrame(JSGlobalObject*, CallFrame* execCaller, CallFrame* execCallee, uint32_t length) 300 { 301 ASSERT(length == execCaller->argumentCount()); 302 unsigned offset = execCaller->argumentOffset(0) * sizeof(Register); 303 memcpy(reinterpret_cast<char*>(execCallee) + offset, reinterpret_cast<char*>(execCaller) + offset, length * sizeof(Register)); 304 execCallee->setArgumentCountIncludingThis(length + 1); 305 } 306 307 void setupForwardArgumentsFrameAndSetThis(JSGlobalObject* globalObject, CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length) 308 { 309 setupForwardArgumentsFrame(globalObject, execCaller, execCallee, length); 310 execCallee->setThisValue(thisValue); 311 } 312 313 314 315 Interpreter::Interpreter(VM& vm) 316 : m_vm(vm) 317 #if ENABLE(C_LOOP) 318 , m_cloopStack(vm) 319 #endif 320 { 321 #if ASSERT_ENABLED 322 static std::once_flag assertOnceKey; 323 std::call_once(assertOnceKey, [] { 324 for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i) { 325 OpcodeID opcodeID = static_cast<OpcodeID>(i); 326 RELEASE_ASSERT(getOpcodeID(getOpcode(opcodeID)) == opcodeID); 327 } 328 }); 329 #endif // ASSERT_ENABLED 330 } 331 332 Interpreter::~Interpreter() 333 { 334 } 335 336 #if ENABLE(COMPUTED_GOTO_OPCODES) 337 #if !ENABLE(LLINT_EMBEDDED_OPCODE_ID) || ASSERT_ENABLED 338 HashMap<Opcode, OpcodeID>& Interpreter::opcodeIDTable() 339 { 340 static LazyNeverDestroyed<HashMap<Opcode, OpcodeID>> opcodeIDTable; 341 342 static std::once_flag initializeKey; 343 std::call_once(initializeKey, [&] { 344 opcodeIDTable.construct(); 345 const Opcode* opcodeTable = LLInt::opcodeMap(); 346 for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i) 347 opcodeIDTable->add(opcodeTable[i], static_cast<OpcodeID>(i)); 348 }); 349 350 return opcodeIDTable; 351 } 352 #endif // !ENABLE(LLINT_EMBEDDED_OPCODE_ID) || ASSERT_ENABLED 353 #endif // ENABLE(COMPUTED_GOTO_OPCODES) 354 355 #if ASSERT_ENABLED 356 bool Interpreter::isOpcode(Opcode opcode) 357 { 358 #if ENABLE(COMPUTED_GOTO_OPCODES) 359 return opcode != HashTraits<Opcode>::emptyValue() 360 && !HashTraits<Opcode>::isDeletedValue(opcode) 361 && opcodeIDTable().contains(opcode); 362 #else 363 return opcode >= 0 && opcode <= op_end; 364 #endif 365 } 366 #endif // ASSERT_ENABLED 367 368 class GetStackTraceFunctor { 369 public: 370 GetStackTraceFunctor(VM& vm, JSCell* owner, Vector<StackFrame>& results, size_t framesToSkip, size_t capacity) 371 : m_vm(vm) 372 , m_owner(owner) 373 , m_results(results) 374 , m_framesToSkip(framesToSkip) 375 , m_remainingCapacityForFrameCapture(capacity) 376 { 377 m_results.reserveInitialCapacity(capacity); 378 } 379 380 StackVisitor::Status operator()(StackVisitor& visitor) const 381 { 382 if (m_framesToSkip > 0) { 383 m_framesToSkip--; 384 return StackVisitor::Continue; 385 } 386 387 if (m_remainingCapacityForFrameCapture) { 388 if (visitor->isWasmFrame()) { 389 m_results.append(StackFrame(visitor->wasmFunctionIndexOrName())); 390 } else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { 391 m_results.append( 392 StackFrame(m_vm, m_owner, visitor->callee().asCell(), visitor->codeBlock(), visitor->bytecodeIndex())); 393 } else { 394 m_results.append( 395 StackFrame(m_vm, m_owner, visitor->callee().asCell())); 396 } 397 398 m_remainingCapacityForFrameCapture--; 399 return StackVisitor::Continue; 400 } 401 return StackVisitor::Done; 402 } 403 404 private: 405 VM& m_vm; 406 JSCell* m_owner; 407 Vector<StackFrame>& m_results; 408 mutable size_t m_framesToSkip; 409 mutable size_t m_remainingCapacityForFrameCapture; 410 }; 411 412 void Interpreter::getStackTrace(JSCell* owner, Vector<StackFrame>& results, size_t framesToSkip, size_t maxStackSize) 413 { 414 DisallowGC disallowGC; 415 VM& vm = m_vm; 416 CallFrame* callFrame = vm.topCallFrame; 417 if (!callFrame || !maxStackSize) 418 return; 419 420 size_t framesCount = 0; 421 size_t maxFramesCountNeeded = maxStackSize + framesToSkip; 422 StackVisitor::visit(callFrame, vm, [&] (StackVisitor&) -> StackVisitor::Status { 423 if (++framesCount < maxFramesCountNeeded) 424 return StackVisitor::Continue; 425 return StackVisitor::Done; 426 }); 427 if (framesCount <= framesToSkip) 428 return; 429 430 framesCount -= framesToSkip; 431 framesCount = std::min(maxStackSize, framesCount); 432 433 GetStackTraceFunctor functor(vm, owner, results, framesToSkip, framesCount); 434 StackVisitor::visit(callFrame, vm, functor); 435 ASSERT(results.size() == results.capacity()); 436 } 437 438 String Interpreter::stackTraceAsString(VM& vm, const Vector<StackFrame>& stackTrace) 439 { 440 // FIXME: JSStringJoiner could be more efficient than StringBuilder here. 441 StringBuilder builder; 442 for (unsigned i = 0; i < stackTrace.size(); i++) { 443 builder.append(String(stackTrace[i].toString(vm))); 444 if (i != stackTrace.size() - 1) 445 builder.append('\n'); 446 } 447 return builder.toString(); 448 } 449 450 ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, RequiredHandler requiredHandler) 451 { 452 ASSERT(codeBlock); 453 #if ENABLE(DFG_JIT) 454 ASSERT(!visitor->isInlinedFrame()); 455 #endif 456 457 CallFrame* callFrame = visitor->callFrame(); 458 unsigned exceptionHandlerIndex; 459 if (JITCode::isOptimizingJIT(codeBlock->jitType())) 460 exceptionHandlerIndex = callFrame->callSiteIndex().bits(); 461 else 462 exceptionHandlerIndex = callFrame->bytecodeIndex().offset(); 463 464 return codeBlock->handlerForIndex(exceptionHandlerIndex, requiredHandler); 465 } 466 467 class GetCatchHandlerFunctor { 468 public: 469 GetCatchHandlerFunctor() 470 : m_handler(nullptr) 471 { 472 } 473 474 HandlerInfo* handler() { return m_handler; } 475 476 StackVisitor::Status operator()(StackVisitor& visitor) const 477 { 478 visitor.unwindToMachineCodeBlockFrame(); 479 480 CodeBlock* codeBlock = visitor->codeBlock(); 481 if (!codeBlock) 482 return StackVisitor::Continue; 483 484 m_handler = findExceptionHandler(visitor, codeBlock, RequiredHandler::CatchHandler); 485 if (m_handler) 486 return StackVisitor::Done; 487 488 return StackVisitor::Continue; 489 } 490 491 private: 492 mutable HandlerInfo* m_handler; 493 }; 494 495 ALWAYS_INLINE static void notifyDebuggerOfUnwinding(VM& vm, CallFrame* callFrame) 496 { 497 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject(vm); 498 auto catchScope = DECLARE_CATCH_SCOPE(vm); 499 if (Debugger* debugger = globalObject->debugger()) { 500 SuspendExceptionScope scope(&vm); 501 if (callFrame->isAnyWasmCallee() 502 || (callFrame->callee().isCell() && callFrame->callee().asCell()->inherits<JSFunction>(vm))) 503 debugger->unwindEvent(callFrame); 504 else 505 debugger->didExecuteProgram(callFrame); 506 catchScope.assertNoException(); 507 } 508 } 509 510 class UnwindFunctor { 511 public: 512 UnwindFunctor(VM& vm, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler) 513 : m_vm(vm) 514 , m_callFrame(callFrame) 515 , m_isTermination(isTermination) 516 , m_codeBlock(codeBlock) 517 , m_handler(handler) 518 { 519 } 520 521 StackVisitor::Status operator()(StackVisitor& visitor) const 522 { 523 visitor.unwindToMachineCodeBlockFrame(); 524 m_callFrame = visitor->callFrame(); 525 m_codeBlock = visitor->codeBlock(); 526 527 m_handler = nullptr; 528 if (m_codeBlock) { 529 if (!m_isTermination) { 530 m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler); 531 if (m_handler) 532 return StackVisitor::Done; 533 } 534 } 535 536 #if ENABLE(WEBASSEMBLY) 537 if (visitor->callee().isCell()) { 538 if (auto* jsToWasmICCallee = jsDynamicCast<JSToWasmICCallee*>(m_vm, visitor->callee().asCell())) 539 m_vm.wasmContext.store(jsToWasmICCallee->function()->previousInstance(m_callFrame), m_vm.softStackLimit()); 540 } 541 #endif 542 543 notifyDebuggerOfUnwinding(m_vm, m_callFrame); 544 545 copyCalleeSavesToEntryFrameCalleeSavesBuffer(visitor); 546 547 bool shouldStopUnwinding = visitor->callerIsEntryFrame(); 548 if (shouldStopUnwinding) 549 return StackVisitor::Done; 550 551 return StackVisitor::Continue; 552 } 553 554 private: 555 void copyCalleeSavesToEntryFrameCalleeSavesBuffer(StackVisitor& visitor) const 556 { 557 #if ENABLE(ASSEMBLER) 558 Optional<RegisterAtOffsetList> currentCalleeSaves = visitor->calleeSaveRegistersForUnwinding(); 559 560 if (!currentCalleeSaves) 561 return; 562 563 RegisterAtOffsetList* allCalleeSaves = RegisterSet::vmCalleeSaveRegisterOffsets(); 564 RegisterSet dontCopyRegisters = RegisterSet::stackRegisters(); 565 CPURegister* frame = reinterpret_cast<CPURegister*>(m_callFrame->registers()); 566 567 unsigned registerCount = currentCalleeSaves->size(); 568 VMEntryRecord* record = vmEntryRecord(m_vm.topEntryFrame); 569 for (unsigned i = 0; i < registerCount; i++) { 570 RegisterAtOffset currentEntry = currentCalleeSaves->at(i); 571 if (dontCopyRegisters.get(currentEntry.reg())) 572 continue; 573 RegisterAtOffset* calleeSavesEntry = allCalleeSaves->find(currentEntry.reg()); 574 575 record->calleeSaveRegistersBuffer[calleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex()); 576 } 577 #else 578 UNUSED_PARAM(visitor); 579 #endif 580 } 581 582 VM& m_vm; 583 CallFrame*& m_callFrame; 584 bool m_isTermination; 585 CodeBlock*& m_codeBlock; 586 HandlerInfo*& m_handler; 587 }; 588 589 NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception) 590 { 591 auto scope = DECLARE_CATCH_SCOPE(vm); 592 593 ASSERT(reinterpret_cast<void*>(callFrame) != vm.topEntryFrame); 594 CodeBlock* codeBlock = callFrame->codeBlock(); 595 596 JSValue exceptionValue = exception->value(); 597 ASSERT(!exceptionValue.isEmpty()); 598 ASSERT(!exceptionValue.isCell() || exceptionValue.asCell()); 599 // This shouldn't be possible (hence the assertions), but we're already in the slowest of 600 // slow cases, so let's harden against it anyway to be safe. 601 if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell())) 602 exceptionValue = jsNull(); 603 604 EXCEPTION_ASSERT_UNUSED(scope, scope.exception()); 605 606 // Calculate an exception handler vPC, unwinding call frames as necessary. 607 HandlerInfo* handler = nullptr; 608 UnwindFunctor functor(vm, callFrame, isTerminatedExecutionException(vm, exception), codeBlock, handler); 609 StackVisitor::visit<StackVisitor::TerminateIfTopEntryFrameIsEmpty>(callFrame, vm, functor); 610 if (vm.hasCheckpointOSRSideState()) 611 vm.popAllCheckpointOSRSideStateUntil(callFrame); 612 613 if (!handler) 614 return nullptr; 615 616 return handler; 617 } 618 619 void Interpreter::notifyDebuggerOfExceptionToBeThrown(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame, Exception* exception) 620 { 621 Debugger* debugger = globalObject->debugger(); 622 if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) { 623 // This code assumes that if the debugger is enabled then there is no inlining. 624 // If that assumption turns out to be false then we'll ignore the inlined call 625 // frames. 626 // https://bugs.webkit.org/show_bug.cgi?id=121754 627 628 bool hasCatchHandler; 629 bool isTermination = isTerminatedExecutionException(vm, exception); 630 if (isTermination) 631 hasCatchHandler = false; 632 else { 633 GetCatchHandlerFunctor functor; 634 StackVisitor::visit(callFrame, vm, functor); 635 HandlerInfo* handler = functor.handler(); 636 ASSERT(!handler || handler->isCatchHandler()); 637 hasCatchHandler = !!handler; 638 } 639 640 debugger->exception(globalObject, callFrame, exception->value(), hasCatchHandler); 641 } 642 exception->setDidNotifyInspectorOfThrow(); 643 } 644 645 JSValue Interpreter::executeProgram(const SourceCode& source, JSGlobalObject*, JSObject* thisObj) 646 { 647 JSScope* scope = thisObj->globalObject()->globalScope(); 648 VM& vm = scope->vm(); 649 auto throwScope = DECLARE_THROW_SCOPE(vm); 650 JSGlobalObject* globalObject = scope->globalObject(vm); 651 JSCallee* globalCallee = globalObject->globalCallee(); 652 653 auto clobberizeValidator = makeScopeExit([&] { 654 vm.didEnterVM = true; 655 }); 656 657 ProgramExecutable* program = ProgramExecutable::create(globalObject, source); 658 EXCEPTION_ASSERT(throwScope.exception() || program); 659 RETURN_IF_EXCEPTION(throwScope, { }); 660 661 throwScope.assertNoException(); 662 ASSERT(!vm.isCollectorBusyOnCurrentThread()); 663 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); 664 if (vm.isCollectorBusyOnCurrentThread()) 665 return jsNull(); 666 667 if (UNLIKELY(!vm.isSafeToRecurseSoft())) 668 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 669 670 // First check if the "program" is actually just a JSON object. If so, 671 // we'll handle the JSON object here. Else, we'll handle real JS code 672 // below at failedJSONP. 673 674 Vector<JSONPData> JSONPData; 675 bool parseResult; 676 StringView programSource = program->source().view(); 677 if (programSource.isNull()) 678 return jsUndefined(); 679 if (programSource.is8Bit()) { 680 LiteralParser<LChar> literalParser(globalObject, programSource.characters8(), programSource.length(), JSONP); 681 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject)); 682 } else { 683 LiteralParser<UChar> literalParser(globalObject, programSource.characters16(), programSource.length(), JSONP); 684 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject)); 685 } 686 687 RETURN_IF_EXCEPTION(throwScope, { }); 688 if (parseResult) { 689 JSValue result; 690 for (unsigned entry = 0; entry < JSONPData.size(); entry++) { 691 Vector<JSONPPathEntry> JSONPPath; 692 JSONPPath.swap(JSONPData[entry].m_path); 693 JSValue JSONPValue = JSONPData[entry].m_value.get(); 694 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclareVar) { 695 globalObject->addVar(globalObject, JSONPPath[0].m_pathEntryName); 696 RETURN_IF_EXCEPTION(throwScope, { }); 697 PutPropertySlot slot(globalObject); 698 globalObject->methodTable(vm)->put(globalObject, globalObject, JSONPPath[0].m_pathEntryName, JSONPValue, slot); 699 RETURN_IF_EXCEPTION(throwScope, { }); 700 result = jsUndefined(); 701 continue; 702 } 703 JSValue baseObject(globalObject); 704 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) { 705 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclareVar); 706 switch (JSONPPath[i].m_type) { 707 case JSONPPathEntryTypeDot: { 708 if (i == 0) { 709 RELEASE_ASSERT(baseObject == globalObject); 710 711 auto doGet = [&] (JSSegmentedVariableObject* scope) { 712 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get); 713 if (scope->getPropertySlot(globalObject, JSONPPath[i].m_pathEntryName, slot)) 714 return slot.getValue(globalObject, JSONPPath[i].m_pathEntryName); 715 return JSValue(); 716 }; 717 718 JSValue result = doGet(globalObject->globalLexicalEnvironment()); 719 RETURN_IF_EXCEPTION(throwScope, JSValue()); 720 if (result) { 721 baseObject = result; 722 continue; 723 } 724 725 result = doGet(globalObject); 726 RETURN_IF_EXCEPTION(throwScope, JSValue()); 727 if (result) { 728 baseObject = result; 729 continue; 730 } 731 732 if (entry) 733 return throwException(globalObject, throwScope, createUndefinedVariableError(globalObject, JSONPPath[i].m_pathEntryName)); 734 goto failedJSONP; 735 } 736 737 baseObject = baseObject.get(globalObject, JSONPPath[i].m_pathEntryName); 738 RETURN_IF_EXCEPTION(throwScope, JSValue()); 739 continue; 740 } 741 case JSONPPathEntryTypeLookup: { 742 baseObject = baseObject.get(globalObject, static_cast<unsigned>(JSONPPath[i].m_pathIndex)); 743 RETURN_IF_EXCEPTION(throwScope, JSValue()); 744 continue; 745 } 746 default: 747 RELEASE_ASSERT_NOT_REACHED(); 748 return jsUndefined(); 749 } 750 } 751 752 if (JSONPPath.size() == 1 && JSONPPath.last().m_type != JSONPPathEntryTypeLookup) { 753 RELEASE_ASSERT(baseObject == globalObject); 754 JSGlobalLexicalEnvironment* scope = globalObject->globalLexicalEnvironment(); 755 if (scope->hasProperty(globalObject, JSONPPath.last().m_pathEntryName)) 756 baseObject = scope; 757 RETURN_IF_EXCEPTION(throwScope, JSValue()); 758 } 759 760 PutPropertySlot slot(baseObject); 761 switch (JSONPPath.last().m_type) { 762 case JSONPPathEntryTypeCall: { 763 JSValue function = baseObject.get(globalObject, JSONPPath.last().m_pathEntryName); 764 RETURN_IF_EXCEPTION(throwScope, JSValue()); 765 auto callData = getCallData(vm, function); 766 if (callData.type == CallData::Type::None) 767 return throwException(globalObject, throwScope, createNotAFunctionError(globalObject, function)); 768 MarkedArgumentBuffer jsonArg; 769 jsonArg.append(JSONPValue); 770 ASSERT(!jsonArg.hasOverflowed()); 771 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined() : baseObject; 772 JSONPValue = JSC::call(globalObject, function, callData, thisValue, jsonArg); 773 RETURN_IF_EXCEPTION(throwScope, JSValue()); 774 break; 775 } 776 case JSONPPathEntryTypeDot: { 777 baseObject.put(globalObject, JSONPPath.last().m_pathEntryName, JSONPValue, slot); 778 RETURN_IF_EXCEPTION(throwScope, JSValue()); 779 break; 780 } 781 case JSONPPathEntryTypeLookup: { 782 baseObject.putByIndex(globalObject, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode()); 783 RETURN_IF_EXCEPTION(throwScope, JSValue()); 784 break; 785 } 786 default: 787 RELEASE_ASSERT_NOT_REACHED(); 788 return jsUndefined(); 789 } 790 result = JSONPValue; 791 } 792 return result; 793 } 794 failedJSONP: 795 // If we get here, then we have already proven that the script is not a JSON 796 // object. 797 798 VMEntryScope entryScope(vm, globalObject); 799 800 // Compile source to bytecode if necessary: 801 JSObject* error = program->initializeGlobalProperties(vm, globalObject, scope); 802 EXCEPTION_ASSERT(!throwScope.exception() || !error); 803 if (UNLIKELY(error)) 804 return checkedReturn(throwException(globalObject, throwScope, error)); 805 806 constexpr auto trapsMask = VMTraps::interruptingTraps(); 807 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 808 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 809 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 810 } 811 812 if (scope->structure(vm)->isUncacheableDictionary()) 813 scope->flattenDictionaryObject(vm); 814 815 ProgramCodeBlock* codeBlock; 816 { 817 CodeBlock* tempCodeBlock; 818 Exception* error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock); 819 EXCEPTION_ASSERT(throwScope.exception() == error); 820 if (UNLIKELY(error)) 821 return checkedReturn(error); 822 codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock); 823 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. 824 } 825 826 RefPtr<JITCode> jitCode; 827 ProtoCallFrame protoCallFrame; 828 { 829 DisallowGC disallowGC; // Ensure no GC happens. GC can replace CodeBlock in Executable. 830 jitCode = program->generatedJITCode(); 831 protoCallFrame.init(codeBlock, globalObject, globalCallee, thisObj, 1); 832 } 833 834 // Execute the code: 835 throwScope.release(); 836 ASSERT(jitCode == program->generatedJITCode().ptr()); 837 JSValue result = jitCode->execute(&vm, &protoCallFrame); 838 return checkedReturn(result); 839 } 840 841 JSValue Interpreter::executeCall(JSGlobalObject* lexicalGlobalObject, JSObject* function, const CallData& callData, JSValue thisValue, const ArgList& args) 842 { 843 VM& vm = lexicalGlobalObject->vm(); 844 auto throwScope = DECLARE_THROW_SCOPE(vm); 845 846 auto clobberizeValidator = makeScopeExit([&] { 847 vm.didEnterVM = true; 848 }); 849 850 throwScope.assertNoException(); 851 ASSERT(!vm.isCollectorBusyOnCurrentThread()); 852 if (vm.isCollectorBusyOnCurrentThread()) 853 return jsNull(); 854 855 bool isJSCall = (callData.type == CallData::Type::JS); 856 JSScope* scope = nullptr; 857 size_t argsCount = 1 + args.size(); // implicit "this" parameter 858 859 JSGlobalObject* globalObject; 860 861 if (isJSCall) { 862 scope = callData.js.scope; 863 globalObject = scope->globalObject(vm); 864 } else { 865 ASSERT(callData.type == CallData::Type::Native); 866 globalObject = function->globalObject(vm); 867 } 868 869 VMEntryScope entryScope(vm, globalObject); 870 if (UNLIKELY(!vm.isSafeToRecurseSoft() || args.size() > maxArguments)) 871 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 872 873 constexpr auto trapsMask = VMTraps::interruptingTraps(); 874 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 875 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 876 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 877 } 878 879 CodeBlock* newCodeBlock = nullptr; 880 if (isJSCall) { 881 // Compile the callee: 882 Exception* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock); 883 EXCEPTION_ASSERT(throwScope.exception() == compileError); 884 if (UNLIKELY(!!compileError)) 885 return checkedReturn(compileError); 886 887 ASSERT(!!newCodeBlock); 888 newCodeBlock->m_shouldAlwaysBeInlined = false; 889 } 890 891 RefPtr<JITCode> jitCode; 892 ProtoCallFrame protoCallFrame; 893 { 894 DisallowGC disallowGC; // Ensure no GC happens. GC can replace CodeBlock in Executable. 895 if (isJSCall) 896 jitCode = callData.js.functionExecutable->generatedJITCodeForCall(); 897 protoCallFrame.init(newCodeBlock, globalObject, function, thisValue, argsCount, args.data()); 898 } 899 900 JSValue result; 901 // Execute the code: 902 if (isJSCall) { 903 throwScope.release(); 904 ASSERT(jitCode == callData.js.functionExecutable->generatedJITCodeForCall().ptr()); 905 result = jitCode->execute(&vm, &protoCallFrame); 906 } else { 907 result = JSValue::decode(vmEntryToNative(callData.native.function.rawPointer(), &vm, &protoCallFrame)); 908 RETURN_IF_EXCEPTION(throwScope, JSValue()); 909 } 910 911 return checkedReturn(result); 912 } 913 914 JSObject* Interpreter::executeConstruct(JSGlobalObject* lexicalGlobalObject, JSObject* constructor, const CallData& constructData, const ArgList& args, JSValue newTarget) 915 { 916 VM& vm = lexicalGlobalObject->vm(); 917 auto throwScope = DECLARE_THROW_SCOPE(vm); 918 919 auto clobberizeValidator = makeScopeExit([&] { 920 vm.didEnterVM = true; 921 }); 922 923 throwScope.assertNoException(); 924 ASSERT(!vm.isCollectorBusyOnCurrentThread()); 925 // We throw in this case because we have to return something "valid" but we're 926 // already in an invalid state. 927 if (UNLIKELY(vm.isCollectorBusyOnCurrentThread())) { 928 throwStackOverflowError(lexicalGlobalObject, throwScope); 929 return nullptr; 930 } 931 932 bool isJSConstruct = (constructData.type == CallData::Type::JS); 933 JSScope* scope = nullptr; 934 size_t argsCount = 1 + args.size(); // implicit "this" parameter 935 936 JSGlobalObject* globalObject; 937 938 if (isJSConstruct) { 939 scope = constructData.js.scope; 940 globalObject = scope->globalObject(vm); 941 } else { 942 ASSERT(constructData.type == CallData::Type::Native); 943 globalObject = constructor->globalObject(vm); 944 } 945 946 VMEntryScope entryScope(vm, globalObject); 947 if (UNLIKELY(!vm.isSafeToRecurseSoft() || args.size() > maxArguments)) { 948 throwStackOverflowError(globalObject, throwScope); 949 return nullptr; 950 } 951 952 constexpr auto trapsMask = VMTraps::interruptingTraps(); 953 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 954 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 955 RETURN_IF_EXCEPTION(throwScope, nullptr); 956 } 957 958 CodeBlock* newCodeBlock = nullptr; 959 if (isJSConstruct) { 960 // Compile the callee: 961 Exception* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock); 962 EXCEPTION_ASSERT(throwScope.exception() == compileError); 963 if (UNLIKELY(!!compileError)) 964 return nullptr; 965 966 ASSERT(!!newCodeBlock); 967 newCodeBlock->m_shouldAlwaysBeInlined = false; 968 } 969 970 RefPtr<JITCode> jitCode; 971 ProtoCallFrame protoCallFrame; 972 { 973 DisallowGC disallowGC; // Ensure no GC happens. GC can replace CodeBlock in Executable. 974 if (isJSConstruct) 975 jitCode = constructData.js.functionExecutable->generatedJITCodeForConstruct(); 976 protoCallFrame.init(newCodeBlock, globalObject, constructor, newTarget, argsCount, args.data()); 977 } 978 979 JSValue result; 980 // Execute the code. 981 if (isJSConstruct) { 982 ASSERT(jitCode == constructData.js.functionExecutable->generatedJITCodeForConstruct().ptr()); 983 result = jitCode->execute(&vm, &protoCallFrame); 984 } else { 985 result = JSValue::decode(vmEntryToNative(constructData.native.function.rawPointer(), &vm, &protoCallFrame)); 986 987 if (LIKELY(!throwScope.exception())) 988 RELEASE_ASSERT(result.isObject()); 989 } 990 991 RETURN_IF_EXCEPTION(throwScope, nullptr); 992 ASSERT(result.isObject()); 993 return checkedReturn(asObject(result)); 994 } 995 996 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, const ArgList& args) 997 { 998 VM& vm = scope->vm(); 999 auto throwScope = DECLARE_THROW_SCOPE(vm); 1000 throwScope.assertNoException(); 1001 1002 if (vm.isCollectorBusyOnCurrentThread()) 1003 return CallFrameClosure(); 1004 1005 // Compile the callee: 1006 CodeBlock* newCodeBlock; 1007 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock); 1008 EXCEPTION_ASSERT(throwScope.exception() == error); 1009 if (UNLIKELY(error)) 1010 return CallFrameClosure(); 1011 newCodeBlock->m_shouldAlwaysBeInlined = false; 1012 1013 size_t argsCount = argumentCountIncludingThis; 1014 1015 protoCallFrame->init(newCodeBlock, function->globalObject(), function, jsUndefined(), argsCount, args.data()); 1016 // Return the successful closure: 1017 CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis }; 1018 return result; 1019 } 1020 1021 JSValue Interpreter::execute(EvalExecutable* eval, JSGlobalObject* lexicalGlobalObject, JSValue thisValue, JSScope* scope) 1022 { 1023 VM& vm = scope->vm(); 1024 auto throwScope = DECLARE_THROW_SCOPE(vm); 1025 1026 auto clobberizeValidator = makeScopeExit([&] { 1027 vm.didEnterVM = true; 1028 }); 1029 1030 ASSERT_UNUSED(lexicalGlobalObject, &vm == &lexicalGlobalObject->vm()); 1031 throwScope.assertNoException(); 1032 ASSERT(!vm.isCollectorBusyOnCurrentThread()); 1033 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); 1034 if (vm.isCollectorBusyOnCurrentThread()) 1035 return jsNull(); 1036 1037 JSGlobalObject* globalObject = scope->globalObject(vm); 1038 VMEntryScope entryScope(vm, globalObject); 1039 if (UNLIKELY(!vm.isSafeToRecurseSoft())) 1040 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 1041 1042 unsigned numVariables = eval->numVariables(); 1043 unsigned numTopLevelFunctionDecls = eval->numTopLevelFunctionDecls(); 1044 unsigned numFunctionHoistingCandidates = eval->numFunctionHoistingCandidates(); 1045 1046 JSScope* variableObject; 1047 if ((numVariables || numTopLevelFunctionDecls) && eval->isInStrictContext()) { 1048 scope = StrictEvalActivation::create(vm, globalObject->strictEvalActivationStructure(), scope); 1049 variableObject = scope; 1050 } else { 1051 for (JSScope* node = scope; ; node = node->next()) { 1052 RELEASE_ASSERT(node); 1053 if (node->isGlobalObject()) { 1054 variableObject = node; 1055 break; 1056 } 1057 if (node->isJSLexicalEnvironment()) { 1058 JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(node); 1059 if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) { 1060 variableObject = node; 1061 break; 1062 } 1063 } 1064 } 1065 } 1066 1067 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1068 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1069 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1070 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1071 } 1072 1073 auto loadCodeBlock = [&](Exception*& compileError) -> EvalCodeBlock* { 1074 CodeBlock* tempCodeBlock; 1075 compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock); 1076 EXCEPTION_ASSERT(throwScope.exception() == compileError); 1077 if (UNLIKELY(!!compileError)) 1078 return nullptr; 1079 return jsCast<EvalCodeBlock*>(tempCodeBlock); 1080 }; 1081 1082 EvalCodeBlock* codeBlock; 1083 { 1084 Exception* compileError = nullptr; 1085 codeBlock = loadCodeBlock(compileError); 1086 EXCEPTION_ASSERT(throwScope.exception() == compileError); 1087 if (UNLIKELY(!!compileError)) 1088 return checkedReturn(compileError); 1089 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. 1090 } 1091 UnlinkedEvalCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedEvalCodeBlock(); 1092 1093 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval. 1094 if (variableObject->isGlobalObject() && !eval->isInStrictContext() && (numVariables || numTopLevelFunctionDecls)) { 1095 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment(); 1096 for (unsigned i = 0; i < numVariables; ++i) { 1097 const Identifier& ident = unlinkedCodeBlock->variable(i); 1098 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry, &vm); 1099 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, globalObject, ident, slot)) { 1100 return checkedReturn(throwTypeError(globalObject, throwScope, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'"))); 1101 } 1102 } 1103 1104 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) { 1105 FunctionExecutable* function = codeBlock->functionDecl(i); 1106 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry, &vm); 1107 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, globalObject, function->name(), slot)) { 1108 return checkedReturn(throwTypeError(globalObject, throwScope, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'"))); 1109 } 1110 } 1111 } 1112 1113 if (variableObject->structure(vm)->isUncacheableDictionary()) 1114 variableObject->flattenDictionaryObject(vm); 1115 1116 if (numVariables || numTopLevelFunctionDecls || numFunctionHoistingCandidates) { 1117 BatchedTransitionOptimizer optimizer(vm, variableObject); 1118 if (variableObject->next() && !eval->isInStrictContext()) 1119 variableObject->globalObject(vm)->varInjectionWatchpoint()->fireAll(vm, "Executed eval, fired VarInjection watchpoint"); 1120 1121 for (unsigned i = 0; i < numVariables; ++i) { 1122 const Identifier& ident = unlinkedCodeBlock->variable(i); 1123 bool hasProperty = variableObject->hasProperty(globalObject, ident); 1124 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1125 if (!hasProperty) { 1126 PutPropertySlot slot(variableObject); 1127 if (!variableObject->isExtensible(globalObject)) 1128 return checkedReturn(throwTypeError(globalObject, throwScope, NonExtensibleObjectPropertyDefineError)); 1129 variableObject->methodTable(vm)->put(variableObject, globalObject, ident, jsUndefined(), slot); 1130 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1131 } 1132 } 1133 1134 if (eval->isInStrictContext()) { 1135 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) { 1136 FunctionExecutable* function = codeBlock->functionDecl(i); 1137 PutPropertySlot slot(variableObject); 1138 // We need create this variables because it will be used to emits code by bytecode generator 1139 variableObject->methodTable(vm)->put(variableObject, globalObject, function->name(), jsUndefined(), slot); 1140 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1141 } 1142 } else { 1143 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) { 1144 FunctionExecutable* function = codeBlock->functionDecl(i); 1145 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(globalObject, scope, function->name()); 1146 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1147 if (resolvedScope.isUndefined()) 1148 return checkedReturn(throwSyntaxError(globalObject, throwScope, makeString("Can't create duplicate variable in eval: '", String(function->name().impl()), "'"))); 1149 PutPropertySlot slot(variableObject); 1150 // We need create this variables because it will be used to emits code by bytecode generator 1151 variableObject->methodTable(vm)->put(variableObject, globalObject, function->name(), jsUndefined(), slot); 1152 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1153 } 1154 1155 for (unsigned i = 0; i < numFunctionHoistingCandidates; ++i) { 1156 const Identifier& ident = unlinkedCodeBlock->functionHoistingCandidate(i); 1157 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(globalObject, scope, ident); 1158 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1159 if (!resolvedScope.isUndefined()) { 1160 bool hasProperty = variableObject->hasProperty(globalObject, ident); 1161 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1162 if (!hasProperty) { 1163 PutPropertySlot slot(variableObject); 1164 variableObject->methodTable(vm)->put(variableObject, globalObject, ident, jsUndefined(), slot); 1165 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception())); 1166 } 1167 } 1168 } 1169 } 1170 } 1171 1172 JSCallee* callee = nullptr; 1173 if (scope == globalObject->globalScope()) 1174 callee = globalObject->globalCallee(); 1175 else 1176 callee = JSCallee::create(vm, globalObject, scope); 1177 1178 // Reload CodeBlock. It is possible that we replaced CodeBlock while setting up the environment. 1179 { 1180 Exception* compileError = nullptr; 1181 codeBlock = loadCodeBlock(compileError); 1182 EXCEPTION_ASSERT(throwScope.exception() == compileError); 1183 if (UNLIKELY(!!compileError)) 1184 return checkedReturn(compileError); 1185 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. 1186 } 1187 1188 RefPtr<JITCode> jitCode; 1189 ProtoCallFrame protoCallFrame; 1190 { 1191 DisallowGC disallowGC; // Ensure no GC happens. GC can replace CodeBlock in Executable. 1192 jitCode = eval->generatedJITCode(); 1193 protoCallFrame.init(codeBlock, globalObject, callee, thisValue, 1); 1194 } 1195 1196 // Execute the code: 1197 throwScope.release(); 1198 ASSERT(jitCode == eval->generatedJITCode().ptr()); 1199 JSValue result = jitCode->execute(&vm, &protoCallFrame); 1200 1201 return checkedReturn(result); 1202 } 1203 1204 JSValue Interpreter::executeModuleProgram(ModuleProgramExecutable* executable, JSGlobalObject* lexicalGlobalObject, JSModuleEnvironment* scope) 1205 { 1206 VM& vm = scope->vm(); 1207 auto throwScope = DECLARE_THROW_SCOPE(vm); 1208 1209 auto clobberizeValidator = makeScopeExit([&] { 1210 vm.didEnterVM = true; 1211 }); 1212 1213 ASSERT_UNUSED(lexicalGlobalObject, &vm == &lexicalGlobalObject->vm()); 1214 throwScope.assertNoException(); 1215 ASSERT(!vm.isCollectorBusyOnCurrentThread()); 1216 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); 1217 if (vm.isCollectorBusyOnCurrentThread()) 1218 return jsNull(); 1219 1220 JSGlobalObject* globalObject = scope->globalObject(vm); 1221 VMEntryScope entryScope(vm, scope->globalObject(vm)); 1222 if (UNLIKELY(!vm.isSafeToRecurseSoft())) 1223 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 1224 1225 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1226 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1227 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1228 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1229 } 1230 1231 if (scope->structure(vm)->isUncacheableDictionary()) 1232 scope->flattenDictionaryObject(vm); 1233 1234 JSCallee* callee = JSCallee::create(vm, globalObject, scope); 1235 ModuleProgramCodeBlock* codeBlock; 1236 { 1237 CodeBlock* tempCodeBlock; 1238 Exception* compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock); 1239 EXCEPTION_ASSERT(throwScope.exception() == compileError); 1240 if (UNLIKELY(!!compileError)) 1241 return checkedReturn(compileError); 1242 codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock); 1243 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'. 1244 } 1245 1246 RefPtr<JITCode> jitCode; 1247 ProtoCallFrame protoCallFrame; 1248 { 1249 DisallowGC disallowGC; // Ensure no GC happens. GC can replace CodeBlock in Executable. 1250 jitCode = executable->generatedJITCode(); 1251 // The |this| of the module is always `undefined`. 1252 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding 1253 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding 1254 protoCallFrame.init(codeBlock, globalObject, callee, jsUndefined(), 1); 1255 } 1256 1257 // Execute the code: 1258 throwScope.release(); 1259 ASSERT(jitCode == executable->generatedJITCode().ptr()); 1260 JSValue result = jitCode->execute(&vm, &protoCallFrame); 1261 1262 return checkedReturn(result); 1263 } 1264 1265 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookType debugHookType) 1266 { 1267 VM& vm = callFrame->deprecatedVM(); 1268 auto scope = DECLARE_CATCH_SCOPE(vm); 1269 1270 if (UNLIKELY(Options::debuggerTriggersBreakpointException()) && debugHookType == DidReachDebuggerStatement) 1271 WTFBreakpointTrap(); 1272 1273 Debugger* debugger = callFrame->lexicalGlobalObject(vm)->debugger(); 1274 if (!debugger) 1275 return; 1276 1277 ASSERT(callFrame->codeBlock()->hasDebuggerRequests()); 1278 scope.assertNoException(); 1279 1280 switch (debugHookType) { 1281 case DidEnterCallFrame: 1282 debugger->callEvent(callFrame); 1283 break; 1284 case WillLeaveCallFrame: 1285 debugger->returnEvent(callFrame); 1286 break; 1287 case WillExecuteStatement: 1288 debugger->atStatement(callFrame); 1289 break; 1290 case WillExecuteExpression: 1291 debugger->atExpression(callFrame); 1292 break; 1293 case WillExecuteProgram: 1294 debugger->willExecuteProgram(callFrame); 1295 break; 1296 case DidExecuteProgram: 1297 debugger->didExecuteProgram(callFrame); 1298 break; 1299 case DidReachDebuggerStatement: 1300 debugger->didReachDebuggerStatement(callFrame); 1301 break; 1302 } 1303 scope.assertNoException(); 1304 } 1305 1306 } // namespace JSC 1307 1308 namespace WTF { 1309 1310 void printInternal(PrintStream& out, JSC::DebugHookType type) 1311 { 1312 switch (type) { 1313 case JSC::WillExecuteProgram: 1314 out.print("WillExecuteProgram"); 1315 return; 1316 case JSC::DidExecuteProgram: 1317 out.print("DidExecuteProgram"); 1318 return; 1319 case JSC::DidEnterCallFrame: 1320 out.print("DidEnterCallFrame"); 1321 return; 1322 case JSC::DidReachDebuggerStatement: 1323 out.print("DidReachDebuggerStatement"); 1324 return; 1325 case JSC::WillLeaveCallFrame: 1326 out.print("WillLeaveCallFrame"); 1327 return; 1328 case JSC::WillExecuteStatement: 1329 out.print("WillExecuteStatement"); 1330 return; 1331 case JSC::WillExecuteExpression: 1332 out.print("WillExecuteExpression"); 1333 return; 1334 } 1335 } 1336 1337 } // namespace WTF