char* newTypedArrayWithOneArgument( ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue value = JSValue::decode(encodedValue); if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) { RefPtr<ArrayBuffer> buffer = jsBuffer->impl(); if (buffer->byteLength() % ViewClass::elementSize) { vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size"))); return 0; } return bitwise_cast<char*>( ViewClass::create( exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize)); } if (JSObject* object = jsDynamicCast<JSObject*>(value)) { unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec); if (exec->hadException()) return 0; ViewClass* result = ViewClass::createUninitialized(exec, structure, length); if (!result) return 0; if (!result->set(exec, object, 0, length)) return 0; return bitwise_cast<char*>(result); } int length; if (value.isInt32()) length = value.asInt32(); else if (!value.isNumber()) { vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument"))); return 0; } else { length = static_cast<int>(value.asNumber()); if (length != value.asNumber()) { vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)"))); return 0; } } if (length < 0) { vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); return 0; } return bitwise_cast<char*>(ViewClass::create(exec, structure, length)); }
// toFixed converts a number to a string, always formatting as an a decimal fraction. // This method takes an argument specifying a number of decimal places to round the // significand to. However when converting large values (1e+21 and above) this // method will instead fallback to calling ToString. EncodedTiValue JSC_HOST_CALL numberProtoFuncToFixed(TiExcState* exec) { // Get x (the double value of this, which should be a Number). TiValue thisValue = exec->hostThisValue(); TiValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); double x = v.uncheckedGetNumber(); // Get the argument. int decimalPlaces; bool isUndefined; // This is ignored; undefined treated as 0. if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined)) return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20")); // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)" // This also covers Ininity, and structure the check so that NaN // values are also handled by numberToString if (!(fabs(x) < 1e+21)) return TiValue::encode(jsString(exec, UString::number(x))); // The check above will return false for NaN or Infinity, these will be // handled by numberToString. ASSERT(!isnan(x) && !isinf(x)); // Convert to decimal with rounding, and format as decimal. NumberToStringBuffer buffer; unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTI::NumberToStringBufferLength); return TiValue::encode(jsString(exec, UString(buffer, length))); }
// toExponential converts a number to a string, always formatting as an expoential. // This method takes an optional argument specifying a number of *decimal places* // to round the significand to (or, put another way, this method optionally rounds // to argument-plus-one significant figures). EncodedTiValue JSC_HOST_CALL numberProtoFuncToExponential(TiExcState* exec) { // Get x (the double value of this, which should be a Number). double x; if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); // Get the argument. int decimalPlacesInExponent; bool isUndefined; if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined)) return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20")); // Handle NaN and Infinity. if (isnan(x) || isinf(x)) return TiValue::encode(jsString(exec, UString::number(x))); // Round if the argument is not undefined, always format as exponential. NumberToStringBuffer buffer; unsigned length = isUndefined ? DecimalNumber(x).toStringExponential(buffer, WTI::NumberToStringBufferLength) : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer, WTI::NumberToStringBufferLength); return TiValue::encode(jsString(exec, UString(buffer, length))); }
static inline double normalizeHighWaterMark(ExecState& exec, JSObject& strategy) { JSValue jsHighWaterMark = getPropertyFromObject(exec, strategy, "highWaterMark"); if (exec.hadException()) return 0; if (jsHighWaterMark.isUndefined()) return 1; double highWaterMark = jsHighWaterMark.toNumber(&exec); if (exec.hadException()) return 0; if (std::isnan(highWaterMark)) { throwVMError(&exec, createTypeError(&exec, ASCIILiteral("Value is NaN"))); return 0; } if (highWaterMark < 0) { throwVMError(&exec, createRangeError(&exec, ASCIILiteral("Not a positive value"))); return 0; } return highWaterMark; }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); if (!std::isfinite(thisDateObj->internalNumber())) return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date"))); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); if (!gregorianDateTime) return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date")))); // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination. char buffer[28]; // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1). int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond)); if (ms < 0) ms += msPerSecond; int charactersWritten; if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0) charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); else charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer)); if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer)) return JSValue::encode(jsEmptyString(exec)); return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten))); }
// toExponential converts a number to a string, always formatting as an expoential. // This method takes an optional argument specifying a number of *decimal places* // to round the significand to (or, put another way, this method optionally rounds // to argument-plus-one significant figures). EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) { double x; if (!toThisNumber(exec->thisValue(), x)) return throwVMTypeError(exec); // Get the argument. int decimalPlacesInExponent; bool isUndefined; if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined)) return throwVMError(exec, createRangeError(exec, ASCIILiteral("toExponential() argument must be between 0 and 20"))); // Handle NaN and Infinity. if (!std::isfinite(x)) return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x))); // Round if the argument is not undefined, always format as exponential. char buffer[WTF::NumberToStringBufferLength]; DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength); const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter(); builder.Reset(); isUndefined ? converter.ToExponential(x, -1, &builder) : converter.ToExponential(x, decimalPlacesInExponent, &builder); return JSValue::encode(jsString(exec, String(builder.Finalize()))); }
// toFixed converts a number to a string, always formatting as an a decimal fraction. // This method takes an argument specifying a number of decimal places to round the // significand to. However when converting large values (1e+21 and above) this // method will instead fallback to calling ToString. EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) { double x; if (!toThisNumber(exec->thisValue(), x)) return throwVMTypeError(exec); // Get the argument. int decimalPlaces; bool isUndefined; // This is ignored; undefined treated as 0. if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined)) return throwVMError(exec, createRangeError(exec, ASCIILiteral("toFixed() argument must be between 0 and 20"))); // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)" // This also covers Ininity, and structure the check so that NaN // values are also handled by numberToString if (!(fabs(x) < 1e+21)) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); // The check above will return false for NaN or Infinity, these will be // handled by numberToString. ASSERT(std::isfinite(x)); NumberToStringBuffer buffer; return JSValue::encode(jsString(exec, String(numberToFixedWidthString(x, decimalPlaces, buffer)))); }
static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); JSValue value = exec->argument(1); WebAssemblyFunction* wasmFunction; WebAssemblyWrapperFunction* wasmWrapperFunction; if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction)) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s))); uint32_t index = toNonWrappingUint32(exec, exec->argument(0)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (index >= table->length()) return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s))); if (value.isNull()) table->clearFunction(index); else { ASSERT(value.isObject() && isWebAssemblyHostFunction(vm, jsCast<JSObject*>(value), wasmFunction, wasmWrapperFunction)); ASSERT(!!wasmFunction || !!wasmWrapperFunction); if (wasmFunction) table->setFunction(vm, index, wasmFunction); else table->setFunction(vm, index, wasmWrapperFunction); } return JSValue::encode(jsUndefined()); }
EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) { double doubleValue; if (!toThisNumber(exec->thisValue(), doubleValue)) return throwVMTypeError(exec); int32_t radix = extractRadixFromArgs(exec); if (radix < 2 || radix > 36) return throwVMError(exec, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36"))); int32_t integerValue = static_cast<int32_t>(doubleValue); if (integerValue == doubleValue) return integerValueToString(exec, radix, integerValue); if (radix == 10) { VM* vm = &exec->vm(); return JSValue::encode(jsString(vm, vm->numericStrings.add(doubleValue))); } if (!std::isfinite(doubleValue)) return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(doubleValue))); RadixBuffer s; return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix))); }
// toPrecision converts a number to a string, takeing an argument specifying a // number of significant figures to round the significand to. For positive // exponent, all values that can be represented using a decimal fraction will // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a // decimal, whilst 1000 is converted to the exponential representation 1.00e+3. // For negative exponents values >= 1e-6 are formated as decimal fractions, // with smaller values converted to exponential representation. EncodedTiValue JSC_HOST_CALL numberProtoFuncToPrecision(TiExcState* exec) { // Get x (the double value of this, which should be a Number). TiValue thisValue = exec->hostThisValue(); TiValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); double x = v.uncheckedGetNumber(); // Get the argument. int significantFigures; bool isUndefined; if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined)) return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21")); // To precision called with no argument is treated as ToString. if (isUndefined) return TiValue::encode(jsString(exec, UString::number(x))); // Handle NaN and Infinity. if (isnan(x) || isinf(x)) return TiValue::encode(jsString(exec, UString::number(x))); // Convert to decimal with rounding. DecimalNumber number(x, RoundingSignificantFigures, significantFigures); // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format // as decimal. Otherwise, format the number as an exponential. Decimal format // demands a minimum of (exponent + 1) digits to represent a number, for example // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c) NumberToStringBuffer buffer; unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures ? number.toStringDecimal(buffer, WTI::NumberToStringBufferLength) : number.toStringExponential(buffer, WTI::NumberToStringBufferLength); return TiValue::encode(jsString(exec, UString(buffer, length))); }
EncodedJSValue getData(ExecState* exec) { JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue()); if (!dataView) return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView")); if (!exec->argumentCount()) return throwVMError(exec, createTypeError(exec, "Need at least one argument (the byteOffset)")); unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); bool littleEndian = false; unsigned elementSize = sizeof(typename Adaptor::Type); if (elementSize > 1 && exec->argumentCount() >= 2) { littleEndian = exec->uncheckedArgument(1).toBoolean(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); } unsigned byteLength = dataView->length(); if (elementSize > byteLength || byteOffset > byteLength - elementSize) return throwVMError(exec, createRangeError(exec, "Out of bounds access")); typename Adaptor::Type value = *reinterpret_cast<typename Adaptor::Type*>(static_cast<uint8_t*>(dataView->vector()) + byteOffset); if (needToFlipBytesIfLittleEndian(littleEndian)) value = flipBytes(value); return JSValue::encode(Adaptor::toJSValue(value)); }
char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); if (UNLIKELY(size < 0)) return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size)); }
char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); if (size < 0) { vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); return 0; } return bitwise_cast<char*>(ViewClass::create(exec, structure, size)); }
JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length) { if (!length.isNumber()) return constructArray(exec, profile, globalObject, &length, 1); uint32_t n = length.toUInt32(exec); if (n != length.toNumber(exec)) return exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))); return constructEmptyArray(exec, profile, globalObject, n); }
void RuntimeArray::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool) { RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (index >= thisObject->getLength()) { exec->vm().throwException(exec, createRangeError(exec, "Range error")); return; } thisObject->getConcreteArray()->setValueAt(exec, index, value); }
Wasm::PageCount JSWebAssemblyMemory::grow(ExecState* exec, uint32_t delta, bool shouldThrowExceptionsOnFailure) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); Wasm::PageCount oldPageCount = memory()->sizeInPages(); if (!Wasm::PageCount::isValid(delta)) { if (shouldThrowExceptionsOnFailure) throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the delta to be a valid page count"))); return Wasm::PageCount(); } Wasm::PageCount newSize = oldPageCount + Wasm::PageCount(delta); if (!newSize) { if (shouldThrowExceptionsOnFailure) throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the grown size to be a valid page count"))); return Wasm::PageCount(); } if (delta) { bool success = memory()->grow(newSize); if (!success) { if (shouldThrowExceptionsOnFailure) throwException(exec, throwScope, createOutOfMemoryError(exec)); return Wasm::PageCount(); } } // We need to clear out the old array buffer because it might now be pointing // to stale memory. // Neuter the old array. if (m_buffer) { ArrayBufferContents dummyContents; m_buffer->transferTo(dummyContents); m_buffer = nullptr; m_bufferWrapper.clear(); } return oldPageCount; }
JSDataView* JSDataView::create( ExecState* exec, Structure* structure, PassRefPtr<ArrayBuffer> passedBuffer, unsigned byteOffset, unsigned byteLength) { RefPtr<ArrayBuffer> buffer = passedBuffer; if (!ArrayBufferView::verifySubRangeLength(buffer, byteOffset, byteLength, sizeof(uint8_t))) { throwVMError(exec, createRangeError(exec, ASCIILiteral("Length out of range of buffer"))); return nullptr; } if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, sizeof(uint8_t))) { exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Byte offset is not aligned"))); return nullptr; } VM& vm = exec->vm(); ConstructionContext context( structure, buffer, byteOffset, byteLength, ConstructionContext::DataView); ASSERT(context); JSDataView* result = new (NotNull, allocateCell<JSDataView>(vm.heap)) JSDataView(vm, context, buffer.get()); result->finishCreation(vm); return result; }
bool RuntimeArray::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (index >= thisObject->getLength()) { throwException(exec, scope, createRangeError(exec, "Range error")); return false; } return thisObject->getConcreteArray()->setValueAt(exec, index, value); }
static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec) { // Until we have iterators we throw if we've been given // any arguments that could require us to throw. if (!exec->argument(0).isUndefinedOrNull()) return JSValue::encode(throwTypeError(exec, ASCIILiteral("Map constructor does not accept arguments"))); if (!exec->argument(1).isUndefined()) return throwVMError(exec, createRangeError(exec, WTF::ASCIILiteral("Invalid comparator function"))); JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); Structure* mapStructure = globalObject->mapStructure(); return JSValue::encode(JSMap::create(exec, mapStructure)); }
static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) { // a single numeric argument denotes the array size (!) if (args.size() == 1 && args.at(0).isNumber()) { uint32_t n = args.at(0).toUInt32(exec); if (n != args.at(0).toNumber(exec)) return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer.")); return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n, CreateInitialized); } // otherwise the array is constructed with the arguments in it return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), args); }
static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) { JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); // a single numeric argument denotes the array size (!) if (args.size() == 1 && args.at(0).isNumber()) { uint32_t n = args.at(0).toUInt32(exec); if (n != args.at(0).toNumber(exec)) return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer.")); return constructEmptyArray(exec, globalObject, n); } // otherwise the array is constructed with the arguments in it return constructArray(exec, globalObject, args); }
void RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { exec->vm().throwException(exec, createRangeError(exec, "Range error")); return; } if (Optional<uint32_t> index = parseIndex(propertyName)) { thisObject->getConcreteArray()->setValueAt(exec, index.value(), value); return; } JSObject::put(thisObject, exec, propertyName, value, slot); }
static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyTable(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSObject* memoryDescriptor; { JSValue argument = exec->argument(0); if (!argument.isObject()) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its first argument to be an object")))); memoryDescriptor = jsCast<JSObject*>(argument); } { Identifier elementIdent = Identifier::fromString(&vm, "element"); JSValue elementValue = memoryDescriptor->get(exec, elementIdent); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); String elementString = elementValue.toWTFString(exec); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (elementString != "anyfunc") return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its 'element' field to be the string 'anyfunc'")))); } Identifier initialIdent = Identifier::fromString(&vm, "initial"); JSValue initialSizeValue = memoryDescriptor->get(exec, initialIdent); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); uint32_t initial = toNonWrappingUint32(exec, initialSizeValue); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); std::optional<uint32_t> maximum; Identifier maximumIdent = Identifier::fromString(&vm, "maximum"); bool hasProperty = memoryDescriptor->hasProperty(exec, maximumIdent); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (hasProperty) { JSValue maxSizeValue = memoryDescriptor->get(exec, maximumIdent); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); maximum = toNonWrappingUint32(exec, maxSizeValue); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (initial > *maximum) { return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("'maximum' property must be greater than or equal to the 'initial' property")))); } } throwScope.release(); return JSValue::encode(JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), initial, maximum)); }
void RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { throwError(exec, createRangeError(exec, "Range error")); return; } unsigned index = propertyName.asIndex(); if (index != PropertyName::NotAnIndex) { thisObject->getConcreteArray()->setValueAt(exec, index, value); return; } JSObject::put(thisObject, exec, propertyName, value, slot); }
bool RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { throwException(exec, scope, createRangeError(exec, "Range error")); return false; } if (Optional<uint32_t> index = parseIndex(propertyName)) return thisObject->getConcreteArray()->setValueAt(exec, index.value(), value); return JSObject::put(thisObject, exec, propertyName, value, slot); }
EncodedJSValue setData(ExecState* exec) { JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue()); if (!dataView) return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView")); if (exec->argumentCount() < 2) return throwVMError(exec, createTypeError(exec, "Need at least two argument (the byteOffset and value)")); unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); const unsigned dataSize = sizeof(typename Adaptor::Type); union { typename Adaptor::Type value; uint8_t rawBytes[dataSize]; } u; u.value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1)); if (exec->hadException()) return JSValue::encode(jsUndefined()); bool littleEndian = false; unsigned elementSize = sizeof(typename Adaptor::Type); if (elementSize > 1 && exec->argumentCount() >= 3) { littleEndian = exec->uncheckedArgument(2).toBoolean(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); } unsigned byteLength = dataView->length(); if (elementSize > byteLength || byteOffset > byteLength - elementSize) return throwVMError(exec, createRangeError(exec, "Out of bounds access")); uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset; if (needToFlipBytesIfLittleEndian(littleEndian)) { for (unsigned i = dataSize; i--;) *dataPtr++ = u.rawBytes[i]; } else { for (unsigned i = 0; i < dataSize; i++) *dataPtr++ = u.rawBytes[i]; } return JSValue::encode(jsUndefined()); }
void RuntimeArray::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { RuntimeArray* thisObject = static_cast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { throwError(exec, createRangeError(exec, "Range error")); return; } bool ok; unsigned index = propertyName.toArrayIndex(ok); if (ok) { thisObject->getConcreteArray()->setValueAt(exec, index, value); return; } JSObject::put(thisObject, exec, propertyName, value, slot); }
static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGet(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); uint32_t index = toNonWrappingUint32(exec, exec->argument(0)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (index >= table->length()) return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.get expects an integer less than the length of the table"_s))); if (JSObject* result = table->getFunction(index)) return JSValue::encode(result); return JSValue::encode(jsNull()); }
static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGrow(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); uint32_t delta = toNonWrappingUint32(exec, exec->argument(0)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); uint32_t oldLength = table->length(); if (!table->grow(delta)) return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.grow could not grow the table"_s))); return JSValue::encode(jsNumber(oldLength)); }
EncodedJSValue setData(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue()); if (!dataView) return throwVMTypeError(exec, scope, ASCIILiteral("Receiver of DataView method must be a DataView")); unsigned byteOffset = exec->argument(0).toIndex(exec, "byteOffset"); RETURN_IF_EXCEPTION(scope, encodedJSValue()); const unsigned dataSize = sizeof(typename Adaptor::Type); union { typename Adaptor::Type value; uint8_t rawBytes[dataSize]; } u; u.value = toNativeFromValue<Adaptor>(exec, exec->argument(1)); RETURN_IF_EXCEPTION(scope, encodedJSValue()); bool littleEndian = false; unsigned elementSize = sizeof(typename Adaptor::Type); if (elementSize > 1 && exec->argumentCount() >= 3) { littleEndian = exec->uncheckedArgument(2).toBoolean(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); } unsigned byteLength = dataView->length(); if (elementSize > byteLength || byteOffset > byteLength - elementSize) return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Out of bounds access"))); uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset; if (needToFlipBytesIfLittleEndian(littleEndian)) { for (unsigned i = dataSize; i--;) *dataPtr++ = u.rawBytes[i]; } else { for (unsigned i = 0; i < dataSize; i++) *dataPtr++ = u.rawBytes[i]; } return JSValue::encode(jsUndefined()); }