diff options
Diffstat (limited to 'src/bun.js/api')
| -rw-r--r-- | src/bun.js/api/ffi.zig | 20 | ||||
| -rw-r--r-- | src/bun.js/api/transpiler.zig | 110 |
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; } |
