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 "DFGOperations.h"
28
29#include "ArrayConstructor.h"
30#include "ButterflyInlines.h"
31#include "ClonedArguments.h"
32#include "CodeBlock.h"
33#include "CommonSlowPaths.h"
34#include "DFGDriver.h"
35#include "DFGJITCode.h"
36#include "DFGOSRExit.h"
37#include "DFGThunks.h"
38#include "DFGToFTLDeferredCompilationCallback.h"
39#include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
40#include "DFGWorklist.h"
41#include "DefinePropertyAttributes.h"
42#include "DirectArguments.h"
43#include "FTLForOSREntryJITCode.h"
44#include "FTLOSREntry.h"
45#include "FrameTracers.h"
46#include "HasOwnPropertyCache.h"
47#include "HostCallReturnValue.h"
48#include "Interpreter.h"
49#include "JIT.h"
50#include "JITExceptions.h"
51#include "JSArrayInlines.h"
52#include "JSBigInt.h"
53#include "JSCInlines.h"
54#include "JSFixedArray.h"
55#include "JSGenericTypedArrayViewConstructorInlines.h"
56#include "JSGlobalObjectFunctions.h"
57#include "JSImmutableButterfly.h"
58#include "JSLexicalEnvironment.h"
59#include "JSMap.h"
60#include "JSPropertyNameEnumerator.h"
61#include "JSSet.h"
62#include "JSWeakMap.h"
63#include "JSWeakSet.h"
64#include "NumberConstructor.h"
65#include "ObjectConstructor.h"
66#include "Operations.h"
67#include "ParseInt.h"
68#include "RegExpGlobalDataInlines.h"
69#include "RegExpMatchesArray.h"
70#include "RegExpObjectInlines.h"
71#include "Repatch.h"
72#include "ScopedArguments.h"
73#include "StringConstructor.h"
74#include "StringPrototypeInlines.h"
75#include "SuperSampler.h"
76#include "Symbol.h"
77#include "TypeProfilerLog.h"
78#include "TypedArrayInlines.h"
79#include "VMInlines.h"
80#include <wtf/InlineASM.h>
81#include <wtf/Variant.h>
82
83#if ENABLE(JIT)
84#if ENABLE(DFG_JIT)
85
86namespace JSC { namespace DFG {
87
88template<bool strict, bool direct>
89static inline void putByVal(ExecState* exec, VM& vm, JSValue baseValue, uint32_t index, JSValue value)
90{
91 ASSERT(isIndex(index));
92 if (direct) {
93 RELEASE_ASSERT(baseValue.isObject());
94 asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
95 return;
96 }
97 if (baseValue.isObject()) {
98 JSObject* object = asObject(baseValue);
99 if (object->canSetIndexQuickly(index)) {
100 object->setIndexQuickly(vm, index, value);
101 return;
102 }
103
104 object->methodTable(vm)->putByIndex(object, exec, index, value, strict);
105 return;
106 }
107
108 baseValue.putByIndex(exec, index, value, strict);
109}
110
111template<bool strict, bool direct>
112ALWAYS_INLINE static void putByValInternal(ExecState* exec, VM& vm, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
113{
114 auto scope = DECLARE_THROW_SCOPE(vm);
115
116 JSValue baseValue = JSValue::decode(encodedBase);
117 JSValue property = JSValue::decode(encodedProperty);
118 JSValue value = JSValue::decode(encodedValue);
119
120 if (LIKELY(property.isUInt32())) {
121 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
122 ASSERT(isIndex(property.asUInt32()));
123 scope.release();
124 putByVal<strict, direct>(exec, vm, baseValue, property.asUInt32(), value);
125 return;
126 }
127
128 if (property.isDouble()) {
129 double propertyAsDouble = property.asDouble();
130 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
131 if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) {
132 scope.release();
133 putByVal<strict, direct>(exec, vm, baseValue, propertyAsUInt32, value);
134 return;
135 }
136 }
137
138 // Don't put to an object if toString throws an exception.
139 auto propertyName = property.toPropertyKey(exec);
140 RETURN_IF_EXCEPTION(scope, void());
141
142 PutPropertySlot slot(baseValue, strict);
143 if (direct) {
144 RELEASE_ASSERT(baseValue.isObject());
145 JSObject* baseObject = asObject(baseValue);
146 if (Optional<uint32_t> index = parseIndex(propertyName)) {
147 scope.release();
148 baseObject->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
149 return;
150 }
151 scope.release();
152 CommonSlowPaths::putDirectWithReify(vm, exec, baseObject, propertyName, value, slot);
153 return;
154 }
155 scope.release();
156 baseValue.put(exec, propertyName, value, slot);
157}
158
159template<bool strict, bool direct>
160ALWAYS_INLINE static void putByValCellInternal(ExecState* exec, VM& vm, JSCell* base, PropertyName propertyName, JSValue value)
161{
162 PutPropertySlot slot(base, strict);
163 if (direct) {
164 RELEASE_ASSERT(base->isObject());
165 JSObject* baseObject = asObject(base);
166 if (Optional<uint32_t> index = parseIndex(propertyName)) {
167 baseObject->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
168 return;
169 }
170 CommonSlowPaths::putDirectWithReify(vm, exec, baseObject, propertyName, value, slot);
171 return;
172 }
173 base->putInline(exec, propertyName, value, slot);
174}
175
176template<bool strict, bool direct>
177ALWAYS_INLINE static void putByValCellStringInternal(ExecState* exec, VM& vm, JSCell* base, JSString* property, JSValue value)
178{
179 auto scope = DECLARE_THROW_SCOPE(vm);
180
181 auto propertyName = property->toIdentifier(exec);
182 RETURN_IF_EXCEPTION(scope, void());
183
184 scope.release();
185 putByValCellInternal<strict, direct>(exec, vm, base, propertyName, value);
186}
187
188template<typename ViewClass>
189char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size, char* vector)
190{
191 VM& vm = exec->vm();
192 NativeCallFrameTracer tracer(&vm, exec);
193 auto scope = DECLARE_THROW_SCOPE(vm);
194
195 if (size < 0) {
196 throwException(exec, scope, createRangeError(exec, "Requested length is negative"_s));
197 return 0;
198 }
199
200 if (vector)
201 return bitwise_cast<char*>(ViewClass::createWithFastVector(exec, structure, size, vector));
202
203 RELEASE_AND_RETURN(scope, bitwise_cast<char*>(ViewClass::create(exec, structure, size)));
204}
205
206template <bool strict>
207static ALWAYS_INLINE void putWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, const Identifier& ident)
208{
209 JSValue baseValue = JSValue::decode(encodedBase);
210 JSValue thisVal = JSValue::decode(encodedThis);
211 JSValue putValue = JSValue::decode(encodedValue);
212 PutPropertySlot slot(thisVal, strict);
213 baseValue.putInline(exec, ident, putValue, slot);
214}
215
216template<typename BigIntOperation, typename Int32Operation>
217static ALWAYS_INLINE EncodedJSValue bitwiseBinaryOp(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, Int32Operation&& int32Op, const char* errorMessage)
218{
219 VM* vm = &exec->vm();
220 NativeCallFrameTracer tracer(vm, exec);
221 auto scope = DECLARE_THROW_SCOPE(*vm);
222
223 JSValue op1 = JSValue::decode(encodedOp1);
224 JSValue op2 = JSValue::decode(encodedOp2);
225
226 auto leftNumeric = op1.toBigIntOrInt32(exec);
227 RETURN_IF_EXCEPTION(scope, encodedJSValue());
228 auto rightNumeric = op2.toBigIntOrInt32(exec);
229 RETURN_IF_EXCEPTION(scope, encodedJSValue());
230
231 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
232 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
233 RELEASE_AND_RETURN(scope, JSValue::encode(bigIntOp(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))));
234
235 return throwVMTypeError(exec, scope, errorMessage);
236 }
237
238 scope.release();
239
240 return JSValue::encode(jsNumber(int32Op(WTF::get<int32_t>(leftNumeric), WTF::get<int32_t>(rightNumeric))));
241}
242
243static ALWAYS_INLINE EncodedJSValue parseIntResult(double input)
244{
245 int asInt = static_cast<int>(input);
246 if (static_cast<double>(asInt) == input)
247 return JSValue::encode(jsNumber(asInt));
248 return JSValue::encode(jsNumber(input));
249}
250
251ALWAYS_INLINE static JSValue getByValObject(ExecState* exec, VM& vm, JSObject* base, PropertyName propertyName)
252{
253 Structure& structure = *base->structure(vm);
254 if (JSCell::canUseFastGetOwnProperty(structure)) {
255 if (JSValue result = base->fastGetOwnProperty(vm, structure, propertyName))
256 return result;
257 }
258 return base->get(exec, propertyName);
259}
260
261extern "C" {
262
263EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
264{
265 VM* vm = &exec->vm();
266 NativeCallFrameTracer tracer(vm, exec);
267
268 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode));
269}
270
271EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp)
272{
273 VM* vm = &exec->vm();
274 NativeCallFrameTracer tracer(vm, exec);
275
276 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode));
277}
278
279JSArray* JIT_OPERATION operationObjectKeys(ExecState* exec, EncodedJSValue encodedObject)
280{
281 VM& vm = exec->vm();
282 NativeCallFrameTracer tracer(&vm, exec);
283 auto scope = DECLARE_THROW_SCOPE(vm);
284
285 JSObject* object = JSValue::decode(encodedObject).toObject(exec);
286 RETURN_IF_EXCEPTION(scope, nullptr);
287 scope.release();
288 return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
289}
290
291JSArray* JIT_OPERATION operationObjectKeysObject(ExecState* exec, JSObject* object)
292{
293 VM& vm = exec->vm();
294 NativeCallFrameTracer tracer(&vm, exec);
295 return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
296}
297
298JSCell* JIT_OPERATION operationObjectCreate(ExecState* exec, EncodedJSValue encodedPrototype)
299{
300 VM& vm = exec->vm();
301 NativeCallFrameTracer tracer(&vm, exec);
302 auto scope = DECLARE_THROW_SCOPE(vm);
303
304 JSValue prototype = JSValue::decode(encodedPrototype);
305
306 if (!prototype.isObject() && !prototype.isNull()) {
307 throwVMTypeError(exec, scope, "Object prototype may only be an Object or null."_s);
308 return nullptr;
309 }
310
311 if (prototype.isObject())
312 RELEASE_AND_RETURN(scope, constructEmptyObject(exec, asObject(prototype)));
313 RELEASE_AND_RETURN(scope, constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure()));
314}
315
316JSCell* JIT_OPERATION operationObjectCreateObject(ExecState* exec, JSObject* prototype)
317{
318 VM& vm = exec->vm();
319 NativeCallFrameTracer tracer(&vm, exec);
320 return constructEmptyObject(exec, prototype);
321}
322
323JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, uint32_t inlineCapacity)
324{
325 VM& vm = exec->vm();
326 NativeCallFrameTracer tracer(&vm, exec);
327 auto scope = DECLARE_THROW_SCOPE(vm);
328 if (constructor->type() == JSFunctionType && jsCast<JSFunction*>(constructor)->canUseAllocationProfile()) {
329 auto rareData = jsCast<JSFunction*>(constructor)->ensureRareDataAndAllocationProfile(exec, inlineCapacity);
330 scope.releaseAssertNoException();
331 ObjectAllocationProfile* allocationProfile = rareData->objectAllocationProfile();
332 Structure* structure = allocationProfile->structure();
333 JSObject* result = constructEmptyObject(exec, structure);
334 if (structure->hasPolyProto()) {
335 JSObject* prototype = allocationProfile->prototype();
336 ASSERT(prototype == jsCast<JSFunction*>(constructor)->prototypeForConstruction(vm, exec));
337 result->putDirect(vm, knownPolyProtoOffset, prototype);
338 prototype->didBecomePrototype();
339 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");
340 }
341 return result;
342 }
343
344 JSValue proto = constructor->get(exec, vm.propertyNames->prototype);
345 RETURN_IF_EXCEPTION(scope, nullptr);
346 if (proto.isObject())
347 return constructEmptyObject(exec, asObject(proto));
348 return constructEmptyObject(exec);
349}
350
351JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedTarget)
352{
353 VM* vm = &exec->vm();
354 NativeCallFrameTracer tracer(vm, exec);
355
356 JSValue value = JSValue::decode(encodedTarget);
357 ASSERT(!value.isObject());
358
359 if (value.isUndefinedOrNull())
360 return constructEmptyObject(exec, globalObject->objectPrototype());
361 return value.toObject(exec, globalObject);
362}
363
364JSCell* JIT_OPERATION operationToObject(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedTarget, UniquedStringImpl* errorMessage)
365{
366 VM* vm = &exec->vm();
367 NativeCallFrameTracer tracer(vm, exec);
368 auto scope = DECLARE_THROW_SCOPE(*vm);
369
370 JSValue value = JSValue::decode(encodedTarget);
371 ASSERT(!value.isObject());
372
373 if (UNLIKELY(value.isUndefinedOrNull())) {
374 if (errorMessage->length()) {
375 throwVMTypeError(exec, scope, errorMessage);
376 return nullptr;
377 }
378 }
379
380 RELEASE_AND_RETURN(scope, value.toObject(exec, globalObject));
381}
382
383EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState* exec, EncodedJSValue encodedOp1)
384{
385 VM* vm = &exec->vm();
386 NativeCallFrameTracer tracer(vm, exec);
387 auto scope = DECLARE_THROW_SCOPE(*vm);
388
389 JSValue op1 = JSValue::decode(encodedOp1);
390
391 auto operandNumeric = op1.toBigIntOrInt32(exec);
392 RETURN_IF_EXCEPTION(scope, encodedJSValue());
393
394 if (WTF::holds_alternative<JSBigInt*>(operandNumeric))
395 RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric))));
396
397 return JSValue::encode(jsNumber(~WTF::get<int32_t>(operandNumeric)));
398}
399
400EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
401{
402 auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
403 return JSBigInt::bitwiseAnd(exec, left, right);
404 };
405
406 auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
407 return left & right;
408 };
409
410 return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'and' operation."_s);
411}
412
413EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
414{
415 auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
416 return JSBigInt::bitwiseOr(exec, left, right);
417 };
418
419 auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
420 return left | right;
421 };
422
423 return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'or' operation."_s);
424}
425
426EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
427{
428 auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
429 return JSBigInt::bitwiseXor(exec, left, right);
430 };
431
432 auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
433 return left ^ right;
434 };
435
436 return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'xor' operation."_s);
437}
438
439EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
440{
441 VM* vm = &exec->vm();
442 NativeCallFrameTracer tracer(vm, exec);
443 auto scope = DECLARE_THROW_SCOPE(*vm);
444
445 JSValue op1 = JSValue::decode(encodedOp1);
446 JSValue op2 = JSValue::decode(encodedOp2);
447
448 int32_t a = op1.toInt32(exec);
449 RETURN_IF_EXCEPTION(scope, encodedJSValue());
450 scope.release();
451 uint32_t b = op2.toUInt32(exec);
452 return JSValue::encode(jsNumber(a << (b & 0x1f)));
453}
454
455EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
456{
457 VM* vm = &exec->vm();
458 NativeCallFrameTracer tracer(vm, exec);
459 auto scope = DECLARE_THROW_SCOPE(*vm);
460
461 JSValue op1 = JSValue::decode(encodedOp1);
462 JSValue op2 = JSValue::decode(encodedOp2);
463
464 int32_t a = op1.toInt32(exec);
465 RETURN_IF_EXCEPTION(scope, encodedJSValue());
466 scope.release();
467 uint32_t b = op2.toUInt32(exec);
468 return JSValue::encode(jsNumber(a >> (b & 0x1f)));
469}
470
471EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
472{
473 VM* vm = &exec->vm();
474 NativeCallFrameTracer tracer(vm, exec);
475 auto scope = DECLARE_THROW_SCOPE(*vm);
476
477 JSValue op1 = JSValue::decode(encodedOp1);
478 JSValue op2 = JSValue::decode(encodedOp2);
479
480 uint32_t a = op1.toUInt32(exec);
481 RETURN_IF_EXCEPTION(scope, encodedJSValue());
482 scope.release();
483 uint32_t b = op2.toUInt32(exec);
484 return JSValue::encode(jsNumber(static_cast<int32_t>(a >> (b & 0x1f))));
485}
486
487EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
488{
489 VM* vm = &exec->vm();
490 NativeCallFrameTracer tracer(vm, exec);
491
492 JSValue op1 = JSValue::decode(encodedOp1);
493 JSValue op2 = JSValue::decode(encodedOp2);
494
495 return JSValue::encode(jsAddNonNumber(exec, op1, op2));
496}
497
498EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
499{
500 VM* vm = &exec->vm();
501 NativeCallFrameTracer tracer(vm, exec);
502 auto scope = DECLARE_THROW_SCOPE(*vm);
503
504 JSValue op1 = JSValue::decode(encodedOp1);
505 JSValue op2 = JSValue::decode(encodedOp2);
506
507 auto leftNumeric = op1.toNumeric(exec);
508 RETURN_IF_EXCEPTION(scope, encodedJSValue());
509 auto rightNumeric = op2.toNumeric(exec);
510 RETURN_IF_EXCEPTION(scope, encodedJSValue());
511
512 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
513 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
514 JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
515 RETURN_IF_EXCEPTION(scope, encodedJSValue());
516 return JSValue::encode(result);
517 }
518
519 return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in division operation.");
520 }
521
522 scope.release();
523
524 double a = WTF::get<double>(leftNumeric);
525 double b = WTF::get<double>(rightNumeric);
526 return JSValue::encode(jsNumber(a / b));
527}
528
529double JIT_OPERATION operationArithAbs(ExecState* exec, EncodedJSValue encodedOp1)
530{
531 VM* vm = &exec->vm();
532 NativeCallFrameTracer tracer(vm, exec);
533 auto scope = DECLARE_THROW_SCOPE(*vm);
534
535 JSValue op1 = JSValue::decode(encodedOp1);
536 double a = op1.toNumber(exec);
537 RETURN_IF_EXCEPTION(scope, PNaN);
538 return fabs(a);
539}
540
541uint32_t JIT_OPERATION operationArithClz32(ExecState* exec, EncodedJSValue encodedOp1)
542{
543 VM* vm = &exec->vm();
544 NativeCallFrameTracer tracer(vm, exec);
545 auto scope = DECLARE_THROW_SCOPE(*vm);
546
547 JSValue op1 = JSValue::decode(encodedOp1);
548 uint32_t value = op1.toUInt32(exec);
549 RETURN_IF_EXCEPTION(scope, 0);
550 return clz(value);
551}
552
553double JIT_OPERATION operationArithFRound(ExecState* exec, EncodedJSValue encodedOp1)
554{
555 VM* vm = &exec->vm();
556 NativeCallFrameTracer tracer(vm, exec);
557 auto scope = DECLARE_THROW_SCOPE(*vm);
558
559 JSValue op1 = JSValue::decode(encodedOp1);
560 double a = op1.toNumber(exec);
561 RETURN_IF_EXCEPTION(scope, PNaN);
562 return static_cast<float>(a);
563}
564
565#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
566double JIT_OPERATION operationArith##capitalizedName(ExecState* exec, EncodedJSValue encodedOp1) \
567{ \
568 VM* vm = &exec->vm(); \
569 NativeCallFrameTracer tracer(vm, exec); \
570 auto scope = DECLARE_THROW_SCOPE(*vm); \
571 JSValue op1 = JSValue::decode(encodedOp1); \
572 double result = op1.toNumber(exec); \
573 RETURN_IF_EXCEPTION(scope, PNaN); \
574 return JSC::Math::lowerName(result); \
575}
576 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
577#undef DFG_ARITH_UNARY
578
579double JIT_OPERATION operationArithSqrt(ExecState* exec, EncodedJSValue encodedOp1)
580{
581 VM* vm = &exec->vm();
582 NativeCallFrameTracer tracer(vm, exec);
583 auto scope = DECLARE_THROW_SCOPE(*vm);
584
585 JSValue op1 = JSValue::decode(encodedOp1);
586 double a = op1.toNumber(exec);
587 RETURN_IF_EXCEPTION(scope, PNaN);
588 return sqrt(a);
589}
590
591EncodedJSValue JIT_OPERATION operationArithRound(ExecState* exec, EncodedJSValue encodedArgument)
592{
593 VM* vm = &exec->vm();
594 NativeCallFrameTracer tracer(vm, exec);
595 auto scope = DECLARE_THROW_SCOPE(*vm);
596
597 JSValue argument = JSValue::decode(encodedArgument);
598 double valueOfArgument = argument.toNumber(exec);
599 RETURN_IF_EXCEPTION(scope, encodedJSValue());
600 return JSValue::encode(jsNumber(jsRound(valueOfArgument)));
601}
602
603EncodedJSValue JIT_OPERATION operationArithFloor(ExecState* exec, EncodedJSValue encodedArgument)
604{
605 VM* vm = &exec->vm();
606 NativeCallFrameTracer tracer(vm, exec);
607 auto scope = DECLARE_THROW_SCOPE(*vm);
608
609 JSValue argument = JSValue::decode(encodedArgument);
610 double valueOfArgument = argument.toNumber(exec);
611 RETURN_IF_EXCEPTION(scope, encodedJSValue());
612 return JSValue::encode(jsNumber(floor(valueOfArgument)));
613}
614
615EncodedJSValue JIT_OPERATION operationArithCeil(ExecState* exec, EncodedJSValue encodedArgument)
616{
617 VM* vm = &exec->vm();
618 NativeCallFrameTracer tracer(vm, exec);
619 auto scope = DECLARE_THROW_SCOPE(*vm);
620
621 JSValue argument = JSValue::decode(encodedArgument);
622 double valueOfArgument = argument.toNumber(exec);
623 RETURN_IF_EXCEPTION(scope, encodedJSValue());
624 return JSValue::encode(jsNumber(ceil(valueOfArgument)));
625}
626
627EncodedJSValue JIT_OPERATION operationArithTrunc(ExecState* exec, EncodedJSValue encodedArgument)
628{
629 VM* vm = &exec->vm();
630 NativeCallFrameTracer tracer(vm, exec);
631 auto scope = DECLARE_THROW_SCOPE(*vm);
632
633 JSValue argument = JSValue::decode(encodedArgument);
634 double truncatedValueOfArgument = argument.toIntegerPreserveNaN(exec);
635 RETURN_IF_EXCEPTION(scope, encodedJSValue());
636 return JSValue::encode(jsNumber(truncatedValueOfArgument));
637}
638
639static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
640{
641 VM& vm = exec->vm();
642 NativeCallFrameTracer tracer(&vm, exec);
643
644 if (base->isObject()) {
645 JSObject* object = asObject(base);
646 if (object->canGetIndexQuickly(index))
647 return JSValue::encode(object->getIndexQuickly(index));
648 }
649
650 if (isJSString(base) && asString(base)->canGetIndex(index))
651 return JSValue::encode(asString(base)->getIndex(exec, index));
652
653 return JSValue::encode(JSValue(base).get(exec, index));
654}
655
656EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
657{
658 VM& vm = exec->vm();
659 NativeCallFrameTracer tracer(&vm, exec);
660 auto scope = DECLARE_THROW_SCOPE(vm);
661
662 JSValue baseValue = JSValue::decode(encodedBase);
663 JSValue property = JSValue::decode(encodedProperty);
664
665 if (LIKELY(baseValue.isCell())) {
666 JSCell* base = baseValue.asCell();
667
668 if (property.isUInt32())
669 RELEASE_AND_RETURN(scope, getByVal(exec, base, property.asUInt32()));
670
671 if (property.isDouble()) {
672 double propertyAsDouble = property.asDouble();
673 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
674 if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
675 RELEASE_AND_RETURN(scope, getByVal(exec, base, propertyAsUInt32));
676
677 } else if (property.isString()) {
678 Structure& structure = *base->structure(vm);
679 if (JSCell::canUseFastGetOwnProperty(structure)) {
680 RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec);
681 RETURN_IF_EXCEPTION(scope, encodedJSValue());
682 if (existingAtomicString) {
683 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
684 return JSValue::encode(result);
685 }
686 }
687 }
688 }
689
690 baseValue.requireObjectCoercible(exec);
691 RETURN_IF_EXCEPTION(scope, encodedJSValue());
692 auto propertyName = property.toPropertyKey(exec);
693 RETURN_IF_EXCEPTION(scope, encodedJSValue());
694 RELEASE_AND_RETURN(scope, JSValue::encode(baseValue.get(exec, propertyName)));
695}
696
697EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
698{
699 VM& vm = exec->vm();
700 NativeCallFrameTracer tracer(&vm, exec);
701 auto scope = DECLARE_THROW_SCOPE(vm);
702
703 JSValue property = JSValue::decode(encodedProperty);
704
705 if (property.isUInt32())
706 RELEASE_AND_RETURN(scope, getByVal(exec, base, property.asUInt32()));
707
708 if (property.isDouble()) {
709 double propertyAsDouble = property.asDouble();
710 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
711 if (propertyAsUInt32 == propertyAsDouble)
712 RELEASE_AND_RETURN(scope, getByVal(exec, base, propertyAsUInt32));
713
714 } else if (property.isString()) {
715 Structure& structure = *base->structure(vm);
716 if (JSCell::canUseFastGetOwnProperty(structure)) {
717 RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec);
718 RETURN_IF_EXCEPTION(scope, encodedJSValue());
719 if (existingAtomicString) {
720 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
721 return JSValue::encode(result);
722 }
723 }
724 }
725
726 auto propertyName = property.toPropertyKey(exec);
727 RETURN_IF_EXCEPTION(scope, encodedJSValue());
728 RELEASE_AND_RETURN(scope, JSValue::encode(JSValue(base).get(exec, propertyName)));
729}
730
731ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
732{
733 VM* vm = &exec->vm();
734 NativeCallFrameTracer tracer(vm, exec);
735
736 if (index < 0) {
737 // Go the slowest way possible because negative indices don't use indexed storage.
738 return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
739 }
740
741 // Use this since we know that the value is out of bounds.
742 return JSValue::encode(JSValue(base).get(exec, static_cast<unsigned>(index)));
743}
744
745EncodedJSValue JIT_OPERATION operationGetByValObjectInt(ExecState* exec, JSObject* base, int32_t index)
746{
747 return getByValCellInt(exec, base, index);
748}
749
750EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
751{
752 return getByValCellInt(exec, base, index);
753}
754
755EncodedJSValue JIT_OPERATION operationGetByValObjectString(ExecState* exec, JSCell* base, JSCell* string)
756{
757 VM& vm = exec->vm();
758 NativeCallFrameTracer tracer(&vm, exec);
759
760 auto scope = DECLARE_THROW_SCOPE(vm);
761
762 auto propertyName = asString(string)->toIdentifier(exec);
763 RETURN_IF_EXCEPTION(scope, encodedJSValue());
764
765 RELEASE_AND_RETURN(scope, JSValue::encode(getByValObject(exec, vm, asObject(base), propertyName)));
766}
767
768EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(ExecState* exec, JSCell* base, JSCell* symbol)
769{
770 VM& vm = exec->vm();
771 NativeCallFrameTracer tracer(&vm, exec);
772
773 auto propertyName = asSymbol(symbol)->privateName();
774 return JSValue::encode(getByValObject(exec, vm, asObject(base), propertyName));
775}
776
777void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
778{
779 VM& vm = exec->vm();
780 NativeCallFrameTracer tracer(&vm, exec);
781
782 putByValInternal<true, false>(exec, vm, encodedBase, encodedProperty, encodedValue);
783}
784
785void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
786{
787 VM& vm = exec->vm();
788 NativeCallFrameTracer tracer(&vm, exec);
789
790 putByValInternal<false, false>(exec, vm, encodedBase, encodedProperty, encodedValue);
791}
792
793void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
794{
795 VM& vm = exec->vm();
796 NativeCallFrameTracer tracer(&vm, exec);
797
798 putByValInternal<true, false>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
799}
800
801void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
802{
803 VM& vm = exec->vm();
804 NativeCallFrameTracer tracer(&vm, exec);
805
806 putByValInternal<false, false>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
807}
808
809void JIT_OPERATION operationPutByValCellStringStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
810{
811 VM& vm = exec->vm();
812 NativeCallFrameTracer tracer(&vm, exec);
813
814 putByValCellStringInternal<true, false>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
815}
816
817void JIT_OPERATION operationPutByValCellStringNonStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
818{
819 VM& vm = exec->vm();
820 NativeCallFrameTracer tracer(&vm, exec);
821
822 putByValCellStringInternal<false, false>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
823}
824
825void JIT_OPERATION operationPutByValCellSymbolStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
826{
827 VM& vm = exec->vm();
828 NativeCallFrameTracer tracer(&vm, exec);
829
830 auto propertyName = asSymbol(symbol)->privateName();
831 putByValCellInternal<true, false>(exec, vm, cell, propertyName, JSValue::decode(encodedValue));
832}
833
834void JIT_OPERATION operationPutByValCellSymbolNonStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
835{
836 VM& vm = exec->vm();
837 NativeCallFrameTracer tracer(&vm, exec);
838
839 auto propertyName = asSymbol(symbol)->privateName();
840 putByValCellInternal<false, false>(exec, vm, cell, propertyName, JSValue::decode(encodedValue));
841}
842
843void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
844{
845 VM& vm = exec->vm();
846 NativeCallFrameTracer tracer(&vm, exec);
847
848 if (index >= 0) {
849 object->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
850 return;
851 }
852
853 PutPropertySlot slot(object, true);
854 object->methodTable(vm)->put(
855 object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
856}
857
858void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
859{
860 VM* vm = &exec->vm();
861 NativeCallFrameTracer tracer(vm, exec);
862
863 if (index >= 0) {
864 object->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
865 return;
866 }
867
868 PutPropertySlot slot(object, false);
869 object->methodTable(*vm)->put(
870 object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
871}
872
873void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
874{
875 VM* vm = &exec->vm();
876 NativeCallFrameTracer tracer(vm, exec);
877
878 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
879
880 if (index >= 0) {
881 object->putByIndexInline(exec, index, jsValue, true);
882 return;
883 }
884
885 PutPropertySlot slot(object, true);
886 object->methodTable(*vm)->put(
887 object, exec, Identifier::from(exec, index), jsValue, slot);
888}
889
890void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
891{
892 VM* vm = &exec->vm();
893 NativeCallFrameTracer tracer(vm, exec);
894
895 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
896
897 if (index >= 0) {
898 object->putByIndexInline(exec, index, jsValue, false);
899 return;
900 }
901
902 PutPropertySlot slot(object, false);
903 object->methodTable(*vm)->put(
904 object, exec, Identifier::from(exec, index), jsValue, slot);
905}
906
907void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
908{
909 VM& vm = exec->vm();
910 NativeCallFrameTracer tracer(&vm, exec);
911
912 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
913
914 if (index >= 0) {
915 object->putDirectIndex(exec, index, jsValue, 0, PutDirectIndexShouldThrow);
916 return;
917 }
918
919 PutPropertySlot slot(object, true);
920 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), jsValue, slot);
921}
922
923void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
924{
925 VM& vm = exec->vm();
926 NativeCallFrameTracer tracer(&vm, exec);
927
928 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
929
930 if (index >= 0) {
931 object->putDirectIndex(exec, index, jsValue);
932 return;
933 }
934
935 PutPropertySlot slot(object, false);
936 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), jsValue, slot);
937}
938
939void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
940{
941 VM& vm = exec->vm();
942 NativeCallFrameTracer tracer(&vm, exec);
943
944 putByValInternal<true, true>(exec, vm, encodedBase, encodedProperty, encodedValue);
945}
946
947void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
948{
949 VM& vm = exec->vm();
950 NativeCallFrameTracer tracer(&vm, exec);
951
952 putByValInternal<false, true>(exec, vm, encodedBase, encodedProperty, encodedValue);
953}
954
955void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
956{
957 VM& vm = exec->vm();
958 NativeCallFrameTracer tracer(&vm, exec);
959
960 putByValInternal<true, true>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
961}
962
963void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
964{
965 VM& vm = exec->vm();
966 NativeCallFrameTracer tracer(&vm, exec);
967
968 putByValInternal<false, true>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
969}
970
971void JIT_OPERATION operationPutByValDirectCellStringStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
972{
973 VM& vm = exec->vm();
974 NativeCallFrameTracer tracer(&vm, exec);
975
976 putByValCellStringInternal<true, true>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
977}
978
979void JIT_OPERATION operationPutByValDirectCellStringNonStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
980{
981 VM& vm = exec->vm();
982 NativeCallFrameTracer tracer(&vm, exec);
983
984 putByValCellStringInternal<false, true>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
985}
986
987void JIT_OPERATION operationPutByValDirectCellSymbolStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
988{
989 VM& vm = exec->vm();
990 NativeCallFrameTracer tracer(&vm, exec);
991
992 auto propertyName = asSymbol(symbol)->privateName();
993 putByValCellInternal<true, true>(exec, vm, cell, propertyName, JSValue::decode(encodedValue));
994}
995
996void JIT_OPERATION operationPutByValDirectCellSymbolNonStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
997{
998 VM& vm = exec->vm();
999 NativeCallFrameTracer tracer(&vm, exec);
1000
1001 auto propertyName = asSymbol(symbol)->privateName();
1002 putByValCellInternal<false, true>(exec, vm, cell, propertyName, JSValue::decode(encodedValue));
1003}
1004
1005void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
1006{
1007 VM& vm = exec->vm();
1008 NativeCallFrameTracer tracer(&vm, exec);
1009 if (index >= 0) {
1010 object->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
1011 return;
1012 }
1013
1014 PutPropertySlot slot(object, true);
1015 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
1016}
1017
1018void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
1019{
1020 VM& vm = exec->vm();
1021 NativeCallFrameTracer tracer(&vm, exec);
1022
1023 if (index >= 0) {
1024 object->putDirectIndex(exec, index, JSValue::decode(encodedValue));
1025 return;
1026 }
1027
1028 PutPropertySlot slot(object, false);
1029 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
1030}
1031
1032EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
1033{
1034 VM* vm = &exec->vm();
1035 NativeCallFrameTracer tracer(vm, exec);
1036
1037 array->pushInline(exec, JSValue::decode(encodedValue));
1038 return JSValue::encode(jsNumber(array->length()));
1039}
1040
1041EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
1042{
1043 VM* vm = &exec->vm();
1044 NativeCallFrameTracer tracer(vm, exec);
1045
1046 array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, value));
1047 return JSValue::encode(jsNumber(array->length()));
1048}
1049
1050EncodedJSValue JIT_OPERATION operationArrayPushMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
1051{
1052 VM& vm = exec->vm();
1053 NativeCallFrameTracer tracer(&vm, exec);
1054 auto scope = DECLARE_THROW_SCOPE(vm);
1055
1056 // We assume that multiple JSArray::push calls with ArrayWithInt32/ArrayWithContiguous do not cause JS traps.
1057 // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
1058 // content of ScratchBuffer. If the IndexingType is now ArrayWithInt32/ArrayWithContiguous, we can ensure
1059 // that there is no indexed accessors in this object and its prototype chain.
1060 //
1061 // ArrayWithArrayStorage is also OK. It can have indexed accessors. But if you define an indexed accessor, the array's length
1062 // becomes larger than that index. So Array#push never overlaps with this accessor. So accessors are never called unless
1063 // the IndexingType is ArrayWithSlowPutArrayStorage which could have an indexed accessor in a prototype chain.
1064 RELEASE_ASSERT(!shouldUseSlowPut(array->indexingType()));
1065
1066 EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
1067 for (int32_t i = 0; i < elementCount; ++i) {
1068 array->pushInline(exec, JSValue::decode(values[i]));
1069 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1070 }
1071 return JSValue::encode(jsNumber(array->length()));
1072}
1073
1074EncodedJSValue JIT_OPERATION operationArrayPushDoubleMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
1075{
1076 VM& vm = exec->vm();
1077 NativeCallFrameTracer tracer(&vm, exec);
1078 auto scope = DECLARE_THROW_SCOPE(vm);
1079
1080 // We assume that multiple JSArray::push calls with ArrayWithDouble do not cause JS traps.
1081 // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
1082 // content of ScratchBuffer. If the IndexingType is now ArrayWithDouble, we can ensure
1083 // that there is no indexed accessors in this object and its prototype chain.
1084 ASSERT(array->indexingMode() == ArrayWithDouble);
1085
1086 double* values = static_cast<double*>(buffer);
1087 for (int32_t i = 0; i < elementCount; ++i) {
1088 array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, values[i]));
1089 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1090 }
1091 return JSValue::encode(jsNumber(array->length()));
1092}
1093
1094EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
1095{
1096 VM* vm = &exec->vm();
1097 NativeCallFrameTracer tracer(vm, exec);
1098
1099 return JSValue::encode(array->pop(exec));
1100}
1101
1102EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array)
1103{
1104 VM* vm = &exec->vm();
1105 NativeCallFrameTracer tracer(vm, exec);
1106
1107 array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1);
1108
1109 return JSValue::encode(array->pop(exec));
1110}
1111
1112EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
1113{
1114 SuperSamplerScope superSamplerScope(false);
1115
1116 VM& vm = globalObject->vm();
1117 NativeCallFrameTracer tracer(&vm, exec);
1118
1119 return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
1120}
1121
1122EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
1123{
1124 SuperSamplerScope superSamplerScope(false);
1125
1126 VM& vm = globalObject->vm();
1127 NativeCallFrameTracer tracer(&vm, exec);
1128 auto scope = DECLARE_THROW_SCOPE(vm);
1129
1130 JSValue argument = JSValue::decode(encodedArgument);
1131
1132 JSString* input = argument.toStringOrNull(exec);
1133 EXCEPTION_ASSERT(!!scope.exception() == !input);
1134 if (!input)
1135 return encodedJSValue();
1136 RELEASE_AND_RETURN(scope, JSValue::encode(regExpObject->execInline(exec, globalObject, input)));
1137}
1138
1139EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
1140{
1141 SuperSamplerScope superSamplerScope(false);
1142
1143 VM& vm = globalObject->vm();
1144 NativeCallFrameTracer tracer(&vm, exec);
1145 auto scope = DECLARE_THROW_SCOPE(vm);
1146
1147 JSValue base = JSValue::decode(encodedBase);
1148 JSValue argument = JSValue::decode(encodedArgument);
1149
1150 auto* regexp = jsDynamicCast<RegExpObject*>(vm, base);
1151 if (UNLIKELY(!regexp))
1152 return throwVMTypeError(exec, scope);
1153
1154 JSString* input = argument.toStringOrNull(exec);
1155 EXCEPTION_ASSERT(!!scope.exception() == !input);
1156 if (!input)
1157 return JSValue::encode(jsUndefined());
1158 RELEASE_AND_RETURN(scope, JSValue::encode(regexp->exec(exec, globalObject, input)));
1159}
1160
1161EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string)
1162{
1163 SuperSamplerScope superSamplerScope(false);
1164
1165 VM& vm = globalObject->vm();
1166 NativeCallFrameTracer tracer(&vm, exec);
1167
1168 auto scope = DECLARE_THROW_SCOPE(vm);
1169
1170 String input = string->value(exec);
1171 RETURN_IF_EXCEPTION(scope, { });
1172
1173 unsigned lastIndex = 0;
1174 MatchResult result;
1175 JSArray* array = createRegExpMatchesArray(vm, globalObject, string, input, regExp, lastIndex, result);
1176 if (!array) {
1177 ASSERT(!scope.exception());
1178 return JSValue::encode(jsNull());
1179 }
1180
1181 RETURN_IF_EXCEPTION(scope, { });
1182 globalObject->regExpGlobalData().recordMatch(vm, globalObject, regExp, string, result);
1183 return JSValue::encode(array);
1184}
1185
1186EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
1187{
1188 SuperSamplerScope superSamplerScope(false);
1189
1190 VM& vm = globalObject->vm();
1191 NativeCallFrameTracer tracer(&vm, exec);
1192
1193 if (!regExpObject->regExp()->global())
1194 return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
1195 return JSValue::encode(regExpObject->matchGlobal(exec, globalObject, argument));
1196}
1197
1198EncodedJSValue JIT_OPERATION operationRegExpMatchFastGlobalString(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string)
1199{
1200 SuperSamplerScope superSamplerScope(false);
1201
1202 VM& vm = globalObject->vm();
1203 NativeCallFrameTracer tracer(&vm, exec);
1204
1205 auto scope = DECLARE_THROW_SCOPE(vm);
1206
1207 ASSERT(regExp->global());
1208
1209 String s = string->value(exec);
1210 RETURN_IF_EXCEPTION(scope, { });
1211
1212 if (regExp->unicode()) {
1213 unsigned stringLength = s.length();
1214 RELEASE_AND_RETURN(scope, JSValue::encode(collectMatches(
1215 vm, exec, string, s, globalObject, regExp,
1216 [&] (size_t end) -> size_t {
1217 return advanceStringUnicode(s, stringLength, end);
1218 })));
1219 }
1220
1221 RELEASE_AND_RETURN(scope, JSValue::encode(collectMatches(
1222 vm, exec, string, s, globalObject, regExp,
1223 [&] (size_t end) -> size_t {
1224 return end + 1;
1225 })));
1226}
1227
1228EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value)
1229{
1230 VM& vm = exec->vm();
1231 NativeCallFrameTracer tracer(&vm, exec);
1232
1233 return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
1234 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
1235 return parseIntResult(parseInt(view, 0));
1236 });
1237}
1238
1239EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState* exec, JSString* string)
1240{
1241 VM& vm = exec->vm();
1242 NativeCallFrameTracer tracer(&vm, exec);
1243 auto scope = DECLARE_THROW_SCOPE(vm);
1244
1245 auto viewWithString = string->viewWithUnderlyingString(exec);
1246 RETURN_IF_EXCEPTION(scope, { });
1247
1248 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
1249 return parseIntResult(parseInt(viewWithString.view, 0));
1250}
1251
1252EncodedJSValue JIT_OPERATION operationParseIntString(ExecState* exec, JSString* string, int32_t radix)
1253{
1254 VM& vm = exec->vm();
1255 NativeCallFrameTracer tracer(&vm, exec);
1256 auto scope = DECLARE_THROW_SCOPE(vm);
1257
1258 auto viewWithString = string->viewWithUnderlyingString(exec);
1259 RETURN_IF_EXCEPTION(scope, { });
1260
1261 return parseIntResult(parseInt(viewWithString.view, radix));
1262}
1263
1264EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState* exec, EncodedJSValue value, int32_t radix)
1265{
1266 VM& vm = exec->vm();
1267 NativeCallFrameTracer tracer(&vm, exec);
1268
1269 return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
1270 return parseIntResult(parseInt(view, radix));
1271 });
1272}
1273
1274size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* input)
1275{
1276 SuperSamplerScope superSamplerScope(false);
1277
1278 VM& vm = globalObject->vm();
1279 NativeCallFrameTracer tracer(&vm, exec);
1280
1281 return regExpObject->testInline(exec, globalObject, input);
1282}
1283
1284size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
1285{
1286 SuperSamplerScope superSamplerScope(false);
1287
1288 VM& vm = globalObject->vm();
1289 NativeCallFrameTracer tracer(&vm, exec);
1290
1291 JSValue argument = JSValue::decode(encodedArgument);
1292
1293 JSString* input = argument.toStringOrNull(exec);
1294 if (!input)
1295 return false;
1296 return regExpObject->testInline(exec, globalObject, input);
1297}
1298
1299size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
1300{
1301 SuperSamplerScope superSamplerScope(false);
1302
1303 VM& vm = globalObject->vm();
1304 NativeCallFrameTracer tracer(&vm, exec);
1305 auto scope = DECLARE_THROW_SCOPE(vm);
1306
1307 JSValue base = JSValue::decode(encodedBase);
1308 JSValue argument = JSValue::decode(encodedArgument);
1309
1310 auto* regexp = jsDynamicCast<RegExpObject*>(vm, base);
1311 if (UNLIKELY(!regexp)) {
1312 throwTypeError(exec, scope);
1313 return false;
1314 }
1315
1316 JSString* input = argument.toStringOrNull(exec);
1317 EXCEPTION_ASSERT(!!scope.exception() == !input);
1318 if (!input)
1319 return false;
1320 RELEASE_AND_RETURN(scope, regexp->test(exec, globalObject, input));
1321}
1322
1323JSCell* JIT_OPERATION operationSubBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1324{
1325 VM* vm = &exec->vm();
1326 NativeCallFrameTracer tracer(vm, exec);
1327
1328 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1329 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1330
1331 return JSBigInt::sub(exec, leftOperand, rightOperand);
1332}
1333
1334JSCell* JIT_OPERATION operationBitNotBigInt(ExecState* exec, JSCell* op1)
1335{
1336 VM* vm = &exec->vm();
1337 NativeCallFrameTracer tracer(vm, exec);
1338
1339 JSBigInt* operand = jsCast<JSBigInt*>(op1);
1340
1341 return JSBigInt::bitwiseNot(exec, operand);
1342}
1343
1344JSCell* JIT_OPERATION operationMulBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1345{
1346 VM* vm = &exec->vm();
1347 NativeCallFrameTracer tracer(vm, exec);
1348
1349 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1350 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1351
1352 return JSBigInt::multiply(exec, leftOperand, rightOperand);
1353}
1354
1355JSCell* JIT_OPERATION operationDivBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1356{
1357 VM* vm = &exec->vm();
1358 NativeCallFrameTracer tracer(vm, exec);
1359
1360 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1361 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1362
1363 return JSBigInt::divide(exec, leftOperand, rightOperand);
1364}
1365
1366JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1367{
1368 VM* vm = &exec->vm();
1369 NativeCallFrameTracer tracer(vm, exec);
1370
1371 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1372 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1373
1374 return JSBigInt::bitwiseAnd(exec, leftOperand, rightOperand);
1375}
1376
1377JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1378{
1379 VM* vm = &exec->vm();
1380 NativeCallFrameTracer tracer(vm, exec);
1381
1382 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1383 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1384
1385 return JSBigInt::add(exec, leftOperand, rightOperand);
1386}
1387
1388JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1389{
1390 VM* vm = &exec->vm();
1391 NativeCallFrameTracer tracer(vm, exec);
1392
1393 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1394 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1395
1396 return JSBigInt::bitwiseOr(exec, leftOperand, rightOperand);
1397}
1398
1399JSCell* JIT_OPERATION operationBitXorBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
1400{
1401 VM* vm = &exec->vm();
1402 NativeCallFrameTracer tracer(vm, exec);
1403
1404 JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
1405 JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
1406
1407 return JSBigInt::bitwiseXor(exec, leftOperand, rightOperand);
1408}
1409
1410size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2)
1411{
1412 VM* vm = &exec->vm();
1413 NativeCallFrameTracer tracer(vm, exec);
1414
1415 return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
1416}
1417
1418size_t JIT_OPERATION operationSameValue(ExecState* exec, EncodedJSValue arg1, EncodedJSValue arg2)
1419{
1420 VM& vm = exec->vm();
1421 NativeCallFrameTracer tracer(&vm, exec);
1422
1423 return sameValue(exec, JSValue::decode(arg1), JSValue::decode(arg2));
1424}
1425
1426EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
1427{
1428 VM* vm = &exec->vm();
1429 NativeCallFrameTracer tracer(vm, exec);
1430
1431 return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
1432}
1433
1434EncodedJSValue JIT_OPERATION operationToNumber(ExecState* exec, EncodedJSValue value)
1435{
1436 VM* vm = &exec->vm();
1437 NativeCallFrameTracer tracer(vm, exec);
1438
1439 return JSValue::encode(jsNumber(JSValue::decode(value).toNumber(exec)));
1440}
1441
1442EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
1443{
1444 VM& vm = exec->vm();
1445 NativeCallFrameTracer tracer(&vm, exec);
1446 auto scope = DECLARE_THROW_SCOPE(vm);
1447
1448 JSValue baseValue = JSValue::decode(encodedBase);
1449 JSValue thisVal = JSValue::decode(encodedThis);
1450 JSValue subscript = JSValue::decode(encodedSubscript);
1451
1452 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1453 Structure& structure = *baseValue.asCell()->structure(vm);
1454 if (JSCell::canUseFastGetOwnProperty(structure)) {
1455 RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec);
1456 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1457 if (existingAtomicString) {
1458 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
1459 return JSValue::encode(result);
1460 }
1461 }
1462 }
1463
1464 PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
1465 if (subscript.isUInt32()) {
1466 uint32_t i = subscript.asUInt32();
1467 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1468 return JSValue::encode(asString(baseValue)->getIndex(exec, i));
1469
1470 RELEASE_AND_RETURN(scope, JSValue::encode(baseValue.get(exec, i, slot)));
1471 }
1472
1473 baseValue.requireObjectCoercible(exec);
1474 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1475
1476 auto property = subscript.toPropertyKey(exec);
1477 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1478 RELEASE_AND_RETURN(scope, JSValue::encode(baseValue.get(exec, property, slot)));
1479}
1480
1481void JIT_OPERATION operationPutByIdWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
1482{
1483 VM& vm = exec->vm();
1484 NativeCallFrameTracer tracer(&vm, exec);
1485
1486 putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
1487}
1488
1489void JIT_OPERATION operationPutByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
1490{
1491 VM& vm = exec->vm();
1492 NativeCallFrameTracer tracer(&vm, exec);
1493
1494 putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
1495}
1496
1497void JIT_OPERATION operationPutByValWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
1498{
1499 VM& vm = exec->vm();
1500 NativeCallFrameTracer tracer(&vm, exec);
1501 auto scope = DECLARE_THROW_SCOPE(vm);
1502
1503 Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
1504 RETURN_IF_EXCEPTION(scope, void());
1505 scope.release();
1506 putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, property);
1507}
1508
1509void JIT_OPERATION operationPutByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
1510{
1511 VM& vm = exec->vm();
1512 NativeCallFrameTracer tracer(&vm, exec);
1513 auto scope = DECLARE_THROW_SCOPE(vm);
1514
1515 Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
1516 RETURN_IF_EXCEPTION(scope, void());
1517 scope.release();
1518 putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, property);
1519}
1520
1521ALWAYS_INLINE static void defineDataProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSValue value, int32_t attributes)
1522{
1523 PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes));
1524 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1525 if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
1526 JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
1527 else
1528 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1529}
1530
1531void JIT_OPERATION operationDefineDataProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, EncodedJSValue encodedValue, int32_t attributes)
1532{
1533 VM& vm = exec->vm();
1534 NativeCallFrameTracer tracer(&vm, exec);
1535 auto scope = DECLARE_THROW_SCOPE(vm);
1536
1537 Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
1538 RETURN_IF_EXCEPTION(scope, void());
1539 scope.release();
1540 defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
1541}
1542
1543void JIT_OPERATION operationDefineDataPropertyString(ExecState* exec, JSObject* base, JSString* property, EncodedJSValue encodedValue, int32_t attributes)
1544{
1545 VM& vm = exec->vm();
1546 NativeCallFrameTracer tracer(&vm, exec);
1547 auto scope = DECLARE_THROW_SCOPE(vm);
1548
1549 Identifier propertyName = property->toIdentifier(exec);
1550 RETURN_IF_EXCEPTION(scope, void());
1551 scope.release();
1552 defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
1553}
1554
1555void JIT_OPERATION operationDefineDataPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, EncodedJSValue encodedValue, int32_t attributes)
1556{
1557 VM& vm = exec->vm();
1558 NativeCallFrameTracer tracer(&vm, exec);
1559 defineDataProperty(exec, vm, base, Identifier::fromUid(&vm, property), JSValue::decode(encodedValue), attributes);
1560}
1561
1562void JIT_OPERATION operationDefineDataPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, EncodedJSValue encodedValue, int32_t attributes)
1563{
1564 VM& vm = exec->vm();
1565 NativeCallFrameTracer tracer(&vm, exec);
1566 defineDataProperty(exec, vm, base, Identifier::fromUid(property->privateName()), JSValue::decode(encodedValue), attributes);
1567}
1568
1569ALWAYS_INLINE static void defineAccessorProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSObject* getter, JSObject* setter, int32_t attributes)
1570{
1571 PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes));
1572 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1573 if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
1574 JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
1575 else
1576 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1577}
1578
1579void JIT_OPERATION operationDefineAccessorProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, JSObject* getter, JSObject* setter, int32_t attributes)
1580{
1581 VM& vm = exec->vm();
1582 NativeCallFrameTracer tracer(&vm, exec);
1583 auto scope = DECLARE_THROW_SCOPE(vm);
1584
1585 Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
1586 RETURN_IF_EXCEPTION(scope, void());
1587 defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
1588}
1589
1590void JIT_OPERATION operationDefineAccessorPropertyString(ExecState* exec, JSObject* base, JSString* property, JSObject* getter, JSObject* setter, int32_t attributes)
1591{
1592 VM& vm = exec->vm();
1593 NativeCallFrameTracer tracer(&vm, exec);
1594 auto scope = DECLARE_THROW_SCOPE(vm);
1595
1596 Identifier propertyName = property->toIdentifier(exec);
1597 RETURN_IF_EXCEPTION(scope, void());
1598 defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
1599}
1600
1601void JIT_OPERATION operationDefineAccessorPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, JSObject* getter, JSObject* setter, int32_t attributes)
1602{
1603 VM& vm = exec->vm();
1604 NativeCallFrameTracer tracer(&vm, exec);
1605 defineAccessorProperty(exec, vm, base, Identifier::fromUid(&vm, property), getter, setter, attributes);
1606}
1607
1608void JIT_OPERATION operationDefineAccessorPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, JSObject* getter, JSObject* setter, int32_t attributes)
1609{
1610 VM& vm = exec->vm();
1611 NativeCallFrameTracer tracer(&vm, exec);
1612 defineAccessorProperty(exec, vm, base, Identifier::fromUid(property->privateName()), getter, setter, attributes);
1613}
1614
1615char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
1616{
1617 VM* vm = &exec->vm();
1618 NativeCallFrameTracer tracer(vm, exec);
1619
1620 return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
1621}
1622
1623char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
1624{
1625 VM* vm = &exec->vm();
1626 NativeCallFrameTracer tracer(vm, exec);
1627
1628 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure));
1629}
1630
1631char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size, Butterfly* butterfly)
1632{
1633 VM& vm = exec->vm();
1634 NativeCallFrameTracer tracer(&vm, exec);
1635 auto scope = DECLARE_THROW_SCOPE(vm);
1636
1637 if (UNLIKELY(size < 0))
1638 return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, "Array size is not a small enough positive integer."_s)));
1639
1640 JSArray* result;
1641 if (butterfly)
1642 result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly);
1643 else
1644 result = JSArray::create(vm, arrayStructure, size);
1645 return bitwise_cast<char*>(result);
1646}
1647
1648char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState* exec, Structure* arrayStructure, int32_t size, int32_t vectorLengthHint, Butterfly* butterfly)
1649{
1650 VM& vm = exec->vm();
1651 NativeCallFrameTracer tracer(&vm, exec);
1652 auto scope = DECLARE_THROW_SCOPE(vm);
1653
1654 if (UNLIKELY(size < 0))
1655 return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, "Array size is not a small enough positive integer."_s)));
1656
1657 JSArray* result;
1658 if (butterfly)
1659 result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly);
1660 else {
1661 result = JSArray::tryCreate(vm, arrayStructure, size, vectorLengthHint);
1662 RELEASE_ASSERT(result);
1663 }
1664 return bitwise_cast<char*>(result);
1665}
1666
1667JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, JSCell* immutableButterflyCell)
1668{
1669 VM& vm = exec->vm();
1670 NativeCallFrameTracer tracer(&vm, exec);
1671 ASSERT(!arrayStructure->outOfLineCapacity());
1672 auto* immutableButterfly = jsCast<JSImmutableButterfly*>(immutableButterflyCell);
1673 ASSERT(arrayStructure->indexingMode() == immutableButterfly->indexingMode() || hasAnyArrayStorage(arrayStructure->indexingMode()));
1674 auto* result = CommonSlowPaths::allocateNewArrayBuffer(vm, arrayStructure, immutableButterfly);
1675 ASSERT(result->indexingMode() == result->structure(vm)->indexingMode());
1676 ASSERT(result->structure(vm) == arrayStructure);
1677 return result;
1678}
1679
1680char* JIT_OPERATION operationNewInt8ArrayWithSize(
1681 ExecState* exec, Structure* structure, int32_t length, char* vector)
1682{
1683 return newTypedArrayWithSize<JSInt8Array>(exec, structure, length, vector);
1684}
1685
1686char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
1687 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1688{
1689 VM& vm = exec->vm();
1690 NativeCallFrameTracer tracer(&vm, exec);
1691 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt8Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1692}
1693
1694char* JIT_OPERATION operationNewInt16ArrayWithSize(
1695 ExecState* exec, Structure* structure, int32_t length, char* vector)
1696{
1697 return newTypedArrayWithSize<JSInt16Array>(exec, structure, length, vector);
1698}
1699
1700char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
1701 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1702{
1703 VM& vm = exec->vm();
1704 NativeCallFrameTracer tracer(&vm, exec);
1705 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt16Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1706}
1707
1708char* JIT_OPERATION operationNewInt32ArrayWithSize(
1709 ExecState* exec, Structure* structure, int32_t length, char* vector)
1710{
1711 return newTypedArrayWithSize<JSInt32Array>(exec, structure, length, vector);
1712}
1713
1714char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
1715 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1716{
1717 VM& vm = exec->vm();
1718 NativeCallFrameTracer tracer(&vm, exec);
1719 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt32Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1720}
1721
1722char* JIT_OPERATION operationNewUint8ArrayWithSize(
1723 ExecState* exec, Structure* structure, int32_t length, char* vector)
1724{
1725 return newTypedArrayWithSize<JSUint8Array>(exec, structure, length, vector);
1726}
1727
1728char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
1729 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1730{
1731 VM& vm = exec->vm();
1732 NativeCallFrameTracer tracer(&vm, exec);
1733 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1734}
1735
1736char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
1737 ExecState* exec, Structure* structure, int32_t length, char* vector)
1738{
1739 return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length, vector);
1740}
1741
1742char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
1743 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1744{
1745 VM& vm = exec->vm();
1746 NativeCallFrameTracer tracer(&vm, exec);
1747 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8ClampedArray>(exec, structure, encodedValue, 0, WTF::nullopt));
1748}
1749
1750char* JIT_OPERATION operationNewUint16ArrayWithSize(
1751 ExecState* exec, Structure* structure, int32_t length, char* vector)
1752{
1753 return newTypedArrayWithSize<JSUint16Array>(exec, structure, length, vector);
1754}
1755
1756char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
1757 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1758{
1759 VM& vm = exec->vm();
1760 NativeCallFrameTracer tracer(&vm, exec);
1761 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint16Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1762}
1763
1764char* JIT_OPERATION operationNewUint32ArrayWithSize(
1765 ExecState* exec, Structure* structure, int32_t length, char* vector)
1766{
1767 return newTypedArrayWithSize<JSUint32Array>(exec, structure, length, vector);
1768}
1769
1770char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
1771 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1772{
1773 VM& vm = exec->vm();
1774 NativeCallFrameTracer tracer(&vm, exec);
1775 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint32Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1776}
1777
1778char* JIT_OPERATION operationNewFloat32ArrayWithSize(
1779 ExecState* exec, Structure* structure, int32_t length, char* vector)
1780{
1781 return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length, vector);
1782}
1783
1784char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
1785 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1786{
1787 VM& vm = exec->vm();
1788 NativeCallFrameTracer tracer(&vm, exec);
1789 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat32Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1790}
1791
1792char* JIT_OPERATION operationNewFloat64ArrayWithSize(
1793 ExecState* exec, Structure* structure, int32_t length, char* vector)
1794{
1795 return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length, vector);
1796}
1797
1798char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
1799 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1800{
1801 VM& vm = exec->vm();
1802 NativeCallFrameTracer tracer(&vm, exec);
1803 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat64Array>(exec, structure, encodedValue, 0, WTF::nullopt));
1804}
1805
1806JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table, EncodedJSValue initialValueEncoded)
1807{
1808 JSValue initialValue = JSValue::decode(initialValueEncoded);
1809 ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
1810 VM& vm = exec->vm();
1811 NativeCallFrameTracer tracer(&vm, exec);
1812 return JSLexicalEnvironment::create(vm, structure, scope, table, initialValue);
1813}
1814
1815JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, uint32_t length, uint32_t minCapacity)
1816{
1817 VM& vm = exec->vm();
1818 NativeCallFrameTracer target(&vm, exec);
1819 DirectArguments* result = DirectArguments::create(
1820 vm, structure, length, std::max(length, minCapacity));
1821 // The caller will store to this object without barriers. Most likely, at this point, this is
1822 // still a young object and so no barriers are needed. But it's good to be careful anyway,
1823 // since the GC should be allowed to do crazy (like pretenuring, for example).
1824 vm.heap.writeBarrier(result);
1825 return result;
1826}
1827
1828JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, uint32_t length, JSFunction* callee, JSLexicalEnvironment* scope)
1829{
1830 VM& vm = exec->vm();
1831 NativeCallFrameTracer target(&vm, exec);
1832
1833 // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I
1834 // didn't feel like changing the max number of arguments for a slow path call from 6 to 7.
1835 ScopedArgumentsTable* table = scope->symbolTable()->arguments();
1836
1837 return ScopedArguments::createByCopyingFrom(
1838 vm, structure, argumentStart, length, callee, table, scope);
1839}
1840
1841JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, uint32_t length, JSFunction* callee)
1842{
1843 VM& vm = exec->vm();
1844 NativeCallFrameTracer target(&vm, exec);
1845 return ClonedArguments::createByCopyingFrom(
1846 exec, structure, argumentStart, length, callee);
1847}
1848
1849JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, uint32_t argumentCount)
1850{
1851 VM& vm = exec->vm();
1852 NativeCallFrameTracer target(&vm, exec);
1853
1854 DeferGCForAWhile deferGC(vm.heap);
1855
1856 CodeBlock* codeBlock;
1857 if (inlineCallFrame)
1858 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
1859 else
1860 codeBlock = exec->codeBlock();
1861
1862 unsigned length = argumentCount - 1;
1863 unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1));
1864 DirectArguments* result = DirectArguments::create(
1865 vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity);
1866
1867 result->setCallee(vm, callee);
1868
1869 Register* arguments =
1870 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
1871 CallFrame::argumentOffset(0);
1872 for (unsigned i = length; i--;)
1873 result->setIndexQuickly(vm, i, arguments[i].jsValue());
1874
1875 return result;
1876}
1877
1878JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, uint32_t argumentCount)
1879{
1880 VM& vm = exec->vm();
1881 NativeCallFrameTracer target(&vm, exec);
1882
1883 DeferGCForAWhile deferGC(vm.heap);
1884
1885 CodeBlock* codeBlock;
1886 if (inlineCallFrame)
1887 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
1888 else
1889 codeBlock = exec->codeBlock();
1890
1891 unsigned length = argumentCount - 1;
1892 ClonedArguments* result = ClonedArguments::createEmpty(
1893 vm, codeBlock->globalObject()->clonedArgumentsStructure(), callee, length);
1894
1895 Register* arguments =
1896 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
1897 CallFrame::argumentOffset(0);
1898 for (unsigned i = length; i--;)
1899 result->putDirectIndex(exec, i, arguments[i].jsValue());
1900
1901
1902 return result;
1903}
1904
1905JSCell* JIT_OPERATION operationCreateRest(ExecState* exec, Register* argumentStart, unsigned numberOfParamsToSkip, unsigned arraySize)
1906{
1907 VM* vm = &exec->vm();
1908 NativeCallFrameTracer tracer(vm, exec);
1909
1910 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1911 Structure* structure = globalObject->restParameterStructure();
1912 static_assert(sizeof(Register) == sizeof(JSValue), "This is a strong assumption here.");
1913 JSValue* argumentsToCopyRegion = bitwise_cast<JSValue*>(argumentStart) + numberOfParamsToSkip;
1914 return constructArray(exec, structure, argumentsToCopyRegion, arraySize);
1915}
1916
1917size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1918{
1919 VM& vm = exec->vm();
1920 NativeCallFrameTracer tracer(&vm, exec);
1921
1922 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1923
1924 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1925 return false;
1926 if (object->isFunction(vm))
1927 return false;
1928 return true;
1929}
1930
1931size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1932{
1933 VM& vm = exec->vm();
1934 NativeCallFrameTracer tracer(&vm, exec);
1935
1936 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1937
1938 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1939 return false;
1940 if (object->isFunction(vm))
1941 return true;
1942 return false;
1943}
1944
1945JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1946{
1947 VM& vm = exec->vm();
1948 NativeCallFrameTracer tracer(&vm, exec);
1949
1950 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1951
1952 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1953 return vm.smallStrings.undefinedString();
1954 if (object->isFunction(vm))
1955 return vm.smallStrings.functionString();
1956 return vm.smallStrings.objectString();
1957}
1958
1959int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1960{
1961 VM& vm = exec->vm();
1962 NativeCallFrameTracer tracer(&vm, exec);
1963
1964 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1965
1966 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1967 return static_cast<int32_t>(TypeofType::Undefined);
1968 if (object->isFunction(vm))
1969 return static_cast<int32_t>(TypeofType::Function);
1970 return static_cast<int32_t>(TypeofType::Object);
1971}
1972
1973char* JIT_OPERATION operationAllocateSimplePropertyStorageWithInitialCapacity(ExecState* exec)
1974{
1975 VM& vm = exec->vm();
1976 NativeCallFrameTracer tracer(&vm, exec);
1977
1978 return reinterpret_cast<char*>(
1979 Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
1980}
1981
1982char* JIT_OPERATION operationAllocateSimplePropertyStorage(ExecState* exec, size_t newSize)
1983{
1984 VM& vm = exec->vm();
1985 NativeCallFrameTracer tracer(&vm, exec);
1986
1987 return reinterpret_cast<char*>(
1988 Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
1989}
1990
1991char* JIT_OPERATION operationAllocateComplexPropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
1992{
1993 VM& vm = exec->vm();
1994 NativeCallFrameTracer tracer(&vm, exec);
1995
1996 ASSERT(!object->structure(vm)->outOfLineCapacity());
1997 return reinterpret_cast<char*>(
1998 object->allocateMoreOutOfLineStorage(vm, 0, initialOutOfLineCapacity));
1999}
2000
2001char* JIT_OPERATION operationAllocateComplexPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
2002{
2003 VM& vm = exec->vm();
2004 NativeCallFrameTracer tracer(&vm, exec);
2005
2006 return reinterpret_cast<char*>(
2007 object->allocateMoreOutOfLineStorage(vm, object->structure(vm)->outOfLineCapacity(), newSize));
2008}
2009
2010char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell)
2011{
2012 VM& vm = exec->vm();
2013 NativeCallFrameTracer tracer(&vm, exec);
2014
2015 if (!cell->isObject())
2016 return 0;
2017
2018 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableInt32(vm).data());
2019 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasInt32(cell->indexingMode())) || !result);
2020 return result;
2021}
2022
2023char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell)
2024{
2025 VM& vm = exec->vm();
2026 NativeCallFrameTracer tracer(&vm, exec);
2027
2028 if (!cell->isObject())
2029 return 0;
2030
2031 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableDouble(vm).data());
2032 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasDouble(cell->indexingMode())) || !result);
2033 return result;
2034}
2035
2036char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
2037{
2038 VM& vm = exec->vm();
2039 NativeCallFrameTracer tracer(&vm, exec);
2040
2041 if (!cell->isObject())
2042 return 0;
2043
2044 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableContiguous(vm).data());
2045 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasContiguous(cell->indexingMode())) || !result);
2046 return result;
2047}
2048
2049char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
2050{
2051 VM& vm = exec->vm();
2052 NativeCallFrameTracer tracer(&vm, exec);
2053
2054 if (!cell->isObject())
2055 return 0;
2056
2057 auto* result = reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
2058 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasAnyArrayStorage(cell->indexingMode())) || !result);
2059 return result;
2060}
2061
2062EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* property)
2063{
2064 VM& vm = exec->vm();
2065 NativeCallFrameTracer tracer(&vm, exec);
2066 auto scope = DECLARE_THROW_SCOPE(vm);
2067
2068 JSValue baseValue = JSValue::decode(encodedBaseValue);
2069 if (baseValue.isUndefinedOrNull())
2070 return JSValue::encode(jsBoolean(false));
2071
2072 JSObject* base = baseValue.toObject(exec);
2073 if (!base)
2074 return JSValue::encode(JSValue());
2075 auto propertyName = asString(property)->toIdentifier(exec);
2076 RETURN_IF_EXCEPTION(scope, { });
2077 RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(base->hasPropertyGeneric(exec, propertyName, PropertySlot::InternalMethodType::GetOwnProperty))));
2078}
2079
2080size_t JIT_OPERATION operationHasIndexedPropertyByInt(ExecState* exec, JSCell* baseCell, int32_t subscript, int32_t internalMethodType)
2081{
2082 VM& vm = exec->vm();
2083 NativeCallFrameTracer tracer(&vm, exec);
2084 JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
2085 if (UNLIKELY(subscript < 0)) {
2086 // Go the slowest way possible because negative indices don't use indexed storage.
2087 return object->hasPropertyGeneric(exec, Identifier::from(exec, subscript), static_cast<PropertySlot::InternalMethodType>(internalMethodType));
2088 }
2089 return object->hasPropertyGeneric(exec, subscript, static_cast<PropertySlot::InternalMethodType>(internalMethodType));
2090}
2091
2092JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, EncodedJSValue encodedBase)
2093{
2094 VM& vm = exec->vm();
2095 NativeCallFrameTracer tracer(&vm, exec);
2096 auto scope = DECLARE_THROW_SCOPE(vm);
2097
2098 JSValue base = JSValue::decode(encodedBase);
2099 if (base.isUndefinedOrNull())
2100 return JSPropertyNameEnumerator::create(vm);
2101
2102 JSObject* baseObject = base.toObject(exec);
2103 RETURN_IF_EXCEPTION(scope, { });
2104
2105 RELEASE_AND_RETURN(scope, propertyNameEnumerator(exec, baseObject));
2106}
2107
2108JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(ExecState* exec, JSCell* cell)
2109{
2110 VM& vm = exec->vm();
2111 NativeCallFrameTracer tracer(&vm, exec);
2112 auto scope = DECLARE_THROW_SCOPE(vm);
2113
2114 JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
2115 RETURN_IF_EXCEPTION(scope, { });
2116
2117 RELEASE_AND_RETURN(scope, propertyNameEnumerator(exec, base));
2118}
2119
2120JSCell* JIT_OPERATION operationToIndexString(ExecState* exec, int32_t index)
2121{
2122 VM& vm = exec->vm();
2123 NativeCallFrameTracer tracer(&vm, exec);
2124 return jsString(exec, Identifier::from(exec, index).string());
2125}
2126
2127JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState* exec, JSCell* regexpPtr, EncodedJSValue encodedLastIndex)
2128{
2129 VM& vm = exec->vm();
2130 NativeCallFrameTracer tracer(&vm, exec);
2131
2132 RegExp* regexp = static_cast<RegExp*>(regexpPtr);
2133 ASSERT(regexp->isValid());
2134 return RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp, JSValue::decode(encodedLastIndex));
2135}
2136
2137StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
2138{
2139 VM& vm = exec->vm();
2140 NativeCallFrameTracer tracer(&vm, exec);
2141
2142 return string->value(exec).impl();
2143}
2144
2145JSString* JIT_OPERATION operationStringValueOf(ExecState* exec, EncodedJSValue encodedArgument)
2146{
2147 VM& vm = exec->vm();
2148 NativeCallFrameTracer tracer(&vm, exec);
2149 auto scope = DECLARE_THROW_SCOPE(vm);
2150
2151 JSValue argument = JSValue::decode(encodedArgument);
2152
2153 if (argument.isString())
2154 return asString(argument);
2155
2156 if (auto* stringObject = jsDynamicCast<StringObject*>(vm, argument))
2157 return stringObject->internalValue();
2158
2159 throwVMTypeError(exec, scope);
2160 return nullptr;
2161}
2162
2163JSCell* JIT_OPERATION operationStringSubstr(ExecState* exec, JSCell* cell, int32_t from, int32_t span)
2164{
2165 VM& vm = exec->vm();
2166 NativeCallFrameTracer tracer(&vm, exec);
2167 auto scope = DECLARE_THROW_SCOPE(vm);
2168
2169 auto string = jsCast<JSString*>(cell)->value(exec);
2170 RETURN_IF_EXCEPTION(scope, nullptr);
2171 return jsSubstring(&vm, string, from, span);
2172}
2173
2174JSCell* JIT_OPERATION operationStringSlice(ExecState* exec, JSCell* cell, int32_t start, int32_t end)
2175{
2176 VM& vm = exec->vm();
2177 NativeCallFrameTracer tracer(&vm, exec);
2178 auto scope = DECLARE_THROW_SCOPE(vm);
2179
2180 auto string = jsCast<JSString*>(cell)->value(exec);
2181 RETURN_IF_EXCEPTION(scope, nullptr);
2182 static_assert(static_cast<uint64_t>(JSString::MaxLength) <= static_cast<uint64_t>(std::numeric_limits<int32_t>::max()), "");
2183
2184 return stringSlice(vm, WTFMove(string), start, end);
2185}
2186
2187JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
2188{
2189 VM& vm = exec->vm();
2190 NativeCallFrameTracer tracer(&vm, exec);
2191
2192 auto scope = DECLARE_THROW_SCOPE(vm);
2193
2194 const String& inputString = string->value(exec);
2195 RETURN_IF_EXCEPTION(scope, nullptr);
2196 if (!inputString.length())
2197 return vm.smallStrings.emptyString();
2198
2199 String lowercasedString = inputString.is8Bit() ? inputString.convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex) : inputString.convertToLowercaseWithoutLocale();
2200 if (lowercasedString.impl() == inputString.impl())
2201 return string;
2202 RELEASE_AND_RETURN(scope, jsString(exec, lowercasedString));
2203}
2204
2205char* JIT_OPERATION operationInt32ToString(ExecState* exec, int32_t value, int32_t radix)
2206{
2207 VM& vm = exec->vm();
2208 NativeCallFrameTracer tracer(&vm, exec);
2209
2210 auto scope = DECLARE_THROW_SCOPE(vm);
2211
2212 if (radix < 2 || radix > 36) {
2213 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2214 return nullptr;
2215 }
2216
2217 return reinterpret_cast<char*>(int32ToString(vm, value, radix));
2218}
2219
2220char* JIT_OPERATION operationInt52ToString(ExecState* exec, int64_t value, int32_t radix)
2221{
2222 VM& vm = exec->vm();
2223 NativeCallFrameTracer tracer(&vm, exec);
2224
2225 auto scope = DECLARE_THROW_SCOPE(vm);
2226
2227 if (radix < 2 || radix > 36) {
2228 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2229 return nullptr;
2230 }
2231
2232 return reinterpret_cast<char*>(int52ToString(vm, value, radix));
2233}
2234
2235char* JIT_OPERATION operationDoubleToString(ExecState* exec, double value, int32_t radix)
2236{
2237 VM& vm = exec->vm();
2238 NativeCallFrameTracer tracer(&vm, exec);
2239
2240 auto scope = DECLARE_THROW_SCOPE(vm);
2241
2242 if (radix < 2 || radix > 36) {
2243 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2244 return nullptr;
2245 }
2246
2247 return reinterpret_cast<char*>(numberToString(vm, value, radix));
2248}
2249
2250char* JIT_OPERATION operationInt32ToStringWithValidRadix(ExecState* exec, int32_t value, int32_t radix)
2251{
2252 VM& vm = exec->vm();
2253 NativeCallFrameTracer tracer(&vm, exec);
2254
2255 return reinterpret_cast<char*>(int32ToString(vm, value, radix));
2256}
2257
2258char* JIT_OPERATION operationInt52ToStringWithValidRadix(ExecState* exec, int64_t value, int32_t radix)
2259{
2260 VM& vm = exec->vm();
2261 NativeCallFrameTracer tracer(&vm, exec);
2262
2263 return reinterpret_cast<char*>(int52ToString(vm, value, radix));
2264}
2265
2266char* JIT_OPERATION operationDoubleToStringWithValidRadix(ExecState* exec, double value, int32_t radix)
2267{
2268 VM& vm = exec->vm();
2269 NativeCallFrameTracer tracer(&vm, exec);
2270
2271 return reinterpret_cast<char*>(numberToString(vm, value, radix));
2272}
2273
2274JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
2275{
2276 VM& vm = exec->vm();
2277 NativeCallFrameTracer tracer(&vm, exec);
2278
2279 return jsSingleCharacterString(exec, static_cast<UChar>(character));
2280}
2281
2282Symbol* JIT_OPERATION operationNewSymbol(ExecState* exec)
2283{
2284 VM& vm = exec->vm();
2285 NativeCallFrameTracer tracer(&vm, exec);
2286
2287 return Symbol::create(vm);
2288}
2289
2290Symbol* JIT_OPERATION operationNewSymbolWithDescription(ExecState* exec, JSString* description)
2291{
2292 VM& vm = exec->vm();
2293 NativeCallFrameTracer tracer(&vm, exec);
2294
2295 return Symbol::create(exec, description);
2296}
2297
2298JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
2299{
2300 VM& vm = exec->vm();
2301 NativeCallFrameTracer tracer(&vm, exec);
2302
2303 return StringObject::create(vm, structure, string);
2304}
2305
2306JSString* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
2307{
2308 VM& vm = exec->vm();
2309 NativeCallFrameTracer tracer(&vm, exec);
2310
2311 return JSValue(cell).toString(exec);
2312}
2313
2314JSString* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
2315{
2316 VM& vm = exec->vm();
2317 NativeCallFrameTracer tracer(&vm, exec);
2318
2319 return JSValue::decode(value).toString(exec);
2320}
2321
2322JSString* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell)
2323{
2324 VM& vm = exec->vm();
2325 NativeCallFrameTracer tracer(&vm, exec);
2326
2327 return stringConstructor(exec, cell);
2328}
2329
2330JSString* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value)
2331{
2332 VM& vm = exec->vm();
2333 NativeCallFrameTracer tracer(&vm, exec);
2334
2335 return stringConstructor(exec, JSValue::decode(value));
2336}
2337
2338JSString* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
2339{
2340 VM& vm = exec->vm();
2341 NativeCallFrameTracer tracer(&vm, exec);
2342
2343 return jsString(exec, left, right);
2344}
2345
2346JSString* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c)
2347{
2348 VM& vm = exec->vm();
2349 NativeCallFrameTracer tracer(&vm, exec);
2350
2351 return jsString(exec, a, b, c);
2352}
2353
2354JSString* JIT_OPERATION operationStrCat2(ExecState* exec, EncodedJSValue a, EncodedJSValue b)
2355{
2356 VM& vm = exec->vm();
2357 NativeCallFrameTracer tracer(&vm, exec);
2358 auto scope = DECLARE_THROW_SCOPE(vm);
2359
2360 ASSERT(!JSValue::decode(a).isSymbol());
2361 ASSERT(!JSValue::decode(b).isSymbol());
2362 JSString* str1 = JSValue::decode(a).toString(exec);
2363 scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
2364 JSString* str2 = JSValue::decode(b).toString(exec);
2365 scope.assertNoException();
2366
2367 RELEASE_AND_RETURN(scope, jsString(exec, str1, str2));
2368}
2369
2370JSString* JIT_OPERATION operationStrCat3(ExecState* exec, EncodedJSValue a, EncodedJSValue b, EncodedJSValue c)
2371{
2372 VM& vm = exec->vm();
2373 NativeCallFrameTracer tracer(&vm, exec);
2374 auto scope = DECLARE_THROW_SCOPE(vm);
2375
2376 ASSERT(!JSValue::decode(a).isSymbol());
2377 ASSERT(!JSValue::decode(b).isSymbol());
2378 ASSERT(!JSValue::decode(c).isSymbol());
2379 JSString* str1 = JSValue::decode(a).toString(exec);
2380 scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
2381 JSString* str2 = JSValue::decode(b).toString(exec);
2382 scope.assertNoException();
2383 JSString* str3 = JSValue::decode(c).toString(exec);
2384 scope.assertNoException();
2385
2386 RELEASE_AND_RETURN(scope, jsString(exec, str1, str2, str3));
2387}
2388
2389char* JIT_OPERATION operationFindSwitchImmTargetForDouble(
2390 ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
2391{
2392 VM& vm = exec->vm();
2393 NativeCallFrameTracer tracer(&vm, exec);
2394
2395 CodeBlock* codeBlock = exec->codeBlock();
2396 SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex);
2397 JSValue value = JSValue::decode(encodedValue);
2398 ASSERT(value.isDouble());
2399 double asDouble = value.asDouble();
2400 int32_t asInt32 = static_cast<int32_t>(asDouble);
2401 if (asDouble == asInt32)
2402 return table.ctiForValue(asInt32).executableAddress<char*>();
2403 return table.ctiDefault.executableAddress<char*>();
2404}
2405
2406char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string)
2407{
2408 VM& vm = exec->vm();
2409 NativeCallFrameTracer tracer(&vm, exec);
2410
2411 return exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress<char*>();
2412}
2413
2414int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string)
2415{
2416 VM& vm = exec->vm();
2417 NativeCallFrameTracer tracer(&vm, exec);
2418
2419 return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
2420}
2421
2422uintptr_t JIT_OPERATION operationCompareStringImplLess(StringImpl* a, StringImpl* b)
2423{
2424 return codePointCompare(a, b) < 0;
2425}
2426
2427uintptr_t JIT_OPERATION operationCompareStringImplLessEq(StringImpl* a, StringImpl* b)
2428{
2429 return codePointCompare(a, b) <= 0;
2430}
2431
2432uintptr_t JIT_OPERATION operationCompareStringImplGreater(StringImpl* a, StringImpl* b)
2433{
2434 return codePointCompare(a, b) > 0;
2435}
2436
2437uintptr_t JIT_OPERATION operationCompareStringImplGreaterEq(StringImpl* a, StringImpl* b)
2438{
2439 return codePointCompare(a, b) >= 0;
2440}
2441
2442uintptr_t JIT_OPERATION operationCompareStringLess(ExecState* exec, JSString* a, JSString* b)
2443{
2444 VM& vm = exec->vm();
2445 NativeCallFrameTracer tracer(&vm, exec);
2446
2447 return codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
2448}
2449
2450uintptr_t JIT_OPERATION operationCompareStringLessEq(ExecState* exec, JSString* a, JSString* b)
2451{
2452 VM& vm = exec->vm();
2453 NativeCallFrameTracer tracer(&vm, exec);
2454
2455 return !codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
2456}
2457
2458uintptr_t JIT_OPERATION operationCompareStringGreater(ExecState* exec, JSString* a, JSString* b)
2459{
2460 VM& vm = exec->vm();
2461 NativeCallFrameTracer tracer(&vm, exec);
2462
2463 return codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
2464}
2465
2466uintptr_t JIT_OPERATION operationCompareStringGreaterEq(ExecState* exec, JSString* a, JSString* b)
2467{
2468 VM& vm = exec->vm();
2469 NativeCallFrameTracer tracer(&vm, exec);
2470
2471 return !codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
2472}
2473
2474void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
2475{
2476 VM& vm = exec->vm();
2477 NativeCallFrameTracer tracer(&vm, exec);
2478
2479 set->touch(vm, "Executed NotifyWrite");
2480}
2481
2482void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec)
2483{
2484 VM& vm = exec->vm();
2485 NativeCallFrameTracer tracer(&vm, exec);
2486 auto scope = DECLARE_THROW_SCOPE(vm);
2487 throwStackOverflowError(exec, scope);
2488}
2489
2490int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, uint32_t firstVarArgOffset)
2491{
2492 VM& vm = exec->vm();
2493 NativeCallFrameTracer tracer(&vm, exec);
2494 JSValue arguments = JSValue::decode(encodedArguments);
2495
2496 return sizeOfVarargs(exec, arguments, firstVarArgOffset);
2497}
2498
2499int32_t JIT_OPERATION operationHasOwnProperty(ExecState* exec, JSObject* thisObject, EncodedJSValue encodedKey)
2500{
2501 VM& vm = exec->vm();
2502 NativeCallFrameTracer tracer(&vm, exec);
2503 auto scope = DECLARE_THROW_SCOPE(vm);
2504
2505 JSValue key = JSValue::decode(encodedKey);
2506 Identifier propertyName = key.toPropertyKey(exec);
2507 RETURN_IF_EXCEPTION(scope, false);
2508
2509 PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
2510 bool result = thisObject->hasOwnProperty(exec, propertyName.impl(), slot);
2511 RETURN_IF_EXCEPTION(scope, false);
2512
2513 HasOwnPropertyCache* hasOwnPropertyCache = vm.hasOwnPropertyCache();
2514 ASSERT(hasOwnPropertyCache);
2515 hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName.impl(), result);
2516 return result;
2517}
2518
2519int32_t JIT_OPERATION operationNumberIsInteger(ExecState* exec, EncodedJSValue value)
2520{
2521 VM& vm = exec->vm();
2522 NativeCallFrameTracer tracer(&vm, exec);
2523 return NumberConstructor::isIntegerImpl(JSValue::decode(value));
2524}
2525
2526int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index)
2527{
2528 VM& vm = exec->vm();
2529 NativeCallFrameTracer tracer(&vm, exec);
2530 auto scope = DECLARE_THROW_SCOPE(vm);
2531
2532 int32_t length = butterfly->publicLength();
2533 auto data = butterfly->contiguous().data();
2534 for (; index < length; ++index) {
2535 JSValue value = data[index].get();
2536 if (!value || !value.isString())
2537 continue;
2538 auto* string = asString(value);
2539 if (string == searchElement)
2540 return index;
2541 if (string->equal(exec, searchElement)) {
2542 scope.assertNoException();
2543 return index;
2544 }
2545 RETURN_IF_EXCEPTION(scope, { });
2546 }
2547 return -1;
2548}
2549
2550int32_t JIT_OPERATION operationArrayIndexOfValueInt32OrContiguous(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
2551{
2552 VM& vm = exec->vm();
2553 NativeCallFrameTracer tracer(&vm, exec);
2554 auto scope = DECLARE_THROW_SCOPE(vm);
2555
2556 JSValue searchElement = JSValue::decode(encodedValue);
2557
2558 int32_t length = butterfly->publicLength();
2559 auto data = butterfly->contiguous().data();
2560 for (; index < length; ++index) {
2561 JSValue value = data[index].get();
2562 if (!value)
2563 continue;
2564 bool isEqual = JSValue::strictEqual(exec, searchElement, value);
2565 RETURN_IF_EXCEPTION(scope, { });
2566 if (isEqual)
2567 return index;
2568 }
2569 return -1;
2570}
2571
2572int32_t JIT_OPERATION operationArrayIndexOfValueDouble(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
2573{
2574 VM& vm = exec->vm();
2575 NativeCallFrameTracer tracer(&vm, exec);
2576
2577 JSValue searchElement = JSValue::decode(encodedValue);
2578
2579 if (!searchElement.isNumber())
2580 return -1;
2581 double number = searchElement.asNumber();
2582
2583 int32_t length = butterfly->publicLength();
2584 const double* data = butterfly->contiguousDouble().data();
2585 for (; index < length; ++index) {
2586 // This comparison ignores NaN.
2587 if (data[index] == number)
2588 return index;
2589 }
2590 return -1;
2591}
2592
2593void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, uint32_t offset, uint32_t length, uint32_t mandatoryMinimum)
2594{
2595 VM& vm = exec->vm();
2596 NativeCallFrameTracer tracer(&vm, exec);
2597 JSValue arguments = JSValue::decode(encodedArguments);
2598
2599 loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length);
2600
2601 for (uint32_t i = length; i < mandatoryMinimum; ++i)
2602 exec->r(firstElementDest + i) = jsUndefined();
2603}
2604
2605double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
2606{
2607 return fmod(a, b);
2608}
2609
2610#if USE(JSVALUE32_64)
2611double JIT_OPERATION operationRandom(JSGlobalObject* globalObject)
2612{
2613 return globalObject->weakRandomNumber();
2614}
2615#endif
2616
2617JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
2618{
2619 VM* vm = &exec->vm();
2620 NativeCallFrameTracer tracer(vm, exec);
2621 return JSC::stringFromCharCode(exec, op1);
2622}
2623
2624EncodedJSValue JIT_OPERATION operationStringFromCharCodeUntyped(ExecState* exec, EncodedJSValue encodedValue)
2625{
2626 VM* vm = &exec->vm();
2627 NativeCallFrameTracer tracer(vm, exec);
2628 JSValue charValue = JSValue::decode(encodedValue);
2629 int32_t chInt = charValue.toUInt32(exec);
2630 return JSValue::encode(JSC::stringFromCharCode(exec, chInt));
2631}
2632
2633int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
2634{
2635 JSValue value = JSValue::decode(encodedValue);
2636 if (!value.isDouble())
2637 return JSValue::notInt52;
2638 return tryConvertToInt52(value.asDouble());
2639}
2640
2641int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
2642{
2643 return tryConvertToInt52(value);
2644}
2645
2646char* JIT_OPERATION operationNewRawObject(ExecState* exec, Structure* structure, int32_t length, Butterfly* butterfly)
2647{
2648 VM& vm = exec->vm();
2649 NativeCallFrameTracer tracer(&vm, exec);
2650
2651 if (!butterfly
2652 && (structure->outOfLineCapacity() || hasIndexedProperties(structure->indexingType()))) {
2653 IndexingHeader header;
2654 header.setVectorLength(length);
2655 header.setPublicLength(0);
2656
2657 butterfly = Butterfly::create(
2658 vm, nullptr, 0, structure->outOfLineCapacity(),
2659 hasIndexedProperties(structure->indexingType()), header,
2660 length * sizeof(EncodedJSValue));
2661 }
2662
2663 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2664 result->butterfly(); // Ensure that the butterfly is in to-space.
2665 return bitwise_cast<char*>(result);
2666}
2667
2668JSCell* JIT_OPERATION operationNewObjectWithButterfly(ExecState* exec, Structure* structure, Butterfly* butterfly)
2669{
2670 VM& vm = exec->vm();
2671 NativeCallFrameTracer tracer(&vm, exec);
2672
2673 if (!butterfly) {
2674 butterfly = Butterfly::create(
2675 vm, nullptr, 0, structure->outOfLineCapacity(), false, IndexingHeader(), 0);
2676 }
2677
2678 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2679 result->butterfly(); // Ensure that the butterfly is in to-space.
2680 return result;
2681}
2682
2683JSCell* JIT_OPERATION operationNewObjectWithButterflyWithIndexingHeaderAndVectorLength(ExecState* exec, Structure* structure, unsigned length, Butterfly* butterfly)
2684{
2685 VM& vm = exec->vm();
2686 NativeCallFrameTracer tracer(&vm, exec);
2687
2688 IndexingHeader header;
2689 header.setVectorLength(length);
2690 header.setPublicLength(0);
2691 if (butterfly)
2692 *butterfly->indexingHeader() = header;
2693 else {
2694 butterfly = Butterfly::create(
2695 vm, nullptr, 0, structure->outOfLineCapacity(), true, header,
2696 sizeof(EncodedJSValue) * length);
2697 }
2698
2699 // Paradoxically this may allocate a JSArray. That's totally cool.
2700 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2701 result->butterfly(); // Ensure that the butterfly is in to-space.
2702 return result;
2703}
2704
2705JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(ExecState* exec, void* buffer, uint32_t numItems)
2706{
2707 VM& vm = exec->vm();
2708 NativeCallFrameTracer tracer(&vm, exec);
2709 auto scope = DECLARE_THROW_SCOPE(vm);
2710
2711 EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
2712 Checked<unsigned, RecordOverflow> checkedLength = 0;
2713 for (unsigned i = 0; i < numItems; i++) {
2714 JSValue value = JSValue::decode(values[i]);
2715 if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value))
2716 checkedLength += array->size();
2717 else
2718 ++checkedLength;
2719 }
2720
2721 if (UNLIKELY(checkedLength.hasOverflowed())) {
2722 throwOutOfMemoryError(exec, scope);
2723 return nullptr;
2724 }
2725
2726 unsigned length = checkedLength.unsafeGet();
2727 if (UNLIKELY(length >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)) {
2728 throwOutOfMemoryError(exec, scope);
2729 return nullptr;
2730 }
2731
2732 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2733 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
2734
2735 JSArray* result = JSArray::tryCreate(vm, structure, length);
2736 if (UNLIKELY(!result)) {
2737 throwOutOfMemoryError(exec, scope);
2738 return nullptr;
2739 }
2740 RETURN_IF_EXCEPTION(scope, nullptr);
2741
2742 unsigned index = 0;
2743 for (unsigned i = 0; i < numItems; i++) {
2744 JSValue value = JSValue::decode(values[i]);
2745 if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value)) {
2746 // We are spreading.
2747 for (unsigned i = 0; i < array->size(); i++) {
2748 result->putDirectIndex(exec, index, array->get(i));
2749 RETURN_IF_EXCEPTION(scope, nullptr);
2750 ++index;
2751 }
2752 } else {
2753 // We are not spreading.
2754 result->putDirectIndex(exec, index, value);
2755 RETURN_IF_EXCEPTION(scope, nullptr);
2756 ++index;
2757 }
2758 }
2759
2760 return result;
2761}
2762
2763JSCell* operationCreateFixedArray(ExecState* exec, unsigned length)
2764{
2765 VM& vm = exec->vm();
2766 NativeCallFrameTracer tracer(&vm, exec);
2767 auto scope = DECLARE_THROW_SCOPE(vm);
2768
2769 if (JSFixedArray* result = JSFixedArray::tryCreate(vm, vm.fixedArrayStructure.get(), length))
2770 return result;
2771
2772 throwOutOfMemoryError(exec, scope);
2773 return nullptr;
2774}
2775
2776JSCell* JIT_OPERATION operationSpreadGeneric(ExecState* exec, JSCell* iterable)
2777{
2778 VM& vm = exec->vm();
2779 NativeCallFrameTracer tracer(&vm, exec);
2780
2781 auto throwScope = DECLARE_THROW_SCOPE(vm);
2782
2783 if (isJSArray(iterable)) {
2784 JSArray* array = jsCast<JSArray*>(iterable);
2785 if (array->isIteratorProtocolFastAndNonObservable())
2786 RELEASE_AND_RETURN(throwScope, JSFixedArray::createFromArray(exec, vm, array));
2787 }
2788
2789 // FIXME: we can probably make this path faster by having our caller JS code call directly into
2790 // the iteration protocol builtin: https://bugs.webkit.org/show_bug.cgi?id=164520
2791
2792 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2793 JSArray* array;
2794 {
2795 JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
2796 CallData callData;
2797 CallType callType = JSC::getCallData(vm, iterationFunction, callData);
2798 ASSERT(callType != CallType::None);
2799
2800 MarkedArgumentBuffer arguments;
2801 arguments.append(iterable);
2802 ASSERT(!arguments.hasOverflowed());
2803 JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
2804 RETURN_IF_EXCEPTION(throwScope, nullptr);
2805 array = jsCast<JSArray*>(arrayResult);
2806 }
2807
2808 RELEASE_AND_RETURN(throwScope, JSFixedArray::createFromArray(exec, vm, array));
2809}
2810
2811JSCell* JIT_OPERATION operationSpreadFastArray(ExecState* exec, JSCell* cell)
2812{
2813 VM& vm = exec->vm();
2814 NativeCallFrameTracer tracer(&vm, exec);
2815
2816 ASSERT(isJSArray(cell));
2817 JSArray* array = jsCast<JSArray*>(cell);
2818 ASSERT(array->isIteratorProtocolFastAndNonObservable());
2819
2820 return JSFixedArray::createFromArray(exec, vm, array);
2821}
2822
2823void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec)
2824{
2825 VM& vm = exec->vm();
2826 NativeCallFrameTracer tracer(&vm, exec);
2827
2828 vm.typeProfilerLog()->processLogEntries(vm, "Log Full, called from inside DFG."_s);
2829}
2830
2831EncodedJSValue JIT_OPERATION operationResolveScopeForHoistingFuncDeclInEval(ExecState* exec, JSScope* scope, UniquedStringImpl* impl)
2832{
2833 VM& vm = exec->vm();
2834 NativeCallFrameTracer tracer(&vm, exec);
2835
2836 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(exec, scope, Identifier::fromUid(exec, impl));
2837 return JSValue::encode(resolvedScope);
2838}
2839
2840JSCell* JIT_OPERATION operationResolveScope(ExecState* exec, JSScope* scope, UniquedStringImpl* impl)
2841{
2842 VM& vm = exec->vm();
2843 NativeCallFrameTracer tracer(&vm, exec);
2844
2845 JSObject* resolvedScope = JSScope::resolve(exec, scope, Identifier::fromUid(exec, impl));
2846 return resolvedScope;
2847}
2848
2849EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState* exec, JSObject* scope, UniquedStringImpl* impl, unsigned getPutInfoBits)
2850{
2851 VM& vm = exec->vm();
2852 NativeCallFrameTracer tracer(&vm, exec);
2853 auto throwScope = DECLARE_THROW_SCOPE(vm);
2854
2855 Identifier ident = Identifier::fromUid(exec, impl);
2856 RELEASE_AND_RETURN(throwScope, JSValue::encode(scope->getPropertySlot(exec, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
2857 if (!found) {
2858 GetPutInfo getPutInfo(getPutInfoBits);
2859 if (getPutInfo.resolveMode() == ThrowIfNotFound)
2860 throwException(exec, throwScope, createUndefinedVariableError(exec, ident));
2861 return jsUndefined();
2862 }
2863
2864 if (scope->isGlobalLexicalEnvironment()) {
2865 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2866 JSValue result = slot.getValue(exec, ident);
2867 if (result == jsTDZValue()) {
2868 throwException(exec, throwScope, createTDZError(exec));
2869 return jsUndefined();
2870 }
2871 return result;
2872 }
2873
2874 return slot.getValue(exec, ident);
2875 })));
2876}
2877
2878ALWAYS_INLINE static void putDynamicVar(ExecState* exec, VM& vm, JSObject* scope, EncodedJSValue value, UniquedStringImpl* impl, unsigned getPutInfoBits, bool isStrictMode)
2879{
2880 auto throwScope = DECLARE_THROW_SCOPE(vm);
2881
2882 const Identifier& ident = Identifier::fromUid(exec, impl);
2883 GetPutInfo getPutInfo(getPutInfoBits);
2884 bool hasProperty = scope->hasProperty(exec, ident);
2885 RETURN_IF_EXCEPTION(throwScope, void());
2886 if (hasProperty
2887 && scope->isGlobalLexicalEnvironment()
2888 && !isInitialization(getPutInfo.initializationMode())) {
2889 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2890 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get);
2891 JSGlobalLexicalEnvironment::getOwnPropertySlot(scope, exec, ident, slot);
2892 if (slot.getValue(exec, ident) == jsTDZValue()) {
2893 throwException(exec, throwScope, createTDZError(exec));
2894 return;
2895 }
2896 }
2897
2898 if (getPutInfo.resolveMode() == ThrowIfNotFound && !hasProperty) {
2899 throwException(exec, throwScope, createUndefinedVariableError(exec, ident));
2900 return;
2901 }
2902
2903 PutPropertySlot slot(scope, isStrictMode, PutPropertySlot::UnknownContext, isInitialization(getPutInfo.initializationMode()));
2904 throwScope.release();
2905 scope->methodTable(vm)->put(scope, exec, ident, JSValue::decode(value), slot);
2906}
2907
2908void JIT_OPERATION operationPutDynamicVarStrict(ExecState* exec, JSObject* scope, EncodedJSValue value, UniquedStringImpl* impl, unsigned getPutInfoBits)
2909{
2910 VM& vm = exec->vm();
2911 NativeCallFrameTracer tracer(&vm, exec);
2912 constexpr bool isStrictMode = true;
2913 return putDynamicVar(exec, vm, scope, value, impl, getPutInfoBits, isStrictMode);
2914}
2915
2916void JIT_OPERATION operationPutDynamicVarNonStrict(ExecState* exec, JSObject* scope, EncodedJSValue value, UniquedStringImpl* impl, unsigned getPutInfoBits)
2917{
2918 VM& vm = exec->vm();
2919 NativeCallFrameTracer tracer(&vm, exec);
2920 constexpr bool isStrictMode = false;
2921 return putDynamicVar(exec, vm, scope, value, impl, getPutInfoBits, isStrictMode);
2922}
2923
2924int32_t JIT_OPERATION operationMapHash(ExecState* exec, EncodedJSValue input)
2925{
2926 VM& vm = exec->vm();
2927 NativeCallFrameTracer tracer(&vm, exec);
2928
2929 return jsMapHash(exec, vm, JSValue::decode(input));
2930}
2931
2932JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
2933{
2934 VM& vm = exec->vm();
2935 NativeCallFrameTracer tracer(&vm, exec);
2936 JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash);
2937 if (!bucket)
2938 return vm.sentinelMapBucket();
2939 return *bucket;
2940}
2941
2942JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
2943{
2944 VM& vm = exec->vm();
2945 NativeCallFrameTracer tracer(&vm, exec);
2946 JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash);
2947 if (!bucket)
2948 return vm.sentinelSetBucket();
2949 return *bucket;
2950}
2951
2952JSCell* JIT_OPERATION operationSetAdd(ExecState* exec, JSCell* set, EncodedJSValue key, int32_t hash)
2953{
2954 VM& vm = exec->vm();
2955 NativeCallFrameTracer tracer(&vm, exec);
2956 auto* bucket = jsCast<JSSet*>(set)->addNormalized(exec, JSValue::decode(key), JSValue(), hash);
2957 if (!bucket)
2958 return vm.sentinelSetBucket();
2959 return bucket;
2960}
2961
2962JSCell* JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSValue key, EncodedJSValue value, int32_t hash)
2963{
2964 VM& vm = exec->vm();
2965 NativeCallFrameTracer tracer(&vm, exec);
2966 auto* bucket = jsCast<JSMap*>(map)->addNormalized(exec, JSValue::decode(key), JSValue::decode(value), hash);
2967 if (!bucket)
2968 return vm.sentinelMapBucket();
2969 return bucket;
2970}
2971
2972void JIT_OPERATION operationWeakSetAdd(ExecState* exec, JSCell* set, JSCell* key, int32_t hash)
2973{
2974 VM& vm = exec->vm();
2975 NativeCallFrameTracer tracer(&vm, exec);
2976 jsCast<JSWeakSet*>(set)->add(vm, asObject(key), JSValue(), hash);
2977}
2978
2979void JIT_OPERATION operationWeakMapSet(ExecState* exec, JSCell* map, JSCell* key, EncodedJSValue value, int32_t hash)
2980{
2981 VM& vm = exec->vm();
2982 NativeCallFrameTracer tracer(&vm, exec);
2983 jsCast<JSWeakMap*>(map)->add(vm, asObject(key), JSValue::decode(value), hash);
2984}
2985
2986EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)
2987{
2988 VM& vm = exec->vm();
2989 NativeCallFrameTracer tracer(&vm, exec);
2990 return JSValue::encode(thisObject->getPrototype(vm, exec));
2991}
2992
2993EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState* exec, EncodedJSValue encodedValue)
2994{
2995 VM& vm = exec->vm();
2996 NativeCallFrameTracer tracer(&vm, exec);
2997 auto scope = DECLARE_THROW_SCOPE(vm);
2998
2999 JSValue thisValue = JSValue::decode(encodedValue).toThis(exec, StrictMode);
3000 if (thisValue.isUndefinedOrNull())
3001 return throwVMError(exec, scope, createNotAnObjectError(exec, thisValue));
3002
3003 JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
3004 if (!thisObject) {
3005 JSObject* prototype = thisValue.synthesizePrototype(exec);
3006 EXCEPTION_ASSERT(!!scope.exception() == !prototype);
3007 if (UNLIKELY(!prototype))
3008 return JSValue::encode(JSValue());
3009 return JSValue::encode(prototype);
3010 }
3011
3012 RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPrototype(vm, exec)));
3013}
3014
3015void JIT_OPERATION operationThrowDFG(ExecState* exec, EncodedJSValue valueToThrow)
3016{
3017 VM& vm = exec->vm();
3018 NativeCallFrameTracer tracer(&vm, exec);
3019 auto scope = DECLARE_THROW_SCOPE(vm);
3020 scope.throwException(exec, JSValue::decode(valueToThrow));
3021}
3022
3023void JIT_OPERATION operationThrowStaticError(ExecState* exec, JSString* message, uint32_t errorType)
3024{
3025 VM& vm = exec->vm();
3026 NativeCallFrameTracer tracer(&vm, exec);
3027 auto scope = DECLARE_THROW_SCOPE(vm);
3028 String errorMessage = message->value(exec);
3029 scope.throwException(exec, createError(exec, static_cast<ErrorType>(errorType), errorMessage));
3030}
3031
3032extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, CodeBlock* optimizedCodeBlock, OSRExitBase* exit)
3033{
3034 // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
3035 // really be profitable.
3036 DeferGCForAWhile deferGC(codeBlock->vm()->heap);
3037
3038 sanitizeStackForVM(codeBlock->vm());
3039
3040 if (Options::verboseOSR())
3041 dataLog(*codeBlock, ": Entered reoptimize\n");
3042 // We must be called with the baseline code block.
3043 ASSERT(JITCode::isBaselineCode(codeBlock->jitType()));
3044
3045 // If I am my own replacement, then reoptimization has already been triggered.
3046 // This can happen in recursive functions.
3047 //
3048 // Note that even if optimizedCodeBlock is an FTLForOSREntry style CodeBlock, this condition is a
3049 // sure bet that we don't have anything else left to do.
3050 CodeBlock* replacement = codeBlock->replacement();
3051 if (!replacement || replacement == codeBlock) {
3052 if (Options::verboseOSR())
3053 dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n");
3054 return;
3055 }
3056
3057 // Otherwise, the replacement must be optimized code. Use this as an opportunity
3058 // to check our logic.
3059 ASSERT(codeBlock->hasOptimizedReplacement());
3060 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
3061
3062 bool didTryToEnterIntoInlinedLoops = false;
3063 for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame(); inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame()) {
3064 if (inlineCallFrame->baselineCodeBlock->ownerExecutable()->didTryToEnterInLoop()) {
3065 didTryToEnterIntoInlinedLoops = true;
3066 break;
3067 }
3068 }
3069
3070 // In order to trigger reoptimization, one of two things must have happened:
3071 // 1) We exited more than some number of times.
3072 // 2) We exited and got stuck in a loop, and now we're exiting again.
3073 bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
3074 bool didGetStuckInLoop =
3075 (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops)
3076 && optimizedCodeBlock->shouldReoptimizeFromLoopNow();
3077
3078 if (!didExitABunch && !didGetStuckInLoop) {
3079 if (Options::verboseOSR())
3080 dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n");
3081 codeBlock->optimizeAfterLongWarmUp();
3082 return;
3083 }
3084
3085 optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization);
3086}
3087
3088#if ENABLE(FTL_JIT)
3089static bool shouldTriggerFTLCompile(CodeBlock* codeBlock, JITCode* jitCode)
3090{
3091 if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
3092 CODEBLOCK_LOG_EVENT(codeBlock, "abortFTLCompile", ());
3093 if (Options::verboseOSR())
3094 dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
3095 jitCode->dontOptimizeAnytimeSoon(codeBlock);
3096 return false;
3097 }
3098
3099 if (!codeBlock->hasOptimizedReplacement()
3100 && !jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
3101 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("counter = ", jitCode->tierUpCounter));
3102 if (Options::verboseOSR())
3103 dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
3104 return false;
3105 }
3106 return true;
3107}
3108
3109static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
3110{
3111 if (codeBlock->codeType() == GlobalCode) {
3112 // Global code runs once, so we don't want to do anything. We don't want to defer indefinitely,
3113 // since this may have been spuriously called from tier-up initiated in a loop, and that loop may
3114 // later want to run faster code. Deferring for warm-up seems safest.
3115 jitCode->optimizeAfterWarmUp(codeBlock);
3116 return;
3117 }
3118
3119 Worklist::State worklistState;
3120 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
3121 worklistState = worklist->completeAllReadyPlansForVM(
3122 *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode));
3123 } else
3124 worklistState = Worklist::NotKnown;
3125
3126 if (worklistState == Worklist::Compiling) {
3127 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling"));
3128 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3129 codeBlock, CompilationDeferred);
3130 return;
3131 }
3132
3133 if (codeBlock->hasOptimizedReplacement()) {
3134 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("has replacement"));
3135 // That's great, we've compiled the code - next time we call this function,
3136 // we'll enter that replacement.
3137 jitCode->optimizeSoon(codeBlock);
3138 return;
3139 }
3140
3141 if (worklistState == Worklist::Compiled) {
3142 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed"));
3143 // This means that we finished compiling, but failed somehow; in that case the
3144 // thresholds will be set appropriately.
3145 if (Options::verboseOSR())
3146 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
3147 return;
3148 }
3149
3150 CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLReplacement", ());
3151 // We need to compile the code.
3152 compile(
3153 *vm, codeBlock->newReplacement(), codeBlock, FTLMode, UINT_MAX,
3154 Operands<Optional<JSValue>>(), ToFTLDeferredCompilationCallback::create());
3155
3156 // If we reached here, the counter has not be reset. Do that now.
3157 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3158 codeBlock, CompilationDeferred);
3159}
3160
3161void JIT_OPERATION triggerTierUpNow(ExecState* exec)
3162{
3163 VM* vm = &exec->vm();
3164 NativeCallFrameTracer tracer(vm, exec);
3165 DeferGCForAWhile deferGC(vm->heap);
3166 CodeBlock* codeBlock = exec->codeBlock();
3167
3168 sanitizeStackForVM(vm);
3169
3170 if (codeBlock->jitType() != JITCode::DFGJIT) {
3171 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
3172 RELEASE_ASSERT_NOT_REACHED();
3173 }
3174
3175 JITCode* jitCode = codeBlock->jitCode()->dfg();
3176
3177 if (Options::verboseOSR()) {
3178 dataLog(
3179 *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
3180 jitCode->tierUpCounter, "\n");
3181 }
3182
3183 if (shouldTriggerFTLCompile(codeBlock, jitCode))
3184 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3185
3186 if (codeBlock->hasOptimizedReplacement()) {
3187 if (jitCode->tierUpEntryTriggers.isEmpty()) {
3188 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("replacement in place, delaying indefinitely"));
3189 // There is nothing more we can do, the only way this will be entered
3190 // is through the function entry point.
3191 jitCode->dontOptimizeAnytimeSoon(codeBlock);
3192 return;
3193 }
3194 if (jitCode->osrEntryBlock() && jitCode->tierUpEntryTriggers.size() == 1) {
3195 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("trigger in place, delaying indefinitely"));
3196 // There is only one outer loop and its trigger must have been set
3197 // when the plan completed.
3198 // Exiting the inner loop is useless, we can ignore the counter and leave
3199 // the trigger do its job.
3200 jitCode->dontOptimizeAnytimeSoon(codeBlock);
3201 return;
3202 }
3203 }
3204}
3205
3206static char* tierUpCommon(ExecState* exec, unsigned originBytecodeIndex, bool canOSREnterHere)
3207{
3208 VM* vm = &exec->vm();
3209 CodeBlock* codeBlock = exec->codeBlock();
3210
3211 // Resolve any pending plan for OSR Enter on this function.
3212 Worklist::State worklistState;
3213 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
3214 worklistState = worklist->completeAllReadyPlansForVM(
3215 *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode));
3216 } else
3217 worklistState = Worklist::NotKnown;
3218
3219 JITCode* jitCode = codeBlock->jitCode()->dfg();
3220
3221 bool triggeredSlowPathToStartCompilation = false;
3222 auto tierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
3223 if (tierUpEntryTriggers != jitCode->tierUpEntryTriggers.end()) {
3224 switch (tierUpEntryTriggers->value) {
3225 case JITCode::TriggerReason::DontTrigger:
3226 // The trigger isn't set, we entered because the counter reached its
3227 // threshold.
3228 break;
3229
3230 case JITCode::TriggerReason::CompilationDone:
3231 // The trigger was set because compilation completed. Don't unset it
3232 // so that further DFG executions OSR enter as well.
3233 break;
3234
3235 case JITCode::TriggerReason::StartCompilation:
3236 // We were asked to enter as soon as possible and start compiling an
3237 // entry for the current bytecode location. Unset this trigger so we
3238 // don't continually enter.
3239 tierUpEntryTriggers->value = JITCode::TriggerReason::DontTrigger;
3240 triggeredSlowPathToStartCompilation = true;
3241 break;
3242 }
3243 }
3244
3245 if (worklistState == Worklist::Compiling) {
3246 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling"));
3247 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3248 return nullptr;
3249 }
3250
3251 // If we can OSR Enter, do it right away.
3252 if (canOSREnterHere) {
3253 auto iter = jitCode->bytecodeIndexToStreamIndex.find(originBytecodeIndex);
3254 if (iter != jitCode->bytecodeIndexToStreamIndex.end()) {
3255 unsigned streamIndex = iter->value;
3256 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
3257 if (Options::verboseOSR())
3258 dataLog("OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(entryBlock), "\n");
3259 if (void* address = FTL::prepareOSREntry(exec, codeBlock, entryBlock, originBytecodeIndex, streamIndex)) {
3260 CODEBLOCK_LOG_EVENT(entryBlock, "osrEntry", ("at bc#", originBytecodeIndex));
3261 return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
3262 }
3263 }
3264 }
3265 }
3266
3267 if (worklistState == Worklist::Compiled) {
3268 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed"));
3269 // This means that compilation failed and we already set the thresholds.
3270 if (Options::verboseOSR())
3271 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
3272 return nullptr;
3273 }
3274
3275 // - If we don't have an FTL code block, then try to compile one.
3276 // - If we do have an FTL code block, then try to enter for a while.
3277 // - If we couldn't enter for a while, then trigger OSR entry.
3278
3279 if (!shouldTriggerFTLCompile(codeBlock, jitCode) && !triggeredSlowPathToStartCompilation)
3280 return nullptr;
3281
3282 if (!jitCode->neverExecutedEntry && !triggeredSlowPathToStartCompilation) {
3283 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3284
3285 if (!codeBlock->hasOptimizedReplacement())
3286 return nullptr;
3287
3288 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
3289 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding OSR entry compile"));
3290 jitCode->osrEntryRetry++;
3291 return nullptr;
3292 }
3293 } else
3294 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding replacement compile"));
3295
3296 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
3297 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
3298 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed, OSR entry threshold not met"));
3299 jitCode->osrEntryRetry++;
3300 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3301 codeBlock, CompilationDeferred);
3302 return nullptr;
3303 }
3304
3305 FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
3306 entryCode->countEntryFailure();
3307 if (entryCode->entryFailureCount() <
3308 Options::ftlOSREntryFailureCountForReoptimization()) {
3309 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed"));
3310 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3311 codeBlock, CompilationDeferred);
3312 return nullptr;
3313 }
3314
3315 // OSR entry failed. Oh no! This implies that we need to retry. We retry
3316 // without exponential backoff and we only do this for the entry code block.
3317 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed too many times"));
3318 unsigned osrEntryBytecode = entryBlock->jitCode()->ftlForOSREntry()->bytecodeIndex();
3319 jitCode->clearOSREntryBlock();
3320 jitCode->osrEntryRetry = 0;
3321 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, JITCode::TriggerReason::DontTrigger);
3322 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3323 codeBlock, CompilationDeferred);
3324 return nullptr;
3325 }
3326
3327 // It's time to try to compile code for OSR entry.
3328
3329 if (!triggeredSlowPathToStartCompilation) {
3330
3331 // An inner loop didn't specifically ask for us to kick off a compilation. This means the counter
3332 // crossed its threshold. We either fall through and kick off a compile for originBytecodeIndex,
3333 // or we flag an outer loop to immediately try to compile itself. If there are outer loops,
3334 // we first try to make them compile themselves. But we will eventually fall back to compiling
3335 // a progressively inner loop if it takes too long for control to reach an outer loop.
3336
3337 auto tryTriggerOuterLoopToCompile = [&] {
3338 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(originBytecodeIndex);
3339 if (tierUpHierarchyEntry == jitCode->tierUpInLoopHierarchy.end())
3340 return false;
3341
3342 // This vector is ordered from innermost to outermost loop. Every bytecode entry in this vector is
3343 // allowed to do OSR entry. We start with the outermost loop and make our way inwards (hence why we
3344 // iterate the vector in reverse). Our policy is that we will trigger an outer loop to compile
3345 // immediately when program control reaches it. If program control is taking too long to reach that
3346 // outer loop, we progressively move inwards, meaning, we'll eventually trigger some loop that is
3347 // executing to compile. We start with trying to compile outer loops since we believe outer loop
3348 // compilations reveal the best opportunities for optimizing code.
3349 for (auto iter = tierUpHierarchyEntry->value.rbegin(), end = tierUpHierarchyEntry->value.rend(); iter != end; ++iter) {
3350 unsigned osrEntryCandidate = *iter;
3351
3352 if (jitCode->tierUpEntryTriggers.get(osrEntryCandidate) == JITCode::TriggerReason::StartCompilation) {
3353 // This means that we already asked this loop to compile. If we've reached here, it
3354 // means program control has not yet reached that loop. So it's taking too long to compile.
3355 // So we move on to asking the inner loop of this loop to compile itself.
3356 continue;
3357 }
3358
3359 // This is where we ask the outer to loop to immediately compile itself if program
3360 // control reaches it.
3361 if (Options::verboseOSR())
3362 dataLog("Inner-loop bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryCandidate, "'s trigger and backing off.\n");
3363 jitCode->tierUpEntryTriggers.set(osrEntryCandidate, JITCode::TriggerReason::StartCompilation);
3364 return true;
3365 }
3366
3367 return false;
3368 };
3369
3370 if (tryTriggerOuterLoopToCompile()) {
3371 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3372 return nullptr;
3373 }
3374 }
3375
3376 if (!canOSREnterHere) {
3377 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3378 return nullptr;
3379 }
3380
3381 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
3382 // something.
3383
3384 auto triggerIterator = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
3385 if (triggerIterator == jitCode->tierUpEntryTriggers.end()) {
3386 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3387 return nullptr;
3388 }
3389
3390 JITCode::TriggerReason* triggerAddress = &(triggerIterator->value);
3391
3392 Operands<Optional<JSValue>> mustHandleValues;
3393 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex);
3394 jitCode->reconstruct(
3395 exec, codeBlock, CodeOrigin(originBytecodeIndex), streamIndex, mustHandleValues);
3396 CodeBlock* replacementCodeBlock = codeBlock->newReplacement();
3397
3398 CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLOSR", ());
3399 CompilationResult forEntryResult = compile(
3400 *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, originBytecodeIndex,
3401 mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(triggerAddress));
3402
3403 if (jitCode->neverExecutedEntry)
3404 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3405
3406 if (forEntryResult != CompilationSuccessful) {
3407 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR ecompilation not successful"));
3408 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3409 codeBlock, CompilationDeferred);
3410 return nullptr;
3411 }
3412
3413 CODEBLOCK_LOG_EVENT(jitCode->osrEntryBlock(), "osrEntry", ("at bc#", originBytecodeIndex));
3414 // It's possible that the for-entry compile already succeeded. In that case OSR
3415 // entry will succeed unless we ran out of stack. It's not clear what we should do.
3416 // We signal to try again after a while if that happens.
3417 if (Options::verboseOSR())
3418 dataLog("Immediate OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(jitCode->osrEntryBlock()), "\n");
3419
3420 void* address = FTL::prepareOSREntry(
3421 exec, codeBlock, jitCode->osrEntryBlock(), originBytecodeIndex, streamIndex);
3422 if (!address)
3423 return nullptr;
3424 return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
3425}
3426
3427void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec, unsigned bytecodeIndex)
3428{
3429 VM* vm = &exec->vm();
3430 NativeCallFrameTracer tracer(vm, exec);
3431 DeferGCForAWhile deferGC(vm->heap);
3432 CodeBlock* codeBlock = exec->codeBlock();
3433
3434 sanitizeStackForVM(vm);
3435
3436 if (codeBlock->jitType() != JITCode::DFGJIT) {
3437 dataLog("Unexpected code block in DFG->FTL trigger tier up now in loop: ", *codeBlock, "\n");
3438 RELEASE_ASSERT_NOT_REACHED();
3439 }
3440
3441 JITCode* jitCode = codeBlock->jitCode()->dfg();
3442
3443 if (Options::verboseOSR()) {
3444 dataLog(
3445 *codeBlock, ": Entered triggerTierUpNowInLoop with executeCounter = ",
3446 jitCode->tierUpCounter, "\n");
3447 }
3448
3449 if (jitCode->tierUpInLoopHierarchy.contains(bytecodeIndex))
3450 tierUpCommon(exec, bytecodeIndex, false);
3451 else if (shouldTriggerFTLCompile(codeBlock, jitCode))
3452 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3453
3454 // Since we cannot OSR Enter here, the default "optimizeSoon()" is not useful.
3455 if (codeBlock->hasOptimizedReplacement()) {
3456 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR in loop failed, deferring"));
3457 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3458 }
3459}
3460
3461char* JIT_OPERATION triggerOSREntryNow(ExecState* exec, unsigned bytecodeIndex)
3462{
3463 VM* vm = &exec->vm();
3464 NativeCallFrameTracer tracer(vm, exec);
3465 DeferGCForAWhile deferGC(vm->heap);
3466 CodeBlock* codeBlock = exec->codeBlock();
3467
3468 sanitizeStackForVM(vm);
3469
3470 if (codeBlock->jitType() != JITCode::DFGJIT) {
3471 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
3472 RELEASE_ASSERT_NOT_REACHED();
3473 }
3474
3475 JITCode* jitCode = codeBlock->jitCode()->dfg();
3476 jitCode->tierUpEntrySeen.add(bytecodeIndex);
3477
3478 if (Options::verboseOSR()) {
3479 dataLog(
3480 *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ",
3481 jitCode->tierUpCounter, "\n");
3482 }
3483
3484 return tierUpCommon(exec, bytecodeIndex, true);
3485}
3486
3487#endif // ENABLE(FTL_JIT)
3488
3489} // extern "C"
3490} } // namespace JSC::DFG
3491
3492#endif // ENABLE(DFG_JIT)
3493
3494#endif // ENABLE(JIT)
3495