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 "CommonSlowPaths.h"
28
29#include "ArithProfile.h"
30#include "ArrayConstructor.h"
31#include "BuiltinNames.h"
32#include "BytecodeStructs.h"
33#include "CallFrame.h"
34#include "ClonedArguments.h"
35#include "CodeProfiling.h"
36#include "DefinePropertyAttributes.h"
37#include "DirectArguments.h"
38#include "Error.h"
39#include "ErrorHandlingScope.h"
40#include "ExceptionFuzz.h"
41#include "FrameTracers.h"
42#include "GetterSetter.h"
43#include "HostCallReturnValue.h"
44#include "ICStats.h"
45#include "Interpreter.h"
46#include "IteratorOperations.h"
47#include "JIT.h"
48#include "JSArrayInlines.h"
49#include "JSCInlines.h"
50#include "JSCJSValue.h"
51#include "JSFixedArray.h"
52#include "JSGlobalObjectFunctions.h"
53#include "JSImmutableButterfly.h"
54#include "JSLexicalEnvironment.h"
55#include "JSPropertyNameEnumerator.h"
56#include "JSString.h"
57#include "JSWithScope.h"
58#include "LLIntCommon.h"
59#include "LLIntExceptions.h"
60#include "LowLevelInterpreter.h"
61#include "MathCommon.h"
62#include "ObjectConstructor.h"
63#include "OpcodeInlines.h"
64#include "ScopedArguments.h"
65#include "StructureRareDataInlines.h"
66#include "ThunkGenerators.h"
67#include "TypeProfilerLog.h"
68#include <wtf/StringPrintStream.h>
69#include <wtf/Variant.h>
70
71namespace JSC {
72
73#define BEGIN_NO_SET_PC() \
74 VM& vm = exec->vm(); \
75 NativeCallFrameTracer tracer(&vm, exec); \
76 auto throwScope = DECLARE_THROW_SCOPE(vm); \
77 UNUSED_PARAM(throwScope)
78
79#ifndef NDEBUG
80#define SET_PC_FOR_STUBS() do { \
81 exec->codeBlock()->bytecodeOffset(pc); \
82 exec->setCurrentVPC(pc); \
83 } while (false)
84#else
85#define SET_PC_FOR_STUBS() do { \
86 exec->setCurrentVPC(pc); \
87 } while (false)
88#endif
89
90#define RETURN_TO_THROW(exec, pc) pc = LLInt::returnToThrow(exec)
91
92#define BEGIN() \
93 BEGIN_NO_SET_PC(); \
94 SET_PC_FOR_STUBS()
95
96#define GET(operand) (exec->uncheckedR(operand.offset()))
97#define GET_C(operand) (exec->r(operand.offset()))
98
99#define RETURN_TWO(first, second) do { \
100 return encodeResult(first, second); \
101 } while (false)
102
103#define END_IMPL() RETURN_TWO(pc, exec)
104
105#define THROW(exceptionToThrow) do { \
106 throwException(exec, throwScope, exceptionToThrow); \
107 RETURN_TO_THROW(exec, pc); \
108 END_IMPL(); \
109 } while (false)
110
111#define CHECK_EXCEPTION() do { \
112 doExceptionFuzzingIfEnabled(exec, throwScope, "CommonSlowPaths", pc); \
113 if (UNLIKELY(throwScope.exception())) { \
114 RETURN_TO_THROW(exec, pc); \
115 END_IMPL(); \
116 } \
117 } while (false)
118
119#define END() do { \
120 CHECK_EXCEPTION(); \
121 END_IMPL(); \
122 } while (false)
123
124#define BRANCH(condition) do { \
125 bool bCondition = (condition); \
126 CHECK_EXCEPTION(); \
127 if (bCondition) \
128 pc = bytecode.m_targetLabel \
129 ? reinterpret_cast<const Instruction*>(reinterpret_cast<const uint8_t*>(pc) + bytecode.m_targetLabel) \
130 : exec->codeBlock()->outOfLineJumpTarget(pc); \
131 else \
132 pc = reinterpret_cast<const Instruction*>(reinterpret_cast<const uint8_t*>(pc) + pc->size()); \
133 END_IMPL(); \
134 } while (false)
135
136#define RETURN_WITH_PROFILING_CUSTOM(result__, value__, profilingAction__) do { \
137 JSValue returnValue__ = (value__); \
138 CHECK_EXCEPTION(); \
139 GET(result__) = returnValue__; \
140 profilingAction__; \
141 END_IMPL(); \
142 } while (false)
143
144#define RETURN_WITH_PROFILING(value__, profilingAction__) RETURN_WITH_PROFILING_CUSTOM(bytecode.m_dst, value__, profilingAction__)
145
146#define RETURN(value) \
147 RETURN_WITH_PROFILING(value, { })
148
149#define RETURN_PROFILED(value__) \
150 RETURN_WITH_PROFILING(value__, PROFILE_VALUE(returnValue__))
151
152#define PROFILE_VALUE(value) do { \
153 bytecode.metadata(exec).m_profile.m_buckets[0] = JSValue::encode(value); \
154 } while (false)
155
156#define CALL_END_IMPL(exec, callTarget, callTargetTag) \
157 RETURN_TWO(retagCodePtr((callTarget), callTargetTag, SlowPathPtrTag), (exec))
158
159#define CALL_CHECK_EXCEPTION(exec, pc) do { \
160 ExecState* cceExec = (exec); \
161 Instruction* ccePC = (pc); \
162 if (UNLIKELY(throwScope.exception())) \
163 CALL_END_IMPL(cceExec, LLInt::callToThrow(cceExec), ExceptionHandlerPtrTag); \
164 } while (false)
165
166static void throwArityCheckStackOverflowError(ExecState* exec, ThrowScope& scope)
167{
168 JSObject* error = createStackOverflowError(exec);
169 throwException(exec, scope, error);
170#if LLINT_TRACING
171 if (UNLIKELY(Options::traceLLIntSlowPath()))
172 dataLog("Throwing exception ", JSValue(scope.exception()), ".\n");
173#endif
174}
175
176SLOW_PATH_DECL(slow_path_call_arityCheck)
177{
178 BEGIN();
179 int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, vm, CodeForCall);
180 if (UNLIKELY(slotsToAdd < 0)) {
181 CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(exec, CodeForCall);
182 exec->convertToStackOverflowFrame(vm, codeBlock);
183 NativeCallFrameTracer tracer(&vm, exec);
184 ErrorHandlingScope errorScope(vm);
185 throwScope.release();
186 throwArityCheckStackOverflowError(exec, throwScope);
187 RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
188 }
189 RETURN_TWO(0, bitwise_cast<void*>(static_cast<uintptr_t>(slotsToAdd)));
190}
191
192SLOW_PATH_DECL(slow_path_construct_arityCheck)
193{
194 BEGIN();
195 int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, vm, CodeForConstruct);
196 if (UNLIKELY(slotsToAdd < 0)) {
197 CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(exec, CodeForConstruct);
198 exec->convertToStackOverflowFrame(vm, codeBlock);
199 NativeCallFrameTracer tracer(&vm, exec);
200 ErrorHandlingScope errorScope(vm);
201 throwArityCheckStackOverflowError(exec, throwScope);
202 RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
203 }
204 RETURN_TWO(0, bitwise_cast<void*>(static_cast<uintptr_t>(slotsToAdd)));
205}
206
207SLOW_PATH_DECL(slow_path_create_direct_arguments)
208{
209 BEGIN();
210 auto bytecode = pc->as<OpCreateDirectArguments>();
211 RETURN(DirectArguments::createByCopying(exec));
212}
213
214SLOW_PATH_DECL(slow_path_create_scoped_arguments)
215{
216 BEGIN();
217 auto bytecode = pc->as<OpCreateScopedArguments>();
218 JSLexicalEnvironment* scope = jsCast<JSLexicalEnvironment*>(GET(bytecode.m_scope).jsValue());
219 ScopedArgumentsTable* table = scope->symbolTable()->arguments();
220 RETURN(ScopedArguments::createByCopying(exec, table, scope));
221}
222
223SLOW_PATH_DECL(slow_path_create_cloned_arguments)
224{
225 BEGIN();
226 auto bytecode = pc->as<OpCreateClonedArguments>();
227 RETURN(ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned));
228}
229
230SLOW_PATH_DECL(slow_path_create_this)
231{
232 BEGIN();
233 auto bytecode = pc->as<OpCreateThis>();
234 JSObject* result;
235 JSObject* constructorAsObject = asObject(GET(bytecode.m_callee).jsValue());
236 if (constructorAsObject->type() == JSFunctionType && jsCast<JSFunction*>(constructorAsObject)->canUseAllocationProfile()) {
237 JSFunction* constructor = jsCast<JSFunction*>(constructorAsObject);
238 WriteBarrier<JSCell>& cachedCallee = bytecode.metadata(exec).m_cachedCallee;
239 if (!cachedCallee)
240 cachedCallee.set(vm, exec->codeBlock(), constructor);
241 else if (cachedCallee.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cachedCallee.get() != constructor)
242 cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
243
244 size_t inlineCapacity = bytecode.m_inlineCapacity;
245 ObjectAllocationProfileWithPrototype* allocationProfile = constructor->ensureRareDataAndAllocationProfile(exec, inlineCapacity)->objectAllocationProfile();
246 throwScope.releaseAssertNoException();
247 Structure* structure = allocationProfile->structure();
248 result = constructEmptyObject(exec, structure);
249 if (structure->hasPolyProto()) {
250 JSObject* prototype = allocationProfile->prototype();
251 ASSERT(prototype == constructor->prototypeForConstruction(vm, exec));
252 result->putDirect(vm, knownPolyProtoOffset, prototype);
253 prototype->didBecomePrototype();
254 ASSERT_WITH_MESSAGE(!hasIndexedProperties(result->indexingType()), "We rely on JSFinalObject not starting out with an indexing type otherwise we would potentially need to convert to slow put storage");
255 }
256 } else {
257 // http://ecma-international.org/ecma-262/6.0/#sec-ordinarycreatefromconstructor
258 JSValue proto = constructorAsObject->get(exec, vm.propertyNames->prototype);
259 CHECK_EXCEPTION();
260 if (proto.isObject())
261 result = constructEmptyObject(exec, asObject(proto));
262 else
263 result = constructEmptyObject(exec);
264 }
265 RETURN(result);
266}
267
268SLOW_PATH_DECL(slow_path_to_this)
269{
270 BEGIN();
271 auto bytecode = pc->as<OpToThis>();
272 auto& metadata = bytecode.metadata(exec);
273 JSValue v1 = GET(bytecode.m_srcDst).jsValue();
274 if (v1.isCell()) {
275 StructureID myStructureID = v1.asCell()->structureID();
276 StructureID otherStructureID = metadata.m_cachedStructureID;
277 if (myStructureID != otherStructureID) {
278 if (otherStructureID)
279 metadata.m_toThisStatus = ToThisConflicted;
280 metadata.m_cachedStructureID = myStructureID;
281 vm.heap.writeBarrier(exec->codeBlock(), vm.getStructure(myStructureID));
282 }
283 } else {
284 metadata.m_toThisStatus = ToThisConflicted;
285 metadata.m_cachedStructureID = 0;
286 }
287 // Note: We only need to do this value profiling here on the slow path. The fast path
288 // just returns the input to to_this if the structure check succeeds. If the structure
289 // check succeeds, doing value profiling here is equivalent to doing it with a potentially
290 // different object that still has the same structure on the fast path since it'll produce
291 // the same SpeculatedType. Therefore, we don't need to worry about value profiling on the
292 // fast path.
293 auto value = v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode);
294 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, value, PROFILE_VALUE(value));
295}
296
297SLOW_PATH_DECL(slow_path_throw_tdz_error)
298{
299 BEGIN();
300 THROW(createTDZError(exec));
301}
302
303SLOW_PATH_DECL(slow_path_check_tdz)
304{
305 BEGIN();
306 THROW(createTDZError(exec));
307}
308
309SLOW_PATH_DECL(slow_path_throw_strict_mode_readonly_property_write_error)
310{
311 BEGIN();
312 THROW(createTypeError(exec, ReadonlyPropertyWriteError));
313}
314
315SLOW_PATH_DECL(slow_path_not)
316{
317 BEGIN();
318 auto bytecode = pc->as<OpNot>();
319 RETURN(jsBoolean(!GET_C(bytecode.m_operand).jsValue().toBoolean(exec)));
320}
321
322SLOW_PATH_DECL(slow_path_eq)
323{
324 BEGIN();
325 auto bytecode = pc->as<OpEq>();
326 RETURN(jsBoolean(JSValue::equal(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
327}
328
329SLOW_PATH_DECL(slow_path_neq)
330{
331 BEGIN();
332 auto bytecode = pc->as<OpNeq>();
333 RETURN(jsBoolean(!JSValue::equal(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
334}
335
336SLOW_PATH_DECL(slow_path_stricteq)
337{
338 BEGIN();
339 auto bytecode = pc->as<OpStricteq>();
340 RETURN(jsBoolean(JSValue::strictEqual(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
341}
342
343SLOW_PATH_DECL(slow_path_nstricteq)
344{
345 BEGIN();
346 auto bytecode = pc->as<OpNstricteq>();
347 RETURN(jsBoolean(!JSValue::strictEqual(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
348}
349
350SLOW_PATH_DECL(slow_path_less)
351{
352 BEGIN();
353 auto bytecode = pc->as<OpLess>();
354 RETURN(jsBoolean(jsLess<true>(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
355}
356
357SLOW_PATH_DECL(slow_path_lesseq)
358{
359 BEGIN();
360 auto bytecode = pc->as<OpLesseq>();
361 RETURN(jsBoolean(jsLessEq<true>(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
362}
363
364SLOW_PATH_DECL(slow_path_greater)
365{
366 BEGIN();
367 auto bytecode = pc->as<OpGreater>();
368 RETURN(jsBoolean(jsLess<false>(exec, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue())));
369}
370
371SLOW_PATH_DECL(slow_path_greatereq)
372{
373 BEGIN();
374 auto bytecode = pc->as<OpGreatereq>();
375 RETURN(jsBoolean(jsLessEq<false>(exec, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue())));
376}
377
378SLOW_PATH_DECL(slow_path_inc)
379{
380 BEGIN();
381 auto bytecode = pc->as<OpInc>();
382 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, jsNumber(GET(bytecode.m_srcDst).jsValue().toNumber(exec) + 1), { });
383}
384
385SLOW_PATH_DECL(slow_path_dec)
386{
387 BEGIN();
388 auto bytecode = pc->as<OpDec>();
389 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, jsNumber(GET(bytecode.m_srcDst).jsValue().toNumber(exec) - 1), { });
390}
391
392SLOW_PATH_DECL(slow_path_to_string)
393{
394 BEGIN();
395 auto bytecode = pc->as<OpToString>();
396 RETURN(GET_C(bytecode.m_operand).jsValue().toString(exec));
397}
398
399#if ENABLE(JIT)
400static void updateArithProfileForUnaryArithOp(OpNegate::Metadata& metadata, JSValue result, JSValue operand)
401{
402 ArithProfile& profile = metadata.m_arithProfile;
403 profile.observeLHS(operand);
404 ASSERT(result.isNumber() || result.isBigInt());
405 if (result.isNumber()) {
406 if (!result.isInt32()) {
407 if (operand.isInt32())
408 profile.setObservedInt32Overflow();
409
410 double doubleVal = result.asNumber();
411 if (!doubleVal && std::signbit(doubleVal))
412 profile.setObservedNegZeroDouble();
413 else {
414 profile.setObservedNonNegZeroDouble();
415
416 // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
417 // Therefore, we will get a false positive if the result is that value. This is intentionally
418 // done to simplify the checking algorithm.
419 static const int64_t int52OverflowPoint = (1ll << 51);
420 int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
421 if (int64Val >= int52OverflowPoint)
422 profile.setObservedInt52Overflow();
423 }
424 }
425 } else if (result.isBigInt())
426 profile.setObservedBigInt();
427 else
428 profile.setObservedNonNumeric();
429}
430#else
431static void updateArithProfileForUnaryArithOp(OpNegate::Metadata&, JSValue, JSValue) { }
432#endif
433
434SLOW_PATH_DECL(slow_path_negate)
435{
436 BEGIN();
437 auto bytecode = pc->as<OpNegate>();
438 auto& metadata = bytecode.metadata(exec);
439 JSValue operand = GET_C(bytecode.m_operand).jsValue();
440 JSValue primValue = operand.toPrimitive(exec, PreferNumber);
441 CHECK_EXCEPTION();
442
443 if (primValue.isBigInt()) {
444 JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
445 RETURN_WITH_PROFILING(result, {
446 updateArithProfileForUnaryArithOp(metadata, result, operand);
447 });
448 }
449
450 JSValue result = jsNumber(-primValue.toNumber(exec));
451 CHECK_EXCEPTION();
452 RETURN_WITH_PROFILING(result, {
453 updateArithProfileForUnaryArithOp(metadata, result, operand);
454 });
455}
456
457#if ENABLE(DFG_JIT)
458static void updateArithProfileForBinaryArithOp(ExecState* exec, const Instruction* pc, JSValue result, JSValue left, JSValue right)
459{
460 CodeBlock* codeBlock = exec->codeBlock();
461 ArithProfile& profile = *codeBlock->arithProfileForPC(pc);
462
463 if (result.isNumber()) {
464 if (!result.isInt32()) {
465 if (left.isInt32() && right.isInt32())
466 profile.setObservedInt32Overflow();
467
468 double doubleVal = result.asNumber();
469 if (!doubleVal && std::signbit(doubleVal))
470 profile.setObservedNegZeroDouble();
471 else {
472 profile.setObservedNonNegZeroDouble();
473
474 // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
475 // Therefore, we will get a false positive if the result is that value. This is intentionally
476 // done to simplify the checking algorithm.
477 static const int64_t int52OverflowPoint = (1ll << 51);
478 int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
479 if (int64Val >= int52OverflowPoint)
480 profile.setObservedInt52Overflow();
481 }
482 }
483 } else if (result.isBigInt())
484 profile.setObservedBigInt();
485 else
486 profile.setObservedNonNumeric();
487}
488#else
489static void updateArithProfileForBinaryArithOp(ExecState*, const Instruction*, JSValue, JSValue, JSValue) { }
490#endif
491
492SLOW_PATH_DECL(slow_path_to_number)
493{
494 BEGIN();
495 auto bytecode = pc->as<OpToNumber>();
496 JSValue argument = GET_C(bytecode.m_operand).jsValue();
497 JSValue result = jsNumber(argument.toNumber(exec));
498 RETURN_PROFILED(result);
499}
500
501SLOW_PATH_DECL(slow_path_to_object)
502{
503 BEGIN();
504 auto bytecode = pc->as<OpToObject>();
505 JSValue argument = GET_C(bytecode.m_operand).jsValue();
506 if (UNLIKELY(argument.isUndefinedOrNull())) {
507 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_message);
508 if (!ident.isEmpty())
509 THROW(createTypeError(exec, ident.impl()));
510 }
511 JSObject* result = argument.toObject(exec);
512 RETURN_PROFILED(result);
513}
514
515SLOW_PATH_DECL(slow_path_add)
516{
517 BEGIN();
518 auto bytecode = pc->as<OpAdd>();
519 JSValue v1 = GET_C(bytecode.m_lhs).jsValue();
520 JSValue v2 = GET_C(bytecode.m_rhs).jsValue();
521
522 ArithProfile& arithProfile = *exec->codeBlock()->arithProfileForPC(pc);
523 arithProfile.observeLHSAndRHS(v1, v2);
524
525 JSValue result = jsAdd(exec, v1, v2);
526
527 RETURN_WITH_PROFILING(result, {
528 updateArithProfileForBinaryArithOp(exec, pc, result, v1, v2);
529 });
530}
531
532// The following arithmetic and bitwise operations need to be sure to run
533// toNumber() on their operands in order. (A call to toNumber() is idempotent
534// if an exception is already set on the ExecState.)
535
536SLOW_PATH_DECL(slow_path_mul)
537{
538 BEGIN();
539 auto bytecode = pc->as<OpMul>();
540 JSValue left = GET_C(bytecode.m_lhs).jsValue();
541 JSValue right = GET_C(bytecode.m_rhs).jsValue();
542 JSValue result = jsMul(exec, left, right);
543 CHECK_EXCEPTION();
544 RETURN_WITH_PROFILING(result, {
545 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
546 });
547}
548
549SLOW_PATH_DECL(slow_path_sub)
550{
551 BEGIN();
552 auto bytecode = pc->as<OpSub>();
553 JSValue left = GET_C(bytecode.m_lhs).jsValue();
554 JSValue right = GET_C(bytecode.m_rhs).jsValue();
555 auto leftNumeric = left.toNumeric(exec);
556 CHECK_EXCEPTION();
557 auto rightNumeric = right.toNumeric(exec);
558 CHECK_EXCEPTION();
559
560 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
561 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
562 JSBigInt* result = JSBigInt::sub(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
563 CHECK_EXCEPTION();
564 RETURN_WITH_PROFILING(result, {
565 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
566 });
567 }
568
569 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in subtraction."));
570 }
571
572 JSValue result = jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric));
573 RETURN_WITH_PROFILING(result, {
574 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
575 });
576}
577
578SLOW_PATH_DECL(slow_path_div)
579{
580 BEGIN();
581 auto bytecode = pc->as<OpDiv>();
582 JSValue left = GET_C(bytecode.m_lhs).jsValue();
583 JSValue right = GET_C(bytecode.m_rhs).jsValue();
584 auto leftNumeric = left.toNumeric(exec);
585 CHECK_EXCEPTION();
586 auto rightNumeric = right.toNumeric(exec);
587 CHECK_EXCEPTION();
588
589 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
590 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
591 JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
592 CHECK_EXCEPTION();
593 RETURN_WITH_PROFILING(result, {
594 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
595 });
596 }
597
598 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in division."));
599 }
600
601 double a = WTF::get<double>(leftNumeric);
602 double b = WTF::get<double>(rightNumeric);
603 JSValue result = jsNumber(a / b);
604 RETURN_WITH_PROFILING(result, {
605 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
606 });
607}
608
609SLOW_PATH_DECL(slow_path_mod)
610{
611 BEGIN();
612 auto bytecode = pc->as<OpMod>();
613 JSValue left = GET_C(bytecode.m_lhs).jsValue();
614 JSValue right = GET_C(bytecode.m_rhs).jsValue();
615 auto leftNumeric = left.toNumeric(exec);
616 CHECK_EXCEPTION();
617 auto rightNumeric = right.toNumeric(exec);
618 CHECK_EXCEPTION();
619
620 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
621 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
622 JSBigInt* result = JSBigInt::remainder(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
623 CHECK_EXCEPTION();
624 RETURN(result);
625 }
626
627 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in remainder operation."));
628 }
629
630 double a = WTF::get<double>(leftNumeric);
631 double b = WTF::get<double>(rightNumeric);
632 RETURN(jsNumber(jsMod(a, b)));
633}
634
635SLOW_PATH_DECL(slow_path_pow)
636{
637 BEGIN();
638 auto bytecode = pc->as<OpPow>();
639 JSValue left = GET_C(bytecode.m_lhs).jsValue();
640 JSValue right = GET_C(bytecode.m_rhs).jsValue();
641 auto leftNumeric = left.toNumeric(exec);
642 CHECK_EXCEPTION();
643 auto rightNumeric = right.toNumeric(exec);
644 CHECK_EXCEPTION();
645
646 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
647 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
648 JSBigInt* result = JSBigInt::exponentiate(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
649 CHECK_EXCEPTION();
650 RETURN(result);
651 }
652
653 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in exponentiation operation."));
654 }
655
656 double a = WTF::get<double>(leftNumeric);
657 double b = WTF::get<double>(rightNumeric);
658
659 RETURN(jsNumber(operationMathPow(a, b)));
660}
661
662SLOW_PATH_DECL(slow_path_lshift)
663{
664 BEGIN();
665 auto bytecode = pc->as<OpLshift>();
666 JSValue left = GET_C(bytecode.m_lhs).jsValue();
667 JSValue right = GET_C(bytecode.m_rhs).jsValue();
668 auto leftNumeric = left.toBigIntOrInt32(exec);
669 CHECK_EXCEPTION();
670 auto rightNumeric = right.toBigIntOrInt32(exec);
671 CHECK_EXCEPTION();
672
673 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
674 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
675 JSBigInt* result = JSBigInt::leftShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
676 CHECK_EXCEPTION();
677 RETURN(result);
678 }
679
680 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in left shift operation."));
681 }
682
683 RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) << (WTF::get<int32_t>(rightNumeric) & 31)));
684}
685
686SLOW_PATH_DECL(slow_path_rshift)
687{
688 BEGIN();
689 auto bytecode = pc->as<OpRshift>();
690 JSValue left = GET_C(bytecode.m_lhs).jsValue();
691 JSValue right = GET_C(bytecode.m_rhs).jsValue();
692 auto leftNumeric = left.toBigIntOrInt32(exec);
693 CHECK_EXCEPTION();
694 auto rightNumeric = right.toBigIntOrInt32(exec);
695 CHECK_EXCEPTION();
696
697 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
698 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
699 JSBigInt* result = JSBigInt::signedRightShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
700 CHECK_EXCEPTION();
701 RETURN(result);
702 }
703
704 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in signed right shift operation."));
705 }
706
707 RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31)));
708}
709
710SLOW_PATH_DECL(slow_path_urshift)
711{
712 BEGIN();
713 auto bytecode = pc->as<OpUrshift>();
714 uint32_t a = GET_C(bytecode.m_lhs).jsValue().toUInt32(exec);
715 if (UNLIKELY(throwScope.exception()))
716 RETURN(JSValue());
717 uint32_t b = GET_C(bytecode.m_rhs).jsValue().toUInt32(exec);
718 RETURN(jsNumber(static_cast<int32_t>(a >> (b & 31))));
719}
720
721SLOW_PATH_DECL(slow_path_unsigned)
722{
723 BEGIN();
724 auto bytecode = pc->as<OpUnsigned>();
725 uint32_t a = GET_C(bytecode.m_operand).jsValue().toUInt32(exec);
726 RETURN(jsNumber(a));
727}
728
729SLOW_PATH_DECL(slow_path_bitnot)
730{
731 BEGIN();
732 auto bytecode = pc->as<OpBitnot>();
733 auto operandNumeric = GET_C(bytecode.m_operand).jsValue().toBigIntOrInt32(exec);
734 CHECK_EXCEPTION();
735
736 if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) {
737 JSBigInt* result = JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric));
738 CHECK_EXCEPTION();
739 RETURN_PROFILED(result);
740 }
741
742 RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric)));
743}
744
745SLOW_PATH_DECL(slow_path_bitand)
746{
747 BEGIN();
748 auto bytecode = pc->as<OpBitand>();
749 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
750 CHECK_EXCEPTION();
751 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
752 CHECK_EXCEPTION();
753 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
754 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
755 JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
756 CHECK_EXCEPTION();
757 RETURN_PROFILED(result);
758 }
759
760 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'and' operation."));
761 }
762
763 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric)));
764}
765
766SLOW_PATH_DECL(slow_path_bitor)
767{
768 BEGIN();
769 auto bytecode = pc->as<OpBitor>();
770 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
771 CHECK_EXCEPTION();
772 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
773 CHECK_EXCEPTION();
774 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
775 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
776 JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
777 CHECK_EXCEPTION();
778 RETURN_PROFILED(result);
779 }
780
781 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'or' operation."));
782 }
783
784 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric)));
785}
786
787SLOW_PATH_DECL(slow_path_bitxor)
788{
789 BEGIN();
790 auto bytecode = pc->as<OpBitxor>();
791 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
792 CHECK_EXCEPTION();
793 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
794 CHECK_EXCEPTION();
795 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
796 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
797 JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
798 CHECK_EXCEPTION();
799 RETURN_PROFILED(result);
800 }
801
802 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'xor' operation."));
803 }
804
805 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
806}
807
808SLOW_PATH_DECL(slow_path_typeof)
809{
810 BEGIN();
811 auto bytecode = pc->as<OpTypeof>();
812 RETURN(jsTypeStringForValue(exec, GET_C(bytecode.m_value).jsValue()));
813}
814
815SLOW_PATH_DECL(slow_path_is_object_or_null)
816{
817 BEGIN();
818 auto bytecode = pc->as<OpIsObjectOrNull>();
819 RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, GET_C(bytecode.m_operand).jsValue())));
820}
821
822SLOW_PATH_DECL(slow_path_is_function)
823{
824 BEGIN();
825 auto bytecode = pc->as<OpIsFunction>();
826 RETURN(jsBoolean(GET_C(bytecode.m_operand).jsValue().isFunction(vm)));
827}
828
829SLOW_PATH_DECL(slow_path_in_by_val)
830{
831 BEGIN();
832 auto bytecode = pc->as<OpInByVal>();
833 auto& metadata = bytecode.metadata(exec);
834 RETURN(jsBoolean(CommonSlowPaths::opInByVal(exec, GET_C(bytecode.m_base).jsValue(), GET_C(bytecode.m_property).jsValue(), &metadata.m_arrayProfile)));
835}
836
837SLOW_PATH_DECL(slow_path_in_by_id)
838{
839 BEGIN();
840
841 auto bytecode = pc->as<OpInById>();
842 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
843 if (!baseValue.isObject())
844 THROW(createInvalidInParameterError(exec, baseValue));
845
846 RETURN(jsBoolean(asObject(baseValue)->hasProperty(exec, exec->codeBlock()->identifier(bytecode.m_property))));
847}
848
849SLOW_PATH_DECL(slow_path_del_by_val)
850{
851 BEGIN();
852 auto bytecode = pc->as<OpDelByVal>();
853 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
854 JSObject* baseObject = baseValue.toObject(exec);
855 CHECK_EXCEPTION();
856
857 JSValue subscript = GET_C(bytecode.m_property).jsValue();
858
859 bool couldDelete;
860
861 uint32_t i;
862 if (subscript.getUInt32(i))
863 couldDelete = baseObject->methodTable(vm)->deletePropertyByIndex(baseObject, exec, i);
864 else {
865 CHECK_EXCEPTION();
866 auto property = subscript.toPropertyKey(exec);
867 CHECK_EXCEPTION();
868 couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, exec, property);
869 }
870
871 if (!couldDelete && exec->codeBlock()->isStrictMode())
872 THROW(createTypeError(exec, UnableToDeletePropertyError));
873
874 RETURN(jsBoolean(couldDelete));
875}
876
877SLOW_PATH_DECL(slow_path_strcat)
878{
879 BEGIN();
880 auto bytecode = pc->as<OpStrcat>();
881 RETURN(jsStringFromRegisterArray(exec, &GET(bytecode.m_src), bytecode.m_count));
882}
883
884SLOW_PATH_DECL(slow_path_to_primitive)
885{
886 BEGIN();
887 auto bytecode = pc->as<OpToPrimitive>();
888 RETURN(GET_C(bytecode.m_src).jsValue().toPrimitive(exec));
889}
890
891SLOW_PATH_DECL(slow_path_enter)
892{
893 BEGIN();
894 CodeBlock* codeBlock = exec->codeBlock();
895 Heap::heap(codeBlock)->writeBarrier(codeBlock);
896 END();
897}
898
899SLOW_PATH_DECL(slow_path_get_enumerable_length)
900{
901 BEGIN();
902 auto bytecode = pc->as<OpGetEnumerableLength>();
903 JSValue enumeratorValue = GET(bytecode.m_base).jsValue();
904 if (enumeratorValue.isUndefinedOrNull())
905 RETURN(jsNumber(0));
906
907 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell());
908
909 RETURN(jsNumber(enumerator->indexedLength()));
910}
911
912SLOW_PATH_DECL(slow_path_has_indexed_property)
913{
914 BEGIN();
915 auto bytecode = pc->as<OpHasIndexedProperty>();
916 auto& metadata = bytecode.metadata(exec);
917 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
918 CHECK_EXCEPTION();
919 JSValue property = GET(bytecode.m_property).jsValue();
920 metadata.m_arrayProfile.observeStructure(base->structure(vm));
921 ASSERT(property.isUInt32AsAnyInt());
922 RETURN(jsBoolean(base->hasPropertyGeneric(exec, property.asUInt32AsAnyInt(), PropertySlot::InternalMethodType::GetOwnProperty)));
923}
924
925SLOW_PATH_DECL(slow_path_has_structure_property)
926{
927 BEGIN();
928 auto bytecode = pc->as<OpHasStructureProperty>();
929 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
930 CHECK_EXCEPTION();
931 JSValue property = GET(bytecode.m_property).jsValue();
932 ASSERT(property.isString());
933 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
934 if (base->structure(vm)->id() == enumerator->cachedStructureID())
935 RETURN(jsBoolean(true));
936 JSString* string = asString(property);
937 auto propertyName = string->toIdentifier(exec);
938 CHECK_EXCEPTION();
939 RETURN(jsBoolean(base->hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::GetOwnProperty)));
940}
941
942SLOW_PATH_DECL(slow_path_has_generic_property)
943{
944 BEGIN();
945 auto bytecode = pc->as<OpHasGenericProperty>();
946 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
947 CHECK_EXCEPTION();
948 JSValue property = GET(bytecode.m_property).jsValue();
949 ASSERT(property.isString());
950 JSString* string = asString(property);
951 auto propertyName = string->toIdentifier(exec);
952 CHECK_EXCEPTION();
953 RETURN(jsBoolean(base->hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::GetOwnProperty)));
954}
955
956SLOW_PATH_DECL(slow_path_get_direct_pname)
957{
958 BEGIN();
959 auto bytecode = pc->as<OpGetDirectPname>();
960 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
961 JSValue property = GET(bytecode.m_property).jsValue();
962 ASSERT(property.isString());
963 JSString* string = asString(property);
964 auto propertyName = string->toIdentifier(exec);
965 CHECK_EXCEPTION();
966 RETURN(baseValue.get(exec, propertyName));
967}
968
969SLOW_PATH_DECL(slow_path_get_property_enumerator)
970{
971 BEGIN();
972 auto bytecode = pc->as<OpGetPropertyEnumerator>();
973 JSValue baseValue = GET(bytecode.m_base).jsValue();
974 if (baseValue.isUndefinedOrNull())
975 RETURN(JSPropertyNameEnumerator::create(vm));
976
977 JSObject* base = baseValue.toObject(exec);
978 CHECK_EXCEPTION();
979
980 RETURN(propertyNameEnumerator(exec, base));
981}
982
983SLOW_PATH_DECL(slow_path_enumerator_structure_pname)
984{
985 BEGIN();
986 auto bytecode = pc->as<OpEnumeratorStructurePname>();
987 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
988 uint32_t index = GET(bytecode.m_index).jsValue().asUInt32();
989
990 JSString* propertyName = nullptr;
991 if (index < enumerator->endStructurePropertyIndex())
992 propertyName = enumerator->propertyNameAtIndex(index);
993 RETURN(propertyName ? propertyName : jsNull());
994}
995
996SLOW_PATH_DECL(slow_path_enumerator_generic_pname)
997{
998 BEGIN();
999 auto bytecode = pc->as<OpEnumeratorGenericPname>();
1000 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
1001 uint32_t index = GET(bytecode.m_index).jsValue().asUInt32();
1002
1003 JSString* propertyName = nullptr;
1004 if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex())
1005 propertyName = enumerator->propertyNameAtIndex(index);
1006 RETURN(propertyName ? propertyName : jsNull());
1007}
1008
1009SLOW_PATH_DECL(slow_path_to_index_string)
1010{
1011 BEGIN();
1012 auto bytecode = pc->as<OpToIndexString>();
1013 JSValue indexValue = GET(bytecode.m_index).jsValue();
1014 ASSERT(indexValue.isUInt32AsAnyInt());
1015 RETURN(jsString(exec, Identifier::from(exec, indexValue.asUInt32AsAnyInt()).string()));
1016}
1017
1018SLOW_PATH_DECL(slow_path_profile_type_clear_log)
1019{
1020 BEGIN();
1021 vm.typeProfilerLog()->processLogEntries(vm, "LLInt log full."_s);
1022 END();
1023}
1024
1025SLOW_PATH_DECL(slow_path_unreachable)
1026{
1027 BEGIN();
1028 UNREACHABLE_FOR_PLATFORM();
1029 END();
1030}
1031
1032SLOW_PATH_DECL(slow_path_create_lexical_environment)
1033{
1034 BEGIN();
1035 auto bytecode = pc->as<OpCreateLexicalEnvironment>();
1036 int scopeReg = bytecode.m_scope.offset();
1037 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1038 SymbolTable* symbolTable = jsCast<SymbolTable*>(GET_C(bytecode.m_symbolTable).jsValue());
1039 JSValue initialValue = GET_C(bytecode.m_initialValue).jsValue();
1040 ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
1041 JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue);
1042 RETURN(newScope);
1043}
1044
1045SLOW_PATH_DECL(slow_path_push_with_scope)
1046{
1047 BEGIN();
1048 auto bytecode = pc->as<OpPushWithScope>();
1049 JSObject* newScope = GET_C(bytecode.m_newScope).jsValue().toObject(exec);
1050 CHECK_EXCEPTION();
1051
1052 int scopeReg = bytecode.m_currentScope.offset();
1053 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1054 RETURN(JSWithScope::create(vm, exec->lexicalGlobalObject(), currentScope, newScope));
1055}
1056
1057SLOW_PATH_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval)
1058{
1059 BEGIN();
1060 auto bytecode = pc->as<OpResolveScopeForHoistingFuncDeclInEval>();
1061 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1062 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1063 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(exec, scope, ident);
1064
1065 CHECK_EXCEPTION();
1066
1067 RETURN(resolvedScope);
1068}
1069
1070SLOW_PATH_DECL(slow_path_resolve_scope)
1071{
1072 BEGIN();
1073 auto bytecode = pc->as<OpResolveScope>();
1074 auto& metadata = bytecode.metadata(exec);
1075 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_var);
1076 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1077 JSObject* resolvedScope = JSScope::resolve(exec, scope, ident);
1078 // Proxy can throw an error here, e.g. Proxy in with statement's @unscopables.
1079 CHECK_EXCEPTION();
1080
1081 ResolveType resolveType = metadata.m_resolveType;
1082
1083 // ModuleVar does not keep the scope register value alive in DFG.
1084 ASSERT(resolveType != ModuleVar);
1085
1086 switch (resolveType) {
1087 case GlobalProperty:
1088 case GlobalPropertyWithVarInjectionChecks:
1089 case UnresolvedProperty:
1090 case UnresolvedPropertyWithVarInjectionChecks: {
1091 if (resolvedScope->isGlobalObject()) {
1092 JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(resolvedScope);
1093 bool hasProperty = globalObject->hasProperty(exec, ident);
1094 CHECK_EXCEPTION();
1095 if (hasProperty) {
1096 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1097 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalPropertyWithVarInjectionChecks : GlobalProperty;
1098 metadata.m_globalObject = globalObject;
1099 metadata.m_globalLexicalBindingEpoch = globalObject->globalLexicalBindingEpoch();
1100 }
1101 } else if (resolvedScope->isGlobalLexicalEnvironment()) {
1102 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope);
1103 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1104 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
1105 metadata.m_globalLexicalEnvironment = globalLexicalEnvironment;
1106 }
1107 break;
1108 }
1109 default:
1110 break;
1111 }
1112
1113 RETURN(resolvedScope);
1114}
1115
1116SLOW_PATH_DECL(slow_path_create_rest)
1117{
1118 BEGIN();
1119 auto bytecode = pc->as<OpCreateRest>();
1120 unsigned arraySize = GET_C(bytecode.m_arraySize).jsValue().asUInt32();
1121 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1122 Structure* structure = globalObject->restParameterStructure();
1123 unsigned numParamsToSkip = bytecode.m_numParametersToSkip;
1124 JSValue* argumentsToCopyRegion = exec->addressOfArgumentsStart() + numParamsToSkip;
1125 RETURN(constructArray(exec, structure, argumentsToCopyRegion, arraySize));
1126}
1127
1128SLOW_PATH_DECL(slow_path_get_by_id_with_this)
1129{
1130 BEGIN();
1131 auto bytecode = pc->as<OpGetByIdWithThis>();
1132 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1133 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1134 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1135 PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
1136 JSValue result = baseValue.get(exec, ident, slot);
1137 RETURN_PROFILED(result);
1138}
1139
1140SLOW_PATH_DECL(slow_path_get_by_val_with_this)
1141{
1142 BEGIN();
1143
1144 auto bytecode = pc->as<OpGetByValWithThis>();
1145 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1146 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1147 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1148
1149 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1150 Structure& structure = *baseValue.asCell()->structure(vm);
1151 if (JSCell::canUseFastGetOwnProperty(structure)) {
1152 RefPtr<AtomStringImpl> existingAtomString = asString(subscript)->toExistingAtomString(exec);
1153 CHECK_EXCEPTION();
1154 if (existingAtomString) {
1155 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomString.get()))
1156 RETURN_PROFILED(result);
1157 }
1158 }
1159 }
1160
1161 PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get);
1162 if (subscript.isUInt32()) {
1163 uint32_t i = subscript.asUInt32();
1164 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1165 RETURN_PROFILED(asString(baseValue)->getIndex(exec, i));
1166
1167 RETURN_PROFILED(baseValue.get(exec, i, slot));
1168 }
1169
1170 baseValue.requireObjectCoercible(exec);
1171 CHECK_EXCEPTION();
1172 auto property = subscript.toPropertyKey(exec);
1173 CHECK_EXCEPTION();
1174 RETURN_PROFILED(baseValue.get(exec, property, slot));
1175}
1176
1177SLOW_PATH_DECL(slow_path_put_by_id_with_this)
1178{
1179 BEGIN();
1180 auto bytecode = pc->as<OpPutByIdWithThis>();
1181 CodeBlock* codeBlock = exec->codeBlock();
1182 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
1183 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1184 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1185 JSValue putValue = GET_C(bytecode.m_value).jsValue();
1186 PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext());
1187 baseValue.putInline(exec, ident, putValue, slot);
1188 END();
1189}
1190
1191SLOW_PATH_DECL(slow_path_put_by_val_with_this)
1192{
1193 BEGIN();
1194 auto bytecode = pc->as<OpPutByValWithThis>();
1195 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1196 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1197 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1198 JSValue value = GET_C(bytecode.m_value).jsValue();
1199
1200 auto property = subscript.toPropertyKey(exec);
1201 CHECK_EXCEPTION();
1202 PutPropertySlot slot(thisValue, exec->codeBlock()->isStrictMode());
1203 baseValue.put(exec, property, value, slot);
1204 END();
1205}
1206
1207SLOW_PATH_DECL(slow_path_define_data_property)
1208{
1209 BEGIN();
1210 auto bytecode = pc->as<OpDefineDataProperty>();
1211 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1212 JSValue property = GET_C(bytecode.m_property).jsValue();
1213 JSValue value = GET_C(bytecode.m_value).jsValue();
1214 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1215 ASSERT(attributes.isInt32());
1216
1217 auto propertyName = property.toPropertyKey(exec);
1218 CHECK_EXCEPTION();
1219 PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes.asInt32()));
1220 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1221 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1222 END();
1223}
1224
1225SLOW_PATH_DECL(slow_path_define_accessor_property)
1226{
1227 BEGIN();
1228 auto bytecode = pc->as<OpDefineAccessorProperty>();
1229 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1230 JSValue property = GET_C(bytecode.m_property).jsValue();
1231 JSValue getter = GET_C(bytecode.m_getter).jsValue();
1232 JSValue setter = GET_C(bytecode.m_setter).jsValue();
1233 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1234 ASSERT(attributes.isInt32());
1235
1236 auto propertyName = property.toPropertyKey(exec);
1237 CHECK_EXCEPTION();
1238 PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes.asInt32()));
1239 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1240 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1241 END();
1242}
1243
1244SLOW_PATH_DECL(slow_path_throw_static_error)
1245{
1246 BEGIN();
1247 auto bytecode = pc->as<OpThrowStaticError>();
1248 JSValue errorMessageValue = GET_C(bytecode.m_message).jsValue();
1249 RELEASE_ASSERT(errorMessageValue.isString());
1250 String errorMessage = asString(errorMessageValue)->value(exec);
1251 ErrorType errorType = bytecode.m_errorType;
1252 THROW(createError(exec, errorType, errorMessage));
1253}
1254
1255SLOW_PATH_DECL(slow_path_new_array_with_spread)
1256{
1257 BEGIN();
1258 auto bytecode = pc->as<OpNewArrayWithSpread>();
1259 int numItems = bytecode.m_argc;
1260 ASSERT(numItems >= 0);
1261 const BitVector& bitVector = exec->codeBlock()->unlinkedCodeBlock()->bitVector(bytecode.m_bitVector);
1262
1263 JSValue* values = bitwise_cast<JSValue*>(&GET(bytecode.m_argv));
1264
1265 Checked<unsigned, RecordOverflow> checkedArraySize = 0;
1266 for (int i = 0; i < numItems; i++) {
1267 if (bitVector.get(i)) {
1268 JSValue value = values[-i];
1269 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1270 checkedArraySize += array->size();
1271 } else
1272 checkedArraySize += 1;
1273 }
1274 if (UNLIKELY(checkedArraySize.hasOverflowed()))
1275 THROW(createOutOfMemoryError(exec));
1276
1277 unsigned arraySize = checkedArraySize.unsafeGet();
1278 if (UNLIKELY(arraySize >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH))
1279 THROW(createOutOfMemoryError(exec));
1280
1281 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1282 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
1283
1284 JSArray* result = JSArray::tryCreate(vm, structure, arraySize);
1285 if (UNLIKELY(!result))
1286 THROW(createOutOfMemoryError(exec));
1287 CHECK_EXCEPTION();
1288
1289 unsigned index = 0;
1290 for (int i = 0; i < numItems; i++) {
1291 JSValue value = values[-i];
1292 if (bitVector.get(i)) {
1293 // We are spreading.
1294 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1295 for (unsigned i = 0; i < array->size(); i++) {
1296 RELEASE_ASSERT(array->get(i));
1297 result->putDirectIndex(exec, index, array->get(i));
1298 CHECK_EXCEPTION();
1299 ++index;
1300 }
1301 } else {
1302 // We are not spreading.
1303 result->putDirectIndex(exec, index, value);
1304 CHECK_EXCEPTION();
1305 ++index;
1306 }
1307 }
1308
1309 RETURN(result);
1310}
1311
1312SLOW_PATH_DECL(slow_path_new_array_buffer)
1313{
1314 BEGIN();
1315 auto bytecode = pc->as<OpNewArrayBuffer>();
1316 ASSERT(exec->codeBlock()->isConstantRegisterIndex(bytecode.m_immutableButterfly.offset()));
1317 JSImmutableButterfly* immutableButterfly = bitwise_cast<JSImmutableButterfly*>(GET_C(bytecode.m_immutableButterfly).jsValue().asCell());
1318 auto& profile = bytecode.metadata(exec).m_arrayAllocationProfile;
1319
1320 IndexingType indexingMode = profile.selectIndexingType();
1321 Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(indexingMode);
1322 ASSERT(isCopyOnWrite(indexingMode));
1323 ASSERT(!structure->outOfLineCapacity());
1324
1325 if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) {
1326 auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length());
1327 for (unsigned i = 0; i < immutableButterfly->length(); ++i)
1328 newButterfly->setIndex(vm, i, immutableButterfly->get(i));
1329 immutableButterfly = newButterfly;
1330 CodeBlock* codeBlock = exec->codeBlock();
1331
1332 // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline.
1333 // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from
1334 // a compilation thread.
1335 WTF::storeStoreFence();
1336 codeBlock->constantRegister(bytecode.m_immutableButterfly.offset()).set(vm, codeBlock, immutableButterfly);
1337 WTF::storeStoreFence();
1338 }
1339
1340 JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, immutableButterfly);
1341 ASSERT(isCopyOnWrite(result->indexingMode()) || exec->lexicalGlobalObject()->isHavingABadTime());
1342 ArrayAllocationProfile::updateLastAllocationFor(&profile, result);
1343 RETURN(result);
1344}
1345
1346SLOW_PATH_DECL(slow_path_spread)
1347{
1348 BEGIN();
1349
1350 auto bytecode = pc->as<OpSpread>();
1351 JSValue iterable = GET_C(bytecode.m_argument).jsValue();
1352
1353 if (iterable.isCell() && isJSArray(iterable.asCell())) {
1354 JSArray* array = jsCast<JSArray*>(iterable);
1355 if (array->isIteratorProtocolFastAndNonObservable()) {
1356 // JSFixedArray::createFromArray does not consult the prototype chain,
1357 // so we must be sure that not consulting the prototype chain would
1358 // produce the same value during iteration.
1359 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1360 }
1361 }
1362
1363 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1364
1365 JSArray* array;
1366 {
1367 JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
1368 CallData callData;
1369 CallType callType = JSC::getCallData(vm, iterationFunction, callData);
1370 ASSERT(callType != CallType::None);
1371
1372 MarkedArgumentBuffer arguments;
1373 arguments.append(iterable);
1374 ASSERT(!arguments.hasOverflowed());
1375 JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
1376 CHECK_EXCEPTION();
1377 array = jsCast<JSArray*>(arrayResult);
1378 }
1379
1380 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1381}
1382
1383} // namespace JSC
1384