aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/JSBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/bindings/JSBuffer.cpp')
-rw-r--r--src/bun.js/bindings/JSBuffer.cpp574
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 } },