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)); }
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); } }
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)); }
static inline T toSmallerUInt(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) { typedef IntTypeLimits<T> LimitsTrait; // Fast path if the value is already a 32-bit unsigned integer in the right range. if (value.isUInt32()) { uint32_t d = value.asUInt32(); if (d <= LimitsTrait::maxValue) return static_cast<T>(d); if (configuration == EnforceRange) { throwTypeError(exec); return 0; } return static_cast<T>(d); } double x = value.toNumber(exec); if (exec->hadException()) return 0; if (configuration == EnforceRange) return enforceRange(exec, x, 0, LimitsTrait::maxValue); if (std::isnan(x) || std::isinf(x) || !x) return 0; x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); return static_cast<T>(fmod(x, LimitsTrait::numberOfValues)); }
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); } }
// http://www.w3.org/TR/WebIDL/#es-octet uint8_t toUInt8(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) { // Fast path if the value is already a 32-bit unsigned integer in the right range. if (value.isUInt32()) { uint32_t d = value.asUInt32(); if (d <= kMaxUInt8) return static_cast<uint8_t>(d); if (configuration == EnforceRange) { throwTypeError(exec); return 0; } return static_cast<uint8_t>(d % 256); // 2^8. } double x = value.toNumber(exec); if (exec->hadException()) return 0; if (configuration == EnforceRange) return enforceRange(exec, x, 0, kMaxUInt8); if (std::isnan(x) || std::isinf(x) || !x) return 0; x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); return static_cast<uint8_t>(fmod(x, 256)); // 2^8. }
// Shared implementation used by test and exec. MatchResult RegExpObject::match(ExecState* exec, JSString* string) { RegExp* regExp = this->regExp(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); String input = string->value(exec); VM& vm = exec->vm(); if (!regExp->global()) return regExpConstructor->performMatch(vm, regExp, string, input, 0); JSValue jsLastIndex = getLastIndex(); unsigned lastIndex; if (LIKELY(jsLastIndex.isUInt32())) { lastIndex = jsLastIndex.asUInt32(); if (lastIndex > input.length()) { setLastIndex(exec, 0); return MatchResult::failed(); } } else { double doubleLastIndex = jsLastIndex.toInteger(exec); if (doubleLastIndex < 0 || doubleLastIndex > input.length()) { setLastIndex(exec, 0); return MatchResult::failed(); } lastIndex = static_cast<unsigned>(doubleLastIndex); } MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex); setLastIndex(exec, result.end); return result; }
// http://www.w3.org/TR/WebIDL/#es-unsigned-long uint32_t toUInt32EnforceRange(ExecState* exec, JSValue value) { if (value.isUInt32()) return value.asUInt32(); double x = value.toNumber(exec); if (exec->hadException()) return 0; return enforceRange(exec, x, 0, kMaxUInt32); }
ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { JSGlobalData* globalData = &exec->globalData(); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { uint32_t i = property.asUInt32(); if (isJSArray(globalData, baseValue)) { JSArray* jsArray = asArray(baseValue); if (jsArray->canSetIndex(i)) { jsArray->setIndex(*globalData, i, value); return; } jsArray->JSArray::put(exec, i, value); return; } if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); // FIXME: the JITstub used to relink this to an optimized form! if (value.isInt32()) { jsByteArray->setIndex(i, value.asInt32()); return; } double dValue = 0; if (value.getNumber(dValue)) { jsByteArray->setIndex(i, dValue); return; } } baseValue.put(exec, i, value); return; } // Don't put to an object if toString throws an exception. Identifier ident(exec, property.toString(exec)); if (!globalData->exception) { PutPropertySlot slot(strict); baseValue.put(exec, ident, value, slot); } }
static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec) { if (exec->argumentCount() < 1) return JSValue::encode(jsUndefined()); JSValue value = exec->uncheckedArgument(0); if (!value.isUInt32()) return JSValue::encode(jsUndefined()); // We need to inc the frame number because the caller would consider // its own frame as frame 0. Hence, we need discount the frame for this // function. unsigned frameNumber = value.asUInt32() + 1; CodeBlock* codeBlock = JSDollarVMPrototype::codeBlockForFrame(exec, frameNumber); return JSValue::encode(JSValue(bitwise_cast<double>(reinterpret_cast<uint64_t>(codeBlock)))); }
// http://www.w3.org/TR/WebIDL/#es-unsigned-long-long uint64_t toUInt64(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) { if (value.isUInt32()) return value.asUInt32(); double x = value.toNumber(exec); if (exec->hadException()) return 0; if (configuration == EnforceRange) return enforceRange(exec, x, 0, kJSMaxInteger); // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64. unsigned long long n; doubleToInteger(x, n); return n; }
static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec) { if (exec->argumentCount() < 1) return JSValue::encode(jsUndefined()); JSValue value = exec->uncheckedArgument(0); if (!value.isUInt32()) return JSValue::encode(jsUndefined()); // We need to inc the frame number because the caller would consider // its own frame as frame 0. Hence, we need discount the frame for this // function. unsigned frameNumber = value.asUInt32() + 1; CodeBlock* codeBlock = JSDollarVMPrototype::codeBlockForFrame(exec, frameNumber); // Though CodeBlock is a JSCell, it is not safe to return it directly back to JS code // as it is an internal type that the JS code cannot handle. Hence, we first encode the // CodeBlock* as a double token (which is safe for JS code to handle) before returning it. return JSValue::encode(JSValue(bitwise_cast<double>(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(codeBlock))))); }
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)); }
// Shared implementation used by test and exec. bool RegExpObject::match(ExecState* exec) { RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); UString input = exec->argument(0).toString(exec); JSGlobalData* globalData = &exec->globalData(); if (!regExp()->global()) { int position; int length; regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length); return position >= 0; } JSValue jsLastIndex = getLastIndex(); unsigned lastIndex; if (LIKELY(jsLastIndex.isUInt32())) { lastIndex = jsLastIndex.asUInt32(); if (lastIndex > input.length()) { setLastIndex(0); return false; } } else { double doubleLastIndex = jsLastIndex.toInteger(exec); if (doubleLastIndex < 0 || doubleLastIndex > input.length()) { setLastIndex(0); return false; } lastIndex = static_cast<unsigned>(doubleLastIndex); } int position; int length = 0; regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length); if (position < 0) { setLastIndex(0); return false; } setLastIndex(position + length); return true; }
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 operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { JSGlobalData* globalData = &exec->globalData(); uint32_t i = property.asUInt32(); // FIXME: the JIT used to handle these in compiled code! if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i)) return JSValue::encode(asArray(base)->getIndex(i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSString(globalData, base) && asString(base)->canGetIndex(i)) return JSValue::encode(asString(base)->getIndex(exec, i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i)) return JSValue::encode(asByteArray(base)->getIndex(exec, i)); return JSValue::encode(baseValue.get(exec, i)); } if (property.isString()) { Identifier propertyName(exec, asString(property)->value(exec)); PropertySlot slot(base); if (base->fastGetOwnPropertySlot(exec, propertyName, slot)) return JSValue::encode(slot.getValue(exec, propertyName)); } } Identifier ident(exec, property.toString(exec)); return JSValue::encode(baseValue.get(exec, ident)); }
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)); }