Beispiel #1
0
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));
}
Beispiel #12
0
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));
}
Beispiel #13
0
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);
}
Beispiel #15
0
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);
}
Beispiel #16
0
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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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);
}
Beispiel #21
0
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);
}
Beispiel #22
0
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);
}
Beispiel #23
0
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));
}
Beispiel #24
0
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);
}
Beispiel #25
0
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());
}
Beispiel #27
0
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));
}
Beispiel #30
0
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());
}