diff options
Diffstat (limited to 'src/bun.js/bindings/JSBuffer.cpp')
-rw-r--r-- | src/bun.js/bindings/JSBuffer.cpp | 574 |
1 files changed, 288 insertions, 286 deletions
diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 2ce07617a..9b3854b95 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -133,6 +133,35 @@ static int normalizeCompareVal(int val, size_t a_length, size_t b_length) return val; } +static inline uint32_t parseIndex(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, JSValue arg) +{ + if (auto num = arg.tryGetAsUint32Index()) + return num.value(); + + if (arg.isNumber()) + throwRangeError(lexicalGlobalObject, scope, "Invalid array length"_s); + else + throwTypeError(lexicalGlobalObject, scope, "Expected number"_s); + + return 0; +} + +static inline WebCore::BufferEncodingType parseEncoding(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, JSValue arg) +{ + if (UNLIKELY(!arg.isString())) { + throwTypeError(lexicalGlobalObject, scope, "Expected string"_s); + return WebCore::BufferEncodingType::utf8; + } + + std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg); + if (UNLIKELY(!encoded)) { + throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); + return WebCore::BufferEncodingType::utf8; + } + + return encoded.value(); +} + namespace WebCore { using namespace JSC; @@ -190,8 +219,11 @@ using namespace JSC; static inline EncodedJSValue writeToBuffer(JSC::JSGlobalObject* lexicalGlobalObject, JSArrayBufferView* castedThis, JSString* str, uint32_t offset, uint32_t length, BufferEncodingType encoding) { + if (UNLIKELY(str->length() == 0)) + return JSC::JSValue::encode(JSC::jsNumber(0)); + auto view = str->tryGetValue(lexicalGlobalObject); - int64_t written = 0; + size_t written = 0; switch (encoding) { case WebCore::BufferEncodingType::utf8: @@ -358,9 +390,6 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); - if (str->length() == 0) - return constructBufferEmpty(lexicalGlobalObject); - if (arg1 && arg1.isString()) { std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg1); if (!encoded) { @@ -371,6 +400,9 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl encoding = encoded.value(); } + if (str->length() == 0) + return constructBufferEmpty(lexicalGlobalObject); + JSC::EncodedJSValue result = constructFromEncoding(lexicalGlobalObject, str, encoding); RELEASE_AND_RETURN(scope, result); @@ -380,7 +412,12 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSG { VM& vm = lexicalGlobalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); - auto length = callFrame->uncheckedArgument(0).toInt32(lexicalGlobalObject); + auto lengthArg = callFrame->uncheckedArgument(0); + if (UNLIKELY(!lengthArg.isNumber())) { + throwTypeError(lexicalGlobalObject, scope, "Expected number"_s); + return JSValue::encode(jsUndefined()); + } + auto length = lengthArg.toInt32(lexicalGlobalObject); if (length < 0) { throwRangeError(lexicalGlobalObject, scope, "Invalid array length"_s); return JSValue::encode(jsUndefined()); @@ -392,10 +429,56 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSG // fill argument if (UNLIKELY(callFrame->argumentCount() > 1)) { auto* uint8Array = JSC::JSUint8Array::createUninitialized(lexicalGlobalObject, subclassStructure, length); - auto value = callFrame->argument(1); - if (!value.isString()) { + if (value.isString()) { + size_t length = uint8Array->byteLength(); + size_t start = 0; + size_t end = length; + WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8; + if (callFrame->argumentCount() > 2) { + EnsureStillAliveScope arg2 = callFrame->uncheckedArgument(2); + if (!arg2.value().isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, arg2.value()); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); + } + } + auto startPtr = uint8Array->typedVector() + start; + auto str_ = value.toWTFString(lexicalGlobalObject); + ZigString str = Zig::toZigString(str_); + + if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) { + throwTypeError(lexicalGlobalObject, scope, "Failed to decode value"_s); + return JSC::JSValue::encode(jsUndefined()); + } + } else if (auto* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value)) { + if (UNLIKELY(view->isDetached())) { + throwVMTypeError(lexicalGlobalObject, scope, "Uint8Array is detached"_s); + return JSValue::encode(jsUndefined()); + } + + size_t length = view->byteLength(); + if (UNLIKELY(length == 0)) { + throwTypeError(lexicalGlobalObject, scope, "Buffer cannot be empty"_s); + return JSC::JSValue::encode(jsUndefined()); + } + + auto* start = uint8Array->typedVector(); + auto* head = start; + size_t remain = uint8Array->byteLength(); + memmove(head, view->vector(), length); + remain -= length; + head += length; + while (remain >= length) { + memcpy(head, start, length); + remain -= length; + head += length; + length <<= 1; + } + if (remain > 0) { + memcpy(head, start, remain); + } + } else { auto value_ = value.toInt32(lexicalGlobalObject) & 0xFF; auto value_uint8 = static_cast<uint8_t>(value_); @@ -408,33 +491,9 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSG auto startPtr = uint8Array->typedVector() + start; auto endPtr = uint8Array->typedVector() + end; memset(startPtr, value_uint8, endPtr - startPtr); - RELEASE_AND_RETURN(scope, JSC::JSValue::encode(uint8Array)); } - { - size_t length = uint8Array->byteLength(); - size_t start = 0; - size_t end = length; - WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8; - if (callFrame->argumentCount() > 2) { - EnsureStillAliveScope arg2 = callFrame->uncheckedArgument(2); - if (arg2.value().isString()) { - std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg2.value()); - if (!encoded) { - throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); - return JSC::JSValue::encode(jsUndefined()); - } - - encoding = encoded.value(); - } - } - auto startPtr = uint8Array->typedVector() + start; - auto str_ = value.toWTFString(lexicalGlobalObject); - ZigString str = Zig::toZigString(str_); - - Bun__Buffer_fill(&str, startPtr, end - start, encoding); - RELEASE_AND_RETURN(scope, JSC::JSValue::encode(uint8Array)); - } + RELEASE_AND_RETURN(scope, JSC::JSValue::encode(uint8Array)); } else { auto* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, length); if (UNLIKELY(!uint8Array)) { @@ -585,6 +644,10 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_compareBody(JSC::J throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Buffer (first argument)"_s); return JSValue::encode(jsUndefined()); } + if (UNLIKELY(castedThis->isDetached())) { + throwVMTypeError(lexicalGlobalObject, throwScope, "Uint8Array (first argument) is detached"_s); + return JSValue::encode(jsUndefined()); + } auto buffer = callFrame->uncheckedArgument(1); JSC::JSArrayBufferView* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(buffer); @@ -592,13 +655,7 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_compareBody(JSC::J throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Buffer (2nd argument)"_s); return JSValue::encode(jsUndefined()); } - if (UNLIKELY(view->isDetached())) { - throwVMTypeError(lexicalGlobalObject, throwScope, "Uint8Array (first argument) is detached"_s); - return JSValue::encode(jsUndefined()); - } - - if (UNLIKELY(castedThis->isDetached())) { throwVMTypeError(lexicalGlobalObject, throwScope, "Uint8Array (second argument) is detached"_s); return JSValue::encode(jsUndefined()); } @@ -611,43 +668,27 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_compareBody(JSC::J size_t sourceEndInit = castedThis->byteLength(); size_t sourceEnd = sourceEndInit; - if (callFrame->argumentCount() > 2) { - if (auto targetEnd_ = callFrame->uncheckedArgument(2).tryGetAsUint32Index()) { - targetStart = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - - if (callFrame->argumentCount() > 3) { - auto targetEndArgument = callFrame->uncheckedArgument(3); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - targetEnd = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } - - if (callFrame->argumentCount() > 4) { - auto targetEndArgument = callFrame->uncheckedArgument(4); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - sourceStart = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } - - if (callFrame->argumentCount() > 5) { - auto targetEndArgument = callFrame->uncheckedArgument(5); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - sourceEnd = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } + switch (callFrame->argumentCount()) { + default: + sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(5)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 5: + sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(4)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 4: + targetEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 3: + targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + break; + case 2: + case 1: + case 0: + break; } targetStart = std::min(targetStart, std::min(targetEnd, targetEndInit)); @@ -822,43 +863,26 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG size_t sourceEndInit = castedThis->byteLength(); size_t sourceEnd = sourceEndInit; - if (callFrame->argumentCount() > 1) { - if (auto targetEnd_ = callFrame->uncheckedArgument(1).tryGetAsUint32Index()) { - targetStart = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - - if (callFrame->argumentCount() > 2) { - auto targetEndArgument = callFrame->uncheckedArgument(2); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - targetEnd = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } - - if (callFrame->argumentCount() > 3) { - auto targetEndArgument = callFrame->uncheckedArgument(3); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - sourceStart = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } - - if (callFrame->argumentCount() > 4) { - auto targetEndArgument = callFrame->uncheckedArgument(4); - if (auto targetEnd_ = targetEndArgument.tryGetAsUint32Index()) { - sourceEnd = targetEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } + switch (callFrame->argumentCount()) { + default: + sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(4)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 4: + sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 3: + targetEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 2: + targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + break; + case 1: + case 0: + break; } targetStart = std::min(targetStart, std::min(targetEnd, targetEndInit)); @@ -905,31 +929,22 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_copyBody(JSC::JSGlob size_t sourceEndInit = castedThis->byteLength(); size_t sourceEnd = sourceEndInit; - if (callFrame->argumentCount() > 1) { - if (auto targetStart_ = callFrame->uncheckedArgument(1).tryGetAsUint32Index()) { - targetStart = targetStart_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - - if (callFrame->argumentCount() > 2) { - if (auto sourceStart_ = callFrame->uncheckedArgument(2).tryGetAsUint32Index()) { - sourceStart = sourceStart_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } - - if (callFrame->argumentCount() > 3) { - if (auto sourceEnd_ = callFrame->uncheckedArgument(3).tryGetAsUint32Index()) { - sourceEnd = sourceEnd_.value(); - } else { - throwVMTypeError(lexicalGlobalObject, throwScope, "Expected number"_s); - return JSValue::encode(jsUndefined()); - } - } + switch (callFrame->argumentCount()) { + default: + sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 3: + sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + FALLTHROUGH; + case 2: + targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + break; + case 1: + case 0: + break; } targetStart = std::min(targetStart, targetEnd); @@ -993,120 +1008,111 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob } auto value = callFrame->uncheckedArgument(0); + const size_t limit = castedThis->byteLength(); + size_t start = 0; + size_t end = limit; + WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8; + JSValue encodingValue = jsUndefined(); + JSValue offsetValue = jsUndefined(); + JSValue lengthValue = jsUndefined(); - if (!value.isString()) { - auto value_ = value.toInt32(lexicalGlobalObject) & 0xFF; + switch (callFrame->argumentCount()) { + case 4: + encodingValue = callFrame->uncheckedArgument(3); + FALLTHROUGH; + case 3: + lengthValue = callFrame->uncheckedArgument(2); + FALLTHROUGH; + case 2: + offsetValue = callFrame->uncheckedArgument(1); + FALLTHROUGH; + default: + break; + } - auto value_uint8 = static_cast<uint8_t>(value_); + if (offsetValue.isUndefined() || offsetValue.isString()) { + encodingValue = offsetValue; + offsetValue = jsUndefined(); + } else if (lengthValue.isString()) { + encodingValue = lengthValue; + lengthValue = jsUndefined(); + } + + if (!encodingValue.isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, encodingValue); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); + } - auto length = castedThis->byteLength(); - auto start = 0; - auto end = length; - if (callFrame->argumentCount() > 1) { - if (auto start_ = callFrame->uncheckedArgument(1).tryGetAsUint32Index()) { - start = start_.value(); - } else { - return throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "start out of range"_s)); - } - if (callFrame->argumentCount() > 2) { - if (auto end_ = callFrame->uncheckedArgument(2).tryGetAsUint32Index()) { - end = end_.value(); - } else { - return throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "end out of range"_s)); - } - } - } - if (start > end) { - return throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "start out of range"_s)); - } - if (end > length) { - return throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "end out of range"_s)); - } - auto startPtr = castedThis->typedVector() + start; - auto endPtr = castedThis->typedVector() + end; - memset(startPtr, value_uint8, endPtr - startPtr); - return JSValue::encode(castedThis); + if (!offsetValue.isUndefined()) { + start = parseIndex(lexicalGlobalObject, scope, offsetValue); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); } - { - EnsureStillAliveScope value_ = callFrame->argument(0); - - size_t length = castedThis->byteLength(); - size_t start = 0; - size_t end = length; - WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8; - - JSValue encodingValue = jsUndefined(); - JSValue offsetValue = jsUndefined(); - JSValue lengthValue = jsUndefined(); - - switch (callFrame->argumentCount()) { - case 4: - encodingValue = callFrame->uncheckedArgument(3); - FALLTHROUGH; - case 3: - lengthValue = callFrame->uncheckedArgument(2); - FALLTHROUGH; - case 2: - offsetValue = callFrame->uncheckedArgument(1); - FALLTHROUGH; - default: - break; - } + if (!lengthValue.isUndefined()) { + end = parseIndex(lexicalGlobalObject, scope, lengthValue); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); + } - if (offsetValue.isUndefined() || offsetValue.isString()) { - encodingValue = offsetValue; - offsetValue = jsUndefined(); - } else if (lengthValue.isString()) { - encodingValue = lengthValue; - lengthValue = jsUndefined(); - } + if (start >= end) { + RELEASE_AND_RETURN(scope, JSValue::encode(castedThis)); + } - if (encodingValue.isString()) { - std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encodingValue); - if (!encoded) { - throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); - return JSC::JSValue::encode(jsUndefined()); - } + if (UNLIKELY(end > limit)) { + throwRangeError(lexicalGlobalObject, scope, "end out of range"_s); + return JSC::JSValue::encode(jsUndefined()); + } - encoding = encoded.value(); - } + if (value.isString()) { + auto startPtr = castedThis->typedVector() + start; + auto str_ = value.toWTFString(lexicalGlobalObject); + ZigString str = Zig::toZigString(str_); - if (!offsetValue.isUndefined()) { - if (auto offset = offsetValue.tryGetAsUint32Index()) { - start = offset.value(); - } else { - throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "start out of range"_s)); - return JSC::JSValue::encode(jsUndefined()); - } + if (str.len == 0) { + memset(startPtr, 0, end - start); + } else if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) { + throwTypeError(lexicalGlobalObject, scope, "Failed to decode value"_s); + return JSC::JSValue::encode(jsUndefined()); } + } else if (auto* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value)) { + auto* startPtr = castedThis->typedVector() + start; + auto* head = startPtr; + size_t remain = end - start; - if (!lengthValue.isUndefined()) { - if (auto length = lengthValue.tryGetAsUint32Index()) { - end = std::min(static_cast<size_t>(length.value()), end); - } else { - throwVMError(lexicalGlobalObject, scope, createRangeError(lexicalGlobalObject, "end out of range"_s)); - return JSC::JSValue::encode(jsUndefined()); - } + if (UNLIKELY(view->isDetached())) { + throwVMTypeError(lexicalGlobalObject, scope, "Uint8Array is detached"_s); + return JSValue::encode(jsUndefined()); } - if (start >= end) { - return JSValue::encode(castedThis); + size_t length = view->byteLength(); + if (UNLIKELY(length == 0)) { + throwTypeError(lexicalGlobalObject, scope, "Buffer cannot be empty"_s); + return JSC::JSValue::encode(jsUndefined()); } - auto startPtr = castedThis->typedVector() + start; - auto str_ = value.toWTFString(lexicalGlobalObject); - ZigString str = Zig::toZigString(str_); - - if (str.len > 0) { - Bun__Buffer_fill(&str, startPtr, end - start, encoding); - } else { - memset(startPtr, 0, end - start); + memmove(head, view->vector(), length); + remain -= length; + head += length; + while (remain >= length) { + memcpy(head, startPtr, length); + remain -= length; + head += length; + length <<= 1; + } + if (remain > 0) { + memcpy(head, startPtr, remain); } + } else { + auto value_ = value.toInt32(lexicalGlobalObject) & 0xFF; - RELEASE_AND_RETURN(scope, JSValue::encode(castedThis)); + auto value_uint8 = static_cast<uint8_t>(value_); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); + + auto startPtr = castedThis->typedVector() + start; + auto endPtr = castedThis->typedVector() + end; + memset(startPtr, value_uint8, endPtr - startPtr); } + + RELEASE_AND_RETURN(scope, JSValue::encode(castedThis)); } static int64_t indexOf(const uint8_t* thisPtr, int64_t thisLength, const uint8_t* valuePtr, int64_t valueLength, int64_t byteOffset) @@ -1150,42 +1156,42 @@ static int64_t indexOf(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* int64_t byteOffset = last ? length - 1 : 0; if (callFrame->argumentCount() > 1) { - auto byteOffset_ = callFrame->uncheckedArgument(1).toNumber(lexicalGlobalObject); - RETURN_IF_EXCEPTION(scope, -1); - - if (std::isnan(byteOffset_) || std::isinf(byteOffset_)) { - byteOffset = last ? length - 1 : 0; - } else if (byteOffset_ < 0) { - byteOffset = length + static_cast<int64_t>(byteOffset_); + EnsureStillAliveScope arg1 = callFrame->uncheckedArgument(1); + if (arg1.value().isString()) { + encoding = parseEncoding(lexicalGlobalObject, scope, arg1.value()); + RETURN_IF_EXCEPTION(scope, -1); } else { - byteOffset = static_cast<int64_t>(byteOffset_); - } + auto byteOffset_ = arg1.value().toNumber(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, -1); - if (last) { - if (byteOffset < 0) { - return -1; - } else if (byteOffset > length - 1) { - byteOffset = length - 1; - } - } else { - if (byteOffset <= 0) { - byteOffset = 0; - } else if (byteOffset > length - 1) { - return -1; + if (std::isnan(byteOffset_) || std::isinf(byteOffset_)) { + byteOffset = last ? length - 1 : 0; + } else if (byteOffset_ < 0) { + byteOffset = length + static_cast<int64_t>(byteOffset_); + } else { + byteOffset = static_cast<int64_t>(byteOffset_); } - } - if (callFrame->argumentCount() > 2) { - EnsureStillAliveScope encodingValue = callFrame->uncheckedArgument(2); - - if (encodingValue.value().isString()) { - std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encodingValue.value()); - if (!encoded) { - throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); - return JSC::JSValue::encode(jsUndefined()); + if (last) { + if (byteOffset < 0) { + return -1; + } else if (byteOffset > length - 1) { + byteOffset = length - 1; + } + } else { + if (byteOffset <= 0) { + byteOffset = 0; + } else if (byteOffset > length - 1) { + return -1; } + } - encoding = encoded.value(); + if (callFrame->argumentCount() > 2) { + EnsureStillAliveScope encodingValue = callFrame->uncheckedArgument(2); + if (!encodingValue.value().isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, encodingValue.value()); + RETURN_IF_EXCEPTION(scope, -1); + } } } } @@ -1420,6 +1426,7 @@ static inline JSC::EncodedJSValue jsBufferToString(JSC::VM& vm, JSC::JSGlobalObj static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis) { auto& vm = JSC::getVM(lexicalGlobalObject); + auto scope = DECLARE_THROW_SCOPE(vm); uint32_t offset = 0; uint32_t length = castedThis->length(); uint32_t byteLength = length; @@ -1436,18 +1443,10 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS case 3: case 1: { EnsureStillAliveScope arg1 = callFrame->uncheckedArgument(0); - if (arg1.value().isString()) { - std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg1.value()); - if (!encoded) { - auto scope = DECLARE_THROW_SCOPE(vm); - - throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); - return JSC::JSValue::encode(jsUndefined()); - } - - encoding = encoded.value(); + if (!arg1.value().isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, arg1.value()); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); } - if (callFrame->argumentCount() == 1) break; } @@ -1456,8 +1455,6 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS JSC::JSValue arg2 = callFrame->uncheckedArgument(1); int32_t ioffset = arg2.toInt32(lexicalGlobalObject); if (ioffset < 0) { - auto scope = DECLARE_THROW_SCOPE(vm); - throwTypeError(lexicalGlobalObject, scope, "Offset must be a positive integer"_s); return JSC::JSValue::encode(jsUndefined()); } @@ -1524,9 +1521,6 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_writeBody(JSC::JSGlo return JSC::JSValue::encode(jsUndefined()); } - if (str->length() == 0) - return JSC::JSValue::encode(JSC::jsNumber(0)); - JSValue offsetValue = jsUndefined(); JSValue lengthValue = jsUndefined(); JSValue encodingValue = jsUndefined(); @@ -1546,14 +1540,8 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_writeBody(JSC::JSGlo } auto setEncoding = [&]() { - if (encodingValue.isString()) { - std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encodingValue); - if (!encoded) { - throwTypeError(lexicalGlobalObject, scope, "Invalid encoding"_s); - return; - } - - encoding = encoded.value(); + if (!encodingValue.isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, encodingValue); } }; @@ -1570,6 +1558,11 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_writeBody(JSC::JSGlo RELEASE_AND_RETURN(scope, writeToBuffer(lexicalGlobalObject, castedThis, str, offset, length, encoding)); } + if (UNLIKELY(!offsetValue.isNumber())) { + throwTypeError(lexicalGlobalObject, scope, "Invalid offset"_s); + return JSC::JSValue::encode(jsUndefined()); + } + int32_t userOffset = offsetValue.toInt32(lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); if (userOffset < 0 || userOffset > max) { @@ -1845,11 +1838,15 @@ static const HashTableValue JSBufferPrototypeTableValues[] { "readInt32BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadInt32BECodeGenerator, 1 } }, { "readInt32LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadInt32LECodeGenerator, 1 } }, { "readInt8"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadInt8CodeGenerator, 2 } }, + { "readIntBE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadIntBECodeGenerator, 1 } }, + { "readIntLE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadIntLECodeGenerator, 1 } }, { "readUInt16BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt16BECodeGenerator, 1 } }, { "readUInt16LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt16LECodeGenerator, 1 } }, { "readUInt32BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt32BECodeGenerator, 1 } }, { "readUInt32LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt32LECodeGenerator, 1 } }, { "readUInt8"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt8CodeGenerator, 1 } }, + { "readUIntBE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUIntBECodeGenerator, 1 } }, + { "readUIntLE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUIntLECodeGenerator, 1 } }, { "readUint16BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt16BECodeGenerator, 1 } }, { "readUint16LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt16LECodeGenerator, 1 } }, { "readUint32BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadUInt32BECodeGenerator, 1 } }, @@ -1861,6 +1858,7 @@ static const HashTableValue JSBufferPrototypeTableValues[] { "swap32"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_swap32, 0 } }, { "swap64"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_swap64, 0 } }, { "toJSON"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeToJSONCodeGenerator, 1 } }, + { "toLocaleString"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_toString, 4 } }, { "toString"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_toString, 4 } }, { "ucs2Slice"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeUcs2SliceCodeGenerator, 2 } }, { "ucs2Write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeUcs2WriteCodeGenerator, 1 } }, @@ -1886,6 +1884,8 @@ static const HashTableValue JSBufferPrototypeTableValues[] { "writeInt32BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteInt32BECodeGenerator, 1 } }, { "writeInt32LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteInt32LECodeGenerator, 1 } }, { "writeInt8"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteInt8CodeGenerator, 1 } }, + { "writeIntBE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteIntBECodeGenerator, 1 } }, + { "writeIntLE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteIntLECodeGenerator, 1 } }, { "writeUInt16"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16LECodeGenerator, 1 } }, { "writeUInt16BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16BECodeGenerator, 1 } }, { "writeUInt16LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16LECodeGenerator, 1 } }, @@ -1893,6 +1893,8 @@ static const HashTableValue JSBufferPrototypeTableValues[] { "writeUInt32BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt32BECodeGenerator, 1 } }, { "writeUInt32LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt32LECodeGenerator, 1 } }, { "writeUInt8"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt8CodeGenerator, 1 } }, + { "writeUIntBE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUIntBECodeGenerator, 1 } }, + { "writeUIntLE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUIntLECodeGenerator, 1 } }, { "writeUint16"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16LECodeGenerator, 1 } }, { "writeUint16BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16BECodeGenerator, 1 } }, { "writeUint16LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeWriteUInt16LECodeGenerator, 1 } }, |