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