aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/api')
-rw-r--r--src/bun.js/api/ffi.zig20
-rw-r--r--src/bun.js/api/transpiler.zig110
2 files changed, 47 insertions, 83 deletions
diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig
index 1e21330e5..afe442096 100644
--- a/src/bun.js/api/ffi.zig
+++ b/src/bun.js/api/ffi.zig
@@ -559,20 +559,18 @@ pub const FFI = struct {
pub fn generateSymbols(global: *JSGlobalObject, symbols: *std.StringArrayHashMapUnmanaged(Function), object: JSC.JSValue) !?JSValue {
const allocator = VirtualMachine.vm.allocator;
- var keys = JSC.C.JSObjectCopyPropertyNames(global.ref(), object.asObjectRef());
- defer JSC.C.JSPropertyNameArrayRelease(keys);
- const count = JSC.C.JSPropertyNameArrayGetCount(keys);
+ var symbols_iter = JSC.JSPropertyIterator(.{
+ .skip_empty_name = true,
+ .name_encoding = .utf8,
+ .include_value = true,
+ }).init(global.ref(), object.asObjectRef());
+ defer symbols_iter.deinit();
- try symbols.ensureTotalCapacity(allocator, count);
+ try symbols.ensureTotalCapacity(allocator, symbols_iter.len);
- var i: usize = 0;
- while (i < count) : (i += 1) {
- var property_name_ref = JSC.C.JSPropertyNameArrayGetNameAtIndex(keys, i);
- const len = JSC.C.JSStringGetLength(property_name_ref);
- if (len == 0) continue;
- var prop = JSC.C.JSStringGetCharacters8Ptr(property_name_ref)[0..len];
+ while (symbols_iter.next()) |prop| {
+ const value = symbols_iter.value;
- var value = JSC.JSValue.c(JSC.C.JSObjectGetProperty(global.ref(), object.asObjectRef(), property_name_ref, null));
if (value.isEmptyOrUndefinedOrNull()) {
return JSC.toTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_VALUE, "Expected an object for key \"{s}\"", .{prop}, global.ref());
}
diff --git a/src/bun.js/api/transpiler.zig b/src/bun.js/api/transpiler.zig
index d71264a18..a21f40e2e 100644
--- a/src/bun.js/api/transpiler.zig
+++ b/src/bun.js/api/transpiler.zig
@@ -363,45 +363,37 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo
return transpiler;
}
- var array = JSC.C.JSObjectCopyPropertyNames(globalThis.ref(), define.asObjectRef());
- defer JSC.C.JSPropertyNameArrayRelease(array);
- const count = JSC.C.JSPropertyNameArrayGetCount(array);
+ var define_iter = JSC.JSPropertyIterator(.{
+ .skip_empty_name = false,
+ .name_encoding = .utf8,
+ .include_value = true,
+ }).init(globalThis.ref(), define.asObjectRef());
+ defer define_iter.deinit();
+
// cannot be a temporary because it may be loaded on different threads.
- var map_entries = allocator.alloc([]u8, count * 2) catch unreachable;
- var names = map_entries[0..count];
-
- var values = map_entries[count..];
-
- var i: usize = 0;
- while (i < count) : (i += 1) {
- // no need to free because we free the name array at once
- var property_name_ref = JSC.C.JSPropertyNameArrayGetNameAtIndex(
- array,
- i,
- );
- const prop: []const u8 = JSC.C.JSStringGetCharacters8Ptr(property_name_ref)[0..JSC.C.JSStringGetLength(property_name_ref)];
- const property_value: JSC.JSValue = JSC.JSValue.fromRef(
- JSC.C.JSObjectGetProperty(
- globalThis.ref(),
- define.asObjectRef(),
- property_name_ref,
- null,
- ),
- );
+ var map_entries = allocator.alloc([]u8, define_iter.len * 2) catch unreachable;
+ var names = map_entries[0..define_iter.len];
+
+ var values = map_entries[define_iter.len..];
+
+ while (define_iter.next()) |prop| {
+ const property_value = define_iter.value;
const value_type = property_value.jsType();
if (!value_type.isStringLike()) {
JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, ctx, exception);
return transpiler;
}
- names[i] = allocator.dupe(u8, prop) catch unreachable;
+
+ names[define_iter.i] = allocator.dupe(u8, prop) catch unreachable;
var val = JSC.ZigString.init("");
property_value.toZigString(&val, globalThis);
if (val.len == 0) {
val = JSC.ZigString.init("\"\"");
}
- values[i] = std.fmt.allocPrint(allocator, "{}", .{val}) catch unreachable;
+ values[define_iter.i] = std.fmt.allocPrint(allocator, "{}", .{val}) catch unreachable;
}
+
transpiler.transform.define = Api.StringMap{
.keys = names,
.values = values,
@@ -645,55 +637,30 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo
return transpiler;
}
- var total_name_buf_len: usize = 0;
-
- var array = js.JSObjectCopyPropertyNames(ctx, replace.asObjectRef());
- defer js.JSPropertyNameArrayRelease(array);
- const property_names_count = @intCast(u32, js.JSPropertyNameArrayGetCount(array));
- var iter = JSC.JSPropertyNameIterator{
- .array = array,
- .count = @intCast(u32, property_names_count),
- };
-
- {
- var key_iter = iter;
- while (key_iter.next()) |item| {
- total_name_buf_len += JSC.C.JSStringGetLength(item);
- }
- }
-
- if (total_name_buf_len > 0) {
- var total_name_buf = try std.ArrayList(u8).initCapacity(bun.default_allocator, total_name_buf_len);
- errdefer total_name_buf.clearAndFree();
-
- try replacements.ensureUnusedCapacity(bun.default_allocator, property_names_count);
- defer {
- if (exception.* != null) {
- total_name_buf.clearAndFree();
- replacements.clearAndFree(bun.default_allocator);
- }
- }
-
- while (iter.next()) |item| {
- // no need to free key because we free the name array at once
-
- const start = total_name_buf.items.len;
- total_name_buf.items.len += @maximum(
- // this returns a null terminated string
- JSC.C.JSStringGetUTF8CString(item, total_name_buf.items.ptr + start, total_name_buf.capacity - start),
- 1,
- ) - 1;
- const key = total_name_buf.items[start..total_name_buf.items.len];
- // if somehow the string is empty, skip it
- if (key.len == 0)
- continue;
-
- const value = replace.get(globalThis, key).?;
+ var iter = JSC.JSPropertyIterator(.{
+ .skip_empty_name = true,
+ .name_encoding = .utf8,
+ .include_value = true,
+ .override_writing_cstring = true,
+ }).initCStringBuffer(globalThis.ref(), replace.asObjectRef(), bun.default_allocator);
+
+ if (iter.len > 0) {
+ errdefer iter.deinit(bun.default_allocator);
+ try replacements.ensureUnusedCapacity(bun.default_allocator, iter.len);
+
+ // We cannot set the exception before `try` because it could be
+ // a double free with the `errdefer`.
+ defer if (exception.* != null) {
+ iter.deinit(bun.default_allocator);
+ replacements.clearAndFree(bun.default_allocator);
+ };
+
+ while (iter.next()) |key| {
+ const value = iter.value;
if (value.isEmpty()) continue;
if (!JSLexer.isIdentifier(key)) {
JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, ctx, exception);
- total_name_buf.deinit();
return transpiler;
}
@@ -713,7 +680,6 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo
if (!JSLexer.isIdentifier(replacement_name)) {
JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, ctx, exception);
- total_name_buf.deinit();
slice.deinit();
return transpiler;
}