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 ObjectAllocationProfile* 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 Structure* myStructure = v1.asCell()->structure(vm);
276 Structure* otherStructure = metadata.m_cachedStructure.get();
277 if (myStructure != otherStructure) {
278 if (otherStructure)
279 metadata.m_toThisStatus = ToThisConflicted;
280 metadata.m_cachedStructure.set(vm, exec->codeBlock(), myStructure);
281 }
282 } else {
283 metadata.m_toThisStatus = ToThisConflicted;
284 metadata.m_cachedStructure.clear();
285 }
286 // Note: We only need to do this value profiling here on the slow path. The fast path
287 // just returns the input to to_this if the structure check succeeds. If the structure
288 // check succeeds, doing value profiling here is equivalent to doing it with a potentially
289 // different object that still has the same structure on the fast path since it'll produce
290 // the same SpeculatedType. Therefore, we don't need to worry about value profiling on the
291 // fast path.
292 auto value = v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode);
293 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, value, PROFILE_VALUE(value));
294}
295
296SLOW_PATH_DECL(slow_path_throw_tdz_error)
297{
298 BEGIN();
299 THROW(createTDZError(exec));
300}
301
302SLOW_PATH_DECL(slow_path_check_tdz)
303{
304 BEGIN();
305 THROW(createTDZError(exec));
306}
307
308SLOW_PATH_DECL(slow_path_throw_strict_mode_readonly_property_write_error)
309{
310 BEGIN();
311 THROW(createTypeError(exec, ReadonlyPropertyWriteError));
312}
313
314SLOW_PATH_DECL(slow_path_not)
315{
316 BEGIN();
317 auto bytecode = pc->as<OpNot>();
318 RETURN(jsBoolean(!GET_C(bytecode.m_operand).jsValue().toBoolean(exec)));
319}
320
321SLOW_PATH_DECL(slow_path_eq)
322{
323 BEGIN();
324 auto bytecode = pc->as<OpEq>();
325 RETURN(jsBoolean(JSValue::equal(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
326}
327
328SLOW_PATH_DECL(slow_path_neq)
329{
330 BEGIN();
331 auto bytecode = pc->as<OpNeq>();
332 RETURN(jsBoolean(!JSValue::equal(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
333}
334
335SLOW_PATH_DECL(slow_path_stricteq)
336{
337 BEGIN();
338 auto bytecode = pc->as<OpStricteq>();
339 RETURN(jsBoolean(JSValue::strictEqual(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
340}
341
342SLOW_PATH_DECL(slow_path_nstricteq)
343{
344 BEGIN();
345 auto bytecode = pc->as<OpNstricteq>();
346 RETURN(jsBoolean(!JSValue::strictEqual(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
347}
348
349SLOW_PATH_DECL(slow_path_less)
350{
351 BEGIN();
352 auto bytecode = pc->as<OpLess>();
353 RETURN(jsBoolean(jsLess<true>(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
354}
355
356SLOW_PATH_DECL(slow_path_lesseq)
357{
358 BEGIN();
359 auto bytecode = pc->as<OpLesseq>();
360 RETURN(jsBoolean(jsLessEq<true>(exec, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue())));
361}
362
363SLOW_PATH_DECL(slow_path_greater)
364{
365 BEGIN();
366 auto bytecode = pc->as<OpGreater>();
367 RETURN(jsBoolean(jsLess<false>(exec, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue())));
368}
369
370SLOW_PATH_DECL(slow_path_greatereq)
371{
372 BEGIN();
373 auto bytecode = pc->as<OpGreatereq>();
374 RETURN(jsBoolean(jsLessEq<false>(exec, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue())));
375}
376
377SLOW_PATH_DECL(slow_path_inc)
378{
379 BEGIN();
380 auto bytecode = pc->as<OpInc>();
381 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, jsNumber(GET(bytecode.m_srcDst).jsValue().toNumber(exec) + 1), { });
382}
383
384SLOW_PATH_DECL(slow_path_dec)
385{
386 BEGIN();
387 auto bytecode = pc->as<OpDec>();
388 RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, jsNumber(GET(bytecode.m_srcDst).jsValue().toNumber(exec) - 1), { });
389}
390
391SLOW_PATH_DECL(slow_path_to_string)
392{
393 BEGIN();
394 auto bytecode = pc->as<OpToString>();
395 RETURN(GET_C(bytecode.m_operand).jsValue().toString(exec));
396}
397
398#if ENABLE(JIT)
399static void updateArithProfileForUnaryArithOp(OpNegate::Metadata& metadata, JSValue result, JSValue operand)
400{
401 ArithProfile& profile = metadata.m_arithProfile;
402 profile.observeLHS(operand);
403 ASSERT(result.isNumber() || result.isBigInt());
404 if (result.isNumber()) {
405 if (!result.isInt32()) {
406 if (operand.isInt32())
407 profile.setObservedInt32Overflow();
408
409 double doubleVal = result.asNumber();
410 if (!doubleVal && std::signbit(doubleVal))
411 profile.setObservedNegZeroDouble();
412 else {
413 profile.setObservedNonNegZeroDouble();
414
415 // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
416 // Therefore, we will get a false positive if the result is that value. This is intentionally
417 // done to simplify the checking algorithm.
418 static const int64_t int52OverflowPoint = (1ll << 51);
419 int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
420 if (int64Val >= int52OverflowPoint)
421 profile.setObservedInt52Overflow();
422 }
423 }
424 } else if (result.isBigInt())
425 profile.setObservedBigInt();
426 else
427 profile.setObservedNonNumeric();
428}
429#else
430static void updateArithProfileForUnaryArithOp(OpNegate::Metadata&, JSValue, JSValue) { }
431#endif
432
433SLOW_PATH_DECL(slow_path_negate)
434{
435 BEGIN();
436 auto bytecode = pc->as<OpNegate>();
437 auto& metadata = bytecode.metadata(exec);
438 JSValue operand = GET_C(bytecode.m_operand).jsValue();
439 JSValue primValue = operand.toPrimitive(exec, PreferNumber);
440 CHECK_EXCEPTION();
441
442 if (primValue.isBigInt()) {
443 JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
444 RETURN_WITH_PROFILING(result, {
445 updateArithProfileForUnaryArithOp(metadata, result, operand);
446 });
447 }
448
449 JSValue result = jsNumber(-primValue.toNumber(exec));
450 CHECK_EXCEPTION();
451 RETURN_WITH_PROFILING(result, {
452 updateArithProfileForUnaryArithOp(metadata, result, operand);
453 });
454}
455
456#if ENABLE(DFG_JIT)
457static void updateArithProfileForBinaryArithOp(ExecState* exec, const Instruction* pc, JSValue result, JSValue left, JSValue right)
458{
459 CodeBlock* codeBlock = exec->codeBlock();
460 ArithProfile& profile = *codeBlock->arithProfileForPC(pc);
461
462 if (result.isNumber()) {
463 if (!result.isInt32()) {
464 if (left.isInt32() && right.isInt32())
465 profile.setObservedInt32Overflow();
466
467 double doubleVal = result.asNumber();
468 if (!doubleVal && std::signbit(doubleVal))
469 profile.setObservedNegZeroDouble();
470 else {
471 profile.setObservedNonNegZeroDouble();
472
473 // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
474 // Therefore, we will get a false positive if the result is that value. This is intentionally
475 // done to simplify the checking algorithm.
476 static const int64_t int52OverflowPoint = (1ll << 51);
477 int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
478 if (int64Val >= int52OverflowPoint)
479 profile.setObservedInt52Overflow();
480 }
481 }
482 } else if (result.isBigInt())
483 profile.setObservedBigInt();
484 else
485 profile.setObservedNonNumeric();
486}
487#else
488static void updateArithProfileForBinaryArithOp(ExecState*, const Instruction*, JSValue, JSValue, JSValue) { }
489#endif
490
491SLOW_PATH_DECL(slow_path_to_number)
492{
493 BEGIN();
494 auto bytecode = pc->as<OpToNumber>();
495 JSValue argument = GET_C(bytecode.m_operand).jsValue();
496 JSValue result = jsNumber(argument.toNumber(exec));
497 RETURN_PROFILED(result);
498}
499
500SLOW_PATH_DECL(slow_path_to_object)
501{
502 BEGIN();
503 auto bytecode = pc->as<OpToObject>();
504 JSValue argument = GET_C(bytecode.m_operand).jsValue();
505 if (UNLIKELY(argument.isUndefinedOrNull())) {
506 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_message);
507 if (!ident.isEmpty())
508 THROW(createTypeError(exec, ident.impl()));
509 }
510 JSObject* result = argument.toObject(exec);
511 RETURN_PROFILED(result);
512}
513
514SLOW_PATH_DECL(slow_path_add)
515{
516 BEGIN();
517 auto bytecode = pc->as<OpAdd>();
518 JSValue v1 = GET_C(bytecode.m_lhs).jsValue();
519 JSValue v2 = GET_C(bytecode.m_rhs).jsValue();
520
521 ArithProfile& arithProfile = *exec->codeBlock()->arithProfileForPC(pc);
522 arithProfile.observeLHSAndRHS(v1, v2);
523
524 JSValue result = jsAdd(exec, v1, v2);
525
526 RETURN_WITH_PROFILING(result, {
527 updateArithProfileForBinaryArithOp(exec, pc, result, v1, v2);
528 });
529}
530
531// The following arithmetic and bitwise operations need to be sure to run
532// toNumber() on their operands in order. (A call to toNumber() is idempotent
533// if an exception is already set on the ExecState.)
534
535SLOW_PATH_DECL(slow_path_mul)
536{
537 BEGIN();
538 auto bytecode = pc->as<OpMul>();
539 JSValue left = GET_C(bytecode.m_lhs).jsValue();
540 JSValue right = GET_C(bytecode.m_rhs).jsValue();
541 JSValue result = jsMul(exec, left, right);
542 CHECK_EXCEPTION();
543 RETURN_WITH_PROFILING(result, {
544 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
545 });
546}
547
548SLOW_PATH_DECL(slow_path_sub)
549{
550 BEGIN();
551 auto bytecode = pc->as<OpSub>();
552 JSValue left = GET_C(bytecode.m_lhs).jsValue();
553 JSValue right = GET_C(bytecode.m_rhs).jsValue();
554 auto leftNumeric = left.toNumeric(exec);
555 CHECK_EXCEPTION();
556 auto rightNumeric = right.toNumeric(exec);
557 CHECK_EXCEPTION();
558
559 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
560 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
561 JSBigInt* result = JSBigInt::sub(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
562 CHECK_EXCEPTION();
563 RETURN_WITH_PROFILING(result, {
564 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
565 });
566 }
567
568 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in subtraction."));
569 }
570
571 JSValue result = jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric));
572 RETURN_WITH_PROFILING(result, {
573 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
574 });
575}
576
577SLOW_PATH_DECL(slow_path_div)
578{
579 BEGIN();
580 auto bytecode = pc->as<OpDiv>();
581 JSValue left = GET_C(bytecode.m_lhs).jsValue();
582 JSValue right = GET_C(bytecode.m_rhs).jsValue();
583 auto leftNumeric = left.toNumeric(exec);
584 CHECK_EXCEPTION();
585 auto rightNumeric = right.toNumeric(exec);
586 CHECK_EXCEPTION();
587
588 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
589 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
590 JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
591 CHECK_EXCEPTION();
592 RETURN_WITH_PROFILING(result, {
593 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
594 });
595 }
596
597 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in division."));
598 }
599
600 double a = WTF::get<double>(leftNumeric);
601 double b = WTF::get<double>(rightNumeric);
602 JSValue result = jsNumber(a / b);
603 RETURN_WITH_PROFILING(result, {
604 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
605 });
606}
607
608SLOW_PATH_DECL(slow_path_mod)
609{
610 BEGIN();
611 auto bytecode = pc->as<OpMod>();
612 JSValue left = GET_C(bytecode.m_lhs).jsValue();
613 JSValue right = GET_C(bytecode.m_rhs).jsValue();
614 auto leftNumeric = left.toNumeric(exec);
615 CHECK_EXCEPTION();
616 auto rightNumeric = right.toNumeric(exec);
617 CHECK_EXCEPTION();
618
619 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
620 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
621 JSBigInt* result = JSBigInt::remainder(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
622 CHECK_EXCEPTION();
623 RETURN(result);
624 }
625
626 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in remainder operation."));
627 }
628
629 double a = WTF::get<double>(leftNumeric);
630 double b = WTF::get<double>(rightNumeric);
631 RETURN(jsNumber(jsMod(a, b)));
632}
633
634SLOW_PATH_DECL(slow_path_pow)
635{
636 BEGIN();
637 auto bytecode = pc->as<OpPow>();
638 double a = GET_C(bytecode.m_lhs).jsValue().toNumber(exec);
639 if (UNLIKELY(throwScope.exception()))
640 RETURN(JSValue());
641 double b = GET_C(bytecode.m_rhs).jsValue().toNumber(exec);
642 if (UNLIKELY(throwScope.exception()))
643 RETURN(JSValue());
644 RETURN(jsNumber(operationMathPow(a, b)));
645}
646
647SLOW_PATH_DECL(slow_path_lshift)
648{
649 BEGIN();
650 auto bytecode = pc->as<OpLshift>();
651 JSValue left = GET_C(bytecode.m_lhs).jsValue();
652 JSValue right = GET_C(bytecode.m_rhs).jsValue();
653 auto leftNumeric = left.toBigIntOrInt32(exec);
654 CHECK_EXCEPTION();
655 auto rightNumeric = right.toBigIntOrInt32(exec);
656 CHECK_EXCEPTION();
657
658 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
659 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
660 JSBigInt* result = JSBigInt::leftShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
661 CHECK_EXCEPTION();
662 RETURN(result);
663 }
664
665 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in left shift operation."));
666 }
667
668 RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) << (WTF::get<int32_t>(rightNumeric) & 31)));
669}
670
671SLOW_PATH_DECL(slow_path_rshift)
672{
673 BEGIN();
674 auto bytecode = pc->as<OpRshift>();
675 JSValue left = GET_C(bytecode.m_lhs).jsValue();
676 JSValue right = GET_C(bytecode.m_rhs).jsValue();
677 auto leftNumeric = left.toBigIntOrInt32(exec);
678 CHECK_EXCEPTION();
679 auto rightNumeric = right.toBigIntOrInt32(exec);
680 CHECK_EXCEPTION();
681
682 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
683 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
684 JSBigInt* result = JSBigInt::signedRightShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
685 CHECK_EXCEPTION();
686 RETURN(result);
687 }
688
689 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in signed right shift operation."));
690 }
691
692 RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31)));
693}
694
695SLOW_PATH_DECL(slow_path_urshift)
696{
697 BEGIN();
698 auto bytecode = pc->as<OpUrshift>();
699 uint32_t a = GET_C(bytecode.m_lhs).jsValue().toUInt32(exec);
700 if (UNLIKELY(throwScope.exception()))
701 RETURN(JSValue());
702 uint32_t b = GET_C(bytecode.m_rhs).jsValue().toUInt32(exec);
703 RETURN(jsNumber(static_cast<int32_t>(a >> (b & 31))));
704}
705
706SLOW_PATH_DECL(slow_path_unsigned)
707{
708 BEGIN();
709 auto bytecode = pc->as<OpUnsigned>();
710 uint32_t a = GET_C(bytecode.m_operand).jsValue().toUInt32(exec);
711 RETURN(jsNumber(a));
712}
713
714SLOW_PATH_DECL(slow_path_bitnot)
715{
716 BEGIN();
717 auto bytecode = pc->as<OpBitnot>();
718 auto operandNumeric = GET_C(bytecode.m_operand).jsValue().toBigIntOrInt32(exec);
719 CHECK_EXCEPTION();
720
721 if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) {
722 JSBigInt* result = JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric));
723 CHECK_EXCEPTION();
724 RETURN_PROFILED(result);
725 }
726
727 RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric)));
728}
729
730SLOW_PATH_DECL(slow_path_bitand)
731{
732 BEGIN();
733 auto bytecode = pc->as<OpBitand>();
734 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
735 CHECK_EXCEPTION();
736 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
737 CHECK_EXCEPTION();
738 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
739 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
740 JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
741 CHECK_EXCEPTION();
742 RETURN_PROFILED(result);
743 }
744
745 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'and' operation."));
746 }
747
748 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric)));
749}
750
751SLOW_PATH_DECL(slow_path_bitor)
752{
753 BEGIN();
754 auto bytecode = pc->as<OpBitor>();
755 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
756 CHECK_EXCEPTION();
757 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
758 CHECK_EXCEPTION();
759 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
760 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
761 JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
762 CHECK_EXCEPTION();
763 RETURN_PROFILED(result);
764 }
765
766 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'or' operation."));
767 }
768
769 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric)));
770}
771
772SLOW_PATH_DECL(slow_path_bitxor)
773{
774 BEGIN();
775 auto bytecode = pc->as<OpBitxor>();
776 auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(exec);
777 CHECK_EXCEPTION();
778 auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(exec);
779 CHECK_EXCEPTION();
780 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
781 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
782 JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
783 CHECK_EXCEPTION();
784 RETURN_PROFILED(result);
785 }
786
787 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise 'xor' operation."));
788 }
789
790 RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
791}
792
793SLOW_PATH_DECL(slow_path_typeof)
794{
795 BEGIN();
796 auto bytecode = pc->as<OpTypeof>();
797 RETURN(jsTypeStringForValue(exec, GET_C(bytecode.m_value).jsValue()));
798}
799
800SLOW_PATH_DECL(slow_path_is_object_or_null)
801{
802 BEGIN();
803 auto bytecode = pc->as<OpIsObjectOrNull>();
804 RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, GET_C(bytecode.m_operand).jsValue())));
805}
806
807SLOW_PATH_DECL(slow_path_is_function)
808{
809 BEGIN();
810 auto bytecode = pc->as<OpIsFunction>();
811 RETURN(jsBoolean(GET_C(bytecode.m_operand).jsValue().isFunction(vm)));
812}
813
814SLOW_PATH_DECL(slow_path_in_by_val)
815{
816 BEGIN();
817 auto bytecode = pc->as<OpInByVal>();
818 auto& metadata = bytecode.metadata(exec);
819 RETURN(jsBoolean(CommonSlowPaths::opInByVal(exec, GET_C(bytecode.m_base).jsValue(), GET_C(bytecode.m_property).jsValue(), &metadata.m_arrayProfile)));
820}
821
822SLOW_PATH_DECL(slow_path_in_by_id)
823{
824 BEGIN();
825
826 auto bytecode = pc->as<OpInById>();
827 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
828 if (!baseValue.isObject())
829 THROW(createInvalidInParameterError(exec, baseValue));
830
831 RETURN(jsBoolean(asObject(baseValue)->hasProperty(exec, exec->codeBlock()->identifier(bytecode.m_property))));
832}
833
834SLOW_PATH_DECL(slow_path_del_by_val)
835{
836 BEGIN();
837 auto bytecode = pc->as<OpDelByVal>();
838 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
839 JSObject* baseObject = baseValue.toObject(exec);
840 CHECK_EXCEPTION();
841
842 JSValue subscript = GET_C(bytecode.m_property).jsValue();
843
844 bool couldDelete;
845
846 uint32_t i;
847 if (subscript.getUInt32(i))
848 couldDelete = baseObject->methodTable(vm)->deletePropertyByIndex(baseObject, exec, i);
849 else {
850 CHECK_EXCEPTION();
851 auto property = subscript.toPropertyKey(exec);
852 CHECK_EXCEPTION();
853 couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, exec, property);
854 }
855
856 if (!couldDelete && exec->codeBlock()->isStrictMode())
857 THROW(createTypeError(exec, UnableToDeletePropertyError));
858
859 RETURN(jsBoolean(couldDelete));
860}
861
862SLOW_PATH_DECL(slow_path_strcat)
863{
864 BEGIN();
865 auto bytecode = pc->as<OpStrcat>();
866 RETURN(jsStringFromRegisterArray(exec, &GET(bytecode.m_src), bytecode.m_count));
867}
868
869SLOW_PATH_DECL(slow_path_to_primitive)
870{
871 BEGIN();
872 auto bytecode = pc->as<OpToPrimitive>();
873 RETURN(GET_C(bytecode.m_src).jsValue().toPrimitive(exec));
874}
875
876SLOW_PATH_DECL(slow_path_enter)
877{
878 BEGIN();
879 CodeBlock* codeBlock = exec->codeBlock();
880 Heap::heap(codeBlock)->writeBarrier(codeBlock);
881 END();
882}
883
884SLOW_PATH_DECL(slow_path_get_enumerable_length)
885{
886 BEGIN();
887 auto bytecode = pc->as<OpGetEnumerableLength>();
888 JSValue enumeratorValue = GET(bytecode.m_base).jsValue();
889 if (enumeratorValue.isUndefinedOrNull())
890 RETURN(jsNumber(0));
891
892 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell());
893
894 RETURN(jsNumber(enumerator->indexedLength()));
895}
896
897SLOW_PATH_DECL(slow_path_has_indexed_property)
898{
899 BEGIN();
900 auto bytecode = pc->as<OpHasIndexedProperty>();
901 auto& metadata = bytecode.metadata(exec);
902 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
903 CHECK_EXCEPTION();
904 JSValue property = GET(bytecode.m_property).jsValue();
905 metadata.m_arrayProfile.observeStructure(base->structure(vm));
906 ASSERT(property.isUInt32());
907 RETURN(jsBoolean(base->hasPropertyGeneric(exec, property.asUInt32(), PropertySlot::InternalMethodType::GetOwnProperty)));
908}
909
910SLOW_PATH_DECL(slow_path_has_structure_property)
911{
912 BEGIN();
913 auto bytecode = pc->as<OpHasStructureProperty>();
914 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
915 CHECK_EXCEPTION();
916 JSValue property = GET(bytecode.m_property).jsValue();
917 ASSERT(property.isString());
918 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
919 if (base->structure(vm)->id() == enumerator->cachedStructureID())
920 RETURN(jsBoolean(true));
921 JSString* string = asString(property);
922 auto propertyName = string->toIdentifier(exec);
923 CHECK_EXCEPTION();
924 RETURN(jsBoolean(base->hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::GetOwnProperty)));
925}
926
927SLOW_PATH_DECL(slow_path_has_generic_property)
928{
929 BEGIN();
930 auto bytecode = pc->as<OpHasGenericProperty>();
931 JSObject* base = GET(bytecode.m_base).jsValue().toObject(exec);
932 CHECK_EXCEPTION();
933 JSValue property = GET(bytecode.m_property).jsValue();
934 ASSERT(property.isString());
935 JSString* string = asString(property);
936 auto propertyName = string->toIdentifier(exec);
937 CHECK_EXCEPTION();
938 RETURN(jsBoolean(base->hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::GetOwnProperty)));
939}
940
941SLOW_PATH_DECL(slow_path_get_direct_pname)
942{
943 BEGIN();
944 auto bytecode = pc->as<OpGetDirectPname>();
945 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
946 JSValue property = GET(bytecode.m_property).jsValue();
947 ASSERT(property.isString());
948 JSString* string = asString(property);
949 auto propertyName = string->toIdentifier(exec);
950 CHECK_EXCEPTION();
951 RETURN(baseValue.get(exec, propertyName));
952}
953
954SLOW_PATH_DECL(slow_path_get_property_enumerator)
955{
956 BEGIN();
957 auto bytecode = pc->as<OpGetPropertyEnumerator>();
958 JSValue baseValue = GET(bytecode.m_base).jsValue();
959 if (baseValue.isUndefinedOrNull())
960 RETURN(JSPropertyNameEnumerator::create(vm));
961
962 JSObject* base = baseValue.toObject(exec);
963 CHECK_EXCEPTION();
964
965 RETURN(propertyNameEnumerator(exec, base));
966}
967
968SLOW_PATH_DECL(slow_path_enumerator_structure_pname)
969{
970 BEGIN();
971 auto bytecode = pc->as<OpEnumeratorStructurePname>();
972 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
973 uint32_t index = GET(bytecode.m_index).jsValue().asUInt32();
974
975 JSString* propertyName = nullptr;
976 if (index < enumerator->endStructurePropertyIndex())
977 propertyName = enumerator->propertyNameAtIndex(index);
978 RETURN(propertyName ? propertyName : jsNull());
979}
980
981SLOW_PATH_DECL(slow_path_enumerator_generic_pname)
982{
983 BEGIN();
984 auto bytecode = pc->as<OpEnumeratorGenericPname>();
985 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell());
986 uint32_t index = GET(bytecode.m_index).jsValue().asUInt32();
987
988 JSString* propertyName = nullptr;
989 if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex())
990 propertyName = enumerator->propertyNameAtIndex(index);
991 RETURN(propertyName ? propertyName : jsNull());
992}
993
994SLOW_PATH_DECL(slow_path_to_index_string)
995{
996 BEGIN();
997 auto bytecode = pc->as<OpToIndexString>();
998 JSValue indexValue = GET(bytecode.m_index).jsValue();
999 ASSERT(indexValue.isAnyInt());
1000 ASSERT(indexValue.asAnyInt() <= UINT32_MAX);
1001 ASSERT(indexValue.asAnyInt() >= 0);
1002 uint32_t index = static_cast<uint32_t>(indexValue.asAnyInt());
1003 RETURN(jsString(exec, Identifier::from(exec, index).string()));
1004}
1005
1006SLOW_PATH_DECL(slow_path_profile_type_clear_log)
1007{
1008 BEGIN();
1009 vm.typeProfilerLog()->processLogEntries(vm, "LLInt log full."_s);
1010 END();
1011}
1012
1013SLOW_PATH_DECL(slow_path_unreachable)
1014{
1015 BEGIN();
1016 UNREACHABLE_FOR_PLATFORM();
1017 END();
1018}
1019
1020SLOW_PATH_DECL(slow_path_create_lexical_environment)
1021{
1022 BEGIN();
1023 auto bytecode = pc->as<OpCreateLexicalEnvironment>();
1024 int scopeReg = bytecode.m_scope.offset();
1025 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1026 SymbolTable* symbolTable = jsCast<SymbolTable*>(GET_C(bytecode.m_symbolTable).jsValue());
1027 JSValue initialValue = GET_C(bytecode.m_initialValue).jsValue();
1028 ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
1029 JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue);
1030 RETURN(newScope);
1031}
1032
1033SLOW_PATH_DECL(slow_path_push_with_scope)
1034{
1035 BEGIN();
1036 auto bytecode = pc->as<OpPushWithScope>();
1037 JSObject* newScope = GET_C(bytecode.m_newScope).jsValue().toObject(exec);
1038 CHECK_EXCEPTION();
1039
1040 int scopeReg = bytecode.m_currentScope.offset();
1041 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1042 RETURN(JSWithScope::create(vm, exec->lexicalGlobalObject(), currentScope, newScope));
1043}
1044
1045SLOW_PATH_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval)
1046{
1047 BEGIN();
1048 auto bytecode = pc->as<OpResolveScopeForHoistingFuncDeclInEval>();
1049 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1050 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1051 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(exec, scope, ident);
1052
1053 CHECK_EXCEPTION();
1054
1055 RETURN(resolvedScope);
1056}
1057
1058SLOW_PATH_DECL(slow_path_resolve_scope)
1059{
1060 BEGIN();
1061 auto bytecode = pc->as<OpResolveScope>();
1062 auto& metadata = bytecode.metadata(exec);
1063 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_var);
1064 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1065 JSObject* resolvedScope = JSScope::resolve(exec, scope, ident);
1066 // Proxy can throw an error here, e.g. Proxy in with statement's @unscopables.
1067 CHECK_EXCEPTION();
1068
1069 ResolveType resolveType = metadata.m_resolveType;
1070
1071 // ModuleVar does not keep the scope register value alive in DFG.
1072 ASSERT(resolveType != ModuleVar);
1073
1074 switch (resolveType) {
1075 case GlobalProperty:
1076 case GlobalPropertyWithVarInjectionChecks:
1077 case UnresolvedProperty:
1078 case UnresolvedPropertyWithVarInjectionChecks: {
1079 if (resolvedScope->isGlobalObject()) {
1080 JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(resolvedScope);
1081 bool hasProperty = globalObject->hasProperty(exec, ident);
1082 CHECK_EXCEPTION();
1083 if (hasProperty) {
1084 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1085 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalPropertyWithVarInjectionChecks : GlobalProperty;
1086 metadata.m_globalObject = globalObject;
1087 metadata.m_globalLexicalBindingEpoch = globalObject->globalLexicalBindingEpoch();
1088 }
1089 } else if (resolvedScope->isGlobalLexicalEnvironment()) {
1090 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope);
1091 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1092 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
1093 metadata.m_globalLexicalEnvironment = globalLexicalEnvironment;
1094 }
1095 break;
1096 }
1097 default:
1098 break;
1099 }
1100
1101 RETURN(resolvedScope);
1102}
1103
1104SLOW_PATH_DECL(slow_path_create_rest)
1105{
1106 BEGIN();
1107 auto bytecode = pc->as<OpCreateRest>();
1108 unsigned arraySize = GET_C(bytecode.m_arraySize).jsValue().asUInt32();
1109 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1110 Structure* structure = globalObject->restParameterStructure();
1111 unsigned numParamsToSkip = bytecode.m_numParametersToSkip;
1112 JSValue* argumentsToCopyRegion = exec->addressOfArgumentsStart() + numParamsToSkip;
1113 RETURN(constructArray(exec, structure, argumentsToCopyRegion, arraySize));
1114}
1115
1116SLOW_PATH_DECL(slow_path_get_by_id_with_this)
1117{
1118 BEGIN();
1119 auto bytecode = pc->as<OpGetByIdWithThis>();
1120 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1121 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1122 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1123 PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
1124 JSValue result = baseValue.get(exec, ident, slot);
1125 RETURN_PROFILED(result);
1126}
1127
1128SLOW_PATH_DECL(slow_path_get_by_val_with_this)
1129{
1130 BEGIN();
1131
1132 auto bytecode = pc->as<OpGetByValWithThis>();
1133 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1134 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1135 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1136
1137 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1138 Structure& structure = *baseValue.asCell()->structure(vm);
1139 if (JSCell::canUseFastGetOwnProperty(structure)) {
1140 RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec);
1141 CHECK_EXCEPTION();
1142 if (existingAtomicString) {
1143 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
1144 RETURN_PROFILED(result);
1145 }
1146 }
1147 }
1148
1149 PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get);
1150 if (subscript.isUInt32()) {
1151 uint32_t i = subscript.asUInt32();
1152 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1153 RETURN_PROFILED(asString(baseValue)->getIndex(exec, i));
1154
1155 RETURN_PROFILED(baseValue.get(exec, i, slot));
1156 }
1157
1158 baseValue.requireObjectCoercible(exec);
1159 CHECK_EXCEPTION();
1160 auto property = subscript.toPropertyKey(exec);
1161 CHECK_EXCEPTION();
1162 RETURN_PROFILED(baseValue.get(exec, property, slot));
1163}
1164
1165SLOW_PATH_DECL(slow_path_put_by_id_with_this)
1166{
1167 BEGIN();
1168 auto bytecode = pc->as<OpPutByIdWithThis>();
1169 CodeBlock* codeBlock = exec->codeBlock();
1170 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
1171 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1172 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1173 JSValue putValue = GET_C(bytecode.m_value).jsValue();
1174 PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext());
1175 baseValue.putInline(exec, ident, putValue, slot);
1176 END();
1177}
1178
1179SLOW_PATH_DECL(slow_path_put_by_val_with_this)
1180{
1181 BEGIN();
1182 auto bytecode = pc->as<OpPutByValWithThis>();
1183 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1184 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1185 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1186 JSValue value = GET_C(bytecode.m_value).jsValue();
1187
1188 auto property = subscript.toPropertyKey(exec);
1189 CHECK_EXCEPTION();
1190 PutPropertySlot slot(thisValue, exec->codeBlock()->isStrictMode());
1191 baseValue.put(exec, property, value, slot);
1192 END();
1193}
1194
1195SLOW_PATH_DECL(slow_path_define_data_property)
1196{
1197 BEGIN();
1198 auto bytecode = pc->as<OpDefineDataProperty>();
1199 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1200 JSValue property = GET_C(bytecode.m_property).jsValue();
1201 JSValue value = GET_C(bytecode.m_value).jsValue();
1202 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1203 ASSERT(attributes.isInt32());
1204
1205 auto propertyName = property.toPropertyKey(exec);
1206 CHECK_EXCEPTION();
1207 PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes.asInt32()));
1208 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1209 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1210 END();
1211}
1212
1213SLOW_PATH_DECL(slow_path_define_accessor_property)
1214{
1215 BEGIN();
1216 auto bytecode = pc->as<OpDefineAccessorProperty>();
1217 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1218 JSValue property = GET_C(bytecode.m_property).jsValue();
1219 JSValue getter = GET_C(bytecode.m_getter).jsValue();
1220 JSValue setter = GET_C(bytecode.m_setter).jsValue();
1221 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1222 ASSERT(attributes.isInt32());
1223
1224 auto propertyName = property.toPropertyKey(exec);
1225 CHECK_EXCEPTION();
1226 PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes.asInt32()));
1227 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1228 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1229 END();
1230}
1231
1232SLOW_PATH_DECL(slow_path_throw_static_error)
1233{
1234 BEGIN();
1235 auto bytecode = pc->as<OpThrowStaticError>();
1236 JSValue errorMessageValue = GET_C(bytecode.m_message).jsValue();
1237 RELEASE_ASSERT(errorMessageValue.isString());
1238 String errorMessage = asString(errorMessageValue)->value(exec);
1239 ErrorType errorType = bytecode.m_errorType;
1240 THROW(createError(exec, errorType, errorMessage));
1241}
1242
1243SLOW_PATH_DECL(slow_path_new_array_with_spread)
1244{
1245 BEGIN();
1246 auto bytecode = pc->as<OpNewArrayWithSpread>();
1247 int numItems = bytecode.m_argc;
1248 ASSERT(numItems >= 0);
1249 const BitVector& bitVector = exec->codeBlock()->unlinkedCodeBlock()->bitVector(bytecode.m_bitVector);
1250
1251 JSValue* values = bitwise_cast<JSValue*>(&GET(bytecode.m_argv));
1252
1253 Checked<unsigned, RecordOverflow> checkedArraySize = 0;
1254 for (int i = 0; i < numItems; i++) {
1255 if (bitVector.get(i)) {
1256 JSValue value = values[-i];
1257 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1258 checkedArraySize += array->size();
1259 } else
1260 checkedArraySize += 1;
1261 }
1262 if (UNLIKELY(checkedArraySize.hasOverflowed()))
1263 THROW(createOutOfMemoryError(exec));
1264
1265 unsigned arraySize = checkedArraySize.unsafeGet();
1266 if (UNLIKELY(arraySize >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH))
1267 THROW(createOutOfMemoryError(exec));
1268
1269 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1270 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
1271
1272 JSArray* result = JSArray::tryCreate(vm, structure, arraySize);
1273 if (UNLIKELY(!result))
1274 THROW(createOutOfMemoryError(exec));
1275 CHECK_EXCEPTION();
1276
1277 unsigned index = 0;
1278 for (int i = 0; i < numItems; i++) {
1279 JSValue value = values[-i];
1280 if (bitVector.get(i)) {
1281 // We are spreading.
1282 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1283 for (unsigned i = 0; i < array->size(); i++) {
1284 RELEASE_ASSERT(array->get(i));
1285 result->putDirectIndex(exec, index, array->get(i));
1286 CHECK_EXCEPTION();
1287 ++index;
1288 }
1289 } else {
1290 // We are not spreading.
1291 result->putDirectIndex(exec, index, value);
1292 CHECK_EXCEPTION();
1293 ++index;
1294 }
1295 }
1296
1297 RETURN(result);
1298}
1299
1300SLOW_PATH_DECL(slow_path_new_array_buffer)
1301{
1302 BEGIN();
1303 auto bytecode = pc->as<OpNewArrayBuffer>();
1304 ASSERT(exec->codeBlock()->isConstantRegisterIndex(bytecode.m_immutableButterfly.offset()));
1305 JSImmutableButterfly* immutableButterfly = bitwise_cast<JSImmutableButterfly*>(GET_C(bytecode.m_immutableButterfly).jsValue().asCell());
1306 auto& profile = bytecode.metadata(exec).m_arrayAllocationProfile;
1307
1308 IndexingType indexingMode = profile.selectIndexingType();
1309 Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(indexingMode);
1310 ASSERT(isCopyOnWrite(indexingMode));
1311 ASSERT(!structure->outOfLineCapacity());
1312
1313 if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) {
1314 auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length());
1315 for (unsigned i = 0; i < immutableButterfly->length(); ++i)
1316 newButterfly->setIndex(vm, i, immutableButterfly->get(i));
1317 immutableButterfly = newButterfly;
1318 CodeBlock* codeBlock = exec->codeBlock();
1319
1320 // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline.
1321 // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from
1322 // a compilation thread.
1323 WTF::storeStoreFence();
1324 codeBlock->constantRegister(bytecode.m_immutableButterfly.offset()).set(vm, codeBlock, immutableButterfly);
1325 WTF::storeStoreFence();
1326 }
1327
1328 JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, immutableButterfly);
1329 ASSERT(isCopyOnWrite(result->indexingMode()) || exec->lexicalGlobalObject()->isHavingABadTime());
1330 ArrayAllocationProfile::updateLastAllocationFor(&profile, result);
1331 RETURN(result);
1332}
1333
1334SLOW_PATH_DECL(slow_path_spread)
1335{
1336 BEGIN();
1337
1338 auto bytecode = pc->as<OpSpread>();
1339 JSValue iterable = GET_C(bytecode.m_argument).jsValue();
1340
1341 if (iterable.isCell() && isJSArray(iterable.asCell())) {
1342 JSArray* array = jsCast<JSArray*>(iterable);
1343 if (array->isIteratorProtocolFastAndNonObservable()) {
1344 // JSFixedArray::createFromArray does not consult the prototype chain,
1345 // so we must be sure that not consulting the prototype chain would
1346 // produce the same value during iteration.
1347 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1348 }
1349 }
1350
1351 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1352
1353 JSArray* array;
1354 {
1355 JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
1356 CallData callData;
1357 CallType callType = JSC::getCallData(vm, iterationFunction, callData);
1358 ASSERT(callType != CallType::None);
1359
1360 MarkedArgumentBuffer arguments;
1361 arguments.append(iterable);
1362 ASSERT(!arguments.hasOverflowed());
1363 JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
1364 CHECK_EXCEPTION();
1365 array = jsCast<JSArray*>(arrayResult);
1366 }
1367
1368 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1369}
1370
1371} // namespace JSC
1372