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.isUInt32AsAnyInt());
907 RETURN(jsBoolean(base->hasPropertyGeneric(exec, property.asUInt32AsAnyInt(), 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.isUInt32AsAnyInt());
1000 RETURN(jsString(exec, Identifier::from(exec, indexValue.asUInt32AsAnyInt()).string()));
1001}
1002
1003SLOW_PATH_DECL(slow_path_profile_type_clear_log)
1004{
1005 BEGIN();
1006 vm.typeProfilerLog()->processLogEntries(vm, "LLInt log full."_s);
1007 END();
1008}
1009
1010SLOW_PATH_DECL(slow_path_unreachable)
1011{
1012 BEGIN();
1013 UNREACHABLE_FOR_PLATFORM();
1014 END();
1015}
1016
1017SLOW_PATH_DECL(slow_path_create_lexical_environment)
1018{
1019 BEGIN();
1020 auto bytecode = pc->as<OpCreateLexicalEnvironment>();
1021 int scopeReg = bytecode.m_scope.offset();
1022 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1023 SymbolTable* symbolTable = jsCast<SymbolTable*>(GET_C(bytecode.m_symbolTable).jsValue());
1024 JSValue initialValue = GET_C(bytecode.m_initialValue).jsValue();
1025 ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
1026 JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue);
1027 RETURN(newScope);
1028}
1029
1030SLOW_PATH_DECL(slow_path_push_with_scope)
1031{
1032 BEGIN();
1033 auto bytecode = pc->as<OpPushWithScope>();
1034 JSObject* newScope = GET_C(bytecode.m_newScope).jsValue().toObject(exec);
1035 CHECK_EXCEPTION();
1036
1037 int scopeReg = bytecode.m_currentScope.offset();
1038 JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
1039 RETURN(JSWithScope::create(vm, exec->lexicalGlobalObject(), currentScope, newScope));
1040}
1041
1042SLOW_PATH_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval)
1043{
1044 BEGIN();
1045 auto bytecode = pc->as<OpResolveScopeForHoistingFuncDeclInEval>();
1046 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1047 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1048 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(exec, scope, ident);
1049
1050 CHECK_EXCEPTION();
1051
1052 RETURN(resolvedScope);
1053}
1054
1055SLOW_PATH_DECL(slow_path_resolve_scope)
1056{
1057 BEGIN();
1058 auto bytecode = pc->as<OpResolveScope>();
1059 auto& metadata = bytecode.metadata(exec);
1060 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_var);
1061 JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
1062 JSObject* resolvedScope = JSScope::resolve(exec, scope, ident);
1063 // Proxy can throw an error here, e.g. Proxy in with statement's @unscopables.
1064 CHECK_EXCEPTION();
1065
1066 ResolveType resolveType = metadata.m_resolveType;
1067
1068 // ModuleVar does not keep the scope register value alive in DFG.
1069 ASSERT(resolveType != ModuleVar);
1070
1071 switch (resolveType) {
1072 case GlobalProperty:
1073 case GlobalPropertyWithVarInjectionChecks:
1074 case UnresolvedProperty:
1075 case UnresolvedPropertyWithVarInjectionChecks: {
1076 if (resolvedScope->isGlobalObject()) {
1077 JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(resolvedScope);
1078 bool hasProperty = globalObject->hasProperty(exec, ident);
1079 CHECK_EXCEPTION();
1080 if (hasProperty) {
1081 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1082 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalPropertyWithVarInjectionChecks : GlobalProperty;
1083 metadata.m_globalObject = globalObject;
1084 metadata.m_globalLexicalBindingEpoch = globalObject->globalLexicalBindingEpoch();
1085 }
1086 } else if (resolvedScope->isGlobalLexicalEnvironment()) {
1087 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope);
1088 ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
1089 metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
1090 metadata.m_globalLexicalEnvironment = globalLexicalEnvironment;
1091 }
1092 break;
1093 }
1094 default:
1095 break;
1096 }
1097
1098 RETURN(resolvedScope);
1099}
1100
1101SLOW_PATH_DECL(slow_path_create_rest)
1102{
1103 BEGIN();
1104 auto bytecode = pc->as<OpCreateRest>();
1105 unsigned arraySize = GET_C(bytecode.m_arraySize).jsValue().asUInt32();
1106 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1107 Structure* structure = globalObject->restParameterStructure();
1108 unsigned numParamsToSkip = bytecode.m_numParametersToSkip;
1109 JSValue* argumentsToCopyRegion = exec->addressOfArgumentsStart() + numParamsToSkip;
1110 RETURN(constructArray(exec, structure, argumentsToCopyRegion, arraySize));
1111}
1112
1113SLOW_PATH_DECL(slow_path_get_by_id_with_this)
1114{
1115 BEGIN();
1116 auto bytecode = pc->as<OpGetByIdWithThis>();
1117 const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_property);
1118 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1119 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1120 PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
1121 JSValue result = baseValue.get(exec, ident, slot);
1122 RETURN_PROFILED(result);
1123}
1124
1125SLOW_PATH_DECL(slow_path_get_by_val_with_this)
1126{
1127 BEGIN();
1128
1129 auto bytecode = pc->as<OpGetByValWithThis>();
1130 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1131 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1132 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1133
1134 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1135 Structure& structure = *baseValue.asCell()->structure(vm);
1136 if (JSCell::canUseFastGetOwnProperty(structure)) {
1137 RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec);
1138 CHECK_EXCEPTION();
1139 if (existingAtomicString) {
1140 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
1141 RETURN_PROFILED(result);
1142 }
1143 }
1144 }
1145
1146 PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get);
1147 if (subscript.isUInt32()) {
1148 uint32_t i = subscript.asUInt32();
1149 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1150 RETURN_PROFILED(asString(baseValue)->getIndex(exec, i));
1151
1152 RETURN_PROFILED(baseValue.get(exec, i, slot));
1153 }
1154
1155 baseValue.requireObjectCoercible(exec);
1156 CHECK_EXCEPTION();
1157 auto property = subscript.toPropertyKey(exec);
1158 CHECK_EXCEPTION();
1159 RETURN_PROFILED(baseValue.get(exec, property, slot));
1160}
1161
1162SLOW_PATH_DECL(slow_path_put_by_id_with_this)
1163{
1164 BEGIN();
1165 auto bytecode = pc->as<OpPutByIdWithThis>();
1166 CodeBlock* codeBlock = exec->codeBlock();
1167 const Identifier& ident = codeBlock->identifier(bytecode.m_property);
1168 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1169 JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue();
1170 JSValue putValue = GET_C(bytecode.m_value).jsValue();
1171 PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext());
1172 baseValue.putInline(exec, ident, putValue, slot);
1173 END();
1174}
1175
1176SLOW_PATH_DECL(slow_path_put_by_val_with_this)
1177{
1178 BEGIN();
1179 auto bytecode = pc->as<OpPutByValWithThis>();
1180 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
1181 JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue();
1182 JSValue subscript = GET_C(bytecode.m_property).jsValue();
1183 JSValue value = GET_C(bytecode.m_value).jsValue();
1184
1185 auto property = subscript.toPropertyKey(exec);
1186 CHECK_EXCEPTION();
1187 PutPropertySlot slot(thisValue, exec->codeBlock()->isStrictMode());
1188 baseValue.put(exec, property, value, slot);
1189 END();
1190}
1191
1192SLOW_PATH_DECL(slow_path_define_data_property)
1193{
1194 BEGIN();
1195 auto bytecode = pc->as<OpDefineDataProperty>();
1196 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1197 JSValue property = GET_C(bytecode.m_property).jsValue();
1198 JSValue value = GET_C(bytecode.m_value).jsValue();
1199 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1200 ASSERT(attributes.isInt32());
1201
1202 auto propertyName = property.toPropertyKey(exec);
1203 CHECK_EXCEPTION();
1204 PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes.asInt32()));
1205 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1206 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1207 END();
1208}
1209
1210SLOW_PATH_DECL(slow_path_define_accessor_property)
1211{
1212 BEGIN();
1213 auto bytecode = pc->as<OpDefineAccessorProperty>();
1214 JSObject* base = asObject(GET_C(bytecode.m_base).jsValue());
1215 JSValue property = GET_C(bytecode.m_property).jsValue();
1216 JSValue getter = GET_C(bytecode.m_getter).jsValue();
1217 JSValue setter = GET_C(bytecode.m_setter).jsValue();
1218 JSValue attributes = GET_C(bytecode.m_attributes).jsValue();
1219 ASSERT(attributes.isInt32());
1220
1221 auto propertyName = property.toPropertyKey(exec);
1222 CHECK_EXCEPTION();
1223 PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes.asInt32()));
1224 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1225 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1226 END();
1227}
1228
1229SLOW_PATH_DECL(slow_path_throw_static_error)
1230{
1231 BEGIN();
1232 auto bytecode = pc->as<OpThrowStaticError>();
1233 JSValue errorMessageValue = GET_C(bytecode.m_message).jsValue();
1234 RELEASE_ASSERT(errorMessageValue.isString());
1235 String errorMessage = asString(errorMessageValue)->value(exec);
1236 ErrorType errorType = bytecode.m_errorType;
1237 THROW(createError(exec, errorType, errorMessage));
1238}
1239
1240SLOW_PATH_DECL(slow_path_new_array_with_spread)
1241{
1242 BEGIN();
1243 auto bytecode = pc->as<OpNewArrayWithSpread>();
1244 int numItems = bytecode.m_argc;
1245 ASSERT(numItems >= 0);
1246 const BitVector& bitVector = exec->codeBlock()->unlinkedCodeBlock()->bitVector(bytecode.m_bitVector);
1247
1248 JSValue* values = bitwise_cast<JSValue*>(&GET(bytecode.m_argv));
1249
1250 Checked<unsigned, RecordOverflow> checkedArraySize = 0;
1251 for (int i = 0; i < numItems; i++) {
1252 if (bitVector.get(i)) {
1253 JSValue value = values[-i];
1254 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1255 checkedArraySize += array->size();
1256 } else
1257 checkedArraySize += 1;
1258 }
1259 if (UNLIKELY(checkedArraySize.hasOverflowed()))
1260 THROW(createOutOfMemoryError(exec));
1261
1262 unsigned arraySize = checkedArraySize.unsafeGet();
1263 if (UNLIKELY(arraySize >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH))
1264 THROW(createOutOfMemoryError(exec));
1265
1266 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1267 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
1268
1269 JSArray* result = JSArray::tryCreate(vm, structure, arraySize);
1270 if (UNLIKELY(!result))
1271 THROW(createOutOfMemoryError(exec));
1272 CHECK_EXCEPTION();
1273
1274 unsigned index = 0;
1275 for (int i = 0; i < numItems; i++) {
1276 JSValue value = values[-i];
1277 if (bitVector.get(i)) {
1278 // We are spreading.
1279 JSFixedArray* array = jsCast<JSFixedArray*>(value);
1280 for (unsigned i = 0; i < array->size(); i++) {
1281 RELEASE_ASSERT(array->get(i));
1282 result->putDirectIndex(exec, index, array->get(i));
1283 CHECK_EXCEPTION();
1284 ++index;
1285 }
1286 } else {
1287 // We are not spreading.
1288 result->putDirectIndex(exec, index, value);
1289 CHECK_EXCEPTION();
1290 ++index;
1291 }
1292 }
1293
1294 RETURN(result);
1295}
1296
1297SLOW_PATH_DECL(slow_path_new_array_buffer)
1298{
1299 BEGIN();
1300 auto bytecode = pc->as<OpNewArrayBuffer>();
1301 ASSERT(exec->codeBlock()->isConstantRegisterIndex(bytecode.m_immutableButterfly.offset()));
1302 JSImmutableButterfly* immutableButterfly = bitwise_cast<JSImmutableButterfly*>(GET_C(bytecode.m_immutableButterfly).jsValue().asCell());
1303 auto& profile = bytecode.metadata(exec).m_arrayAllocationProfile;
1304
1305 IndexingType indexingMode = profile.selectIndexingType();
1306 Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(indexingMode);
1307 ASSERT(isCopyOnWrite(indexingMode));
1308 ASSERT(!structure->outOfLineCapacity());
1309
1310 if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) {
1311 auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length());
1312 for (unsigned i = 0; i < immutableButterfly->length(); ++i)
1313 newButterfly->setIndex(vm, i, immutableButterfly->get(i));
1314 immutableButterfly = newButterfly;
1315 CodeBlock* codeBlock = exec->codeBlock();
1316
1317 // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline.
1318 // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from
1319 // a compilation thread.
1320 WTF::storeStoreFence();
1321 codeBlock->constantRegister(bytecode.m_immutableButterfly.offset()).set(vm, codeBlock, immutableButterfly);
1322 WTF::storeStoreFence();
1323 }
1324
1325 JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, immutableButterfly);
1326 ASSERT(isCopyOnWrite(result->indexingMode()) || exec->lexicalGlobalObject()->isHavingABadTime());
1327 ArrayAllocationProfile::updateLastAllocationFor(&profile, result);
1328 RETURN(result);
1329}
1330
1331SLOW_PATH_DECL(slow_path_spread)
1332{
1333 BEGIN();
1334
1335 auto bytecode = pc->as<OpSpread>();
1336 JSValue iterable = GET_C(bytecode.m_argument).jsValue();
1337
1338 if (iterable.isCell() && isJSArray(iterable.asCell())) {
1339 JSArray* array = jsCast<JSArray*>(iterable);
1340 if (array->isIteratorProtocolFastAndNonObservable()) {
1341 // JSFixedArray::createFromArray does not consult the prototype chain,
1342 // so we must be sure that not consulting the prototype chain would
1343 // produce the same value during iteration.
1344 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1345 }
1346 }
1347
1348 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1349
1350 JSArray* array;
1351 {
1352 JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
1353 CallData callData;
1354 CallType callType = JSC::getCallData(vm, iterationFunction, callData);
1355 ASSERT(callType != CallType::None);
1356
1357 MarkedArgumentBuffer arguments;
1358 arguments.append(iterable);
1359 ASSERT(!arguments.hasOverflowed());
1360 JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
1361 CHECK_EXCEPTION();
1362 array = jsCast<JSArray*>(arrayResult);
1363 }
1364
1365 RETURN(JSFixedArray::createFromArray(exec, vm, array));
1366}
1367
1368} // namespace JSC
1369