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