1/*
2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "LLIntSlowPaths.h"
28
29#include "ArrayConstructor.h"
30#include "BytecodeGenerator.h"
31#include "CallFrame.h"
32#include "CommonSlowPaths.h"
33#include "Error.h"
34#include "ErrorHandlingScope.h"
35#include "EvalCodeBlock.h"
36#include "Exception.h"
37#include "ExceptionFuzz.h"
38#include "ExecutableBaseInlines.h"
39#include "FrameTracers.h"
40#include "FunctionCodeBlock.h"
41#include "FunctionWhitelist.h"
42#include "GetterSetter.h"
43#include "HostCallReturnValue.h"
44#include "InterpreterInlines.h"
45#include "IteratorOperations.h"
46#include "JIT.h"
47#include "JITExceptions.h"
48#include "JITWorklist.h"
49#include "JSAsyncFunction.h"
50#include "JSAsyncGeneratorFunction.h"
51#include "JSCInlines.h"
52#include "JSCJSValue.h"
53#include "JSGeneratorFunction.h"
54#include "JSGlobalObjectFunctions.h"
55#include "JSLexicalEnvironment.h"
56#include "JSString.h"
57#include "JSWithScope.h"
58#include "LLIntCommon.h"
59#include "LLIntData.h"
60#include "LLIntExceptions.h"
61#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
62#include "LowLevelInterpreter.h"
63#include "ModuleProgramCodeBlock.h"
64#include "ObjectConstructor.h"
65#include "ObjectPropertyConditionSet.h"
66#include "OpcodeInlines.h"
67#include "ProgramCodeBlock.h"
68#include "ProtoCallFrameInlines.h"
69#include "RegExpObject.h"
70#include "ShadowChicken.h"
71#include "StructureRareDataInlines.h"
72#include "SuperSampler.h"
73#include "VMInlines.h"
74#include <wtf/NeverDestroyed.h>
75#include <wtf/StringPrintStream.h>
76
77namespace JSC { namespace LLInt {
78
79#define LLINT_BEGIN_NO_SET_PC() \
80 CodeBlock* codeBlock = callFrame->codeBlock(); \
81 JSGlobalObject* globalObject = codeBlock->globalObject(); \
82 VM& vm = codeBlock->vm(); \
83 SlowPathFrameTracer tracer(vm, callFrame); \
84 auto throwScope = DECLARE_THROW_SCOPE(vm)
85
86#ifndef NDEBUG
87#define LLINT_SET_PC_FOR_STUBS() do { \
88 codeBlock->bytecodeOffset(pc); \
89 callFrame->setCurrentVPC(pc); \
90 } while (false)
91#else
92#define LLINT_SET_PC_FOR_STUBS() do { \
93 callFrame->setCurrentVPC(pc); \
94 } while (false)
95#endif
96
97#define LLINT_BEGIN() \
98 LLINT_BEGIN_NO_SET_PC(); \
99 LLINT_SET_PC_FOR_STUBS()
100
101inline JSValue getNonConstantOperand(CallFrame* callFrame, const VirtualRegister& operand) { return callFrame->uncheckedR(operand.offset()).jsValue(); }
102inline JSValue getOperand(CallFrame* callFrame, const VirtualRegister& operand) { return callFrame->r(operand.offset()).jsValue(); }
103
104#define LLINT_RETURN_TWO(first, second) do { \
105 return encodeResult(first, second); \
106 } while (false)
107
108#define LLINT_END_IMPL() LLINT_RETURN_TWO(pc, nullptr)
109
110#define LLINT_THROW(exceptionToThrow) do { \
111 throwException(globalObject, throwScope, exceptionToThrow); \
112 pc = returnToThrow(vm); \
113 LLINT_END_IMPL(); \
114 } while (false)
115
116#define LLINT_CHECK_EXCEPTION() do { \
117 doExceptionFuzzingIfEnabled(globalObject, throwScope, "LLIntSlowPaths", pc); \
118 if (UNLIKELY(throwScope.exception())) { \
119 pc = returnToThrow(vm); \
120 LLINT_END_IMPL(); \
121 } \
122 } while (false)
123
124#define LLINT_END() do { \
125 LLINT_CHECK_EXCEPTION(); \
126 LLINT_END_IMPL(); \
127 } while (false)
128
129#define JUMP_OFFSET(targetOffset) \
130 ((targetOffset) ? (targetOffset) : codeBlock->outOfLineJumpOffset(pc))
131
132#define JUMP_TO(target) do { \
133 pc = reinterpret_cast<const Instruction*>(reinterpret_cast<const uint8_t*>(pc) + (target)); \
134 } while (false)
135
136#define LLINT_BRANCH(condition) do { \
137 bool __b_condition = (condition); \
138 LLINT_CHECK_EXCEPTION(); \
139 if (__b_condition) \
140 JUMP_TO(JUMP_OFFSET(bytecode.m_targetLabel)); \
141 else \
142 JUMP_TO(pc->size()); \
143 LLINT_END_IMPL(); \
144 } while (false)
145
146#define LLINT_RETURN(value) do { \
147 JSValue __r_returnValue = (value); \
148 LLINT_CHECK_EXCEPTION(); \
149 callFrame->uncheckedR(bytecode.m_dst) = __r_returnValue; \
150 LLINT_END_IMPL(); \
151 } while (false)
152
153#define LLINT_RETURN_PROFILED(value) do { \
154 JSValue __rp_returnValue = (value); \
155 LLINT_CHECK_EXCEPTION(); \
156 callFrame->uncheckedR(bytecode.m_dst) = __rp_returnValue; \
157 LLINT_PROFILE_VALUE(__rp_returnValue); \
158 LLINT_END_IMPL(); \
159 } while (false)
160
161#define LLINT_PROFILE_VALUE(value) do { \
162 bytecode.metadata(codeBlock).m_profile.m_buckets[0] = JSValue::encode(value); \
163 } while (false)
164
165#define LLINT_CALL_END_IMPL(callFrame, callTarget, callTargetTag) \
166 LLINT_RETURN_TWO(retagCodePtr((callTarget), callTargetTag, SlowPathPtrTag), (callFrame))
167
168#define LLINT_CALL_THROW(globalObject, exceptionToThrow) do { \
169 JSGlobalObject* __ct_globalObject = (globalObject); \
170 throwException(__ct_globalObject, throwScope, exceptionToThrow); \
171 LLINT_CALL_END_IMPL(nullptr, callToThrow(vm), ExceptionHandlerPtrTag); \
172 } while (false)
173
174#define LLINT_CALL_CHECK_EXCEPTION(globalObject) do { \
175 JSGlobalObject* __cce_globalObject = (globalObject); \
176 doExceptionFuzzingIfEnabled(__cce_globalObject, throwScope, "LLIntSlowPaths/call", nullptr); \
177 if (UNLIKELY(throwScope.exception())) \
178 LLINT_CALL_END_IMPL(nullptr, callToThrow(vm), ExceptionHandlerPtrTag); \
179 } while (false)
180
181#define LLINT_CALL_RETURN(globalObject, calleeFrame, callTarget, callTargetTag) do { \
182 JSGlobalObject* __cr_globalObject = (globalObject); \
183 CallFrame* __cr_calleeFrame = (calleeFrame); \
184 void* __cr_callTarget = (callTarget); \
185 LLINT_CALL_CHECK_EXCEPTION(__cr_globalObject); \
186 LLINT_CALL_END_IMPL(__cr_calleeFrame, __cr_callTarget, callTargetTag); \
187 } while (false)
188
189#define LLINT_RETURN_CALLEE_FRAME(calleeFrame) do { \
190 CallFrame* __rcf_calleeFrame = (calleeFrame); \
191 LLINT_RETURN_TWO(pc, __rcf_calleeFrame); \
192 } while (false)
193
194#if LLINT_TRACING
195
196template<typename... Types>
197void slowPathLog(const Types&... values)
198{
199 dataLogIf(Options::traceLLIntSlowPath(), values...);
200}
201
202template<typename... Types>
203void slowPathLn(const Types&... values)
204{
205 dataLogLnIf(Options::traceLLIntSlowPath(), values...);
206}
207
208template<typename... Types>
209void slowPathLogF(const char* format, const Types&... values)
210{
211 ALLOW_NONLITERAL_FORMAT_BEGIN
212 IGNORE_WARNINGS_BEGIN("format-security")
213 if (Options::traceLLIntSlowPath())
214 dataLogF(format, values...);
215 IGNORE_WARNINGS_END
216 ALLOW_NONLITERAL_FORMAT_END
217}
218
219#else // not LLINT_TRACING
220
221template<typename... Types> void slowPathLog(const Types&...) { }
222template<typename... Types> void slowPathLogLn(const Types&...) { }
223template<typename... Types> void slowPathLogF(const char*, const Types&...) { }
224
225#endif // LLINT_TRACING
226
227extern "C" SlowPathReturnType llint_trace_operand(CallFrame* callFrame, const Instruction* pc, int fromWhere, int operand)
228{
229 if (!Options::traceLLIntExecution())
230 LLINT_END_IMPL();
231
232 LLINT_BEGIN();
233 dataLogF(
234 "<%p> %p / %p: executing bc#%zu, op#%u: Trace(%d): %d\n",
235 &Thread::current(),
236 callFrame->codeBlock(),
237 globalObject,
238 static_cast<intptr_t>(callFrame->codeBlock()->bytecodeOffset(pc)),
239 pc->opcodeID(),
240 fromWhere,
241 operand);
242 LLINT_END();
243}
244
245extern "C" SlowPathReturnType llint_trace_value(CallFrame* callFrame, const Instruction* pc, int fromWhere, VirtualRegister operand)
246{
247 if (!Options::traceLLIntExecution())
248 LLINT_END_IMPL();
249
250 JSValue value = getOperand(callFrame, operand);
251 union {
252 struct {
253 uint32_t tag;
254 uint32_t payload;
255 } bits;
256 EncodedJSValue asValue;
257 } u;
258 u.asValue = JSValue::encode(value);
259 dataLogF(
260 "<%p> %p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %08x:%08x: %s\n",
261 &Thread::current(),
262 callFrame->codeBlock(),
263 callFrame,
264 static_cast<intptr_t>(callFrame->codeBlock()->bytecodeOffset(pc)),
265 pc->opcodeID(),
266 fromWhere,
267 operand.offset(),
268 u.bits.tag,
269 u.bits.payload,
270 toCString(value).data());
271 LLINT_END_IMPL();
272}
273
274LLINT_SLOW_PATH_DECL(trace_prologue)
275{
276 if (!Options::traceLLIntExecution())
277 LLINT_END_IMPL();
278
279 CodeBlock* codeBlock = callFrame->codeBlock();
280 dataLogF("<%p> %p / %p: in prologue of ", &Thread::current(), codeBlock, callFrame);
281 dataLog(codeBlock, "\n");
282 LLINT_END_IMPL();
283}
284
285static void traceFunctionPrologue(CallFrame* callFrame, const char* comment, CodeSpecializationKind kind)
286{
287 if (!Options::traceLLIntExecution())
288 return;
289
290 JSFunction* callee = jsCast<JSFunction*>(callFrame->jsCallee());
291 FunctionExecutable* executable = callee->jsExecutable();
292 CodeBlock* codeBlock = executable->codeBlockFor(kind);
293 dataLogF("<%p> %p / %p: in %s of ", &Thread::current(), codeBlock, callFrame, comment);
294 dataLog(codeBlock);
295 dataLogF(" function %p, executable %p; numVars = %u, numParameters = %u, numCalleeLocals = %u, caller = %p.\n",
296 callee, executable, codeBlock->numVars(), codeBlock->numParameters(), codeBlock->numCalleeLocals(), callFrame->callerFrame());
297}
298
299LLINT_SLOW_PATH_DECL(trace_prologue_function_for_call)
300{
301 traceFunctionPrologue(callFrame, "call prologue", CodeForCall);
302 LLINT_END_IMPL();
303}
304
305LLINT_SLOW_PATH_DECL(trace_prologue_function_for_construct)
306{
307 traceFunctionPrologue(callFrame, "construct prologue", CodeForConstruct);
308 LLINT_END_IMPL();
309}
310
311LLINT_SLOW_PATH_DECL(trace_arityCheck_for_call)
312{
313 traceFunctionPrologue(callFrame, "call arity check", CodeForCall);
314 LLINT_END_IMPL();
315}
316
317LLINT_SLOW_PATH_DECL(trace_arityCheck_for_construct)
318{
319 traceFunctionPrologue(callFrame, "construct arity check", CodeForConstruct);
320 LLINT_END_IMPL();
321}
322
323LLINT_SLOW_PATH_DECL(trace)
324{
325 if (!Options::traceLLIntExecution())
326 LLINT_END_IMPL();
327
328 CodeBlock* codeBlock = callFrame->codeBlock();
329 OpcodeID opcodeID = pc->opcodeID();
330 dataLogF("<%p> %p / %p: executing bc#%zu, %s, pc = %p\n",
331 &Thread::current(),
332 codeBlock,
333 callFrame,
334 static_cast<intptr_t>(codeBlock->bytecodeOffset(pc)),
335 pc->name(),
336 pc);
337 if (opcodeID == op_enter) {
338 dataLogF("Frame will eventually return to %p\n", callFrame->returnPC().value());
339 *removeCodePtrTag<volatile char*>(callFrame->returnPC().value());
340 }
341 if (opcodeID == op_ret) {
342 dataLogF("Will be returning to %p\n", callFrame->returnPC().value());
343 dataLogF("The new cfr will be %p\n", callFrame->callerFrame());
344 }
345 LLINT_END_IMPL();
346}
347
348enum EntryKind { Prologue, ArityCheck };
349
350#if ENABLE(JIT)
351static FunctionWhitelist& ensureGlobalJITWhitelist()
352{
353 static LazyNeverDestroyed<FunctionWhitelist> baselineWhitelist;
354 static std::once_flag initializeWhitelistFlag;
355 std::call_once(initializeWhitelistFlag, [] {
356 const char* functionWhitelistFile = Options::jitWhitelist();
357 baselineWhitelist.construct(functionWhitelistFile);
358 });
359 return baselineWhitelist;
360}
361
362inline bool shouldJIT(CodeBlock* codeBlock)
363{
364 if (!Options::bytecodeRangeToJITCompile().isInRange(codeBlock->instructionsSize())
365 || !ensureGlobalJITWhitelist().contains(codeBlock))
366 return false;
367
368 return VM::canUseJIT() && Options::useBaselineJIT();
369}
370
371// Returns true if we should try to OSR.
372inline bool jitCompileAndSetHeuristics(VM& vm, CodeBlock* codeBlock, BytecodeIndex loopOSREntryBytecodeIndex = BytecodeIndex(0))
373{
374 DeferGCForAWhile deferGC(vm.heap); // My callers don't set top callframe, so we don't want to GC here at all.
375 ASSERT(VM::canUseJIT());
376
377 codeBlock->updateAllValueProfilePredictions();
378
379 if (!codeBlock->checkIfJITThresholdReached()) {
380 CODEBLOCK_LOG_EVENT(codeBlock, "delayJITCompile", ("threshold not reached, counter = ", codeBlock->llintExecuteCounter()));
381 if (Options::verboseOSR())
382 dataLogF(" JIT threshold should be lifted.\n");
383 return false;
384 }
385
386 JITWorklist::ensureGlobalWorklist().poll(vm);
387
388 switch (codeBlock->jitType()) {
389 case JITType::BaselineJIT: {
390 if (Options::verboseOSR())
391 dataLogF(" Code was already compiled.\n");
392 codeBlock->jitSoon();
393 return true;
394 }
395 case JITType::InterpreterThunk: {
396 JITWorklist::ensureGlobalWorklist().compileLater(codeBlock, loopOSREntryBytecodeIndex);
397 return codeBlock->jitType() == JITType::BaselineJIT;
398 }
399 default:
400 dataLog("Unexpected code block in LLInt: ", *codeBlock, "\n");
401 RELEASE_ASSERT_NOT_REACHED();
402 return false;
403 }
404}
405
406static SlowPathReturnType entryOSR(CodeBlock* codeBlock, const char *name, EntryKind kind)
407{
408 if (Options::verboseOSR()) {
409 dataLog(
410 *codeBlock, ": Entered ", name, " with executeCounter = ",
411 codeBlock->llintExecuteCounter(), "\n");
412 }
413
414 if (!shouldJIT(codeBlock)) {
415 codeBlock->dontJITAnytimeSoon();
416 LLINT_RETURN_TWO(nullptr, nullptr);
417 }
418 VM& vm = codeBlock->vm();
419 if (!jitCompileAndSetHeuristics(vm, codeBlock))
420 LLINT_RETURN_TWO(nullptr, nullptr);
421
422 CODEBLOCK_LOG_EVENT(codeBlock, "OSR entry", ("in prologue"));
423
424 if (kind == Prologue)
425 LLINT_RETURN_TWO(codeBlock->jitCode()->executableAddress(), nullptr);
426 ASSERT(kind == ArityCheck);
427 LLINT_RETURN_TWO(codeBlock->jitCode()->addressForCall(MustCheckArity).executableAddress(), nullptr);
428}
429#else // ENABLE(JIT)
430static SlowPathReturnType entryOSR(CodeBlock* codeBlock, const char*, EntryKind)
431{
432 codeBlock->dontJITAnytimeSoon();
433 LLINT_RETURN_TWO(nullptr, nullptr);
434}
435#endif // ENABLE(JIT)
436
437LLINT_SLOW_PATH_DECL(entry_osr)
438{
439 UNUSED_PARAM(pc);
440 return entryOSR(callFrame->codeBlock(), "entry_osr", Prologue);
441}
442
443LLINT_SLOW_PATH_DECL(entry_osr_function_for_call)
444{
445 UNUSED_PARAM(pc);
446 return entryOSR(jsCast<JSFunction*>(callFrame->jsCallee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call", Prologue);
447}
448
449LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct)
450{
451 UNUSED_PARAM(pc);
452 return entryOSR(jsCast<JSFunction*>(callFrame->jsCallee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct", Prologue);
453}
454
455LLINT_SLOW_PATH_DECL(entry_osr_function_for_call_arityCheck)
456{
457 UNUSED_PARAM(pc);
458 return entryOSR(jsCast<JSFunction*>(callFrame->jsCallee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call_arityCheck", ArityCheck);
459}
460
461LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct_arityCheck)
462{
463 UNUSED_PARAM(pc);
464 return entryOSR(jsCast<JSFunction*>(callFrame->jsCallee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct_arityCheck", ArityCheck);
465}
466
467LLINT_SLOW_PATH_DECL(loop_osr)
468{
469 LLINT_BEGIN_NO_SET_PC();
470 UNUSED_PARAM(throwScope);
471 UNUSED_PARAM(globalObject);
472
473#if ENABLE(JIT)
474 if (Options::verboseOSR()) {
475 dataLog(
476 *codeBlock, ": Entered loop_osr with executeCounter = ",
477 codeBlock->llintExecuteCounter(), "\n");
478 }
479
480 auto loopOSREntryBytecodeIndex = BytecodeIndex(codeBlock->bytecodeOffset(pc));
481
482 if (!shouldJIT(codeBlock)) {
483 codeBlock->dontJITAnytimeSoon();
484 LLINT_RETURN_TWO(0, 0);
485 }
486
487 if (!jitCompileAndSetHeuristics(vm, codeBlock, loopOSREntryBytecodeIndex))
488 LLINT_RETURN_TWO(0, 0);
489
490 CODEBLOCK_LOG_EVENT(codeBlock, "osrEntry", ("at ", loopOSREntryBytecodeIndex));
491
492 ASSERT(codeBlock->jitType() == JITType::BaselineJIT);
493
494 const JITCodeMap& codeMap = codeBlock->jitCodeMap();
495 CodeLocationLabel<JSEntryPtrTag> codeLocation = codeMap.find(loopOSREntryBytecodeIndex);
496 ASSERT(codeLocation);
497
498 void* jumpTarget = codeLocation.executableAddress();
499 ASSERT(jumpTarget);
500
501 LLINT_RETURN_TWO(jumpTarget, callFrame->topOfFrame());
502#else // ENABLE(JIT)
503 UNUSED_PARAM(pc);
504 codeBlock->dontJITAnytimeSoon();
505 LLINT_RETURN_TWO(0, 0);
506#endif // ENABLE(JIT)
507}
508
509LLINT_SLOW_PATH_DECL(replace)
510{
511 LLINT_BEGIN_NO_SET_PC();
512 UNUSED_PARAM(throwScope);
513 UNUSED_PARAM(globalObject);
514
515#if ENABLE(JIT)
516 if (Options::verboseOSR()) {
517 dataLog(
518 *codeBlock, ": Entered replace with executeCounter = ",
519 codeBlock->llintExecuteCounter(), "\n");
520 }
521
522 if (shouldJIT(codeBlock))
523 jitCompileAndSetHeuristics(vm, codeBlock);
524 else
525 codeBlock->dontJITAnytimeSoon();
526 LLINT_END_IMPL();
527#else // ENABLE(JIT)
528 codeBlock->dontJITAnytimeSoon();
529 LLINT_END_IMPL();
530#endif // ENABLE(JIT)
531}
532
533LLINT_SLOW_PATH_DECL(stack_check)
534{
535 CodeBlock* codeBlock = callFrame->codeBlock();
536 JSGlobalObject* globalObject = codeBlock->globalObject();
537 VM& vm = codeBlock->vm();
538 auto throwScope = DECLARE_THROW_SCOPE(vm);
539
540 // It's ok to create the SlowPathFrameTracer here before we
541 // convertToStackOverflowFrame() because this function is always called
542 // after the frame has been propulated with a proper CodeBlock and callee.
543 SlowPathFrameTracer tracer(vm, callFrame);
544
545 LLINT_SET_PC_FOR_STUBS();
546
547 slowPathLogF("Checking stack height with callFrame = %p.\n", callFrame);
548 slowPathLog("CodeBlock = ", codeBlock, "\n");
549 if (codeBlock) {
550 slowPathLogF("Num callee registers = %u.\n", codeBlock->numCalleeLocals());
551 slowPathLogF("Num vars = %u.\n", codeBlock->numVars());
552 }
553 slowPathLogF("Current OS stack end is at %p.\n", vm.softStackLimit());
554#if ENABLE(C_LOOP)
555 slowPathLogF("Current C Loop stack end is at %p.\n", vm.cloopStackLimit());
556#endif
557
558 // If the stack check succeeds and we don't need to throw the error, then
559 // we'll return 0 instead. The prologue will check for a non-zero value
560 // when determining whether to set the callFrame or not.
561
562 // For JIT enabled builds which uses the C stack, the stack is not growable.
563 // Hence, if we get here, then we know a stack overflow is imminent. So, just
564 // throw the StackOverflowError unconditionally.
565#if ENABLE(C_LOOP)
566 Register* topOfFrame = callFrame->topOfFrame();
567 if (LIKELY(topOfFrame < reinterpret_cast<Register*>(callFrame))) {
568 ASSERT(!vm.interpreter->cloopStack().containsAddress(topOfFrame));
569 if (LIKELY(vm.ensureStackCapacityFor(topOfFrame)))
570 LLINT_RETURN_TWO(pc, 0);
571 }
572#endif
573
574 callFrame->convertToStackOverflowFrame(vm, codeBlock);
575 ErrorHandlingScope errorScope(vm);
576 throwStackOverflowError(globalObject, throwScope);
577 pc = returnToThrow(vm);
578 LLINT_RETURN_TWO(pc, callFrame);
579}
580
581LLINT_SLOW_PATH_DECL(slow_path_new_object)
582{
583 LLINT_BEGIN();
584 auto bytecode = pc->as<OpNewObject>();
585 auto& metadata = bytecode.metadata(codeBlock);
586 LLINT_RETURN(constructEmptyObject(vm, metadata.m_objectAllocationProfile.structure()));
587}
588
589LLINT_SLOW_PATH_DECL(slow_path_new_array)
590{
591 LLINT_BEGIN();
592 auto bytecode = pc->as<OpNewArray>();
593 auto& metadata = bytecode.metadata(codeBlock);
594 LLINT_RETURN(constructArrayNegativeIndexed(globalObject, &metadata.m_arrayAllocationProfile, bitwise_cast<JSValue*>(&callFrame->uncheckedR(bytecode.m_argv)), bytecode.m_argc));
595}
596
597LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size)
598{
599 LLINT_BEGIN();
600 auto bytecode = pc->as<OpNewArrayWithSize>();
601 auto& metadata = bytecode.metadata(codeBlock);
602 LLINT_RETURN(constructArrayWithSizeQuirk(globalObject, &metadata.m_arrayAllocationProfile, getOperand(callFrame, bytecode.m_length)));
603}
604
605LLINT_SLOW_PATH_DECL(slow_path_new_regexp)
606{
607 LLINT_BEGIN();
608 auto bytecode = pc->as<OpNewRegexp>();
609 RegExp* regExp = jsCast<RegExp*>(getOperand(callFrame, bytecode.m_regexp));
610 ASSERT(regExp->isValid());
611 LLINT_RETURN(RegExpObject::create(vm, globalObject->regExpStructure(), regExp));
612}
613
614LLINT_SLOW_PATH_DECL(slow_path_instanceof)
615{
616 LLINT_BEGIN();
617 auto bytecode = pc->as<OpInstanceof>();
618 JSValue value = getOperand(callFrame, bytecode.m_value);
619 JSValue proto = getOperand(callFrame, bytecode.m_prototype);
620 LLINT_RETURN(jsBoolean(JSObject::defaultHasInstance(globalObject, value, proto)));
621}
622
623LLINT_SLOW_PATH_DECL(slow_path_instanceof_custom)
624{
625 LLINT_BEGIN();
626
627 auto bytecode = pc->as<OpInstanceofCustom>();
628 JSValue value = getOperand(callFrame, bytecode.m_value);
629 JSValue constructor = getOperand(callFrame, bytecode.m_constructor);
630 JSValue hasInstanceValue = getOperand(callFrame, bytecode.m_hasInstanceValue);
631
632 ASSERT(constructor.isObject());
633 ASSERT(hasInstanceValue != globalObject->functionProtoHasInstanceSymbolFunction() || !constructor.getObject()->structure(vm)->typeInfo().implementsDefaultHasInstance());
634
635 JSValue result = jsBoolean(constructor.getObject()->hasInstance(globalObject, value, hasInstanceValue));
636 LLINT_RETURN(result);
637}
638
639LLINT_SLOW_PATH_DECL(slow_path_try_get_by_id)
640{
641 LLINT_BEGIN();
642 auto bytecode = pc->as<OpTryGetById>();
643 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
644 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
645 PropertySlot slot(baseValue, PropertySlot::PropertySlot::InternalMethodType::VMInquiry);
646
647 baseValue.getPropertySlot(globalObject, ident, slot);
648 JSValue result = slot.getPureResult();
649
650 LLINT_RETURN_PROFILED(result);
651}
652
653LLINT_SLOW_PATH_DECL(slow_path_get_by_id_direct)
654{
655 LLINT_BEGIN();
656 auto bytecode = pc->as<OpGetByIdDirect>();
657 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
658 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
659 PropertySlot slot(baseValue, PropertySlot::PropertySlot::InternalMethodType::GetOwnProperty);
660
661 bool found = baseValue.getOwnPropertySlot(globalObject, ident, slot);
662 LLINT_CHECK_EXCEPTION();
663 JSValue result = found ? slot.getValue(globalObject, ident) : jsUndefined();
664 LLINT_CHECK_EXCEPTION();
665
666 if (!LLINT_ALWAYS_ACCESS_SLOW && slot.isCacheable()) {
667 auto& metadata = bytecode.metadata(codeBlock);
668 {
669 StructureID oldStructureID = metadata.m_structureID;
670 if (oldStructureID) {
671 Structure* a = vm.heap.structureIDTable().get(oldStructureID);
672 Structure* b = baseValue.asCell()->structure(vm);
673
674 if (Structure::shouldConvertToPolyProto(a, b)) {
675 ASSERT(a->rareData()->sharedPolyProtoWatchpoint().get() == b->rareData()->sharedPolyProtoWatchpoint().get());
676 a->rareData()->sharedPolyProtoWatchpoint()->invalidate(vm, StringFireDetail("Detected poly proto opportunity."));
677 }
678 }
679 }
680
681 JSCell* baseCell = baseValue.asCell();
682 Structure* structure = baseCell->structure(vm);
683 if (slot.isValue()) {
684 // Start out by clearing out the old cache.
685 metadata.m_structureID = 0;
686 metadata.m_offset = 0;
687
688 if (structure->propertyAccessesAreCacheable() && !structure->needImpurePropertyWatchpoint()) {
689 {
690 ConcurrentJSLocker locker(codeBlock->m_lock);
691 metadata.m_structureID = structure->id();
692 metadata.m_offset = slot.cachedOffset();
693 }
694 vm.heap.writeBarrier(codeBlock);
695 }
696 }
697 }
698
699 LLINT_RETURN_PROFILED(result);
700}
701
702
703static void setupGetByIdPrototypeCache(JSGlobalObject* globalObject, VM& vm, CodeBlock* codeBlock, const Instruction* pc, OpGetById::Metadata& metadata, JSCell* baseCell, PropertySlot& slot, const Identifier& ident)
704{
705 Structure* structure = baseCell->structure(vm);
706
707 if (structure->typeInfo().prohibitsPropertyCaching())
708 return;
709
710 if (structure->needImpurePropertyWatchpoint())
711 return;
712
713 if (structure->isDictionary()) {
714 if (structure->hasBeenFlattenedBefore())
715 return;
716 structure->flattenDictionaryStructure(vm, jsCast<JSObject*>(baseCell));
717 }
718
719 preparePrototypeChainForCaching(globalObject, baseCell, slot);
720
721 ObjectPropertyConditionSet conditions;
722 if (slot.isUnset())
723 conditions = generateConditionsForPropertyMiss(vm, codeBlock, globalObject, structure, ident.impl());
724 else
725 conditions = generateConditionsForPrototypePropertyHit(vm, codeBlock, globalObject, structure, slot.slotBase(), ident.impl());
726
727 if (!conditions.isValid())
728 return;
729
730 unsigned bytecodeOffset = codeBlock->bytecodeOffset(pc);
731 PropertyOffset offset = invalidOffset;
732 CodeBlock::StructureWatchpointMap& watchpointMap = codeBlock->llintGetByIdWatchpointMap();
733 Vector<LLIntPrototypeLoadAdaptiveStructureWatchpoint> watchpoints;
734 watchpoints.reserveInitialCapacity(conditions.size());
735 for (ObjectPropertyCondition condition : conditions) {
736 if (!condition.isWatchable())
737 return;
738 if (condition.condition().kind() == PropertyCondition::Presence)
739 offset = condition.condition().offset();
740 watchpoints.uncheckedConstructAndAppend(codeBlock, condition, bytecodeOffset);
741 watchpoints.last().install(vm);
742 }
743
744 ASSERT((offset == invalidOffset) == slot.isUnset());
745 auto result = watchpointMap.add(std::make_tuple(structure->id(), bytecodeOffset), WTFMove(watchpoints));
746 ASSERT_UNUSED(result, result.isNewEntry);
747
748 {
749 ConcurrentJSLocker locker(codeBlock->m_lock);
750 if (slot.isUnset())
751 metadata.m_modeMetadata.setUnsetMode(structure);
752 else {
753 ASSERT(slot.isValue());
754 metadata.m_modeMetadata.setProtoLoadMode(structure, offset, slot.slotBase());
755 }
756 }
757 vm.heap.writeBarrier(codeBlock);
758}
759
760
761LLINT_SLOW_PATH_DECL(slow_path_get_by_id)
762{
763 LLINT_BEGIN();
764 auto bytecode = pc->as<OpGetById>();
765 auto& metadata = bytecode.metadata(codeBlock);
766 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
767 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
768 PropertySlot slot(baseValue, PropertySlot::PropertySlot::InternalMethodType::Get);
769
770 JSValue result = baseValue.get(globalObject, ident, slot);
771 LLINT_CHECK_EXCEPTION();
772 callFrame->uncheckedR(bytecode.m_dst) = result;
773
774 if (!LLINT_ALWAYS_ACCESS_SLOW
775 && baseValue.isCell()
776 && slot.isCacheable()) {
777 {
778 StructureID oldStructureID;
779 switch (metadata.m_modeMetadata.mode) {
780 case GetByIdMode::Default:
781 oldStructureID = metadata.m_modeMetadata.defaultMode.structureID;
782 break;
783 case GetByIdMode::Unset:
784 oldStructureID = metadata.m_modeMetadata.unsetMode.structureID;
785 break;
786 case GetByIdMode::ProtoLoad:
787 oldStructureID = metadata.m_modeMetadata.protoLoadMode.structureID;
788 break;
789 default:
790 oldStructureID = 0;
791 }
792 if (oldStructureID) {
793 Structure* a = vm.heap.structureIDTable().get(oldStructureID);
794 Structure* b = baseValue.asCell()->structure(vm);
795
796 if (Structure::shouldConvertToPolyProto(a, b)) {
797 ASSERT(a->rareData()->sharedPolyProtoWatchpoint().get() == b->rareData()->sharedPolyProtoWatchpoint().get());
798 a->rareData()->sharedPolyProtoWatchpoint()->invalidate(vm, StringFireDetail("Detected poly proto opportunity."));
799 }
800 }
801 }
802
803 JSCell* baseCell = baseValue.asCell();
804 Structure* structure = baseCell->structure(vm);
805 if (slot.isValue() && slot.slotBase() == baseValue) {
806 ConcurrentJSLocker locker(codeBlock->m_lock);
807 // Start out by clearing out the old cache.
808 metadata.m_modeMetadata.clearToDefaultModeWithoutCache();
809
810 // Prevent the prototype cache from ever happening.
811 metadata.m_modeMetadata.hitCountForLLIntCaching = 0;
812
813 if (structure->propertyAccessesAreCacheable() && !structure->needImpurePropertyWatchpoint()) {
814 metadata.m_modeMetadata.defaultMode.structureID = structure->id();
815 metadata.m_modeMetadata.defaultMode.cachedOffset = slot.cachedOffset();
816 vm.heap.writeBarrier(codeBlock);
817 }
818 } else if (UNLIKELY(metadata.m_modeMetadata.hitCountForLLIntCaching && (slot.isValue() || slot.isUnset()))) {
819 ASSERT(slot.slotBase() != baseValue);
820
821 if (!(--metadata.m_modeMetadata.hitCountForLLIntCaching))
822 setupGetByIdPrototypeCache(globalObject, vm, codeBlock, pc, metadata, baseCell, slot, ident);
823 }
824 } else if (!LLINT_ALWAYS_ACCESS_SLOW && isJSArray(baseValue) && ident == vm.propertyNames->length) {
825 {
826 ConcurrentJSLocker locker(codeBlock->m_lock);
827 metadata.m_modeMetadata.setArrayLengthMode();
828 metadata.m_modeMetadata.arrayLengthMode.arrayProfile.observeStructure(baseValue.asCell()->structure(vm));
829 }
830 vm.heap.writeBarrier(codeBlock);
831 }
832
833 LLINT_PROFILE_VALUE(result);
834 LLINT_END();
835}
836
837LLINT_SLOW_PATH_DECL(slow_path_put_by_id)
838{
839 LLINT_BEGIN();
840 auto bytecode = pc->as<OpPutById>();
841 auto& metadata = bytecode.metadata(codeBlock);
842 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
843
844 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
845 PutPropertySlot slot(baseValue, codeBlock->isStrictMode(), codeBlock->putByIdContext());
846 if (bytecode.m_flags & PutByIdIsDirect)
847 CommonSlowPaths::putDirectWithReify(vm, globalObject, asObject(baseValue), ident, getOperand(callFrame, bytecode.m_value), slot);
848 else
849 baseValue.putInline(globalObject, ident, getOperand(callFrame, bytecode.m_value), slot);
850 LLINT_CHECK_EXCEPTION();
851
852 if (!LLINT_ALWAYS_ACCESS_SLOW
853 && baseValue.isCell()
854 && slot.isCacheablePut()) {
855
856 {
857 StructureID oldStructureID = metadata.m_oldStructureID;
858 if (oldStructureID) {
859 Structure* a = vm.heap.structureIDTable().get(oldStructureID);
860 Structure* b = baseValue.asCell()->structure(vm);
861 if (slot.type() == PutPropertySlot::NewProperty)
862 b = b->previousID();
863
864 if (Structure::shouldConvertToPolyProto(a, b)) {
865 a->rareData()->sharedPolyProtoWatchpoint()->invalidate(vm, StringFireDetail("Detected poly proto opportunity."));
866 b->rareData()->sharedPolyProtoWatchpoint()->invalidate(vm, StringFireDetail("Detected poly proto opportunity."));
867 }
868 }
869 }
870
871 // Start out by clearing out the old cache.
872 metadata.m_oldStructureID = 0;
873 metadata.m_offset = 0;
874 metadata.m_newStructureID = 0;
875 metadata.m_structureChain.clear();
876
877 JSCell* baseCell = baseValue.asCell();
878 Structure* structure = baseCell->structure(vm);
879
880 if (!structure->isUncacheableDictionary() && !structure->typeInfo().prohibitsPropertyCaching() && baseCell == slot.base()) {
881 if (slot.type() == PutPropertySlot::NewProperty) {
882 GCSafeConcurrentJSLocker locker(codeBlock->m_lock, vm.heap);
883 if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
884 ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
885
886 bool sawPolyProto = false;
887 auto result = normalizePrototypeChain(globalObject, baseCell, sawPolyProto);
888 if (result != InvalidPrototypeChain && !sawPolyProto) {
889 ASSERT(structure->previousID()->isObject());
890 metadata.m_oldStructureID = structure->previousID()->id();
891 metadata.m_offset = slot.cachedOffset();
892 metadata.m_newStructureID = structure->id();
893 if (!(bytecode.m_flags & PutByIdIsDirect)) {
894 StructureChain* chain = structure->prototypeChain(globalObject, asObject(baseCell));
895 ASSERT(chain);
896 metadata.m_structureChain.set(vm, codeBlock, chain);
897 }
898 vm.heap.writeBarrier(codeBlock);
899 }
900 }
901 } else {
902 structure->didCachePropertyReplacement(vm, slot.cachedOffset());
903 {
904 ConcurrentJSLocker locker(codeBlock->m_lock);
905 metadata.m_oldStructureID = structure->id();
906 metadata.m_offset = slot.cachedOffset();
907 }
908 vm.heap.writeBarrier(codeBlock);
909 }
910 }
911 }
912
913 LLINT_END();
914}
915
916LLINT_SLOW_PATH_DECL(slow_path_del_by_id)
917{
918 LLINT_BEGIN();
919 auto bytecode = pc->as<OpDelById>();
920 JSObject* baseObject = getOperand(callFrame, bytecode.m_base).toObject(globalObject);
921 LLINT_CHECK_EXCEPTION();
922 bool couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, codeBlock->identifier(bytecode.m_property));
923 LLINT_CHECK_EXCEPTION();
924 if (!couldDelete && codeBlock->isStrictMode())
925 LLINT_THROW(createTypeError(globalObject, UnableToDeletePropertyError));
926 LLINT_RETURN(jsBoolean(couldDelete));
927}
928
929static ALWAYS_INLINE JSValue getByVal(VM& vm, JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, OpGetByVal bytecode)
930{
931 auto scope = DECLARE_THROW_SCOPE(vm);
932
933 if (LIKELY(baseValue.isCell() && subscript.isString())) {
934 Structure& structure = *baseValue.asCell()->structure(vm);
935 if (JSCell::canUseFastGetOwnProperty(structure)) {
936 RefPtr<AtomStringImpl> existingAtomString = asString(subscript)->toExistingAtomString(globalObject);
937 RETURN_IF_EXCEPTION(scope, JSValue());
938 if (existingAtomString) {
939 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomString.get()))
940 return result;
941 }
942 }
943 }
944
945 if (subscript.isUInt32()) {
946 uint32_t i = subscript.asUInt32();
947 auto& metadata = bytecode.metadata(codeBlock);
948 ArrayProfile* arrayProfile = &metadata.m_arrayProfile;
949
950 if (isJSString(baseValue)) {
951 if (asString(baseValue)->canGetIndex(i)) {
952 scope.release();
953 return asString(baseValue)->getIndex(globalObject, i);
954 }
955 arrayProfile->setOutOfBounds();
956 } else if (baseValue.isObject()) {
957 JSObject* object = asObject(baseValue);
958 if (object->canGetIndexQuickly(i))
959 return object->getIndexQuickly(i);
960
961 bool skipMarkingOutOfBounds = false;
962
963 if (object->indexingType() == ArrayWithContiguous && i < object->butterfly()->publicLength()) {
964 // FIXME: expand this to ArrayStorage, Int32, and maybe Double:
965 // https://bugs.webkit.org/show_bug.cgi?id=182940
966 auto* globalObject = object->globalObject(vm);
967 skipMarkingOutOfBounds = globalObject->isOriginalArrayStructure(object->structure(vm)) && globalObject->arrayPrototypeChainIsSane();
968 }
969
970 if (!skipMarkingOutOfBounds && !CommonSlowPaths::canAccessArgumentIndexQuickly(*object, i))
971 arrayProfile->setOutOfBounds();
972 }
973
974 scope.release();
975 return baseValue.get(globalObject, i);
976 }
977
978 baseValue.requireObjectCoercible(globalObject);
979 RETURN_IF_EXCEPTION(scope, JSValue());
980 auto property = subscript.toPropertyKey(globalObject);
981 RETURN_IF_EXCEPTION(scope, JSValue());
982 scope.release();
983 return baseValue.get(globalObject, property);
984}
985
986LLINT_SLOW_PATH_DECL(slow_path_get_by_val)
987{
988 LLINT_BEGIN();
989 auto bytecode = pc->as<OpGetByVal>();
990 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
991 JSValue subscript = getOperand(callFrame, bytecode.m_property);
992 LLINT_RETURN_PROFILED(getByVal(vm, globalObject, codeBlock, baseValue, subscript, bytecode));
993}
994
995LLINT_SLOW_PATH_DECL(slow_path_put_by_val)
996{
997 LLINT_BEGIN();
998
999 auto bytecode = pc->as<OpPutByVal>();
1000 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
1001 JSValue subscript = getOperand(callFrame, bytecode.m_property);
1002 JSValue value = getOperand(callFrame, bytecode.m_value);
1003 bool isStrictMode = codeBlock->isStrictMode();
1004
1005 if (LIKELY(subscript.isUInt32())) {
1006 uint32_t i = subscript.asUInt32();
1007 if (baseValue.isObject()) {
1008 JSObject* object = asObject(baseValue);
1009 if (object->canSetIndexQuickly(i, value))
1010 object->setIndexQuickly(vm, i, value);
1011 else
1012 object->methodTable(vm)->putByIndex(object, globalObject, i, value, isStrictMode);
1013 LLINT_END();
1014 }
1015 baseValue.putByIndex(globalObject, i, value, isStrictMode);
1016 LLINT_END();
1017 }
1018
1019 auto property = subscript.toPropertyKey(globalObject);
1020 LLINT_CHECK_EXCEPTION();
1021 PutPropertySlot slot(baseValue, isStrictMode);
1022 baseValue.put(globalObject, property, value, slot);
1023 LLINT_END();
1024}
1025
1026LLINT_SLOW_PATH_DECL(slow_path_put_by_val_direct)
1027{
1028 LLINT_BEGIN();
1029
1030 auto bytecode = pc->as<OpPutByValDirect>();
1031 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
1032 JSValue subscript = getOperand(callFrame, bytecode.m_property);
1033 JSValue value = getOperand(callFrame, bytecode.m_value);
1034 RELEASE_ASSERT(baseValue.isObject());
1035 JSObject* baseObject = asObject(baseValue);
1036 bool isStrictMode = codeBlock->isStrictMode();
1037 if (LIKELY(subscript.isUInt32())) {
1038 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
1039 ASSERT(isIndex(subscript.asUInt32()));
1040 baseObject->putDirectIndex(globalObject, subscript.asUInt32(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
1041 LLINT_END();
1042 }
1043
1044 if (subscript.isDouble()) {
1045 double subscriptAsDouble = subscript.asDouble();
1046 uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
1047 if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) {
1048 baseObject->putDirectIndex(globalObject, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
1049 LLINT_END();
1050 }
1051 }
1052
1053 // Don't put to an object if toString threw an exception.
1054 auto property = subscript.toPropertyKey(globalObject);
1055 if (UNLIKELY(throwScope.exception()))
1056 LLINT_END();
1057
1058 if (Optional<uint32_t> index = parseIndex(property))
1059 baseObject->putDirectIndex(globalObject, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
1060 else {
1061 PutPropertySlot slot(baseObject, isStrictMode);
1062 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, property, value, slot);
1063 }
1064 LLINT_END();
1065}
1066
1067LLINT_SLOW_PATH_DECL(slow_path_del_by_val)
1068{
1069 LLINT_BEGIN();
1070 auto bytecode = pc->as<OpDelByVal>();
1071 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
1072 JSObject* baseObject = baseValue.toObject(globalObject);
1073 LLINT_CHECK_EXCEPTION();
1074
1075 JSValue subscript = getOperand(callFrame, bytecode.m_property);
1076
1077 bool couldDelete;
1078
1079 uint32_t i;
1080 if (subscript.getUInt32(i))
1081 couldDelete = baseObject->methodTable(vm)->deletePropertyByIndex(baseObject, globalObject, i);
1082 else {
1083 LLINT_CHECK_EXCEPTION();
1084 auto property = subscript.toPropertyKey(globalObject);
1085 LLINT_CHECK_EXCEPTION();
1086 couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, property);
1087 }
1088 LLINT_CHECK_EXCEPTION();
1089
1090 if (!couldDelete && codeBlock->isStrictMode())
1091 LLINT_THROW(createTypeError(globalObject, UnableToDeletePropertyError));
1092
1093 LLINT_RETURN(jsBoolean(couldDelete));
1094}
1095
1096LLINT_SLOW_PATH_DECL(slow_path_put_getter_by_id)
1097{
1098 LLINT_BEGIN();
1099 auto bytecode = pc->as<OpPutGetterById>();
1100 ASSERT(getNonConstantOperand(callFrame, bytecode.m_base).isObject());
1101 JSObject* baseObj = asObject(getNonConstantOperand(callFrame, bytecode.m_base));
1102
1103 unsigned options = bytecode.m_attributes;
1104
1105 JSValue getter = getNonConstantOperand(callFrame, bytecode.m_accessor);
1106 ASSERT(getter.isObject());
1107
1108 baseObj->putGetter(globalObject, codeBlock->identifier(bytecode.m_property), asObject(getter), options);
1109 LLINT_END();
1110}
1111
1112LLINT_SLOW_PATH_DECL(slow_path_put_setter_by_id)
1113{
1114 LLINT_BEGIN();
1115 auto bytecode = pc->as<OpPutSetterById>();
1116 ASSERT(getNonConstantOperand(callFrame, bytecode.m_base).isObject());
1117 JSObject* baseObj = asObject(getNonConstantOperand(callFrame, bytecode.m_base));
1118
1119 unsigned options = bytecode.m_attributes;
1120
1121 JSValue setter = getNonConstantOperand(callFrame, bytecode.m_accessor);
1122 ASSERT(setter.isObject());
1123
1124 baseObj->putSetter(globalObject, codeBlock->identifier(bytecode.m_property), asObject(setter), options);
1125 LLINT_END();
1126}
1127
1128LLINT_SLOW_PATH_DECL(slow_path_put_getter_setter_by_id)
1129{
1130 LLINT_BEGIN();
1131 auto bytecode = pc->as<OpPutGetterSetterById>();
1132 ASSERT(getNonConstantOperand(callFrame, bytecode.m_base).isObject());
1133 JSObject* baseObject = asObject(getNonConstantOperand(callFrame, bytecode.m_base));
1134
1135 JSValue getter = getNonConstantOperand(callFrame, bytecode.m_getter);
1136 JSValue setter = getNonConstantOperand(callFrame, bytecode.m_setter);
1137 ASSERT(getter.isObject() || setter.isObject());
1138 GetterSetter* accessor = GetterSetter::create(vm, globalObject, getter, setter);
1139
1140 CommonSlowPaths::putDirectAccessorWithReify(vm, globalObject, baseObject, codeBlock->identifier(bytecode.m_property), accessor, bytecode.m_attributes);
1141 LLINT_END();
1142}
1143
1144LLINT_SLOW_PATH_DECL(slow_path_put_getter_by_val)
1145{
1146 LLINT_BEGIN();
1147 auto bytecode = pc->as<OpPutGetterByVal>();
1148 ASSERT(getNonConstantOperand(callFrame, bytecode.m_base).isObject());
1149 JSObject* baseObj = asObject(getNonConstantOperand(callFrame, bytecode.m_base));
1150 JSValue subscript = getOperand(callFrame, bytecode.m_property);
1151
1152 unsigned options = bytecode.m_attributes;
1153
1154 JSValue getter = getNonConstantOperand(callFrame, bytecode.m_accessor);
1155 ASSERT(getter.isObject());
1156
1157 auto property = subscript.toPropertyKey(globalObject);
1158 LLINT_CHECK_EXCEPTION();
1159
1160 baseObj->putGetter(globalObject, property, asObject(getter), options);
1161 LLINT_END();
1162}
1163
1164LLINT_SLOW_PATH_DECL(slow_path_put_setter_by_val)
1165{
1166 LLINT_BEGIN();
1167 auto bytecode = pc->as<OpPutSetterByVal>();
1168 ASSERT(getNonConstantOperand(callFrame, bytecode.m_base).isObject());
1169 JSObject* baseObj = asObject(getNonConstantOperand(callFrame, bytecode.m_base));
1170 JSValue subscript = getOperand(callFrame, bytecode.m_property);
1171
1172 unsigned options = bytecode.m_attributes;
1173
1174 JSValue setter = getNonConstantOperand(callFrame, bytecode.m_accessor);
1175 ASSERT(setter.isObject());
1176
1177 auto property = subscript.toPropertyKey(globalObject);
1178 LLINT_CHECK_EXCEPTION();
1179
1180 baseObj->putSetter(globalObject, property, asObject(setter), options);
1181 LLINT_END();
1182}
1183
1184LLINT_SLOW_PATH_DECL(slow_path_jtrue)
1185{
1186 LLINT_BEGIN();
1187 auto bytecode = pc->as<OpJtrue>();
1188 LLINT_BRANCH(getOperand(callFrame, bytecode.m_condition).toBoolean(globalObject));
1189}
1190
1191LLINT_SLOW_PATH_DECL(slow_path_jfalse)
1192{
1193 LLINT_BEGIN();
1194 auto bytecode = pc->as<OpJfalse>();
1195 LLINT_BRANCH(!getOperand(callFrame, bytecode.m_condition).toBoolean(globalObject));
1196}
1197
1198LLINT_SLOW_PATH_DECL(slow_path_jless)
1199{
1200 LLINT_BEGIN();
1201 auto bytecode = pc->as<OpJless>();
1202 LLINT_BRANCH(jsLess<true>(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1203}
1204
1205LLINT_SLOW_PATH_DECL(slow_path_jnless)
1206{
1207 LLINT_BEGIN();
1208 auto bytecode = pc->as<OpJnless>();
1209 LLINT_BRANCH(!jsLess<true>(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1210}
1211
1212LLINT_SLOW_PATH_DECL(slow_path_jgreater)
1213{
1214 LLINT_BEGIN();
1215 auto bytecode = pc->as<OpJgreater>();
1216 LLINT_BRANCH(jsLess<false>(globalObject, getOperand(callFrame, bytecode.m_rhs), getOperand(callFrame, bytecode.m_lhs)));
1217}
1218
1219LLINT_SLOW_PATH_DECL(slow_path_jngreater)
1220{
1221 LLINT_BEGIN();
1222 auto bytecode = pc->as<OpJngreater>();
1223 LLINT_BRANCH(!jsLess<false>(globalObject, getOperand(callFrame, bytecode.m_rhs), getOperand(callFrame, bytecode.m_lhs)));
1224}
1225
1226LLINT_SLOW_PATH_DECL(slow_path_jlesseq)
1227{
1228 LLINT_BEGIN();
1229 auto bytecode = pc->as<OpJlesseq>();
1230 LLINT_BRANCH(jsLessEq<true>(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1231}
1232
1233LLINT_SLOW_PATH_DECL(slow_path_jnlesseq)
1234{
1235 LLINT_BEGIN();
1236 auto bytecode = pc->as<OpJnlesseq>();
1237 LLINT_BRANCH(!jsLessEq<true>(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1238}
1239
1240LLINT_SLOW_PATH_DECL(slow_path_jgreatereq)
1241{
1242 LLINT_BEGIN();
1243 auto bytecode = pc->as<OpJgreatereq>();
1244 LLINT_BRANCH(jsLessEq<false>(globalObject, getOperand(callFrame, bytecode.m_rhs), getOperand(callFrame, bytecode.m_lhs)));
1245}
1246
1247LLINT_SLOW_PATH_DECL(slow_path_jngreatereq)
1248{
1249 LLINT_BEGIN();
1250 auto bytecode = pc->as<OpJngreatereq>();
1251 LLINT_BRANCH(!jsLessEq<false>(globalObject, getOperand(callFrame, bytecode.m_rhs), getOperand(callFrame, bytecode.m_lhs)));
1252}
1253
1254LLINT_SLOW_PATH_DECL(slow_path_jeq)
1255{
1256 LLINT_BEGIN();
1257 auto bytecode = pc->as<OpJeq>();
1258 LLINT_BRANCH(JSValue::equal(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1259}
1260
1261LLINT_SLOW_PATH_DECL(slow_path_jneq)
1262{
1263 LLINT_BEGIN();
1264 auto bytecode = pc->as<OpJneq>();
1265 LLINT_BRANCH(!JSValue::equal(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1266}
1267
1268LLINT_SLOW_PATH_DECL(slow_path_jstricteq)
1269{
1270 LLINT_BEGIN();
1271 auto bytecode = pc->as<OpJstricteq>();
1272 LLINT_BRANCH(JSValue::strictEqual(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1273}
1274
1275LLINT_SLOW_PATH_DECL(slow_path_jnstricteq)
1276{
1277 LLINT_BEGIN();
1278 auto bytecode = pc->as<OpJnstricteq>();
1279 LLINT_BRANCH(!JSValue::strictEqual(globalObject, getOperand(callFrame, bytecode.m_lhs), getOperand(callFrame, bytecode.m_rhs)));
1280}
1281
1282LLINT_SLOW_PATH_DECL(slow_path_switch_imm)
1283{
1284 LLINT_BEGIN();
1285 auto bytecode = pc->as<OpSwitchImm>();
1286 JSValue scrutinee = getOperand(callFrame, bytecode.m_scrutinee);
1287 ASSERT(scrutinee.isDouble());
1288 double value = scrutinee.asDouble();
1289 int32_t intValue = static_cast<int32_t>(value);
1290 int defaultOffset = JUMP_OFFSET(bytecode.m_defaultOffset);
1291 if (value == intValue)
1292 JUMP_TO(codeBlock->switchJumpTable(bytecode.m_tableIndex).offsetForValue(intValue, defaultOffset));
1293 else
1294 JUMP_TO(defaultOffset);
1295 LLINT_END();
1296}
1297
1298LLINT_SLOW_PATH_DECL(slow_path_switch_char)
1299{
1300 LLINT_BEGIN();
1301 auto bytecode = pc->as<OpSwitchChar>();
1302 JSValue scrutinee = getOperand(callFrame, bytecode.m_scrutinee);
1303 ASSERT(scrutinee.isString());
1304 JSString* string = asString(scrutinee);
1305 ASSERT(string->length() == 1);
1306 int defaultOffset = JUMP_OFFSET(bytecode.m_defaultOffset);
1307 StringImpl* impl = string->value(globalObject).impl();
1308 JUMP_TO(codeBlock->switchJumpTable(bytecode.m_tableIndex).offsetForValue((*impl)[0], defaultOffset));
1309 LLINT_END();
1310}
1311
1312LLINT_SLOW_PATH_DECL(slow_path_switch_string)
1313{
1314 LLINT_BEGIN();
1315 auto bytecode = pc->as<OpSwitchString>();
1316 JSValue scrutinee = getOperand(callFrame, bytecode.m_scrutinee);
1317 int defaultOffset = JUMP_OFFSET(bytecode.m_defaultOffset);
1318 if (!scrutinee.isString())
1319 JUMP_TO(defaultOffset);
1320 else {
1321 StringImpl* scrutineeStringImpl = asString(scrutinee)->value(globalObject).impl();
1322
1323 LLINT_CHECK_EXCEPTION();
1324
1325 JUMP_TO(codeBlock->stringSwitchJumpTable(bytecode.m_tableIndex).offsetForValue(scrutineeStringImpl, defaultOffset));
1326 }
1327 LLINT_END();
1328}
1329
1330LLINT_SLOW_PATH_DECL(slow_path_new_func)
1331{
1332 LLINT_BEGIN();
1333 auto bytecode = pc->as<OpNewFunc>();
1334 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1335 slowPathLogF("Creating function!\n");
1336 LLINT_RETURN(JSFunction::create(vm, codeBlock->functionDecl(bytecode.m_functionDecl), scope));
1337}
1338
1339LLINT_SLOW_PATH_DECL(slow_path_new_generator_func)
1340{
1341 LLINT_BEGIN();
1342 auto bytecode = pc->as<OpNewGeneratorFunc>();
1343 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1344 slowPathLogF("Creating function!\n");
1345 LLINT_RETURN(JSGeneratorFunction::create(vm, codeBlock->functionDecl(bytecode.m_functionDecl), scope));
1346}
1347
1348LLINT_SLOW_PATH_DECL(slow_path_new_async_func)
1349{
1350 LLINT_BEGIN();
1351 auto bytecode = pc->as<OpNewAsyncFunc>();
1352 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1353 slowPathLogF("Creating async function!\n");
1354 LLINT_RETURN(JSAsyncFunction::create(vm, codeBlock->functionDecl(bytecode.m_functionDecl), scope));
1355}
1356
1357LLINT_SLOW_PATH_DECL(slow_path_new_async_generator_func)
1358{
1359 LLINT_BEGIN();
1360 auto bytecode = pc->as<OpNewAsyncGeneratorFunc>();
1361 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1362 slowPathLogF("Creating async generator function!\n");
1363 LLINT_RETURN(JSAsyncGeneratorFunction::create(vm, codeBlock->functionDecl(bytecode.m_functionDecl), scope));
1364}
1365
1366LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
1367{
1368 LLINT_BEGIN();
1369
1370 auto bytecode = pc->as<OpNewFuncExp>();
1371 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1372 FunctionExecutable* executable = codeBlock->functionExpr(bytecode.m_functionDecl);
1373
1374 LLINT_RETURN(JSFunction::create(vm, executable, scope));
1375}
1376
1377LLINT_SLOW_PATH_DECL(slow_path_new_generator_func_exp)
1378{
1379 LLINT_BEGIN();
1380
1381 auto bytecode = pc->as<OpNewGeneratorFuncExp>();
1382 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1383 FunctionExecutable* executable = codeBlock->functionExpr(bytecode.m_functionDecl);
1384
1385 LLINT_RETURN(JSGeneratorFunction::create(vm, executable, scope));
1386}
1387
1388LLINT_SLOW_PATH_DECL(slow_path_new_async_func_exp)
1389{
1390 LLINT_BEGIN();
1391
1392 auto bytecode = pc->as<OpNewAsyncFuncExp>();
1393 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1394 FunctionExecutable* executable = codeBlock->functionExpr(bytecode.m_functionDecl);
1395
1396 LLINT_RETURN(JSAsyncFunction::create(vm, executable, scope));
1397}
1398
1399LLINT_SLOW_PATH_DECL(slow_path_new_async_generator_func_exp)
1400{
1401 LLINT_BEGIN();
1402
1403 auto bytecode = pc->as<OpNewAsyncGeneratorFuncExp>();
1404 JSScope* scope = callFrame->uncheckedR(bytecode.m_scope).Register::scope();
1405 FunctionExecutable* executable = codeBlock->functionExpr(bytecode.m_functionDecl);
1406
1407 LLINT_RETURN(JSAsyncGeneratorFunction::create(vm, executable, scope));
1408}
1409
1410LLINT_SLOW_PATH_DECL(slow_path_set_function_name)
1411{
1412 LLINT_BEGIN();
1413 auto bytecode = pc->as<OpSetFunctionName>();
1414 JSFunction* func = jsCast<JSFunction*>(getNonConstantOperand(callFrame, bytecode.m_function));
1415 JSValue name = getOperand(callFrame, bytecode.m_name);
1416 func->setFunctionName(globalObject, name);
1417 LLINT_END();
1418}
1419
1420static SlowPathReturnType handleHostCall(CallFrame* calleeFrame, JSValue callee, CodeSpecializationKind kind)
1421{
1422 slowPathLog("Performing host call.\n");
1423
1424 CallFrame* callFrame = calleeFrame->callerFrame();
1425 CodeBlock* callerCodeBlock = callFrame->codeBlock();
1426 JSGlobalObject* globalObject = callerCodeBlock->globalObject();
1427 VM& vm = callerCodeBlock->vm();
1428 auto throwScope = DECLARE_THROW_SCOPE(vm);
1429
1430 calleeFrame->setCodeBlock(nullptr);
1431 calleeFrame->clearReturnPC();
1432
1433 if (kind == CodeForCall) {
1434 CallData callData;
1435 CallType callType = getCallData(vm, callee, callData);
1436
1437 ASSERT(callType != CallType::JS);
1438
1439 if (callType == CallType::Host) {
1440 SlowPathFrameTracer tracer(vm, calleeFrame);
1441 calleeFrame->setCallee(asObject(callee));
1442 vm.hostCallReturnValue = JSValue::decode(callData.native.function(asObject(callee)->globalObject(vm), calleeFrame));
1443 LLINT_CALL_RETURN(globalObject, calleeFrame, LLInt::getCodePtr(getHostCallReturnValue), CFunctionPtrTag);
1444 }
1445
1446 slowPathLog("Call callee is not a function: ", callee, "\n");
1447
1448 ASSERT(callType == CallType::None);
1449 LLINT_CALL_THROW(globalObject, createNotAFunctionError(globalObject, callee));
1450 }
1451
1452 ASSERT(kind == CodeForConstruct);
1453
1454 ConstructData constructData;
1455 ConstructType constructType = getConstructData(vm, callee, constructData);
1456
1457 ASSERT(constructType != ConstructType::JS);
1458
1459 if (constructType == ConstructType::Host) {
1460 SlowPathFrameTracer tracer(vm, calleeFrame);
1461 calleeFrame->setCallee(asObject(callee));
1462 vm.hostCallReturnValue = JSValue::decode(constructData.native.function(asObject(callee)->globalObject(vm), calleeFrame));
1463 LLINT_CALL_RETURN(globalObject, calleeFrame, LLInt::getCodePtr(getHostCallReturnValue), CFunctionPtrTag);
1464 }
1465
1466 slowPathLog("Constructor callee is not a function: ", callee, "\n");
1467
1468 ASSERT(constructType == ConstructType::None);
1469 LLINT_CALL_THROW(globalObject, createNotAConstructorError(globalObject, callee));
1470}
1471
1472inline SlowPathReturnType setUpCall(CallFrame* calleeFrame, CodeSpecializationKind kind, JSValue calleeAsValue, LLIntCallLinkInfo* callLinkInfo = nullptr)
1473{
1474 CallFrame* callFrame = calleeFrame->callerFrame();
1475 CodeBlock* callerCodeBlock = callFrame->codeBlock();
1476 JSGlobalObject* globalObject = callerCodeBlock->globalObject();
1477 VM& vm = callerCodeBlock->vm();
1478 auto throwScope = DECLARE_THROW_SCOPE(vm);
1479
1480 slowPathLogF("Performing call with recorded PC = %p\n", callFrame->currentVPC());
1481
1482 JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
1483 if (!calleeAsFunctionCell) {
1484 if (auto* internalFunction = jsDynamicCast<InternalFunction*>(vm, calleeAsValue)) {
1485 MacroAssemblerCodePtr<JSEntryPtrTag> codePtr = vm.getCTIInternalFunctionTrampolineFor(kind);
1486 ASSERT(!!codePtr);
1487
1488 if (!LLINT_ALWAYS_ACCESS_SLOW && callLinkInfo) {
1489 ConcurrentJSLocker locker(callerCodeBlock->m_lock);
1490 callLinkInfo->link(vm, callerCodeBlock, internalFunction, codePtr);
1491 }
1492
1493 assertIsTaggedWith(codePtr.executableAddress(), JSEntryPtrTag);
1494 LLINT_CALL_RETURN(globalObject, calleeFrame, codePtr.executableAddress(), JSEntryPtrTag);
1495 }
1496 RELEASE_AND_RETURN(throwScope, handleHostCall(calleeFrame, calleeAsValue, kind));
1497 }
1498 JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
1499 JSScope* scope = callee->scopeUnchecked();
1500 ExecutableBase* executable = callee->executable();
1501
1502 MacroAssemblerCodePtr<JSEntryPtrTag> codePtr;
1503 CodeBlock* codeBlock = nullptr;
1504 if (executable->isHostFunction())
1505 codePtr = executable->entrypointFor(kind, MustCheckArity);
1506 else {
1507 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
1508
1509 if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
1510 LLINT_CALL_THROW(globalObject, createNotAConstructorError(globalObject, callee));
1511
1512 CodeBlock** codeBlockSlot = calleeFrame->addressOfCodeBlock();
1513 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, callee, scope, kind, *codeBlockSlot);
1514