EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue property = JSValue::decode(encodedProperty); if (property.isUInt32()) return getByVal(exec, base, property.asUInt32()); if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { if (AtomicStringImpl* existingAtomicString = asString(property)->toExistingAtomicString(exec)) { if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString)) return JSValue::encode(result); } } } PropertyName propertyName = property.toPropertyKey(exec); return JSValue::encode(JSValue(base).get(exec, propertyName)); }
int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue) { JSValue value = JSValue::decode(encodedValue); if (!value.isDouble()) return JSValue::notInt52; return tryConvertToInt52(value.asDouble()); }
ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { putByVal<strict>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsDouble == propertyAsUInt32) { putByVal<strict>(exec, baseValue, propertyAsUInt32, value); return; } } // Don't put to an object if toString throws an exception. Identifier ident(exec, property.toString(exec)->value(exec)); if (!globalData->exception) { PutPropertySlot slot(strict); baseValue.put(exec, ident, value, slot); } }
ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsDouble == propertyAsUInt32) { putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } // Don't put to an object if toString throws an exception. PropertyName propertyName = property.toPropertyKey(exec); if (!vm->exception()) { PutPropertySlot slot(baseValue, strict); if (direct) { RELEASE_ASSERT(baseValue.isObject()); asObject(baseValue)->putDirect(*vm, propertyName, value, slot); } else baseValue.put(exec, propertyName, value, slot); } }
SpeculatedType speculationFromValue(JSValue value) { if (value.isEmpty()) return SpecEmpty; if (value.isInt32()) return SpecInt32; if (value.isDouble()) { double number = value.asNumber(); if (number == number) { int64_t asInt64 = static_cast<int64_t>(number); if (asInt64 == number && (asInt64 || !std::signbit(number)) && asInt64 < (static_cast<int64_t>(1) << 47) && asInt64 >= -(static_cast<int64_t>(1) << 47)) { return SpecInt48AsDouble; } return SpecNonIntAsDouble; } return SpecDoubleNaN; } if (value.isCell()) return speculationFromCell(value.asCell()); if (value.isBoolean()) return SpecBoolean; ASSERT(value.isUndefinedOrNull()); return SpecOther; }
static CodeBlock* codeBlockFromArg(ExecState* exec) { VM& vm = exec->vm(); if (exec->argumentCount() < 1) return nullptr; JSValue value = exec->uncheckedArgument(0); CodeBlock* candidateCodeBlock = nullptr; if (value.isCell()) { JSFunction* func = jsDynamicCast<JSFunction*>(vm, value.asCell()); if (func) { if (func->isHostFunction()) candidateCodeBlock = nullptr; else candidateCodeBlock = func->jsExecutable()->eitherCodeBlock(); } } else if (value.isDouble()) { // If the value is a double, it may be an encoded CodeBlock* that came from // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's // valid below before using. candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble())); } if (candidateCodeBlock && JSDollarVMPrototype::isValidCodeBlock(exec, candidateCodeBlock)) return candidateCodeBlock; if (candidateCodeBlock) dataLog("Invalid codeBlock: ", RawPointer(candidateCodeBlock), " ", value, "\n"); else dataLog("Invalid codeBlock: ", value, "\n"); return nullptr; }
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) return JSValue::encode(result); } } Identifier ident(exec, property.toString(exec)->value(exec)); return JSValue::encode(baseValue.get(exec, ident)); }
static RefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSValue value, int maxDepth) { if (!value) { ASSERT_NOT_REACHED(); return nullptr; } if (!maxDepth) return nullptr; maxDepth--; if (value.isNull() || value.isUndefined()) return InspectorValue::null(); if (value.isBoolean()) return InspectorValue::create(value.asBoolean()); if (value.isNumber() && value.isDouble()) return InspectorValue::create(value.asNumber()); if (value.isNumber() && value.isMachineInt()) return InspectorValue::create(static_cast<int>(value.asMachineInt())); if (value.isString()) return InspectorValue::create(value.getString(scriptState)); if (value.isObject()) { if (isJSArray(value)) { Ref<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { JSValue element = array->getIndex(scriptState, i); RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element, maxDepth); if (!elementValue) return nullptr; inspectorArray->pushValue(WTFMove(elementValue)); } return WTFMove(inspectorArray); } Ref<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState, PropertyNameMode::Strings); object->methodTable()->getOwnPropertyNames(object, scriptState, propertyNames, EnumerationMode()); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue, maxDepth); if (!inspectorValue) return nullptr; inspectorObject->setValue(name.string(), WTFMove(inspectorValue)); } return WTFMove(inspectorObject); } ASSERT_NOT_REACHED(); return nullptr; }
PredictedType predictionFromValue(JSValue value) { if (value.isInt32()) return PredictInt32; if (value.isDouble()) return PredictDouble; if (value.isCell()) return predictionFromCell(value.asCell()); if (value.isBoolean()) return PredictBoolean; ASSERT(value.isUndefinedOrNull()); return PredictOther; }
char* JIT_OPERATION operationFindSwitchImmTargetForDouble( ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex) { CodeBlock* codeBlock = exec->codeBlock(); SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex); JSValue value = JSValue::decode(encodedValue); ASSERT(value.isDouble()); double asDouble = value.asDouble(); int32_t asInt32 = static_cast<int32_t>(asDouble); if (asDouble == asInt32) return static_cast<char*>(table.ctiForValue(asInt32).executableAddress()); return static_cast<char*>(table.ctiDefault.executableAddress()); }
// ECMA-262 20.1.2.5 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState* exec) { JSValue argument = exec->argument(0); bool isInteger; if (argument.isInt32()) isInteger = true; else if (!argument.isDouble()) isInteger = false; else { double number = argument.asDouble(); isInteger = trunc(number) == number && std::abs(number) <= 9007199254740991.0; } return JSValue::encode(jsBoolean(isInteger)); }
// ECMA-262 20.1.2.3 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec) { JSValue argument = exec->argument(0); bool isInteger; if (argument.isInt32()) isInteger = true; else if (!argument.isDouble()) isInteger = false; else { double number = argument.asDouble(); isInteger = std::isfinite(number) && trunc(number) == number; } return JSValue::encode(jsBoolean(isInteger)); }
PredictedType predictionFromValue(JSValue value) { if (value.isInt32()) return PredictInt32; if (value.isDouble()) { double number = value.asNumber(); if (number == number) return PredictDoubleReal; return PredictDoubleNaN; } if (value.isCell()) return predictionFromCell(value.asCell()); if (value.isBoolean()) return PredictBoolean; ASSERT(value.isUndefinedOrNull()); return PredictOther; }
EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) { JSValue property = JSValue::decode(encodedProperty); if (property.isUInt32()) return getByVal(exec, base, property.asUInt32()); if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) return JSValue::encode(result); } Identifier ident(exec, property.toString(exec)); return JSValue::encode(JSValue(base).get(exec, ident)); }
static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x) { if (thisValue.isInt32()) { x = thisValue.asInt32(); return true; } if (thisValue.isDouble()) { x = thisValue.asDouble(); return true; } if (thisValue.isCell() && thisValue.asCell()->type() == NumberObjectType) { x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber(); return true; } return false; }
void ValueProfile::computeStatistics(Statistics& statistics) const { for (unsigned i = 0; i < numberOfBuckets; ++i) { JSValue value = JSValue::decode(m_buckets[i]); if (!value) continue; statistics.samples++; if (value.isInt32()) statistics.int32s++; else if (value.isDouble()) statistics.doubles++; else if (value.isCell()) computeStatistics(value.asCell()->structure()->classInfo(), statistics); else if (value.isBoolean()) statistics.booleans++; } }
static CodeBlock* codeBlockFromArg(ExecState* exec) { if (exec->argumentCount() < 1) return nullptr; JSValue value = exec->uncheckedArgument(0); if (!value.isDouble()) { dataLog("Invalid codeBlock: ", value, "\n"); return nullptr; } CodeBlock* codeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble())); if (JSDollarVMPrototype::isValidCodeBlock(exec, codeBlock)) return codeBlock; dataLogF("Invalid codeBlock: %p ", codeBlock); dataLog(value, "\n"); return nullptr; }
SpeculatedType speculationFromValue(JSValue value) { if (value.isEmpty()) return SpecEmpty; if (value.isInt32()) return SpecInt32; if (value.isDouble()) { double number = value.asNumber(); if (number != number) return SpecDoubleNaN; if (value.isMachineInt()) return SpecInt52AsDouble; return SpecNonIntAsDouble; } if (value.isCell()) return speculationFromCell(value.asCell()); if (value.isBoolean()) return SpecBoolean; ASSERT(value.isUndefinedOrNull()); return SpecOther; }
ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. ASSERT(isIndex(property.asUInt32())); putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) { putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } // Don't put to an object if toString throws an exception. auto propertyName = property.toPropertyKey(exec); if (vm->exception()) return; PutPropertySlot slot(baseValue, strict); if (direct) { RELEASE_ASSERT(baseValue.isObject()); if (Optional<uint32_t> index = parseIndex(propertyName)) asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); else asObject(baseValue)->putDirect(*vm, propertyName, value, slot); } else baseValue.put(exec, propertyName, value, slot); }
EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32)) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { if (AtomicStringImpl* existingAtomicString = asString(property)->toExistingAtomicString(exec)) { if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString)) return JSValue::encode(result); } } } } baseValue.requireObjectCoercible(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); auto propertyName = property.toPropertyKey(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); return JSValue::encode(baseValue.get(exec, propertyName)); }
// ECMA-262 20.1.2.4 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState* exec) { JSValue argument = exec->argument(0); return JSValue::encode(jsBoolean(argument.isDouble() && std::isnan(argument.asDouble()))); }