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