2 * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGOperations.h"
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"
50 #include "JITExceptions.h"
51 #include "JSArrayInlines.h"
52 #include "JSCInlines.h"
53 #include "JSFixedArray.h"
54 #include "JSGenericTypedArrayViewConstructorInlines.h"
55 #include "JSGlobalObjectFunctions.h"
56 #include "JSImmutableButterfly.h"
57 #include "JSLexicalEnvironment.h"
59 #include "JSPropertyNameEnumerator.h"
61 #include "JSWeakMap.h"
62 #include "JSWeakSet.h"
63 #include "NumberConstructor.h"
64 #include "ObjectConstructor.h"
65 #include "Operations.h"
67 #include "RegExpConstructor.h"
68 #include "RegExpMatchesArray.h"
69 #include "RegExpObjectInlines.h"
71 #include "ScopedArguments.h"
72 #include "StringConstructor.h"
73 #include "SuperSampler.h"
75 #include "TypeProfilerLog.h"
76 #include "TypedArrayInlines.h"
77 #include "VMInlines.h"
78 #include <wtf/InlineASM.h>
79 #include <wtf/Variant.h>
84 namespace JSC { namespace DFG {
86 template<bool strict, bool direct>
87 static inline void putByVal(ExecState* exec, VM& vm, JSValue baseValue, uint32_t index, JSValue value)
89 ASSERT(isIndex(index));
91 RELEASE_ASSERT(baseValue.isObject());
92 asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
95 if (baseValue.isObject()) {
96 JSObject* object = asObject(baseValue);
97 if (object->canSetIndexQuickly(index)) {
98 object->setIndexQuickly(vm, index, value);
102 object->methodTable(vm)->putByIndex(object, exec, index, value, strict);
106 baseValue.putByIndex(exec, index, value, strict);
109 template<bool strict, bool direct>
110 ALWAYS_INLINE static void putByValInternal(ExecState* exec, VM& vm, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
112 auto scope = DECLARE_THROW_SCOPE(vm);
114 JSValue baseValue = JSValue::decode(encodedBase);
115 JSValue property = JSValue::decode(encodedProperty);
116 JSValue value = JSValue::decode(encodedValue);
118 if (LIKELY(property.isUInt32())) {
119 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
120 ASSERT(isIndex(property.asUInt32()));
122 putByVal<strict, direct>(exec, vm, baseValue, property.asUInt32(), value);
126 if (property.isDouble()) {
127 double propertyAsDouble = property.asDouble();
128 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
129 if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) {
131 putByVal<strict, direct>(exec, vm, baseValue, propertyAsUInt32, value);
136 // Don't put to an object if toString throws an exception.
137 auto propertyName = property.toPropertyKey(exec);
138 RETURN_IF_EXCEPTION(scope, void());
140 PutPropertySlot slot(baseValue, strict);
142 RELEASE_ASSERT(baseValue.isObject());
143 JSObject* baseObject = asObject(baseValue);
144 if (std::optional<uint32_t> index = parseIndex(propertyName)) {
146 baseObject->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
150 CommonSlowPaths::putDirectWithReify(vm, exec, baseObject, propertyName, value, slot);
154 baseValue.put(exec, propertyName, value, slot);
157 template<bool strict, bool direct>
158 ALWAYS_INLINE static void putByValCellInternal(ExecState* exec, VM& vm, JSCell* base, PropertyName propertyName, JSValue value)
160 PutPropertySlot slot(base, strict);
162 RELEASE_ASSERT(base->isObject());
163 JSObject* baseObject = asObject(base);
164 if (std::optional<uint32_t> index = parseIndex(propertyName)) {
165 baseObject->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
168 CommonSlowPaths::putDirectWithReify(vm, exec, baseObject, propertyName, value, slot);
171 base->putInline(exec, propertyName, value, slot);
174 template<bool strict, bool direct>
175 ALWAYS_INLINE static void putByValCellStringInternal(ExecState* exec, VM& vm, JSCell* base, JSString* property, JSValue value)
177 auto scope = DECLARE_THROW_SCOPE(vm);
179 auto propertyName = property->toIdentifier(exec);
180 RETURN_IF_EXCEPTION(scope, void());
183 putByValCellInternal<strict, direct>(exec, vm, base, propertyName, value);
186 template<typename ViewClass>
187 char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size, char* vector)
190 NativeCallFrameTracer tracer(&vm, exec);
191 auto scope = DECLARE_THROW_SCOPE(vm);
194 throwException(exec, scope, createRangeError(exec, "Requested length is negative"_s));
199 return bitwise_cast<char*>(ViewClass::createWithFastVector(exec, structure, size, vector));
202 return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
205 template <bool strict>
206 static ALWAYS_INLINE void putWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, const Identifier& ident)
208 JSValue baseValue = JSValue::decode(encodedBase);
209 JSValue thisVal = JSValue::decode(encodedThis);
210 JSValue putValue = JSValue::decode(encodedValue);
211 PutPropertySlot slot(thisVal, strict);
212 baseValue.putInline(exec, ident, putValue, slot);
215 static ALWAYS_INLINE EncodedJSValue parseIntResult(double input)
217 int asInt = static_cast<int>(input);
218 if (static_cast<double>(asInt) == input)
219 return JSValue::encode(jsNumber(asInt));
220 return JSValue::encode(jsNumber(input));
223 ALWAYS_INLINE static JSValue getByValObject(ExecState* exec, VM& vm, JSObject* base, PropertyName propertyName)
225 Structure& structure = *base->structure(vm);
226 if (JSCell::canUseFastGetOwnProperty(structure)) {
227 if (JSValue result = base->fastGetOwnProperty(vm, structure, propertyName))
230 return base->get(exec, propertyName);
235 EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
237 VM* vm = &exec->vm();
238 NativeCallFrameTracer tracer(vm, exec);
240 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode));
243 EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp)
245 VM* vm = &exec->vm();
246 NativeCallFrameTracer tracer(vm, exec);
248 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode));
251 JSCell* JIT_OPERATION operationObjectCreate(ExecState* exec, EncodedJSValue encodedPrototype)
254 NativeCallFrameTracer tracer(&vm, exec);
255 auto scope = DECLARE_THROW_SCOPE(vm);
257 JSValue prototype = JSValue::decode(encodedPrototype);
259 if (!prototype.isObject() && !prototype.isNull()) {
260 throwVMTypeError(exec, scope, "Object prototype may only be an Object or null."_s);
264 if (prototype.isObject()) {
266 return constructEmptyObject(exec, asObject(prototype));
269 return constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
272 JSCell* JIT_OPERATION operationObjectCreateObject(ExecState* exec, JSObject* prototype)
275 NativeCallFrameTracer tracer(&vm, exec);
276 return constructEmptyObject(exec, prototype);
279 JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, uint32_t inlineCapacity)
282 NativeCallFrameTracer tracer(&vm, exec);
283 auto scope = DECLARE_THROW_SCOPE(vm);
284 if (constructor->type() == JSFunctionType && jsCast<JSFunction*>(constructor)->canUseAllocationProfile()) {
285 auto rareData = jsCast<JSFunction*>(constructor)->ensureRareDataAndAllocationProfile(exec, inlineCapacity);
286 RETURN_IF_EXCEPTION(scope, nullptr);
287 ObjectAllocationProfile* allocationProfile = rareData->objectAllocationProfile();
288 Structure* structure = allocationProfile->structure();
289 JSObject* result = constructEmptyObject(exec, structure);
290 if (structure->hasPolyProto()) {
291 JSObject* prototype = allocationProfile->prototype();
292 ASSERT(prototype == jsCast<JSFunction*>(constructor)->prototypeForConstruction(vm, exec));
293 result->putDirect(vm, knownPolyProtoOffset, prototype);
294 prototype->didBecomePrototype();
295 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");
300 JSValue proto = constructor->get(exec, vm.propertyNames->prototype);
301 RETURN_IF_EXCEPTION(scope, nullptr);
302 if (proto.isObject())
303 return constructEmptyObject(exec, asObject(proto));
304 return constructEmptyObject(exec);
307 JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedTarget)
309 VM* vm = &exec->vm();
310 NativeCallFrameTracer tracer(vm, exec);
312 JSValue value = JSValue::decode(encodedTarget);
313 ASSERT(!value.isObject());
315 if (value.isUndefinedOrNull())
316 return constructEmptyObject(exec, globalObject->objectPrototype());
317 return value.toObject(exec, globalObject);
320 JSCell* JIT_OPERATION operationToObject(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedTarget, UniquedStringImpl* errorMessage)
322 VM* vm = &exec->vm();
323 NativeCallFrameTracer tracer(vm, exec);
324 auto scope = DECLARE_THROW_SCOPE(*vm);
326 JSValue value = JSValue::decode(encodedTarget);
327 ASSERT(!value.isObject());
329 if (UNLIKELY(value.isUndefinedOrNull())) {
330 if (errorMessage->length()) {
331 throwVMTypeError(exec, scope, errorMessage);
337 return value.toObject(exec, globalObject);
340 EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
342 VM* vm = &exec->vm();
343 NativeCallFrameTracer tracer(vm, exec);
344 auto scope = DECLARE_THROW_SCOPE(*vm);
346 JSValue op1 = JSValue::decode(encodedOp1);
347 JSValue op2 = JSValue::decode(encodedOp2);
349 int32_t a = op1.toInt32(exec);
350 RETURN_IF_EXCEPTION(scope, encodedJSValue());
352 int32_t b = op2.toInt32(exec);
353 return JSValue::encode(jsNumber(a & b));
356 EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
358 VM* vm = &exec->vm();
359 NativeCallFrameTracer tracer(vm, exec);
360 auto scope = DECLARE_THROW_SCOPE(*vm);
362 JSValue op1 = JSValue::decode(encodedOp1);
363 JSValue op2 = JSValue::decode(encodedOp2);
365 int32_t a = op1.toInt32(exec);
366 RETURN_IF_EXCEPTION(scope, encodedJSValue());
368 int32_t b = op2.toInt32(exec);
369 return JSValue::encode(jsNumber(a | b));
372 EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
374 VM* vm = &exec->vm();
375 NativeCallFrameTracer tracer(vm, exec);
376 auto scope = DECLARE_THROW_SCOPE(*vm);
378 JSValue op1 = JSValue::decode(encodedOp1);
379 JSValue op2 = JSValue::decode(encodedOp2);
381 int32_t a = op1.toInt32(exec);
382 RETURN_IF_EXCEPTION(scope, encodedJSValue());
384 int32_t b = op2.toInt32(exec);
385 return JSValue::encode(jsNumber(a ^ b));
388 EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
390 VM* vm = &exec->vm();
391 NativeCallFrameTracer tracer(vm, exec);
392 auto scope = DECLARE_THROW_SCOPE(*vm);
394 JSValue op1 = JSValue::decode(encodedOp1);
395 JSValue op2 = JSValue::decode(encodedOp2);
397 int32_t a = op1.toInt32(exec);
398 RETURN_IF_EXCEPTION(scope, encodedJSValue());
400 uint32_t b = op2.toUInt32(exec);
401 return JSValue::encode(jsNumber(a << (b & 0x1f)));
404 EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
406 VM* vm = &exec->vm();
407 NativeCallFrameTracer tracer(vm, exec);
408 auto scope = DECLARE_THROW_SCOPE(*vm);
410 JSValue op1 = JSValue::decode(encodedOp1);
411 JSValue op2 = JSValue::decode(encodedOp2);
413 int32_t a = op1.toInt32(exec);
414 RETURN_IF_EXCEPTION(scope, encodedJSValue());
416 uint32_t b = op2.toUInt32(exec);
417 return JSValue::encode(jsNumber(a >> (b & 0x1f)));
420 EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
422 VM* vm = &exec->vm();
423 NativeCallFrameTracer tracer(vm, exec);
424 auto scope = DECLARE_THROW_SCOPE(*vm);
426 JSValue op1 = JSValue::decode(encodedOp1);
427 JSValue op2 = JSValue::decode(encodedOp2);
429 uint32_t a = op1.toUInt32(exec);
430 RETURN_IF_EXCEPTION(scope, encodedJSValue());
432 uint32_t b = op2.toUInt32(exec);
433 return JSValue::encode(jsNumber(static_cast<int32_t>(a >> (b & 0x1f))));
436 EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
438 VM* vm = &exec->vm();
439 NativeCallFrameTracer tracer(vm, exec);
441 JSValue op1 = JSValue::decode(encodedOp1);
442 JSValue op2 = JSValue::decode(encodedOp2);
444 ASSERT(!op1.isNumber() || !op2.isNumber());
446 if (op1.isString() && !op2.isObject())
447 return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec)));
449 return JSValue::encode(jsAddSlowCase(exec, op1, op2));
452 EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
454 VM* vm = &exec->vm();
455 NativeCallFrameTracer tracer(vm, exec);
456 auto scope = DECLARE_THROW_SCOPE(*vm);
458 JSValue op1 = JSValue::decode(encodedOp1);
459 JSValue op2 = JSValue::decode(encodedOp2);
461 auto leftNumeric = op1.toNumeric(exec);
462 RETURN_IF_EXCEPTION(scope, encodedJSValue());
463 auto rightNumeric = op2.toNumeric(exec);
464 RETURN_IF_EXCEPTION(scope, encodedJSValue());
466 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
467 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
468 JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
469 RETURN_IF_EXCEPTION(scope, encodedJSValue());
470 return JSValue::encode(result);
473 return throwVMTypeError(exec, scope, "Invalid operand in BigInt operation.");
478 double a = WTF::get<double>(leftNumeric);
479 double b = WTF::get<double>(rightNumeric);
480 return JSValue::encode(jsNumber(a / b));
483 double JIT_OPERATION operationArithAbs(ExecState* exec, EncodedJSValue encodedOp1)
485 VM* vm = &exec->vm();
486 NativeCallFrameTracer tracer(vm, exec);
487 auto scope = DECLARE_THROW_SCOPE(*vm);
489 JSValue op1 = JSValue::decode(encodedOp1);
490 double a = op1.toNumber(exec);
491 RETURN_IF_EXCEPTION(scope, PNaN);
495 uint32_t JIT_OPERATION operationArithClz32(ExecState* exec, EncodedJSValue encodedOp1)
497 VM* vm = &exec->vm();
498 NativeCallFrameTracer tracer(vm, exec);
499 auto scope = DECLARE_THROW_SCOPE(*vm);
501 JSValue op1 = JSValue::decode(encodedOp1);
502 uint32_t value = op1.toUInt32(exec);
503 RETURN_IF_EXCEPTION(scope, 0);
507 double JIT_OPERATION operationArithFRound(ExecState* exec, EncodedJSValue encodedOp1)
509 VM* vm = &exec->vm();
510 NativeCallFrameTracer tracer(vm, exec);
511 auto scope = DECLARE_THROW_SCOPE(*vm);
513 JSValue op1 = JSValue::decode(encodedOp1);
514 double a = op1.toNumber(exec);
515 RETURN_IF_EXCEPTION(scope, PNaN);
516 return static_cast<float>(a);
519 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \
520 double JIT_OPERATION operationArith##capitalizedName(ExecState* exec, EncodedJSValue encodedOp1) \
522 VM* vm = &exec->vm(); \
523 NativeCallFrameTracer tracer(vm, exec); \
524 auto scope = DECLARE_THROW_SCOPE(*vm); \
525 JSValue op1 = JSValue::decode(encodedOp1); \
526 double result = op1.toNumber(exec); \
527 RETURN_IF_EXCEPTION(scope, PNaN); \
528 return JSC::Math::lowerName(result); \
530 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
531 #undef DFG_ARITH_UNARY
533 double JIT_OPERATION operationArithSqrt(ExecState* exec, EncodedJSValue encodedOp1)
535 VM* vm = &exec->vm();
536 NativeCallFrameTracer tracer(vm, exec);
537 auto scope = DECLARE_THROW_SCOPE(*vm);
539 JSValue op1 = JSValue::decode(encodedOp1);
540 double a = op1.toNumber(exec);
541 RETURN_IF_EXCEPTION(scope, PNaN);
545 EncodedJSValue JIT_OPERATION operationArithRound(ExecState* exec, EncodedJSValue encodedArgument)
547 VM* vm = &exec->vm();
548 NativeCallFrameTracer tracer(vm, exec);
549 auto scope = DECLARE_THROW_SCOPE(*vm);
551 JSValue argument = JSValue::decode(encodedArgument);
552 double valueOfArgument = argument.toNumber(exec);
553 RETURN_IF_EXCEPTION(scope, encodedJSValue());
554 return JSValue::encode(jsNumber(jsRound(valueOfArgument)));
557 EncodedJSValue JIT_OPERATION operationArithFloor(ExecState* exec, EncodedJSValue encodedArgument)
559 VM* vm = &exec->vm();
560 NativeCallFrameTracer tracer(vm, exec);
561 auto scope = DECLARE_THROW_SCOPE(*vm);
563 JSValue argument = JSValue::decode(encodedArgument);
564 double valueOfArgument = argument.toNumber(exec);
565 RETURN_IF_EXCEPTION(scope, encodedJSValue());
566 return JSValue::encode(jsNumber(floor(valueOfArgument)));
569 EncodedJSValue JIT_OPERATION operationArithCeil(ExecState* exec, EncodedJSValue encodedArgument)
571 VM* vm = &exec->vm();
572 NativeCallFrameTracer tracer(vm, exec);
573 auto scope = DECLARE_THROW_SCOPE(*vm);
575 JSValue argument = JSValue::decode(encodedArgument);
576 double valueOfArgument = argument.toNumber(exec);
577 RETURN_IF_EXCEPTION(scope, encodedJSValue());
578 return JSValue::encode(jsNumber(ceil(valueOfArgument)));
581 EncodedJSValue JIT_OPERATION operationArithTrunc(ExecState* exec, EncodedJSValue encodedArgument)
583 VM* vm = &exec->vm();
584 NativeCallFrameTracer tracer(vm, exec);
585 auto scope = DECLARE_THROW_SCOPE(*vm);
587 JSValue argument = JSValue::decode(encodedArgument);
588 double truncatedValueOfArgument = argument.toIntegerPreserveNaN(exec);
589 RETURN_IF_EXCEPTION(scope, encodedJSValue());
590 return JSValue::encode(jsNumber(truncatedValueOfArgument));
593 static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
596 NativeCallFrameTracer tracer(&vm, exec);
598 if (base->isObject()) {
599 JSObject* object = asObject(base);
600 if (object->canGetIndexQuickly(index))
601 return JSValue::encode(object->getIndexQuickly(index));
604 if (isJSString(base) && asString(base)->canGetIndex(index))
605 return JSValue::encode(asString(base)->getIndex(exec, index));
607 return JSValue::encode(JSValue(base).get(exec, index));
610 EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
613 NativeCallFrameTracer tracer(&vm, exec);
614 auto scope = DECLARE_THROW_SCOPE(vm);
616 JSValue baseValue = JSValue::decode(encodedBase);
617 JSValue property = JSValue::decode(encodedProperty);
619 if (LIKELY(baseValue.isCell())) {
620 JSCell* base = baseValue.asCell();
622 if (property.isUInt32()) {
624 return getByVal(exec, base, property.asUInt32());
626 if (property.isDouble()) {
627 double propertyAsDouble = property.asDouble();
628 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
629 if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32)) {
631 return getByVal(exec, base, propertyAsUInt32);
633 } else if (property.isString()) {
634 Structure& structure = *base->structure(vm);
635 if (JSCell::canUseFastGetOwnProperty(structure)) {
636 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
637 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
638 return JSValue::encode(result);
644 baseValue.requireObjectCoercible(exec);
645 RETURN_IF_EXCEPTION(scope, encodedJSValue());
646 auto propertyName = property.toPropertyKey(exec);
647 RETURN_IF_EXCEPTION(scope, encodedJSValue());
649 return JSValue::encode(baseValue.get(exec, propertyName));
652 EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
655 NativeCallFrameTracer tracer(&vm, exec);
656 auto scope = DECLARE_THROW_SCOPE(vm);
658 JSValue property = JSValue::decode(encodedProperty);
660 if (property.isUInt32()) {
662 return getByVal(exec, base, property.asUInt32());
664 if (property.isDouble()) {
665 double propertyAsDouble = property.asDouble();
666 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
667 if (propertyAsUInt32 == propertyAsDouble) {
669 return getByVal(exec, base, propertyAsUInt32);
671 } else if (property.isString()) {
672 Structure& structure = *base->structure(vm);
673 if (JSCell::canUseFastGetOwnProperty(structure)) {
674 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
675 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
676 return JSValue::encode(result);
681 auto propertyName = property.toPropertyKey(exec);
682 RETURN_IF_EXCEPTION(scope, encodedJSValue());
684 return JSValue::encode(JSValue(base).get(exec, propertyName));
687 ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
689 VM* vm = &exec->vm();
690 NativeCallFrameTracer tracer(vm, exec);
693 // Go the slowest way possible because negative indices don't use indexed storage.
694 return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
697 // Use this since we know that the value is out of bounds.
698 return JSValue::encode(JSValue(base).get(exec, static_cast<unsigned>(index)));
701 EncodedJSValue JIT_OPERATION operationGetByValObjectInt(ExecState* exec, JSObject* base, int32_t index)
703 return getByValCellInt(exec, base, index);
706 EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
708 return getByValCellInt(exec, base, index);
711 EncodedJSValue JIT_OPERATION operationGetByValObjectString(ExecState* exec, JSCell* base, JSCell* string)
714 NativeCallFrameTracer tracer(&vm, exec);
716 auto scope = DECLARE_THROW_SCOPE(vm);
718 auto propertyName = asString(string)->toIdentifier(exec);
719 RETURN_IF_EXCEPTION(scope, encodedJSValue());
722 return JSValue::encode(getByValObject(exec, vm, asObject(base), propertyName));
725 EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(ExecState* exec, JSCell* base, JSCell* symbol)
728 NativeCallFrameTracer tracer(&vm, exec);
730 return JSValue::encode(getByValObject(exec, vm, asObject(base), asSymbol(symbol)->privateName()));
733 void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
736 NativeCallFrameTracer tracer(&vm, exec);
738 putByValInternal<true, false>(exec, vm, encodedBase, encodedProperty, encodedValue);
741 void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
744 NativeCallFrameTracer tracer(&vm, exec);
746 putByValInternal<false, false>(exec, vm, encodedBase, encodedProperty, encodedValue);
749 void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
752 NativeCallFrameTracer tracer(&vm, exec);
754 putByValInternal<true, false>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
757 void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
760 NativeCallFrameTracer tracer(&vm, exec);
762 putByValInternal<false, false>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
765 void JIT_OPERATION operationPutByValCellStringStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
768 NativeCallFrameTracer tracer(&vm, exec);
770 putByValCellStringInternal<true, false>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
773 void JIT_OPERATION operationPutByValCellStringNonStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
776 NativeCallFrameTracer tracer(&vm, exec);
778 putByValCellStringInternal<false, false>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
781 void JIT_OPERATION operationPutByValCellSymbolStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
784 NativeCallFrameTracer tracer(&vm, exec);
786 putByValCellInternal<true, false>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
789 void JIT_OPERATION operationPutByValCellSymbolNonStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
792 NativeCallFrameTracer tracer(&vm, exec);
794 putByValCellInternal<false, false>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
797 void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
800 NativeCallFrameTracer tracer(&vm, exec);
803 object->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
807 PutPropertySlot slot(object, true);
808 object->methodTable(vm)->put(
809 object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
812 void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
814 VM* vm = &exec->vm();
815 NativeCallFrameTracer tracer(vm, exec);
818 object->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
822 PutPropertySlot slot(object, false);
823 object->methodTable(*vm)->put(
824 object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
827 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
829 VM* vm = &exec->vm();
830 NativeCallFrameTracer tracer(vm, exec);
832 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
835 object->putByIndexInline(exec, index, jsValue, true);
839 PutPropertySlot slot(object, true);
840 object->methodTable(*vm)->put(
841 object, exec, Identifier::from(exec, index), jsValue, slot);
844 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
846 VM* vm = &exec->vm();
847 NativeCallFrameTracer tracer(vm, exec);
849 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
852 object->putByIndexInline(exec, index, jsValue, false);
856 PutPropertySlot slot(object, false);
857 object->methodTable(*vm)->put(
858 object, exec, Identifier::from(exec, index), jsValue, slot);
861 void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
864 NativeCallFrameTracer tracer(&vm, exec);
866 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
869 object->putDirectIndex(exec, index, jsValue, 0, PutDirectIndexShouldThrow);
873 PutPropertySlot slot(object, true);
874 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), jsValue, slot);
877 void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
880 NativeCallFrameTracer tracer(&vm, exec);
882 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
885 object->putDirectIndex(exec, index, jsValue);
889 PutPropertySlot slot(object, false);
890 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), jsValue, slot);
893 void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
896 NativeCallFrameTracer tracer(&vm, exec);
898 putByValInternal<true, true>(exec, vm, encodedBase, encodedProperty, encodedValue);
901 void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
904 NativeCallFrameTracer tracer(&vm, exec);
906 putByValInternal<false, true>(exec, vm, encodedBase, encodedProperty, encodedValue);
909 void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
912 NativeCallFrameTracer tracer(&vm, exec);
914 putByValInternal<true, true>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
917 void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
920 NativeCallFrameTracer tracer(&vm, exec);
922 putByValInternal<false, true>(exec, vm, JSValue::encode(cell), encodedProperty, encodedValue);
925 void JIT_OPERATION operationPutByValDirectCellStringStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
928 NativeCallFrameTracer tracer(&vm, exec);
930 putByValCellStringInternal<true, true>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
933 void JIT_OPERATION operationPutByValDirectCellStringNonStrict(ExecState* exec, JSCell* cell, JSCell* string, EncodedJSValue encodedValue)
936 NativeCallFrameTracer tracer(&vm, exec);
938 putByValCellStringInternal<false, true>(exec, vm, cell, asString(string), JSValue::decode(encodedValue));
941 void JIT_OPERATION operationPutByValDirectCellSymbolStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
944 NativeCallFrameTracer tracer(&vm, exec);
946 putByValCellInternal<true, true>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
949 void JIT_OPERATION operationPutByValDirectCellSymbolNonStrict(ExecState* exec, JSCell* cell, JSCell* symbol, EncodedJSValue encodedValue)
952 NativeCallFrameTracer tracer(&vm, exec);
954 putByValCellInternal<false, true>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
957 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
960 NativeCallFrameTracer tracer(&vm, exec);
962 object->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
966 PutPropertySlot slot(object, true);
967 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
970 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
973 NativeCallFrameTracer tracer(&vm, exec);
976 object->putDirectIndex(exec, index, JSValue::decode(encodedValue));
980 PutPropertySlot slot(object, false);
981 CommonSlowPaths::putDirectWithReify(vm, exec, object, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
984 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
986 VM* vm = &exec->vm();
987 NativeCallFrameTracer tracer(vm, exec);
989 array->pushInline(exec, JSValue::decode(encodedValue));
990 return JSValue::encode(jsNumber(array->length()));
993 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
995 VM* vm = &exec->vm();
996 NativeCallFrameTracer tracer(vm, exec);
998 array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, value));
999 return JSValue::encode(jsNumber(array->length()));
1002 EncodedJSValue JIT_OPERATION operationArrayPushMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
1004 VM& vm = exec->vm();
1005 NativeCallFrameTracer tracer(&vm, exec);
1006 auto scope = DECLARE_THROW_SCOPE(vm);
1008 // We assume that multiple JSArray::push calls with ArrayWithInt32/ArrayWithContiguous do not cause JS traps.
1009 // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
1010 // content of ScratchBuffer. If the IndexingType is now ArrayWithInt32/ArrayWithContiguous, we can ensure
1011 // that there is no indexed accessors in this object and its prototype chain.
1013 // ArrayWithArrayStorage is also OK. It can have indexed accessors. But if you define an indexed accessor, the array's length
1014 // becomes larger than that index. So Array#push never overlaps with this accessor. So accessors are never called unless
1015 // the IndexingType is ArrayWithSlowPutArrayStorage which could have an indexed accessor in a prototype chain.
1016 RELEASE_ASSERT(!shouldUseSlowPut(array->indexingType()));
1018 EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
1019 for (int32_t i = 0; i < elementCount; ++i) {
1020 array->pushInline(exec, JSValue::decode(values[i]));
1021 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1023 return JSValue::encode(jsNumber(array->length()));
1026 EncodedJSValue JIT_OPERATION operationArrayPushDoubleMultiple(ExecState* exec, JSArray* array, void* buffer, int32_t elementCount)
1028 VM& vm = exec->vm();
1029 NativeCallFrameTracer tracer(&vm, exec);
1030 auto scope = DECLARE_THROW_SCOPE(vm);
1032 // We assume that multiple JSArray::push calls with ArrayWithDouble do not cause JS traps.
1033 // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the
1034 // content of ScratchBuffer. If the IndexingType is now ArrayWithDouble, we can ensure
1035 // that there is no indexed accessors in this object and its prototype chain.
1036 ASSERT(array->indexingMode() == ArrayWithDouble);
1038 double* values = static_cast<double*>(buffer);
1039 for (int32_t i = 0; i < elementCount; ++i) {
1040 array->pushInline(exec, JSValue(JSValue::EncodeAsDouble, values[i]));
1041 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1043 return JSValue::encode(jsNumber(array->length()));
1046 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
1048 VM* vm = &exec->vm();
1049 NativeCallFrameTracer tracer(vm, exec);
1051 return JSValue::encode(array->pop(exec));
1054 EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array)
1056 VM* vm = &exec->vm();
1057 NativeCallFrameTracer tracer(vm, exec);
1059 array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1);
1061 return JSValue::encode(array->pop(exec));
1064 EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
1066 SuperSamplerScope superSamplerScope(false);
1068 VM& vm = globalObject->vm();
1069 NativeCallFrameTracer tracer(&vm, exec);
1071 return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
1074 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
1076 SuperSamplerScope superSamplerScope(false);
1078 VM& vm = globalObject->vm();
1079 NativeCallFrameTracer tracer(&vm, exec);
1080 auto scope = DECLARE_THROW_SCOPE(vm);
1082 JSValue argument = JSValue::decode(encodedArgument);
1084 JSString* input = argument.toStringOrNull(exec);
1085 EXCEPTION_ASSERT(!!scope.exception() == !input);
1087 return encodedJSValue();
1089 return JSValue::encode(regExpObject->execInline(exec, globalObject, input));
1092 EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
1094 SuperSamplerScope superSamplerScope(false);
1096 VM& vm = globalObject->vm();
1097 NativeCallFrameTracer tracer(&vm, exec);
1098 auto scope = DECLARE_THROW_SCOPE(vm);
1100 JSValue base = JSValue::decode(encodedBase);
1101 JSValue argument = JSValue::decode(encodedArgument);
1103 auto* regexp = jsDynamicCast<RegExpObject*>(vm, base);
1104 if (UNLIKELY(!regexp))
1105 return throwVMTypeError(exec, scope);
1107 JSString* input = argument.toStringOrNull(exec);
1108 EXCEPTION_ASSERT(!!scope.exception() == !input);
1110 return JSValue::encode(jsUndefined());
1112 return JSValue::encode(regexp->exec(exec, globalObject, input));
1115 EncodedJSValue JIT_OPERATION operationRegExpExecNonGlobalOrSticky(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string)
1117 SuperSamplerScope superSamplerScope(false);
1119 VM& vm = globalObject->vm();
1120 NativeCallFrameTracer tracer(&vm, exec);
1122 auto scope = DECLARE_THROW_SCOPE(vm);
1124 RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
1125 String input = string->value(exec);
1126 RETURN_IF_EXCEPTION(scope, { });
1128 unsigned lastIndex = 0;
1130 JSArray* array = createRegExpMatchesArray(vm, globalObject, string, input, regExp, lastIndex, result);
1132 ASSERT(!scope.exception());
1133 return JSValue::encode(jsNull());
1136 RETURN_IF_EXCEPTION(scope, { });
1137 regExpConstructor->recordMatch(vm, regExp, string, result);
1138 return JSValue::encode(array);
1141 EncodedJSValue JIT_OPERATION operationRegExpMatchFastString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* argument)
1143 SuperSamplerScope superSamplerScope(false);
1145 VM& vm = globalObject->vm();
1146 NativeCallFrameTracer tracer(&vm, exec);
1148 if (!regExpObject->regExp()->global())
1149 return JSValue::encode(regExpObject->execInline(exec, globalObject, argument));
1150 return JSValue::encode(regExpObject->matchGlobal(exec, globalObject, argument));
1153 EncodedJSValue JIT_OPERATION operationRegExpMatchFastGlobalString(ExecState* exec, JSGlobalObject* globalObject, RegExp* regExp, JSString* string)
1155 SuperSamplerScope superSamplerScope(false);
1157 VM& vm = globalObject->vm();
1158 NativeCallFrameTracer tracer(&vm, exec);
1160 auto scope = DECLARE_THROW_SCOPE(vm);
1162 ASSERT(regExp->global());
1164 String s = string->value(exec);
1165 RETURN_IF_EXCEPTION(scope, { });
1167 RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
1169 if (regExp->unicode()) {
1170 unsigned stringLength = s.length();
1172 return JSValue::encode(collectMatches(
1173 vm, exec, string, s, regExpConstructor, regExp,
1174 [&] (size_t end) -> size_t {
1175 return advanceStringUnicode(s, stringLength, end);
1180 return JSValue::encode(collectMatches(
1181 vm, exec, string, s, regExpConstructor, regExp,
1182 [&] (size_t end) -> size_t {
1187 EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value)
1189 VM& vm = exec->vm();
1190 NativeCallFrameTracer tracer(&vm, exec);
1192 return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
1193 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
1194 return parseIntResult(parseInt(view, 0));
1198 EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState* exec, JSString* string)
1200 VM& vm = exec->vm();
1201 NativeCallFrameTracer tracer(&vm, exec);
1202 auto scope = DECLARE_THROW_SCOPE(vm);
1204 auto viewWithString = string->viewWithUnderlyingString(exec);
1205 RETURN_IF_EXCEPTION(scope, { });
1207 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
1208 return parseIntResult(parseInt(viewWithString.view, 0));
1211 EncodedJSValue JIT_OPERATION operationParseIntString(ExecState* exec, JSString* string, int32_t radix)
1213 VM& vm = exec->vm();
1214 NativeCallFrameTracer tracer(&vm, exec);
1215 auto scope = DECLARE_THROW_SCOPE(vm);
1217 auto viewWithString = string->viewWithUnderlyingString(exec);
1218 RETURN_IF_EXCEPTION(scope, { });
1220 return parseIntResult(parseInt(viewWithString.view, radix));
1223 EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState* exec, EncodedJSValue value, int32_t radix)
1225 VM& vm = exec->vm();
1226 NativeCallFrameTracer tracer(&vm, exec);
1228 return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
1229 return parseIntResult(parseInt(view, radix));
1233 size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* input)
1235 SuperSamplerScope superSamplerScope(false);
1237 VM& vm = globalObject->vm();
1238 NativeCallFrameTracer tracer(&vm, exec);
1240 return regExpObject->testInline(exec, globalObject, input);
1243 size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, EncodedJSValue encodedArgument)
1245 SuperSamplerScope superSamplerScope(false);
1247 VM& vm = globalObject->vm();
1248 NativeCallFrameTracer tracer(&vm, exec);
1250 JSValue argument = JSValue::decode(encodedArgument);
1252 JSString* input = argument.toStringOrNull(exec);
1255 return regExpObject->testInline(exec, globalObject, input);
1258 size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
1260 SuperSamplerScope superSamplerScope(false);
1262 VM& vm = globalObject->vm();
1263 NativeCallFrameTracer tracer(&vm, exec);
1264 auto scope = DECLARE_THROW_SCOPE(vm);
1266 JSValue base = JSValue::decode(encodedBase);
1267 JSValue argument = JSValue::decode(encodedArgument);
1269 auto* regexp = jsDynamicCast<RegExpObject*>(vm, base);
1270 if (UNLIKELY(!regexp)) {
1271 throwTypeError(exec, scope);
1275 JSString* input = argument.toStringOrNull(exec);
1276 EXCEPTION_ASSERT(!!scope.exception() == !input);
1280 return regexp->test(exec, globalObject, input);
1283 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2)
1285 VM* vm = &exec->vm();
1286 NativeCallFrameTracer tracer(vm, exec);
1288 return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
1291 size_t JIT_OPERATION operationSameValue(ExecState* exec, EncodedJSValue arg1, EncodedJSValue arg2)
1293 VM& vm = exec->vm();
1294 NativeCallFrameTracer tracer(&vm, exec);
1296 return sameValue(exec, JSValue::decode(arg1), JSValue::decode(arg2));
1299 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
1301 VM* vm = &exec->vm();
1302 NativeCallFrameTracer tracer(vm, exec);
1304 return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
1307 EncodedJSValue JIT_OPERATION operationToNumber(ExecState* exec, EncodedJSValue value)
1309 VM* vm = &exec->vm();
1310 NativeCallFrameTracer tracer(vm, exec);
1312 return JSValue::encode(jsNumber(JSValue::decode(value).toNumber(exec)));
1315 EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
1317 VM& vm = exec->vm();
1318 NativeCallFrameTracer tracer(&vm, exec);
1319 auto scope = DECLARE_THROW_SCOPE(vm);
1321 JSValue baseValue = JSValue::decode(encodedBase);
1322 JSValue thisVal = JSValue::decode(encodedThis);
1323 JSValue subscript = JSValue::decode(encodedSubscript);
1325 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1326 Structure& structure = *baseValue.asCell()->structure(vm);
1327 if (JSCell::canUseFastGetOwnProperty(structure)) {
1328 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
1329 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
1330 return JSValue::encode(result);
1335 PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
1336 if (subscript.isUInt32()) {
1337 uint32_t i = subscript.asUInt32();
1338 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1339 return JSValue::encode(asString(baseValue)->getIndex(exec, i));
1342 return JSValue::encode(baseValue.get(exec, i, slot));
1345 baseValue.requireObjectCoercible(exec);
1346 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1348 auto property = subscript.toPropertyKey(exec);
1349 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1351 return JSValue::encode(baseValue.get(exec, property, slot));
1354 void JIT_OPERATION operationPutByIdWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
1356 VM& vm = exec->vm();
1357 NativeCallFrameTracer tracer(&vm, exec);
1359 putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
1362 void JIT_OPERATION operationPutByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
1364 VM& vm = exec->vm();
1365 NativeCallFrameTracer tracer(&vm, exec);
1367 putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
1370 void JIT_OPERATION operationPutByValWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
1372 VM& vm = exec->vm();
1373 NativeCallFrameTracer tracer(&vm, exec);
1374 auto scope = DECLARE_THROW_SCOPE(vm);
1376 Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
1377 RETURN_IF_EXCEPTION(scope, void());
1379 putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, property);
1382 void JIT_OPERATION operationPutByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
1384 VM& vm = exec->vm();
1385 NativeCallFrameTracer tracer(&vm, exec);
1386 auto scope = DECLARE_THROW_SCOPE(vm);
1388 Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
1389 RETURN_IF_EXCEPTION(scope, void());
1391 putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, property);
1394 ALWAYS_INLINE static void defineDataProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSValue value, int32_t attributes)
1396 PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes));
1397 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1398 if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
1399 JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
1401 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1404 void JIT_OPERATION operationDefineDataProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, EncodedJSValue encodedValue, int32_t attributes)
1406 VM& vm = exec->vm();
1407 NativeCallFrameTracer tracer(&vm, exec);
1408 auto scope = DECLARE_THROW_SCOPE(vm);
1410 Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
1411 RETURN_IF_EXCEPTION(scope, void());
1413 defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
1416 void JIT_OPERATION operationDefineDataPropertyString(ExecState* exec, JSObject* base, JSString* property, EncodedJSValue encodedValue, int32_t attributes)
1418 VM& vm = exec->vm();
1419 NativeCallFrameTracer tracer(&vm, exec);
1420 auto scope = DECLARE_THROW_SCOPE(vm);
1422 Identifier propertyName = property->toIdentifier(exec);
1423 RETURN_IF_EXCEPTION(scope, void());
1425 defineDataProperty(exec, vm, base, propertyName, JSValue::decode(encodedValue), attributes);
1428 void JIT_OPERATION operationDefineDataPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, EncodedJSValue encodedValue, int32_t attributes)
1430 VM& vm = exec->vm();
1431 NativeCallFrameTracer tracer(&vm, exec);
1432 defineDataProperty(exec, vm, base, Identifier::fromUid(&vm, property), JSValue::decode(encodedValue), attributes);
1435 void JIT_OPERATION operationDefineDataPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, EncodedJSValue encodedValue, int32_t attributes)
1437 VM& vm = exec->vm();
1438 NativeCallFrameTracer tracer(&vm, exec);
1439 defineDataProperty(exec, vm, base, Identifier::fromUid(property->privateName()), JSValue::decode(encodedValue), attributes);
1442 ALWAYS_INLINE static void defineAccessorProperty(ExecState* exec, VM& vm, JSObject* base, const Identifier& propertyName, JSObject* getter, JSObject* setter, int32_t attributes)
1444 PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes));
1445 ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor()));
1446 if (base->methodTable(vm)->defineOwnProperty == JSObject::defineOwnProperty)
1447 JSObject::defineOwnProperty(base, exec, propertyName, descriptor, true);
1449 base->methodTable(vm)->defineOwnProperty(base, exec, propertyName, descriptor, true);
1452 void JIT_OPERATION operationDefineAccessorProperty(ExecState* exec, JSObject* base, EncodedJSValue encodedProperty, JSObject* getter, JSObject* setter, int32_t attributes)
1454 VM& vm = exec->vm();
1455 NativeCallFrameTracer tracer(&vm, exec);
1456 auto scope = DECLARE_THROW_SCOPE(vm);
1458 Identifier propertyName = JSValue::decode(encodedProperty).toPropertyKey(exec);
1459 RETURN_IF_EXCEPTION(scope, void());
1460 defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
1463 void JIT_OPERATION operationDefineAccessorPropertyString(ExecState* exec, JSObject* base, JSString* property, JSObject* getter, JSObject* setter, int32_t attributes)
1465 VM& vm = exec->vm();
1466 NativeCallFrameTracer tracer(&vm, exec);
1467 auto scope = DECLARE_THROW_SCOPE(vm);
1469 Identifier propertyName = property->toIdentifier(exec);
1470 RETURN_IF_EXCEPTION(scope, void());
1471 defineAccessorProperty(exec, vm, base, propertyName, getter, setter, attributes);
1474 void JIT_OPERATION operationDefineAccessorPropertyStringIdent(ExecState* exec, JSObject* base, UniquedStringImpl* property, JSObject* getter, JSObject* setter, int32_t attributes)
1476 VM& vm = exec->vm();
1477 NativeCallFrameTracer tracer(&vm, exec);
1478 defineAccessorProperty(exec, vm, base, Identifier::fromUid(&vm, property), getter, setter, attributes);
1481 void JIT_OPERATION operationDefineAccessorPropertySymbol(ExecState* exec, JSObject* base, Symbol* property, JSObject* getter, JSObject* setter, int32_t attributes)
1483 VM& vm = exec->vm();
1484 NativeCallFrameTracer tracer(&vm, exec);
1485 defineAccessorProperty(exec, vm, base, Identifier::fromUid(property->privateName()), getter, setter, attributes);
1488 char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
1490 VM* vm = &exec->vm();
1491 NativeCallFrameTracer tracer(vm, exec);
1493 return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
1496 char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
1498 VM* vm = &exec->vm();
1499 NativeCallFrameTracer tracer(vm, exec);
1501 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure));
1504 char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size, Butterfly* butterfly)
1506 VM& vm = exec->vm();
1507 NativeCallFrameTracer tracer(&vm, exec);
1508 auto scope = DECLARE_THROW_SCOPE(vm);
1510 if (UNLIKELY(size < 0))
1511 return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, "Array size is not a small enough positive integer."_s)));
1515 result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly);
1517 result = JSArray::create(vm, arrayStructure, size);
1518 return bitwise_cast<char*>(result);
1521 char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState* exec, Structure* arrayStructure, int32_t size, int32_t vectorLengthHint, Butterfly* butterfly)
1523 VM& vm = exec->vm();
1524 NativeCallFrameTracer tracer(&vm, exec);
1525 auto scope = DECLARE_THROW_SCOPE(vm);
1527 if (UNLIKELY(size < 0))
1528 return bitwise_cast<char*>(throwException(exec, scope, createRangeError(exec, "Array size is not a small enough positive integer."_s)));
1532 result = JSArray::createWithButterfly(vm, nullptr, arrayStructure, butterfly);
1534 result = JSArray::tryCreate(vm, arrayStructure, size, vectorLengthHint);
1535 RELEASE_ASSERT(result);
1537 return bitwise_cast<char*>(result);
1540 JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, JSCell* immutableButterflyCell)
1542 VM& vm = exec->vm();
1543 NativeCallFrameTracer tracer(&vm, exec);
1544 ASSERT(!arrayStructure->outOfLineCapacity());
1545 auto* immutableButterfly = jsCast<JSImmutableButterfly*>(immutableButterflyCell);
1546 ASSERT(arrayStructure->indexingMode() == immutableButterfly->indexingMode() || hasAnyArrayStorage(arrayStructure->indexingMode()));
1547 auto* result = CommonSlowPaths::allocateNewArrayBuffer(vm, arrayStructure, immutableButterfly);
1548 ASSERT(result->indexingMode() == result->structure(vm)->indexingMode());
1549 ASSERT(result->structure(vm) == arrayStructure);
1553 char* JIT_OPERATION operationNewInt8ArrayWithSize(
1554 ExecState* exec, Structure* structure, int32_t length, char* vector)
1556 return newTypedArrayWithSize<JSInt8Array>(exec, structure, length, vector);
1559 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
1560 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1562 VM& vm = exec->vm();
1563 NativeCallFrameTracer tracer(&vm, exec);
1564 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt8Array>(exec, structure, encodedValue, 0, std::nullopt));
1567 char* JIT_OPERATION operationNewInt16ArrayWithSize(
1568 ExecState* exec, Structure* structure, int32_t length, char* vector)
1570 return newTypedArrayWithSize<JSInt16Array>(exec, structure, length, vector);
1573 char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
1574 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1576 VM& vm = exec->vm();
1577 NativeCallFrameTracer tracer(&vm, exec);
1578 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt16Array>(exec, structure, encodedValue, 0, std::nullopt));
1581 char* JIT_OPERATION operationNewInt32ArrayWithSize(
1582 ExecState* exec, Structure* structure, int32_t length, char* vector)
1584 return newTypedArrayWithSize<JSInt32Array>(exec, structure, length, vector);
1587 char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
1588 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1590 VM& vm = exec->vm();
1591 NativeCallFrameTracer tracer(&vm, exec);
1592 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt32Array>(exec, structure, encodedValue, 0, std::nullopt));
1595 char* JIT_OPERATION operationNewUint8ArrayWithSize(
1596 ExecState* exec, Structure* structure, int32_t length, char* vector)
1598 return newTypedArrayWithSize<JSUint8Array>(exec, structure, length, vector);
1601 char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
1602 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1604 VM& vm = exec->vm();
1605 NativeCallFrameTracer tracer(&vm, exec);
1606 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8Array>(exec, structure, encodedValue, 0, std::nullopt));
1609 char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
1610 ExecState* exec, Structure* structure, int32_t length, char* vector)
1612 return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length, vector);
1615 char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
1616 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1618 VM& vm = exec->vm();
1619 NativeCallFrameTracer tracer(&vm, exec);
1620 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8ClampedArray>(exec, structure, encodedValue, 0, std::nullopt));
1623 char* JIT_OPERATION operationNewUint16ArrayWithSize(
1624 ExecState* exec, Structure* structure, int32_t length, char* vector)
1626 return newTypedArrayWithSize<JSUint16Array>(exec, structure, length, vector);
1629 char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
1630 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1632 VM& vm = exec->vm();
1633 NativeCallFrameTracer tracer(&vm, exec);
1634 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint16Array>(exec, structure, encodedValue, 0, std::nullopt));
1637 char* JIT_OPERATION operationNewUint32ArrayWithSize(
1638 ExecState* exec, Structure* structure, int32_t length, char* vector)
1640 return newTypedArrayWithSize<JSUint32Array>(exec, structure, length, vector);
1643 char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
1644 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1646 VM& vm = exec->vm();
1647 NativeCallFrameTracer tracer(&vm, exec);
1648 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint32Array>(exec, structure, encodedValue, 0, std::nullopt));
1651 char* JIT_OPERATION operationNewFloat32ArrayWithSize(
1652 ExecState* exec, Structure* structure, int32_t length, char* vector)
1654 return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length, vector);
1657 char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
1658 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1660 VM& vm = exec->vm();
1661 NativeCallFrameTracer tracer(&vm, exec);
1662 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat32Array>(exec, structure, encodedValue, 0, std::nullopt));
1665 char* JIT_OPERATION operationNewFloat64ArrayWithSize(
1666 ExecState* exec, Structure* structure, int32_t length, char* vector)
1668 return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length, vector);
1671 char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
1672 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
1674 VM& vm = exec->vm();
1675 NativeCallFrameTracer tracer(&vm, exec);
1676 return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat64Array>(exec, structure, encodedValue, 0, std::nullopt));
1679 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table, EncodedJSValue initialValueEncoded)
1681 JSValue initialValue = JSValue::decode(initialValueEncoded);
1682 ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
1683 VM& vm = exec->vm();
1684 NativeCallFrameTracer tracer(&vm, exec);
1685 return JSLexicalEnvironment::create(vm, structure, scope, table, initialValue);
1688 JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, uint32_t length, uint32_t minCapacity)
1690 VM& vm = exec->vm();
1691 NativeCallFrameTracer target(&vm, exec);
1692 DirectArguments* result = DirectArguments::create(
1693 vm, structure, length, std::max(length, minCapacity));
1694 // The caller will store to this object without barriers. Most likely, at this point, this is
1695 // still a young object and so no barriers are needed. But it's good to be careful anyway,
1696 // since the GC should be allowed to do crazy (like pretenuring, for example).
1697 vm.heap.writeBarrier(result);
1701 JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, uint32_t length, JSFunction* callee, JSLexicalEnvironment* scope)
1703 VM& vm = exec->vm();
1704 NativeCallFrameTracer target(&vm, exec);
1706 // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I
1707 // didn't feel like changing the max number of arguments for a slow path call from 6 to 7.
1708 ScopedArgumentsTable* table = scope->symbolTable()->arguments();
1710 return ScopedArguments::createByCopyingFrom(
1711 vm, structure, argumentStart, length, callee, table, scope);
1714 JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, uint32_t length, JSFunction* callee)
1716 VM& vm = exec->vm();
1717 NativeCallFrameTracer target(&vm, exec);
1718 return ClonedArguments::createByCopyingFrom(
1719 exec, structure, argumentStart, length, callee);
1722 JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, uint32_t argumentCount)
1724 VM& vm = exec->vm();
1725 NativeCallFrameTracer target(&vm, exec);
1727 DeferGCForAWhile deferGC(vm.heap);
1729 CodeBlock* codeBlock;
1730 if (inlineCallFrame)
1731 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
1733 codeBlock = exec->codeBlock();
1735 unsigned length = argumentCount - 1;
1736 unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1));
1737 DirectArguments* result = DirectArguments::create(
1738 vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity);
1740 result->setCallee(vm, callee);
1742 Register* arguments =
1743 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
1744 CallFrame::argumentOffset(0);
1745 for (unsigned i = length; i--;)
1746 result->setIndexQuickly(vm, i, arguments[i].jsValue());
1751 JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, uint32_t argumentCount)
1753 VM& vm = exec->vm();
1754 NativeCallFrameTracer target(&vm, exec);
1756 DeferGCForAWhile deferGC(vm.heap);
1758 CodeBlock* codeBlock;
1759 if (inlineCallFrame)
1760 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
1762 codeBlock = exec->codeBlock();
1764 unsigned length = argumentCount - 1;
1765 ClonedArguments* result = ClonedArguments::createEmpty(
1766 vm, codeBlock->globalObject()->clonedArgumentsStructure(), callee, length);
1768 Register* arguments =
1769 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
1770 CallFrame::argumentOffset(0);
1771 for (unsigned i = length; i--;)
1772 result->putDirectIndex(exec, i, arguments[i].jsValue());
1778 JSCell* JIT_OPERATION operationCreateRest(ExecState* exec, Register* argumentStart, unsigned numberOfParamsToSkip, unsigned arraySize)
1780 VM* vm = &exec->vm();
1781 NativeCallFrameTracer tracer(vm, exec);
1783 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1784 Structure* structure = globalObject->restParameterStructure();
1785 static_assert(sizeof(Register) == sizeof(JSValue), "This is a strong assumption here.");
1786 JSValue* argumentsToCopyRegion = bitwise_cast<JSValue*>(argumentStart) + numberOfParamsToSkip;
1787 return constructArray(exec, structure, argumentsToCopyRegion, arraySize);
1790 size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1792 VM& vm = exec->vm();
1793 NativeCallFrameTracer tracer(&vm, exec);
1795 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1797 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1799 if (object->isFunction(vm))
1804 size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1806 VM& vm = exec->vm();
1807 NativeCallFrameTracer tracer(&vm, exec);
1809 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1811 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1813 if (object->isFunction(vm))
1818 JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1820 VM& vm = exec->vm();
1821 NativeCallFrameTracer tracer(&vm, exec);
1823 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1825 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1826 return vm.smallStrings.undefinedString();
1827 if (object->isFunction(vm))
1828 return vm.smallStrings.functionString();
1829 return vm.smallStrings.objectString();
1832 int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
1834 VM& vm = exec->vm();
1835 NativeCallFrameTracer tracer(&vm, exec);
1837 ASSERT(jsDynamicCast<JSObject*>(vm, object));
1839 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
1840 return static_cast<int32_t>(TypeofType::Undefined);
1841 if (object->isFunction(vm))
1842 return static_cast<int32_t>(TypeofType::Function);
1843 return static_cast<int32_t>(TypeofType::Object);
1846 char* JIT_OPERATION operationAllocateSimplePropertyStorageWithInitialCapacity(ExecState* exec)
1848 VM& vm = exec->vm();
1849 NativeCallFrameTracer tracer(&vm, exec);
1851 return reinterpret_cast<char*>(
1852 Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
1855 char* JIT_OPERATION operationAllocateSimplePropertyStorage(ExecState* exec, size_t newSize)
1857 VM& vm = exec->vm();
1858 NativeCallFrameTracer tracer(&vm, exec);
1860 return reinterpret_cast<char*>(
1861 Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
1864 char* JIT_OPERATION operationAllocateComplexPropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
1866 VM& vm = exec->vm();
1867 NativeCallFrameTracer tracer(&vm, exec);
1869 ASSERT(!object->structure(vm)->outOfLineCapacity());
1870 return reinterpret_cast<char*>(
1871 object->allocateMoreOutOfLineStorage(vm, 0, initialOutOfLineCapacity));
1874 char* JIT_OPERATION operationAllocateComplexPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
1876 VM& vm = exec->vm();
1877 NativeCallFrameTracer tracer(&vm, exec);
1879 return reinterpret_cast<char*>(
1880 object->allocateMoreOutOfLineStorage(vm, object->structure(vm)->outOfLineCapacity(), newSize));
1883 char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell)
1885 VM& vm = exec->vm();
1886 NativeCallFrameTracer tracer(&vm, exec);
1888 if (!cell->isObject())
1891 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableInt32(vm).data());
1892 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasInt32(cell->indexingMode())) || !result);
1896 char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell)
1898 VM& vm = exec->vm();
1899 NativeCallFrameTracer tracer(&vm, exec);
1901 if (!cell->isObject())
1904 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableDouble(vm).data());
1905 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasDouble(cell->indexingMode())) || !result);
1909 char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
1911 VM& vm = exec->vm();
1912 NativeCallFrameTracer tracer(&vm, exec);
1914 if (!cell->isObject())
1917 auto* result = reinterpret_cast<char*>(asObject(cell)->tryMakeWritableContiguous(vm).data());
1918 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasContiguous(cell->indexingMode())) || !result);
1922 char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
1924 VM& vm = exec->vm();
1925 NativeCallFrameTracer tracer(&vm, exec);
1927 if (!cell->isObject())
1930 auto* result = reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
1931 ASSERT((!isCopyOnWrite(asObject(cell)->indexingMode()) && hasAnyArrayStorage(cell->indexingMode())) || !result);
1935 EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName)
1937 VM& vm = exec->vm();
1938 NativeCallFrameTracer tracer(&vm, exec);
1939 JSValue baseValue = JSValue::decode(encodedBaseValue);
1940 if (baseValue.isUndefinedOrNull())
1941 return JSValue::encode(jsBoolean(false));
1943 JSObject* base = baseValue.toObject(exec);
1945 return JSValue::encode(JSValue());
1946 return JSValue::encode(jsBoolean(base->hasPropertyGeneric(exec, asString(propertyName)->toIdentifier(exec), PropertySlot::InternalMethodType::GetOwnProperty)));
1949 size_t JIT_OPERATION operationHasIndexedPropertyByInt(ExecState* exec, JSCell* baseCell, int32_t subscript, int32_t internalMethodType)
1951 VM& vm = exec->vm();
1952 NativeCallFrameTracer tracer(&vm, exec);
1953 JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
1954 if (UNLIKELY(subscript < 0)) {
1955 // Go the slowest way possible because negative indices don't use indexed storage.
1956 return object->hasPropertyGeneric(exec, Identifier::from(exec, subscript), static_cast<PropertySlot::InternalMethodType>(internalMethodType));
1958 return object->hasPropertyGeneric(exec, subscript, static_cast<PropertySlot::InternalMethodType>(internalMethodType));
1961 JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, EncodedJSValue encodedBase)
1963 VM& vm = exec->vm();
1964 NativeCallFrameTracer tracer(&vm, exec);
1965 auto scope = DECLARE_THROW_SCOPE(vm);
1967 JSValue base = JSValue::decode(encodedBase);
1968 if (base.isUndefinedOrNull())
1969 return JSPropertyNameEnumerator::create(vm);
1971 JSObject* baseObject = base.toObject(exec);
1972 RETURN_IF_EXCEPTION(scope, { });
1975 return propertyNameEnumerator(exec, baseObject);
1978 JSCell* JIT_OPERATION operationGetPropertyEnumeratorCell(ExecState* exec, JSCell* cell)
1980 VM& vm = exec->vm();
1981 NativeCallFrameTracer tracer(&vm, exec);
1982 auto scope = DECLARE_THROW_SCOPE(vm);
1984 JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
1985 RETURN_IF_EXCEPTION(scope, { });
1988 return propertyNameEnumerator(exec, base);
1991 JSCell* JIT_OPERATION operationToIndexString(ExecState* exec, int32_t index)
1993 VM& vm = exec->vm();
1994 NativeCallFrameTracer tracer(&vm, exec);
1995 return jsString(exec, Identifier::from(exec, index).string());
1998 JSCell* JIT_OPERATION operationNewRegexpWithLastIndex(ExecState* exec, JSCell* regexpPtr, EncodedJSValue encodedLastIndex)
2000 VM& vm = exec->vm();
2001 NativeCallFrameTracer tracer(&vm, exec);
2003 RegExp* regexp = static_cast<RegExp*>(regexpPtr);
2004 ASSERT(regexp->isValid());
2005 return RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp, JSValue::decode(encodedLastIndex));
2008 StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
2010 VM& vm = exec->vm();
2011 NativeCallFrameTracer tracer(&vm, exec);
2013 return string->value(exec).impl();
2016 JSCell* JIT_OPERATION operationStringSubstr(ExecState* exec, JSCell* cell, int32_t from, int32_t span)
2018 VM& vm = exec->vm();
2019 NativeCallFrameTracer tracer(&vm, exec);
2020 auto scope = DECLARE_THROW_SCOPE(vm);
2022 auto string = jsCast<JSString*>(cell)->value(exec);
2023 RETURN_IF_EXCEPTION(scope, nullptr);
2024 return jsSubstring(exec, string, from, span);
2027 JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
2029 VM& vm = exec->vm();
2030 NativeCallFrameTracer tracer(&vm, exec);
2032 auto scope = DECLARE_THROW_SCOPE(vm);
2034 const String& inputString = string->value(exec);
2035 RETURN_IF_EXCEPTION(scope, nullptr);
2036 if (!inputString.length())
2037 return vm.smallStrings.emptyString();
2039 String lowercasedString = inputString.is8Bit() ? inputString.convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex) : inputString.convertToLowercaseWithoutLocale();
2040 if (lowercasedString.impl() == inputString.impl())
2043 return jsString(exec, lowercasedString);
2046 char* JIT_OPERATION operationInt32ToString(ExecState* exec, int32_t value, int32_t radix)
2048 VM& vm = exec->vm();
2049 NativeCallFrameTracer tracer(&vm, exec);
2051 auto scope = DECLARE_THROW_SCOPE(vm);
2053 if (radix < 2 || radix > 36) {
2054 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2058 return reinterpret_cast<char*>(int32ToString(vm, value, radix));
2061 char* JIT_OPERATION operationInt52ToString(ExecState* exec, int64_t value, int32_t radix)
2063 VM& vm = exec->vm();
2064 NativeCallFrameTracer tracer(&vm, exec);
2066 auto scope = DECLARE_THROW_SCOPE(vm);
2068 if (radix < 2 || radix > 36) {
2069 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2073 return reinterpret_cast<char*>(int52ToString(vm, value, radix));
2076 char* JIT_OPERATION operationDoubleToString(ExecState* exec, double value, int32_t radix)
2078 VM& vm = exec->vm();
2079 NativeCallFrameTracer tracer(&vm, exec);
2081 auto scope = DECLARE_THROW_SCOPE(vm);
2083 if (radix < 2 || radix > 36) {
2084 throwVMError(exec, scope, createRangeError(exec, "toString() radix argument must be between 2 and 36"_s));
2088 return reinterpret_cast<char*>(numberToString(vm, value, radix));
2091 char* JIT_OPERATION operationInt32ToStringWithValidRadix(ExecState* exec, int32_t value, int32_t radix)
2093 VM& vm = exec->vm();
2094 NativeCallFrameTracer tracer(&vm, exec);
2096 return reinterpret_cast<char*>(int32ToString(vm, value, radix));
2099 char* JIT_OPERATION operationInt52ToStringWithValidRadix(ExecState* exec, int64_t value, int32_t radix)
2101 VM& vm = exec->vm();
2102 NativeCallFrameTracer tracer(&vm, exec);
2104 return reinterpret_cast<char*>(int52ToString(vm, value, radix));
2107 char* JIT_OPERATION operationDoubleToStringWithValidRadix(ExecState* exec, double value, int32_t radix)
2109 VM& vm = exec->vm();
2110 NativeCallFrameTracer tracer(&vm, exec);
2112 return reinterpret_cast<char*>(numberToString(vm, value, radix));
2115 JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
2117 VM& vm = exec->vm();
2118 NativeCallFrameTracer tracer(&vm, exec);
2120 return jsSingleCharacterString(exec, static_cast<UChar>(character));
2123 JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
2125 VM& vm = exec->vm();
2126 NativeCallFrameTracer tracer(&vm, exec);
2128 return StringObject::create(vm, structure, string);
2131 JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
2133 VM& vm = exec->vm();
2134 NativeCallFrameTracer tracer(&vm, exec);
2136 return JSValue(cell).toString(exec);
2139 JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
2141 VM& vm = exec->vm();
2142 NativeCallFrameTracer tracer(&vm, exec);
2144 return JSValue::decode(value).toString(exec);
2147 JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell)
2149 VM& vm = exec->vm();
2150 NativeCallFrameTracer tracer(&vm, exec);
2152 return stringConstructor(exec, cell);
2155 JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value)
2157 VM& vm = exec->vm();
2158 NativeCallFrameTracer tracer(&vm, exec);
2160 return stringConstructor(exec, JSValue::decode(value));
2163 JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
2165 VM& vm = exec->vm();
2166 NativeCallFrameTracer tracer(&vm, exec);
2168 return jsString(exec, left, right);
2171 JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c)
2173 VM& vm = exec->vm();
2174 NativeCallFrameTracer tracer(&vm, exec);
2176 return jsString(exec, a, b, c);
2179 JSCell* JIT_OPERATION operationStrCat2(ExecState* exec, EncodedJSValue a, EncodedJSValue b)
2181 VM& vm = exec->vm();
2182 NativeCallFrameTracer tracer(&vm, exec);
2183 auto scope = DECLARE_THROW_SCOPE(vm);
2185 ASSERT(!JSValue::decode(a).isSymbol());
2186 ASSERT(!JSValue::decode(b).isSymbol());
2187 JSString* str1 = JSValue::decode(a).toString(exec);
2188 scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
2189 JSString* str2 = JSValue::decode(b).toString(exec);
2190 scope.assertNoException();
2193 return jsString(exec, str1, str2);
2196 JSCell* JIT_OPERATION operationStrCat3(ExecState* exec, EncodedJSValue a, EncodedJSValue b, EncodedJSValue c)
2198 VM& vm = exec->vm();
2199 NativeCallFrameTracer tracer(&vm, exec);
2200 auto scope = DECLARE_THROW_SCOPE(vm);
2202 ASSERT(!JSValue::decode(a).isSymbol());
2203 ASSERT(!JSValue::decode(b).isSymbol());
2204 ASSERT(!JSValue::decode(c).isSymbol());
2205 JSString* str1 = JSValue::decode(a).toString(exec);
2206 scope.assertNoException(); // Impossible, since we must have been given non-Symbol primitives.
2207 JSString* str2 = JSValue::decode(b).toString(exec);
2208 scope.assertNoException();
2209 JSString* str3 = JSValue::decode(c).toString(exec);
2210 scope.assertNoException();
2213 return jsString(exec, str1, str2, str3);
2216 char* JIT_OPERATION operationFindSwitchImmTargetForDouble(
2217 ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
2219 VM& vm = exec->vm();
2220 NativeCallFrameTracer tracer(&vm, exec);
2222 CodeBlock* codeBlock = exec->codeBlock();
2223 SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex);
2224 JSValue value = JSValue::decode(encodedValue);
2225 ASSERT(value.isDouble());
2226 double asDouble = value.asDouble();
2227 int32_t asInt32 = static_cast<int32_t>(asDouble);
2228 if (asDouble == asInt32)
2229 return table.ctiForValue(asInt32).executableAddress<char*>();
2230 return table.ctiDefault.executableAddress<char*>();
2233 char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string)
2235 VM& vm = exec->vm();
2236 NativeCallFrameTracer tracer(&vm, exec);
2238 return exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress<char*>();
2241 int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string)
2243 VM& vm = exec->vm();
2244 NativeCallFrameTracer tracer(&vm, exec);
2246 return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
2249 uintptr_t JIT_OPERATION operationCompareStringImplLess(StringImpl* a, StringImpl* b)
2251 return codePointCompare(a, b) < 0;
2254 uintptr_t JIT_OPERATION operationCompareStringImplLessEq(StringImpl* a, StringImpl* b)
2256 return codePointCompare(a, b) <= 0;
2259 uintptr_t JIT_OPERATION operationCompareStringImplGreater(StringImpl* a, StringImpl* b)
2261 return codePointCompare(a, b) > 0;
2264 uintptr_t JIT_OPERATION operationCompareStringImplGreaterEq(StringImpl* a, StringImpl* b)
2266 return codePointCompare(a, b) >= 0;
2269 uintptr_t JIT_OPERATION operationCompareStringLess(ExecState* exec, JSString* a, JSString* b)
2271 VM& vm = exec->vm();
2272 NativeCallFrameTracer tracer(&vm, exec);
2274 return codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
2277 uintptr_t JIT_OPERATION operationCompareStringLessEq(ExecState* exec, JSString* a, JSString* b)
2279 VM& vm = exec->vm();
2280 NativeCallFrameTracer tracer(&vm, exec);
2282 return !codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
2285 uintptr_t JIT_OPERATION operationCompareStringGreater(ExecState* exec, JSString* a, JSString* b)
2287 VM& vm = exec->vm();
2288 NativeCallFrameTracer tracer(&vm, exec);
2290 return codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
2293 uintptr_t JIT_OPERATION operationCompareStringGreaterEq(ExecState* exec, JSString* a, JSString* b)
2295 VM& vm = exec->vm();
2296 NativeCallFrameTracer tracer(&vm, exec);
2298 return !codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
2301 void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
2303 VM& vm = exec->vm();
2304 NativeCallFrameTracer tracer(&vm, exec);
2306 set->touch(vm, "Executed NotifyWrite");
2309 void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec)
2311 VM& vm = exec->vm();
2312 NativeCallFrameTracer tracer(&vm, exec);
2313 auto scope = DECLARE_THROW_SCOPE(vm);
2314 throwStackOverflowError(exec, scope);
2317 int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, uint32_t firstVarArgOffset)
2319 VM& vm = exec->vm();
2320 NativeCallFrameTracer tracer(&vm, exec);
2321 JSValue arguments = JSValue::decode(encodedArguments);
2323 return sizeOfVarargs(exec, arguments, firstVarArgOffset);
2326 int32_t JIT_OPERATION operationHasOwnProperty(ExecState* exec, JSObject* thisObject, EncodedJSValue encodedKey)
2328 VM& vm = exec->vm();
2329 NativeCallFrameTracer tracer(&vm, exec);
2330 auto scope = DECLARE_THROW_SCOPE(vm);
2332 JSValue key = JSValue::decode(encodedKey);
2333 Identifier propertyName = key.toPropertyKey(exec);
2334 RETURN_IF_EXCEPTION(scope, false);
2336 PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
2337 bool result = thisObject->hasOwnProperty(exec, propertyName.impl(), slot);
2338 RETURN_IF_EXCEPTION(scope, false);
2340 HasOwnPropertyCache* hasOwnPropertyCache = vm.hasOwnPropertyCache();
2341 ASSERT(hasOwnPropertyCache);
2342 hasOwnPropertyCache->tryAdd(vm, slot, thisObject, propertyName.impl(), result);
2346 int32_t JIT_OPERATION operationNumberIsInteger(ExecState* exec, EncodedJSValue value)
2348 VM& vm = exec->vm();
2349 NativeCallFrameTracer tracer(&vm, exec);
2350 return NumberConstructor::isIntegerImpl(JSValue::decode(value));
2353 int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index)
2355 VM& vm = exec->vm();
2356 NativeCallFrameTracer tracer(&vm, exec);
2357 auto scope = DECLARE_THROW_SCOPE(vm);
2359 int32_t length = butterfly->publicLength();
2360 auto data = butterfly->contiguous().data();
2361 for (; index < length; ++index) {
2362 JSValue value = data[index].get();
2363 if (!value || !value.isString())
2365 auto* string = asString(value);
2366 if (string == searchElement)
2368 if (string->equal(exec, searchElement))
2370 RETURN_IF_EXCEPTION(scope, { });
2375 int32_t JIT_OPERATION operationArrayIndexOfValueInt32OrContiguous(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
2377 VM& vm = exec->vm();
2378 NativeCallFrameTracer tracer(&vm, exec);
2379 auto scope = DECLARE_THROW_SCOPE(vm);
2381 JSValue searchElement = JSValue::decode(encodedValue);
2383 int32_t length = butterfly->publicLength();
2384 auto data = butterfly->contiguous().data();
2385 for (; index < length; ++index) {
2386 JSValue value = data[index].get();
2389 if (JSValue::strictEqual(exec, searchElement, value))
2391 RETURN_IF_EXCEPTION(scope, { });
2396 int32_t JIT_OPERATION operationArrayIndexOfValueDouble(ExecState* exec, Butterfly* butterfly, EncodedJSValue encodedValue, int32_t index)
2398 VM& vm = exec->vm();
2399 NativeCallFrameTracer tracer(&vm, exec);
2401 JSValue searchElement = JSValue::decode(encodedValue);
2403 if (!searchElement.isNumber())
2405 double number = searchElement.asNumber();
2407 int32_t length = butterfly->publicLength();
2408 const double* data = butterfly->contiguousDouble().data();
2409 for (; index < length; ++index) {
2410 // This comparison ignores NaN.
2411 if (data[index] == number)
2417 void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, uint32_t offset, uint32_t length, uint32_t mandatoryMinimum)
2419 VM& vm = exec->vm();
2420 NativeCallFrameTracer tracer(&vm, exec);
2421 JSValue arguments = JSValue::decode(encodedArguments);
2423 loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length);
2425 for (uint32_t i = length; i < mandatoryMinimum; ++i)
2426 exec->r(firstElementDest + i) = jsUndefined();
2429 double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
2434 #if USE(JSVALUE32_64)
2435 double JIT_OPERATION operationRandom(JSGlobalObject* globalObject)
2437 return globalObject->weakRandomNumber();
2441 JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
2443 VM* vm = &exec->vm();
2444 NativeCallFrameTracer tracer(vm, exec);
2445 return JSC::stringFromCharCode(exec, op1);
2448 EncodedJSValue JIT_OPERATION operationStringFromCharCodeUntyped(ExecState* exec, EncodedJSValue encodedValue)
2450 VM* vm = &exec->vm();
2451 NativeCallFrameTracer tracer(vm, exec);
2452 JSValue charValue = JSValue::decode(encodedValue);
2453 int32_t chInt = charValue.toUInt32(exec);
2454 return JSValue::encode(JSC::stringFromCharCode(exec, chInt));
2457 int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
2459 JSValue value = JSValue::decode(encodedValue);
2460 if (!value.isDouble())
2461 return JSValue::notInt52;
2462 return tryConvertToInt52(value.asDouble());
2465 int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
2467 return tryConvertToInt52(value);
2470 char* JIT_OPERATION operationNewRawObject(ExecState* exec, Structure* structure, int32_t length, Butterfly* butterfly)
2472 VM& vm = exec->vm();
2473 NativeCallFrameTracer tracer(&vm, exec);
2476 && (structure->outOfLineCapacity() || hasIndexedProperties(structure->indexingType()))) {
2477 IndexingHeader header;
2478 header.setVectorLength(length);
2479 header.setPublicLength(0);
2481 butterfly = Butterfly::create(
2482 vm, nullptr, 0, structure->outOfLineCapacity(),
2483 hasIndexedProperties(structure->indexingType()), header,
2484 length * sizeof(EncodedJSValue));
2487 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2488 result->butterfly(); // Ensure that the butterfly is in to-space.
2489 return bitwise_cast<char*>(result);
2492 JSCell* JIT_OPERATION operationNewObjectWithButterfly(ExecState* exec, Structure* structure, Butterfly* butterfly)
2494 VM& vm = exec->vm();
2495 NativeCallFrameTracer tracer(&vm, exec);
2498 butterfly = Butterfly::create(
2499 vm, nullptr, 0, structure->outOfLineCapacity(), false, IndexingHeader(), 0);
2502 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2503 result->butterfly(); // Ensure that the butterfly is in to-space.
2507 JSCell* JIT_OPERATION operationNewObjectWithButterflyWithIndexingHeaderAndVectorLength(ExecState* exec, Structure* structure, unsigned length, Butterfly* butterfly)
2509 VM& vm = exec->vm();
2510 NativeCallFrameTracer tracer(&vm, exec);
2512 IndexingHeader header;
2513 header.setVectorLength(length);
2514 header.setPublicLength(0);
2516 *butterfly->indexingHeader() = header;
2518 butterfly = Butterfly::create(
2519 vm, nullptr, 0, structure->outOfLineCapacity(), true, header,
2520 sizeof(EncodedJSValue) * length);
2523 // Paradoxically this may allocate a JSArray. That's totally cool.
2524 JSObject* result = JSObject::createRawObject(exec, structure, butterfly);
2525 result->butterfly(); // Ensure that the butterfly is in to-space.
2529 JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(ExecState* exec, void* buffer, uint32_t numItems)
2531 VM& vm = exec->vm();
2532 NativeCallFrameTracer tracer(&vm, exec);
2533 auto scope = DECLARE_THROW_SCOPE(vm);
2535 EncodedJSValue* values = static_cast<EncodedJSValue*>(buffer);
2536 Checked<unsigned, RecordOverflow> checkedLength = 0;
2537 for (unsigned i = 0; i < numItems; i++) {
2538 JSValue value = JSValue::decode(values[i]);
2539 if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value))
2540 checkedLength += array->size();
2545 if (UNLIKELY(checkedLength.hasOverflowed())) {
2546 throwOutOfMemoryError(exec, scope);
2550 unsigned length = checkedLength.unsafeGet();
2551 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2552 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
2554 JSArray* result = JSArray::tryCreate(vm, structure, length);
2555 if (UNLIKELY(!result)) {
2556 throwOutOfMemoryError(exec, scope);
2559 RETURN_IF_EXCEPTION(scope, nullptr);
2562 for (unsigned i = 0; i < numItems; i++) {
2563 JSValue value = JSValue::decode(values[i]);
2564 if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value)) {
2565 // We are spreading.
2566 for (unsigned i = 0; i < array->size(); i++) {
2567 result->putDirectIndex(exec, index, array->get(i));
2568 RETURN_IF_EXCEPTION(scope, nullptr);
2572 // We are not spreading.
2573 result->putDirectIndex(exec, index, value);
2574 RETURN_IF_EXCEPTION(scope, nullptr);
2582 JSCell* operationCreateFixedArray(ExecState* exec, unsigned length)
2584 VM& vm = exec->vm();
2585 NativeCallFrameTracer tracer(&vm, exec);
2586 auto scope = DECLARE_THROW_SCOPE(vm);
2588 if (JSFixedArray* result = JSFixedArray::tryCreate(vm, vm.fixedArrayStructure.get(), length))
2591 throwOutOfMemoryError(exec, scope);
2595 JSCell* JIT_OPERATION operationSpreadGeneric(ExecState* exec, JSCell* iterable)
2597 VM& vm = exec->vm();
2598 NativeCallFrameTracer tracer(&vm, exec);
2600 auto throwScope = DECLARE_THROW_SCOPE(vm);
2602 if (isJSArray(iterable)) {
2603 JSArray* array = jsCast<JSArray*>(iterable);
2604 if (array->isIteratorProtocolFastAndNonObservable()) {
2605 throwScope.release();
2606 return JSFixedArray::createFromArray(exec, vm, array);
2610 // FIXME: we can probably make this path faster by having our caller JS code call directly into
2611 // the iteration protocol builtin: https://bugs.webkit.org/show_bug.cgi?id=164520
2613 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2616 JSFunction* iterationFunction = globalObject->iteratorProtocolFunction();
2618 CallType callType = JSC::getCallData(vm, iterationFunction, callData);
2619 ASSERT(callType != CallType::None);
2621 MarkedArgumentBuffer arguments;
2622 arguments.append(iterable);
2623 ASSERT(!arguments.hasOverflowed());
2624 JSValue arrayResult = call(exec, iterationFunction, callType, callData, jsNull(), arguments);
2625 RETURN_IF_EXCEPTION(throwScope, nullptr);
2626 array = jsCast<JSArray*>(arrayResult);
2629 throwScope.release();
2630 return JSFixedArray::createFromArray(exec, vm, array);
2633 JSCell* JIT_OPERATION operationSpreadFastArray(ExecState* exec, JSCell* cell)
2635 VM& vm = exec->vm();
2636 NativeCallFrameTracer tracer(&vm, exec);
2638 ASSERT(isJSArray(cell));
2639 JSArray* array = jsCast<JSArray*>(cell);
2640 ASSERT(array->isIteratorProtocolFastAndNonObservable());
2642 return JSFixedArray::createFromArray(exec, vm, array);
2645 void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec)
2647 VM& vm = exec->vm();
2648 NativeCallFrameTracer tracer(&vm, exec);
2650 vm.typeProfilerLog()->processLogEntries("Log Full, called from inside DFG."_s);
2653 EncodedJSValue JIT_OPERATION operationResolveScopeForHoistingFuncDeclInEval(ExecState* exec, JSScope* scope, UniquedStringImpl* impl)
2655 VM& vm = exec->vm();
2656 NativeCallFrameTracer tracer(&vm, exec);
2658 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(exec, scope, Identifier::fromUid(exec, impl));
2659 return JSValue::encode(resolvedScope);
2662 JSCell* JIT_OPERATION operationResolveScope(ExecState* exec, JSScope* scope, UniquedStringImpl* impl)
2664 VM& vm = exec->vm();
2665 NativeCallFrameTracer tracer(&vm, exec);
2667 JSObject* resolvedScope = JSScope::resolve(exec, scope, Identifier::fromUid(exec, impl));
2668 return resolvedScope;
2671 EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState* exec, JSObject* scope, UniquedStringImpl* impl, unsigned getPutInfoBits)
2673 VM& vm = exec->vm();
2674 NativeCallFrameTracer tracer(&vm, exec);
2675 auto throwScope = DECLARE_THROW_SCOPE(vm);
2677 Identifier ident = Identifier::fromUid(exec, impl);
2678 throwScope.release();
2679 return JSValue::encode(scope->getPropertySlot(exec, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
2681 GetPutInfo getPutInfo(getPutInfoBits);
2682 if (getPutInfo.resolveMode() == ThrowIfNotFound)
2683 throwException(exec, throwScope, createUndefinedVariableError(exec, ident));
2684 return jsUndefined();
2687 if (scope->isGlobalLexicalEnvironment()) {
2688 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2689 JSValue result = slot.getValue(exec, ident);
2690 if (result == jsTDZValue()) {
2691 throwException(exec, throwScope, createTDZError(exec));
2692 return jsUndefined();
2697 return slot.getValue(exec, ident);
2701 void JIT_OPERATION operationPutDynamicVar(ExecState* exec, JSObject* scope, EncodedJSValue value, UniquedStringImpl* impl, unsigned getPutInfoBits)
2703 VM& vm = exec->vm();
2704 NativeCallFrameTracer tracer(&vm, exec);
2705 auto throwScope = DECLARE_THROW_SCOPE(vm);
2707 const Identifier& ident = Identifier::fromUid(exec, impl);
2708 GetPutInfo getPutInfo(getPutInfoBits);
2709 bool hasProperty = scope->hasProperty(exec, ident);
2710 RETURN_IF_EXCEPTION(throwScope, void());
2712 && scope->isGlobalLexicalEnvironment()
2713 && !isInitialization(getPutInfo.initializationMode())) {
2714 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2715 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get);
2716 JSGlobalLexicalEnvironment::getOwnPropertySlot(scope, exec, ident, slot);
2717 if (slot.getValue(exec, ident) == jsTDZValue()) {
2718 throwException(exec, throwScope, createTDZError(exec));
2723 if (getPutInfo.resolveMode() == ThrowIfNotFound && !hasProperty) {
2724 throwException(exec, throwScope, createUndefinedVariableError(exec, ident));
2728 CodeOrigin origin = exec->codeOrigin();
2730 if (origin.inlineCallFrame)
2731 strictMode = origin.inlineCallFrame->baselineCodeBlock->isStrictMode();
2733 strictMode = exec->codeBlock()->isStrictMode();
2734 PutPropertySlot slot(scope, strictMode, PutPropertySlot::UnknownContext, isInitialization(getPutInfo.initializationMode()));
2735 throwScope.release();
2736 scope->methodTable(vm)->put(scope, exec, ident, JSValue::decode(value), slot);
2739 int32_t JIT_OPERATION operationMapHash(ExecState* exec, EncodedJSValue input)
2741 VM& vm = exec->vm();
2742 NativeCallFrameTracer tracer(&vm, exec);
2744 return jsMapHash(exec, vm, JSValue::decode(input));
2747 JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
2749 VM& vm = exec->vm();
2750 NativeCallFrameTracer tracer(&vm, exec);
2751 JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash);
2753 return vm.sentinelMapBucket.get();
2757 JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
2759 VM& vm = exec->vm();
2760 NativeCallFrameTracer tracer(&vm, exec);
2761 JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash);
2763 return vm.sentinelSetBucket.get();
2767 JSCell* JIT_OPERATION operationSetAdd(ExecState* exec, JSCell* set, EncodedJSValue key, int32_t hash)
2769 VM& vm = exec->vm();
2770 NativeCallFrameTracer tracer(&vm, exec);
2771 auto* bucket = jsCast<JSSet*>(set)->addNormalized(exec, JSValue::decode(key), JSValue(), hash);
2773 return vm.sentinelSetBucket.get();
2777 JSCell* JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSValue key, EncodedJSValue value, int32_t hash)
2779 VM& vm = exec->vm();
2780 NativeCallFrameTracer tracer(&vm, exec);
2781 auto* bucket = jsCast<JSMap*>(map)->addNormalized(exec, JSValue::decode(key), JSValue::decode(value), hash);
2783 return vm.sentinelMapBucket.get();
2787 void JIT_OPERATION operationWeakSetAdd(ExecState* exec, JSCell* set, JSCell* key, int32_t hash)
2789 VM& vm = exec->vm();
2790 NativeCallFrameTracer tracer(&vm, exec);
2791 jsCast<JSWeakSet*>(set)->add(vm, asObject(key), JSValue(), hash);
2794 void JIT_OPERATION operationWeakMapSet(ExecState* exec, JSCell* map, JSCell* key, EncodedJSValue value, int32_t hash)
2796 VM& vm = exec->vm();
2797 NativeCallFrameTracer tracer(&vm, exec);
2798 jsCast<JSWeakMap*>(map)->add(vm, asObject(key), JSValue::decode(value), hash);
2801 EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)
2803 VM& vm = exec->vm();
2804 NativeCallFrameTracer tracer(&vm, exec);
2805 return JSValue::encode(thisObject->getPrototype(vm, exec));
2808 EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState* exec, EncodedJSValue encodedValue)
2810 VM& vm = exec->vm();
2811 NativeCallFrameTracer tracer(&vm, exec);
2812 auto scope = DECLARE_THROW_SCOPE(vm);
2814 JSValue thisValue = JSValue::decode(encodedValue).toThis(exec, StrictMode);
2815 if (thisValue.isUndefinedOrNull())
2816 return throwVMError(exec, scope, createNotAnObjectError(exec, thisValue));
2818 JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
2820 JSObject* prototype = thisValue.synthesizePrototype(exec);
2821 EXCEPTION_ASSERT(!!scope.exception() == !prototype);
2822 if (UNLIKELY(!prototype))
2823 return JSValue::encode(JSValue());
2824 return JSValue::encode(prototype);
2828 return JSValue::encode(thisObject->getPrototype(vm, exec));
2831 void JIT_OPERATION operationThrowDFG(ExecState* exec, EncodedJSValue valueToThrow)
2833 VM& vm = exec->vm();
2834 NativeCallFrameTracer tracer(&vm, exec);
2835 auto scope = DECLARE_THROW_SCOPE(vm);
2836 scope.throwException(exec, JSValue::decode(valueToThrow));
2839 void JIT_OPERATION operationThrowStaticError(ExecState* exec, JSString* message, uint32_t errorType)
2841 VM& vm = exec->vm();
2842 NativeCallFrameTracer tracer(&vm, exec);
2843 auto scope = DECLARE_THROW_SCOPE(vm);
2844 String errorMessage = message->value(exec);
2845 scope.throwException(exec, createError(exec, static_cast<ErrorType>(errorType), errorMessage));
2848 extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, CodeBlock* optimizedCodeBlock, OSRExitBase* exit)
2850 // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
2851 // really be profitable.
2852 DeferGCForAWhile deferGC(codeBlock->vm()->heap);
2854 sanitizeStackForVM(codeBlock->vm());
2856 if (Options::verboseOSR())
2857 dataLog(*codeBlock, ": Entered reoptimize\n");
2858 // We must be called with the baseline code block.
2859 ASSERT(JITCode::isBaselineCode(codeBlock->jitType()));
2861 // If I am my own replacement, then reoptimization has already been triggered.
2862 // This can happen in recursive functions.
2864 // Note that even if optimizedCodeBlock is an FTLForOSREntry style CodeBlock, this condition is a
2865 // sure bet that we don't have anything else left to do.
2866 if (codeBlock->replacement() == codeBlock) {
2867 if (Options::verboseOSR())
2868 dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n");
2872 // Otherwise, the replacement must be optimized code. Use this as an opportunity
2873 // to check our logic.
2874 ASSERT(codeBlock->hasOptimizedReplacement());
2875 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
2877 bool didTryToEnterIntoInlinedLoops = false;
2878 for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
2879 if (inlineCallFrame->baselineCodeBlock->ownerScriptExecutable()->didTryToEnterInLoop()) {
2880 didTryToEnterIntoInlinedLoops = true;
2885 // In order to trigger reoptimization, one of two things must have happened:
2886 // 1) We exited more than some number of times.
2887 // 2) We exited and got stuck in a loop, and now we're exiting again.
2888 bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
2889 bool didGetStuckInLoop =
2890 (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops)
2891 && optimizedCodeBlock->shouldReoptimizeFromLoopNow();
2893 if (!didExitABunch && !didGetStuckInLoop) {
2894 if (Options::verboseOSR())
2895 dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n");
2896 codeBlock->optimizeAfterLongWarmUp();
2900 optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization);
2904 static bool shouldTriggerFTLCompile(CodeBlock* codeBlock, JITCode* jitCode)
2906 if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
2907 CODEBLOCK_LOG_EVENT(codeBlock, "abortFTLCompile", ());
2908 if (Options::verboseOSR())
2909 dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
2910 jitCode->dontOptimizeAnytimeSoon(codeBlock);
2914 if (!codeBlock->hasOptimizedReplacement()
2915 && !jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
2916 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("counter = ", jitCode->tierUpCounter));
2917 if (Options::verboseOSR())
2918 dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
2924 static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
2926 if (codeBlock->codeType() == GlobalCode) {
2927 // Global code runs once, so we don't want to do anything. We don't want to defer indefinitely,
2928 // since this may have been spuriously called from tier-up initiated in a loop, and that loop may
2929 // later want to run faster code. Deferring for warm-up seems safest.
2930 jitCode->optimizeAfterWarmUp(codeBlock);
2934 Worklist::State worklistState;
2935 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
2936 worklistState = worklist->completeAllReadyPlansForVM(
2937 *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode));
2939 worklistState = Worklist::NotKnown;
2941 if (worklistState == Worklist::Compiling) {
2942 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling"));
2943 jitCode->setOptimizationThresholdBasedOnCompilationResult(
2944 codeBlock, CompilationDeferred);
2948 if (codeBlock->hasOptimizedReplacement()) {
2949 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("has replacement"));
2950 // That's great, we've compiled the code - next time we call this function,
2951 // we'll enter that replacement.
2952 jitCode->optimizeSoon(codeBlock);
2956 if (worklistState == Worklist::Compiled) {
2957 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed"));
2958 // This means that we finished compiling, but failed somehow; in that case the
2959 // thresholds will be set appropriately.
2960 if (Options::verboseOSR())
2961 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
2965 CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLReplacement", ());
2966 // We need to compile the code.
2968 *vm, codeBlock->newReplacement(), codeBlock, FTLMode, UINT_MAX,
2969 Operands<JSValue>(), ToFTLDeferredCompilationCallback::create());
2971 // If we reached here, the counter has not be reset. Do that now.
2972 jitCode->setOptimizationThresholdBasedOnCompilationResult(
2973 codeBlock, CompilationDeferred);
2976 void JIT_OPERATION triggerTierUpNow(ExecState* exec)
2978 VM* vm = &exec->vm();
2979 NativeCallFrameTracer tracer(vm, exec);
2980 DeferGCForAWhile deferGC(vm->heap);
2981 CodeBlock* codeBlock = exec->codeBlock();
2983 sanitizeStackForVM(vm);
2985 if (codeBlock->jitType() != JITCode::DFGJIT) {
2986 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
2987 RELEASE_ASSERT_NOT_REACHED();
2990 JITCode* jitCode = codeBlock->jitCode()->dfg();
2992 if (Options::verboseOSR()) {
2994 *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
2995 jitCode->tierUpCounter, "\n");
2998 if (shouldTriggerFTLCompile(codeBlock, jitCode))
2999 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3001 if (codeBlock->hasOptimizedReplacement()) {
3002 if (jitCode->tierUpEntryTriggers.isEmpty()) {
3003 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("replacement in place, delaying indefinitely"));
3004 // There is nothing more we can do, the only way this will be entered
3005 // is through the function entry point.
3006 jitCode->dontOptimizeAnytimeSoon(codeBlock);
3009 if (jitCode->osrEntryBlock() && jitCode->tierUpEntryTriggers.size() == 1) {
3010 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("trigger in place, delaying indefinitely"));
3011 // There is only one outer loop and its trigger must have been set
3012 // when the plan completed.
3013 // Exiting the inner loop is useless, we can ignore the counter and leave
3014 // the trigger do its job.
3015 jitCode->dontOptimizeAnytimeSoon(codeBlock);
3021 static char* tierUpCommon(ExecState* exec, unsigned originBytecodeIndex, bool canOSREnterHere)
3023 VM* vm = &exec->vm();
3024 CodeBlock* codeBlock = exec->codeBlock();
3026 // Resolve any pending plan for OSR Enter on this function.
3027 Worklist::State worklistState;
3028 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
3029 worklistState = worklist->completeAllReadyPlansForVM(
3030 *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode));
3032 worklistState = Worklist::NotKnown;
3034 JITCode* jitCode = codeBlock->jitCode()->dfg();
3036 bool triggeredSlowPathToStartCompilation = false;
3037 auto tierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
3038 if (tierUpEntryTriggers != jitCode->tierUpEntryTriggers.end()) {
3039 switch (tierUpEntryTriggers->value) {
3040 case JITCode::TriggerReason::DontTrigger:
3041 // The trigger isn't set, we entered because the counter reached its
3045 case JITCode::TriggerReason::CompilationDone:
3046 // The trigger was set because compilation completed. Don't unset it
3047 // so that further DFG executions OSR enter as well.
3050 case JITCode::TriggerReason::StartCompilation:
3051 // We were asked to enter as soon as possible and start compiling an
3052 // entry for the current bytecode location. Unset this trigger so we
3053 // don't continually enter.
3054 tierUpEntryTriggers->value = JITCode::TriggerReason::DontTrigger;
3055 triggeredSlowPathToStartCompilation = true;
3060 if (worklistState == Worklist::Compiling) {
3061 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling"));
3062 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3066 // If we can OSR Enter, do it right away.
3067 if (canOSREnterHere) {
3068 auto iter = jitCode->bytecodeIndexToStreamIndex.find(originBytecodeIndex);
3069 if (iter != jitCode->bytecodeIndexToStreamIndex.end()) {
3070 unsigned streamIndex = iter->value;
3071 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
3072 if (Options::verboseOSR())
3073 dataLog("OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(entryBlock), "\n");
3074 if (void* address = FTL::prepareOSREntry(exec, codeBlock, entryBlock, originBytecodeIndex, streamIndex)) {
3075 CODEBLOCK_LOG_EVENT(entryBlock, "osrEntry", ("at bc#", originBytecodeIndex));
3076 return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
3082 if (worklistState == Worklist::Compiled) {
3083 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed"));
3084 // This means that compilation failed and we already set the thresholds.
3085 if (Options::verboseOSR())
3086 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
3090 // - If we don't have an FTL code block, then try to compile one.
3091 // - If we do have an FTL code block, then try to enter for a while.
3092 // - If we couldn't enter for a while, then trigger OSR entry.
3094 if (!shouldTriggerFTLCompile(codeBlock, jitCode) && !triggeredSlowPathToStartCompilation)
3097 if (!jitCode->neverExecutedEntry && !triggeredSlowPathToStartCompilation) {
3098 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3100 if (!codeBlock->hasOptimizedReplacement())
3103 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
3104 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding OSR entry compile"));
3105 jitCode->osrEntryRetry++;
3109 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding replacement compile"));
3111 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
3112 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
3113 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed, OSR entry threshold not met"));
3114 jitCode->osrEntryRetry++;
3115 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3116 codeBlock, CompilationDeferred);
3120 FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
3121 entryCode->countEntryFailure();
3122 if (entryCode->entryFailureCount() <
3123 Options::ftlOSREntryFailureCountForReoptimization()) {
3124 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed"));
3125 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3126 codeBlock, CompilationDeferred);
3130 // OSR entry failed. Oh no! This implies that we need to retry. We retry
3131 // without exponential backoff and we only do this for the entry code block.
3132 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed too many times"));
3133 unsigned osrEntryBytecode = entryBlock->jitCode()->ftlForOSREntry()->bytecodeIndex();
3134 jitCode->clearOSREntryBlock();
3135 jitCode->osrEntryRetry = 0;
3136 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, JITCode::TriggerReason::DontTrigger);
3137 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3138 codeBlock, CompilationDeferred);
3142 // It's time to try to compile code for OSR entry.
3144 if (!triggeredSlowPathToStartCompilation) {
3146 // An inner loop didn't specifically ask for us to kick off a compilation. This means the counter
3147 // crossed its threshold. We either fall through and kick off a compile for originBytecodeIndex,
3148 // or we flag an outer loop to immediately try to compile itself. If there are outer loops,
3149 // we first try to make them compile themselves. But we will eventually fall back to compiling
3150 // a progressively inner loop if it takes too long for control to reach an outer loop.
3152 auto tryTriggerOuterLoopToCompile = [&] {
3153 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(originBytecodeIndex);
3154 if (tierUpHierarchyEntry == jitCode->tierUpInLoopHierarchy.end())
3157 // This vector is ordered from innermost to outermost loop. Every bytecode entry in this vector is
3158 // allowed to do OSR entry. We start with the outermost loop and make our way inwards (hence why we
3159 // iterate the vector in reverse). Our policy is that we will trigger an outer loop to compile
3160 // immediately when program control reaches it. If program control is taking too long to reach that
3161 // outer loop, we progressively move inwards, meaning, we'll eventually trigger some loop that is
3162 // executing to compile. We start with trying to compile outer loops since we believe outer loop
3163 // compilations reveal the best opportunities for optimizing code.
3164 for (auto iter = tierUpHierarchyEntry->value.rbegin(), end = tierUpHierarchyEntry->value.rend(); iter != end; ++iter) {
3165 unsigned osrEntryCandidate = *iter;
3167 if (jitCode->tierUpEntryTriggers.get(osrEntryCandidate) == JITCode::TriggerReason::StartCompilation) {
3168 // This means that we already asked this loop to compile. If we've reached here, it
3169 // means program control has not yet reached that loop. So it's taking too long to compile.
3170 // So we move on to asking the inner loop of this loop to compile itself.
3174 // This is where we ask the outer to loop to immediately compile itself if program
3175 // control reaches it.
3176 if (Options::verboseOSR())
3177 dataLog("Inner-loop bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryCandidate, "'s trigger and backing off.\n");
3178 jitCode->tierUpEntryTriggers.set(osrEntryCandidate, JITCode::TriggerReason::StartCompilation);
3185 if (tryTriggerOuterLoopToCompile()) {
3186 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3191 if (!canOSREnterHere) {
3192 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3196 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
3199 auto triggerIterator = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
3200 if (triggerIterator == jitCode->tierUpEntryTriggers.end()) {
3201 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3205 JITCode::TriggerReason* triggerAddress = &(triggerIterator->value);
3207 Operands<JSValue> mustHandleValues;
3208 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex);
3209 jitCode->reconstruct(
3210 exec, codeBlock, CodeOrigin(originBytecodeIndex), streamIndex, mustHandleValues);
3211 CodeBlock* replacementCodeBlock = codeBlock->newReplacement();
3213 CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLOSR", ());
3214 CompilationResult forEntryResult = compile(
3215 *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, originBytecodeIndex,
3216 mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(triggerAddress));
3218 if (jitCode->neverExecutedEntry)
3219 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3221 if (forEntryResult != CompilationSuccessful) {
3222 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR ecompilation not successful"));
3223 jitCode->setOptimizationThresholdBasedOnCompilationResult(
3224 codeBlock, CompilationDeferred);
3228 CODEBLOCK_LOG_EVENT(jitCode->osrEntryBlock(), "osrEntry", ("at bc#", originBytecodeIndex));
3229 // It's possible that the for-entry compile already succeeded. In that case OSR
3230 // entry will succeed unless we ran out of stack. It's not clear what we should do.
3231 // We signal to try again after a while if that happens.
3232 if (Options::verboseOSR())
3233 dataLog("Immediate OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(jitCode->osrEntryBlock()), "\n");
3235 void* address = FTL::prepareOSREntry(
3236 exec, codeBlock, jitCode->osrEntryBlock(), originBytecodeIndex, streamIndex);
3239 return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
3242 void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec, unsigned bytecodeIndex)
3244 VM* vm = &exec->vm();
3245 NativeCallFrameTracer tracer(vm, exec);
3246 DeferGCForAWhile deferGC(vm->heap);
3247 CodeBlock* codeBlock = exec->codeBlock();
3249 sanitizeStackForVM(vm);
3251 if (codeBlock->jitType() != JITCode::DFGJIT) {
3252 dataLog("Unexpected code block in DFG->FTL trigger tier up now in loop: ", *codeBlock, "\n");
3253 RELEASE_ASSERT_NOT_REACHED();
3256 JITCode* jitCode = codeBlock->jitCode()->dfg();
3258 if (Options::verboseOSR()) {
3260 *codeBlock, ": Entered triggerTierUpNowInLoop with executeCounter = ",
3261 jitCode->tierUpCounter, "\n");
3264 if (jitCode->tierUpInLoopHierarchy.contains(bytecodeIndex))
3265 tierUpCommon(exec, bytecodeIndex, false);
3266 else if (shouldTriggerFTLCompile(codeBlock, jitCode))
3267 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
3269 // Since we cannot OSR Enter here, the default "optimizeSoon()" is not useful.
3270 if (codeBlock->hasOptimizedReplacement()) {
3271 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR in loop failed, deferring"));
3272 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
3276 char* JIT_OPERATION triggerOSREntryNow(ExecState* exec, unsigned bytecodeIndex)
3278 VM* vm = &exec->vm();
3279 NativeCallFrameTracer tracer(vm, exec);
3280 DeferGCForAWhile deferGC(vm->heap);
3281 CodeBlock* codeBlock = exec->codeBlock();
3283 sanitizeStackForVM(vm);
3285 if (codeBlock->jitType() != JITCode::DFGJIT) {
3286 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
3287 RELEASE_ASSERT_NOT_REACHED();
3290 JITCode* jitCode = codeBlock->jitCode()->dfg();
3291 jitCode->tierUpEntrySeen.add(bytecodeIndex);
3293 if (Options::verboseOSR()) {
3295 *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ",
3296 jitCode->tierUpCounter, "\n");
3299 return tierUpCommon(exec, bytecodeIndex, true);
3302 #endif // ENABLE(FTL_JIT)
3305 } } // namespace JSC::DFG
3307 #endif // ENABLE(DFG_JIT)
3309 #endif // ENABLE(JIT)