diff options
Diffstat (limited to 'src')
25 files changed, 1697 insertions, 242 deletions
diff --git a/src/feature_flags.zig b/src/feature_flags.zig index 16adec042..828bae1fd 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -38,3 +38,6 @@ pub const CSSModulePolyfill = enum { // Just return whatever the property key they referenced was facade, }; + +// having issues compiling WebKit with this enabled +pub const remote_inspector = false; diff --git a/src/global.zig b/src/global.zig index 5a1428049..16a515086 100644 --- a/src/global.zig +++ b/src/global.zig @@ -7,7 +7,7 @@ pub usingnamespace @import("env.zig"); pub const FeatureFlags = @import("feature_flags.zig"); pub const Output = struct { - threadlocal var source: *Source = undefined; + threadlocal var source: Source = undefined; pub const Source = struct { const StreamType = { if (isWasm) { @@ -41,7 +41,7 @@ pub const Output = struct { } pub fn set(_source: *Source) void { - source = _source; + source = _source.*; } }; pub var enable_ansi_colors = isNative; diff --git a/src/http.zig b/src/http.zig index f9d1acf0e..0514e88aa 100644 --- a/src/http.zig +++ b/src/http.zig @@ -44,7 +44,7 @@ threadlocal var res_headers_buf: [100]picohttp.Header = undefined; const sync = @import("./sync.zig"); const JavaScript = @import("./javascript/jsc/JavaScript.zig"); const js = @import("javascript/jsc/javascript.zig"); - +const Router = @import("./router.zig"); pub const Watcher = watcher.NewWatcher(*Server); const ENABLE_LOGGER = false; @@ -193,6 +193,7 @@ pub const RequestContext = struct { controlled: bool = false, watcher: *Watcher, timer: std.time.Timer, + matched_route: ?Router.Match = null, full_url: [:0]const u8 = "", res_headers_count: usize = 0, diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig index 0f1a624ce..d1a3a9f22 100644 --- a/src/javascript/jsc/JavascriptCore.zig +++ b/src/javascript/jsc/JavascriptCore.zig @@ -240,6 +240,15 @@ pub const OpaqueJSPropertyNameArray = struct_OpaqueJSPropertyNameArray; pub const OpaqueJSPropertyNameAccumulator = struct_OpaqueJSPropertyNameAccumulator; pub const OpaqueJSValue = struct_OpaqueJSValue; +// const JSProcessID = ; +pub extern fn JSRemoteInspectorDisableAutoStart() void; +pub extern fn JSRemoteInspectorStart() void; +// JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) JSC_API_AVAILABLE(macos(10.11), ios(9.0)); + +pub extern fn JSRemoteInspectorSetLogToSystemConsole(enabled: bool) void; +pub extern fn JSRemoteInspectorGetInspectionEnabledByDefault(void) bool; +pub extern fn JSRemoteInspectorSetInspectionEnabledByDefault(enabled: bool) void; + // -- Manual -- // StringImpl::createWithoutCopying @@ -266,6 +275,262 @@ pub fn isObjectOfClassAndResolveIfNeeded(ctx: JSContextRef, obj: JSObjectRef, cl if (prop == null) { return null; } - - } + +pub const UTF8Ptr = [*c]const u8; +pub const UTF16Ptr = [*c]const u16; + +// --- Custom Methods! ---- +pub const Encoding = enum(u8) { + empty = 0, + char8 = 8, + char16 = 16, +}; +pub const JSCellValue = u64; +pub const CellType = enum(u8) { + CellType = 0, + StringType = 1, + HeapBigIntType = 2, + LastMaybeFalsyCellPrimitive = 2, + SymbolType = 3, + GetterSetterType = 4, + CustomGetterSetterType = 5, + APIValueWrapperType = 6, + NativeExecutableType = 7, + ProgramExecutableType = 8, + ModuleProgramExecutableType = 9, + EvalExecutableType = 10, + FunctionExecutableType = 11, + UnlinkedFunctionExecutableType = 12, + UnlinkedProgramCodeBlockType = 13, + UnlinkedModuleProgramCodeBlockType = 14, + UnlinkedEvalCodeBlockType = 15, + UnlinkedFunctionCodeBlockType = 16, + CodeBlockType = 17, + JSImmutableButterflyType = 18, + JSSourceCodeType = 19, + JSScriptFetcherType = 20, + JSScriptFetchParametersType = 21, + ObjectType = 22, + FinalObjectType = 23, + JSCalleeType = 24, + JSFunctionType = 25, + InternalFunctionType = 26, + NullSetterFunctionType = 27, + BooleanObjectType = 28, + NumberObjectType = 29, + ErrorInstanceType = 30, + PureForwardingProxyType = 31, + DirectArgumentsType = 32, + ScopedArgumentsType = 33, + ClonedArgumentsType = 34, + ArrayType = 35, + DerivedArrayType = 36, + ArrayBufferType = 37, + Int8ArrayType = 38, + Uint8ArrayType = 39, + Uint8ClampedArrayType = 40, + Int16ArrayType = 41, + Uint16ArrayType = 42, + Int32ArrayType = 43, + Uint32ArrayType = 44, + Float32ArrayType = 45, + Float64ArrayType = 46, + BigInt64ArrayType = 47, + BigUint64ArrayType = 48, + DataViewType = 49, + GlobalObjectType = 50, + GlobalLexicalEnvironmentType = 51, + LexicalEnvironmentType = 52, + ModuleEnvironmentType = 53, + StrictEvalActivationType = 54, + WithScopeType = 55, + ModuleNamespaceObjectType = 56, + RegExpObjectType = 57, + JSDateType = 58, + ProxyObjectType = 59, + JSGeneratorType = 60, + JSAsyncGeneratorType = 61, + JSArrayIteratorType = 62, + JSMapIteratorType = 63, + JSSetIteratorType = 64, + JSStringIteratorType = 65, + JSPromiseType = 66, + JSMapType = 67, + JSSetType = 68, + JSWeakMapType = 69, + JSWeakSetType = 70, + WebAssemblyModuleType = 71, + StringObjectType = 72, + DerivedStringObjectType = 73, + LastJSCObjectType = 73, + MaxJSType = 255, + _, + + pub fn isString(this: CellType) bool { + return switch (this) { + .StringType => true, + else => false, + }; + } +}; +pub const ExternalStringFinalizer = fn (finalize_ptr: ?*c_void, ref: JSStringRef, buffer: *c_void, byteLength: usize) callconv(.C) void; +pub extern fn JSStringCreate(string: UTF8Ptr, length: usize) JSStringRef; +pub extern fn JSStringCreateStatic(string: UTF8Ptr, length: usize) JSStringRef; +pub extern fn JSStringCreateExternal(string: UTF8Ptr, length: usize, finalize_ptr: ?*c_void, finalizer: ExternalStringFinalizer) JSStringRef; +pub extern fn JSStringIsEqualToString(a: JSStringRef, string: UTF8Ptr, length: usize) bool; +pub extern fn JSStringEncoding(string: JSStringRef) Encoding; +pub extern fn JSStringGetCharacters8Ptr(string: JSStringRef) UTF8Ptr; +extern fn JSStringIterate(string: JSCellValue, iter: *JSStringIterator_) void; +pub extern fn JSCellType(cell: JSCellValue) CellType; +pub extern fn JSStringIsStatic(ref: JSStringRef) bool; +pub extern fn JSStringIsExternal(ref: JSStringRef) bool; + +pub const JStringIteratorAppendCallback = fn (ctx: *JSStringIterator_, ptr: *c_void, length: u32) callconv(.C) c_void; +pub const JStringIteratorWriteCallback = fn (ctx: *JSStringIterator_, ptr: *c_void, length: u32, offset: u32) callconv(.C) c_void; +const JSStringIterator_ = extern struct { + ctx: *c_void, + stop: u8, + + append8: JStringIteratorAppendCallback, + append16: JStringIteratorAppendCallback, + write8: JStringIteratorWriteCallback, + write16: JStringIteratorWriteCallback, +}; + +pub const JSString = struct { + pub const Callback = fn (finalize_ptr_: ?*c_void, ref: JSStringRef, buffer: *c_void, byteLength: usize) callconv(.C) void; + _ref: JSStringRef = null, + backing: Backing = .{ .gc = 0 }, + + pub const Backing = union(Ownership) { + external: ExternalString, + static: []const u8, + gc: u0, + }; + + pub fn deref(this: *JSString) void { + if (this._ref == null) return; + + JSStringRetain(this._ref); + } + + const ExternalString = struct { + callback: Callback, + external_callback: *c_void, + external_ptr: ?*c_void = null, + slice: []const u8, + }; + + pub fn External(comptime ExternalType: type, external_type: *ExternalType, str: []const u8, callback: fn (this: *ExternalType, buffer: []const u8) void) JSString { + const CallbackFunctionType = @TypeOf(callback); + + const ExternalWrapper = struct { + pub fn finalizer_callback(finalize_ptr_: ?*c_void, buffer: *c_void, byteLength: usize) callconv(.C) void { + var finalize_ptr = finalize_ptr_ orelse return; + + var jsstring = @ptrCast( + *JSString, + @alignCast( + @alignOf( + *JSString, + ), + finalize_ptr, + ), + ); + + var cb = @as(CallbackFunctionType, jsstring.external_callback orelse return); + var raw_external_ptr = jsstring.external_ptr orelse return; + + var external_ptr = @ptrCast( + *ExternalType, + @alignCast( + @alignOf( + *ExternalType, + ), + raw_external_ptr, + ), + ); + + cb(external_ptr, @ptrCast([*]u8, buffer)[0..byteLength]); + } + }; + + return JSString{ + .backing = .{ + .external = .{ + .slice = str, + .external_callback = callback, + .external_ptr = external_type, + .callback = ExternalWrapper.finalizer_callback, + }, + }, + }; + } + + // pub fn Iterator(comptime WriterType: type) type { + // return struct { + + // }; + // } + + pub const Ownership = enum { external, static, gc }; + + pub fn Static(str: []const u8) JSString { + return JSString{ ._ref = null, .backing = .{ .static = str } }; + } + + pub fn ref(this: *JSString) JSStringRef { + if (this._ref == null) { + switch (this.backing) { + .External => |external| { + this._ref = JSStringCreateExternal(external.slice, external.slice.len, this, this.external_callback.?); + }, + .Static => |slice| { + this._ref = JSStringCreateStatic(slice.ptr, slice.len); + }, + .gc => { + return null; + }, + } + } + + JSStringRetain(this._ref); + + return this._ref; + } + + pub fn fromStringRef(string_ref: JSStringRef) JSString {} + + pub fn init(str: []const u8) JSString {} + + pub fn static(str: []const u8) JSString {} + + pub fn finalize(this: *JSString) void { + this.loaded = false; + } + + pub fn value(this: *JSString, ctx: JSContextRef) JSValueRef { + return JSValueMakeString(ctx, this.ref()); + } + + pub fn len(this: *const JSString) usize { + return JSStringGetLength(this.ref); + } + + pub fn encoding(this: *const JSString) Encoding { + return JSStringEncoding(this.ref); + } + + // pub fn eql(this: *const JSString, str: string) { + + // } + + pub fn eqlJS(this: *const JSString, ctx: JSContextRef, comptime Type: type, that: Type) bool { + switch (comptime Type) { + JSValueRef => {}, + JSStringRef => {}, + JSString => {}, + } + } +}; diff --git a/src/javascript/jsc/WebKit b/src/javascript/jsc/WebKit -Subproject 26db06f4db00380b673808316cb959e2c0d0160 +Subproject 7d494581249d31ff34d65436f077e76ea2516b9 diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig index b37cdf55e..84dad71ef 100644 --- a/src/javascript/jsc/api/router.zig +++ b/src/javascript/jsc/api/router.zig @@ -2,40 +2,57 @@ usingnamespace @import("../base.zig"); const std = @import("std"); const Api = @import("../../../api/schema.zig").Api; const FilesystemRouter = @import("../../../router.zig"); +const http = @import("../../../http.zig"); const JavaScript = @import("../javascript.zig"); usingnamespace @import("../webcore/response.zig"); const Router = @This(); -match: FilesystemRouter.RouteMap.MatchedRoute, +route: *const FilesystemRouter.Match, file_path_str: js.JSStringRef = null, pathname_str: js.JSStringRef = null, -pub fn constructor( +pub fn importRoute( + this: *Router, ctx: js.JSContextRef, function: js.JSObjectRef, + thisObject: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSObjectRef { - return null; + return JavaScript.VirtualMachine.instance.require( + ctx, + std.fs.path.dirname(this.route.file_path).?, + this.route.file_path, + exception, + ); } pub fn match( obj: *c_void, ctx: js.JSContextRef, function: js.JSObjectRef, + thisObject: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSObjectRef { - return null; -} + if (arguments.len == 0) { + JSError(getAllocator(ctx), "Expected string, FetchEvent, or Request but there were no arguments", .{}, ctx, exception); + return null; + } + + if (js.JSValueIsObjectOfClass(ctx, arguments[0], FetchEvent.Class.get().*)) { + return matchFetchEvent(ctx, To.Zig.ptr(FetchEvent, arguments[0]), exception); + } + + if (js.JSValueIsString(ctx, arguments[0])) { + return matchPathName(ctx, arguments[0], exception); + } + + if (js.JSValueIsObjectOfClass(ctx, arguments[0], Request.Class.get().*)) { + return matchRequest(ctx, To.Zig.ptr(Request, arguments[0]), exception); + } -fn matcher( - obj: *c_void, - ctx: js.JSContextRef, - arg: js.JSValueRef, - exception: js.ExceptionRef, -) js.JSObjectRef { return null; } @@ -44,13 +61,19 @@ fn matchRequest( request: *const Request, exception: js.ExceptionRef, ) js.JSObjectRef { - return null; + return createRouteObject(ctx, request.request_context, exception); } -fn matchPathName( +fn matchPathNameString( ctx: js.JSContextRef, pathname: string, exception: js.ExceptionRef, +) js.JSObjectRef {} + +fn matchPathName( + ctx: js.JSContextRef, + pathname: js.JSStringRef, + exception: js.ExceptionRef, ) js.JSObjectRef { return null; } @@ -60,36 +83,49 @@ fn matchFetchEvent( fetch_event: *const FetchEvent, exception: js.ExceptionRef, ) js.JSObjectRef { - return null; + return createRouteObject(ctx, fetch_event.request_context, exception); +} + +fn createRouteObject(ctx: js.JSContextRef, req: *const http.RequestContext, exception: js.ExceptionRef) js.JSValueRef { + const route = &(req.matched_route orelse { + return js.JSValueMakeNull(ctx); + }); + + var router = getAllocator(ctx).create(Router) catch unreachable; + router.* = Router{ + .route = route, + }; + + return Class.new(ctx, router); } const match_type_definition = &[_]d.ts{ .{ - .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a Route from the local filesystem.", + .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a `Route` from the local filesystem. Returns `null` if there is no match.", .args = &[_]d.ts.arg{ .{ - .name = "request", - .@"return" = "Request", + .name = "event", + .@"return" = "FetchEvent", }, }, .@"return" = "Route | null", }, .{ - .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a Route from the local filesystem.", + .tsdoc = "Match a `pathname` to a `Route` from the local filesystem. Returns `null` if there is no match.", .args = &[_]d.ts.arg{ .{ - .name = "event", - .@"return" = "FetchEvent", + .name = "pathname", + .@"return" = "string", }, }, .@"return" = "Route | null", }, .{ - .tsdoc = "Match a `pathname` to a Route from the local filesystem.", + .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a `Route` from the local filesystem. Returns `null` if there is no match.", .args = &[_]d.ts.arg{ .{ - .name = "pathname", - .@"return" = "string", + .name = "request", + .@"return" = "Request", }, }, .@"return" = "Route | null", @@ -110,7 +146,7 @@ pub const Class = NewClass( }, .{ .match = .{ - .get = match, + .rfn = match, .ts = match_type_definition, }, }, @@ -136,9 +172,14 @@ pub const Instance = NewClass( .finalize = .{ .rfn = finalize, }, - .constructor = .{ - .rfn = constructor, - .ts = match_type_definition, + .import = .{ + .rfn = importRoute, + .ts = d.ts{ + .@"return" = "Object", + .tsdoc = + \\Synchronously load & evaluate the file corresponding to the route. Returns the exports of the route. This is similar to `await import(route.filepath)`, except it's synchronous. It is recommended to use this function instead of `import`. + , + }, }, }, .{ @@ -156,11 +197,7 @@ pub const Instance = NewClass( .ts = d.ts{ .@"return" = "string", .tsdoc = - \\Project-relative filesystem path to the route file. Useful for importing. - \\ - \\@example ```tsx - \\await import(route.filepath); - \\``` + \\Project-relative filesystem path to the route file. , }, }, @@ -213,7 +250,7 @@ pub fn getFilePath( exception: js.ExceptionRef, ) js.JSValueRef { if (this.file_path_str == null) { - this.file_path_str = js.JSStringCreateWithUTF8CString(this.match.file_path.ptr); + this.file_path_str = js.JSStringCreateWithUTF8CString(this.route.file_path.ptr); } return js.JSValueMakeString(ctx, this.file_path_str); @@ -234,7 +271,7 @@ pub fn getPathname( exception: js.ExceptionRef, ) js.JSValueRef { if (this.pathname_str == null) { - this.pathname_str = js.JSStringCreateWithUTF8CString(this.match.pathname.ptr); + this.pathname_str = js.JSStringCreateWithUTF8CString(this.route.pathname.ptr); } return js.JSValueMakeString(ctx, this.pathname_str); diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index f0c5dc4b6..36567000a 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -163,6 +163,17 @@ pub const To = struct { pub inline fn str(ref: anytype, buf: anytype) string { return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)]; } + pub inline fn ptr(comptime StructType: type, obj: js.JSObjectRef) *StructType { + return @ptrCast( + *StructType, + @alignCast( + @alignOf( + *StructType, + ), + js.JSObjectGetPrivate(obj).?, + ), + ); + } }; }; @@ -194,23 +205,23 @@ pub const RuntimeImports = struct { pub const Properties = struct { pub const UTF8 = struct { - pub const module = "module"; - pub const globalThis = "globalThis"; - pub const exports = "exports"; - pub const log = "log"; - pub const debug = "debug"; - pub const name = "name"; - pub const info = "info"; - pub const error_ = "error"; - pub const warn = "warn"; - pub const console = "console"; - pub const require = "require"; - pub const description = "description"; - pub const initialize_bundled_module = "$$m"; - pub const load_module_function = "$lOaDuRcOdE$"; - pub const window = "window"; - pub const default = "default"; - pub const include = "include"; + pub const module: string = "module"; + pub const globalThis: string = "globalThis"; + pub const exports: string = "exports"; + pub const log: string = "log"; + pub const debug: string = "debug"; + pub const name: string = "name"; + pub const info: string = "info"; + pub const error_: string = "error"; + pub const warn: string = "warn"; + pub const console: string = "console"; + pub const require: string = "require"; + pub const description: string = "description"; + pub const initialize_bundled_module: string = "$$m"; + pub const load_module_function: string = "$lOaDuRcOdE$"; + pub const window: string = "window"; + pub const default: string = "default"; + pub const include: string = "include"; pub const GET = "GET"; pub const PUT = "PUT"; @@ -287,16 +298,14 @@ pub const Properties = struct { pub fn init() void { inline for (std.meta.fieldNames(UTF8)) |name| { - @field(Refs, name) = js.JSStringRetain( - js.JSStringCreateWithCharactersNoCopy( - @field(StringStore.UTF16, name).ptr, - @field(StringStore.UTF16, name).len - 1, - ), + @field(Refs, name) = js.JSStringCreateStatic( + @field(UTF8, name).ptr, + @field(UTF8, name).len, ); if (isDebug) { std.debug.assert( - js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]), + js.JSStringIsEqualToString(@field(Refs, name), @field(UTF8, name).ptr, @field(UTF8, name).len), ); } } @@ -315,22 +324,22 @@ fn hasTypeScript(comptime Type: type) bool { return true; } - return @hasDecl(d.ts, "ts"); + return @hasDecl(Type, "ts"); } fn getTypeScript(comptime Type: type, value: Type) d.ts.or_decl { if (comptime hasTypeScriptField(Type)) { - if (comptime Type.ts == d.ts.decl) { + if (@TypeOf(Type.ts) == d.ts.decl) { return d.ts.or_decl{ .decl = value }; } else { - return d.ts.or_decl{ .ts = value }; + return d.ts.or_decl{ .ts = value.ts }; } } - if (comptime Type.ts == d.ts.decl) { - return d.ts.or_decl{ .decl = value }; + if (@TypeOf(Type.ts) == d.ts.decl) { + return d.ts.or_decl{ .decl = Type.ts }; } else { - return d.ts.or_decl{ .ts = value }; + return d.ts.or_decl{ .ts = value.ts }; } } @@ -723,30 +732,7 @@ pub fn NewClass( const name = options.name; const ClassDefinitionCreator = @This(); const function_names = std.meta.fieldNames(@TypeOf(staticFunctions)); - const names_buf = brk: { - var total_len: usize = 0; - for (function_names) |field, i| { - total_len += std.unicode.utf8ToUtf16LeStringLiteral(field).len; - } - var offset: usize = 0; - var names_buf_ = std.mem.zeroes([total_len]u16); - for (function_names) |field, i| { - var name_ = std.unicode.utf8ToUtf16LeStringLiteral(field); - std.mem.copy(u16, names_buf_[offset .. name_.len + offset], name_[0..]); - offset += name_.len; - } - break :brk names_buf_; - }; - const function_name_literals: [function_names.len][]const js.JSChar = brk: { - var names = std.mem.zeroes([function_names.len][]const js.JSChar); - var len: usize = 0; - for (function_names) |field, i| { - const end = len + std.unicode.utf8ToUtf16LeStringLiteral(field).len; - names[i] = names_buf[len..end]; - len = end; - } - break :brk names; - }; + const function_name_literals = function_names; var function_name_refs: [function_names.len]js.JSStringRef = undefined; var class_name_str = name[0.. :0].ptr; @@ -755,13 +741,7 @@ pub fn NewClass( var instance_functions: [function_names.len]js.JSObjectRef = undefined; const property_names = std.meta.fieldNames(@TypeOf(properties)); var property_name_refs: [property_names.len]js.JSStringRef = undefined; - const property_name_literals: [property_names.len][]const js.JSChar = brk: { - var list = std.mem.zeroes([property_names.len][]const js.JSChar); - for (property_names) |prop_name, i| { - list[i] = std.unicode.utf8ToUtf16LeStringLiteral(prop_name); - } - break :brk list; - }; + const property_name_literals = property_names; var static_properties: [property_names.len]js.JSStaticValue = undefined; pub var ref: js.JSClassRef = null; @@ -784,15 +764,19 @@ pub fn NewClass( pub const static_value_count = static_properties.len; - /// only use with singletons - pub fn make(ctx: js.JSContextRef) js.JSObjectRef {} + pub fn new(ctx: js.JSContextRef, ptr: ?*ZigType) js.JSObjectRef { + return js.JSObjectMake(ctx, get().*, ptr); + } pub fn get() callconv(.C) [*c]js.JSClassRef { if (!loaded) { loaded = true; definition = define(); - ref = js.JSClassRetain(js.JSClassCreate(&definition)); + ref = js.JSClassCreate(&definition); } + + _ = js.JSClassRetain(ref); + return &ref; } @@ -905,11 +889,11 @@ pub fn NewClass( ); var exc: js.JSValueRef = null; - - switch (comptime @typeInfo(@TypeOf(@field( + const Field = @TypeOf(@field( properties, property_names[id], - )))) { + )); + switch (comptime @typeInfo(Field)) { .Fn => { return @field( properties, @@ -922,19 +906,46 @@ pub fn NewClass( ); }, .Struct => { - return @field( + const func = @field( @field( properties, property_names[id], ), "get", - )( - this, - ctx, - obj, - prop, - exception, ); + + const Func = @typeInfo(@TypeOf(func)); + const WithPropFn = fn ( + *ZigType, + js.JSContextRef, + js.JSObjectRef, + js.JSStringRef, + js.ExceptionRef, + ) js.JSValueRef; + + const WithoutPropFn = fn ( + *ZigType, + js.JSContextRef, + js.JSObjectRef, + js.ExceptionRef, + ) js.JSValueRef; + + if (Func.Fn.args.len == @typeInfo(WithPropFn).Fn.args.len) { + return func( + this, + ctx, + obj, + prop, + exception, + ); + } else { + return func( + this, + ctx, + obj, + exception, + ); + } }, else => unreachable, } @@ -1026,12 +1037,14 @@ pub fn NewClass( switch (@typeInfo(Func)) { .Struct => { if (hasTypeScript(Func)) { - var ts_functions: if (std.meta.trait.isIndexable(@TypeOf(func.ts))) @TypeOf(func.ts) else [1]@TypeOf(func.ts) = undefined; + var ts_functions: []const d.ts = &[_]d.ts{}; if (std.meta.trait.isIndexable(@TypeOf(func.ts))) { - ts_functions = func.ts; + ts_functions = std.mem.span(func.ts); } else { - ts_functions = .{func.ts}; + var funcs1 = std.mem.zeroes([1]d.ts); + funcs1[0] = func.ts; + ts_functions = std.mem.span(&funcs1); } for (ts_functions) |ts_function_| { @@ -1193,11 +1206,14 @@ pub fn NewClass( switch (@typeInfo(Func)) { .Struct => { if (hasTypeScript(Func)) { - var ts_functions = std.mem.zeroes([count]d.ts); + var ts_functions: []const d.ts = &[_]d.ts{}; + if (std.meta.trait.isIndexable(@TypeOf(func.ts))) { - ts_functions = func.ts; + ts_functions = std.mem.span(func.ts); } else { - ts_functions[0] = func.ts; + var funcs1 = std.mem.zeroes([1]d.ts); + funcs1[0] = func.ts; + ts_functions = std.mem.span(&funcs1); } for (ts_functions) |ts_function_| { @@ -1206,6 +1222,10 @@ pub fn NewClass( ts_function.name = function_names[i]; } + if (class.interface and strings.eqlComptime(ts_function.name, "constructor")) { + ts_function.name = "new"; + } + if (ts_function.read_only == null) { ts_function.read_only = class.read_only; } @@ -1277,10 +1297,16 @@ pub fn NewClass( } else if (comptime strings.eqlComptime(function_names[i], "finalize")) { def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize.rfn).rfn; } else { - var callback = To.JS.Callback( - ZigType, - @field(staticFunctions, function_names[i]).rfn, + const ctxfn = @field(staticFunctions, function_names[i]).rfn; + const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn; + + const PointerType = std.meta.Child(Func.args[0].arg_type.?); + + var callback = if (Func.calling_convention == .C) ctxfn else To.JS.Callback( + PointerType, + ctxfn, ).rfn; + static_functions[count] = js.JSStaticFunction{ .name = (function_names[i][0.. :0]).ptr, .callAsFunction = callback, @@ -1323,7 +1349,7 @@ pub fn NewClass( if (property_names.len > 0) { inline for (comptime property_name_literals) |prop_name, i| { - property_name_refs[i] = js.JSStringCreateWithCharactersNoCopy( + property_name_refs[i] = js.JSStringCreateStatic( prop_name.ptr, prop_name.len, ); @@ -1335,7 +1361,7 @@ pub fn NewClass( if (comptime hasSetter(@TypeOf(field))) { static_properties[i].setProperty = StaticProperty(i).setter; } - static_properties[i].name = property_names[i][0.. :0]; + static_properties[i].name = property_names[i][0.. :0].ptr; } def.staticValues = (&static_properties); diff --git a/src/javascript/jsc/bindings/DefaultGlobal.cpp b/src/javascript/jsc/bindings/DefaultGlobal.cpp new file mode 100644 index 000000000..2c83c0e3c --- /dev/null +++ b/src/javascript/jsc/bindings/DefaultGlobal.cpp @@ -0,0 +1,162 @@ + +#include "root.h" +#include "DefaultGlobal.h" + +#include <wtf/text/AtomStringImpl.h> + +#include <JavaScriptCore/APICast.h> +#include <JavaScriptCore/CallFrameInlines.h> +#include <JavaScriptCore/CatchScope.h> +#include <JavaScriptCore/Completion.h> +#include <JavaScriptCore/Error.h> +#include <JavaScriptCore/Exception.h> +#include <JavaScriptCore/JSContextInternal.h> +#include <JavaScriptCore/JSInternalPromise.h> +#include <JavaScriptCore/JSModuleLoader.h> +#include <JavaScriptCore/JSNativeStdFunction.h> +#include <JavaScriptCore/JSPromise.h> +#include <JavaScriptCore/JSSourceCode.h> +#include <JavaScriptCore/JSValueInternal.h> +#include <JavaScriptCore/JSVirtualMachineInternal.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <JavaScriptCore/ObjectConstructor.h> +#include <JavaScriptCore/SourceOrigin.h> +#include <wtf/URL.h> + +#include "JSCInlines.h" + + + +class Script; +namespace JSC { + class Identifier; + class JSObject; + class JSString; + +} + + + + + +namespace Wundle { + + + +const ClassInfo DefaultGlobal::s_info = { "GlobalObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DefaultGlobal) }; +const GlobalObjectMethodTable DefaultGlobal::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + nullptr, // queueTaskToEventLoop + &shouldInterruptScriptBeforeTimeout, + &moduleLoaderImportModule, // moduleLoaderImportModule + &moduleLoaderResolve, // moduleLoaderResolve + &moduleLoaderFetch, // moduleLoaderFetch + &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties + &moduleLoaderEvaluate, // moduleLoaderEvaluate + nullptr, // promiseRejectionTracker + &reportUncaughtExceptionAtEventLoop, + ¤tScriptExecutionOwner, + &scriptExecutionStatus, + nullptr, // defaultLanguage + nullptr, // compileStreaming + nullptr, // instantiateStreaming +}; + + +void DefaultGlobal::reportUncaughtExceptionAtEventLoop(JSGlobalObject* globalObject, Exception* exception) {} +JSC::Identifier DefaultGlobal::moduleLoaderResolve(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, JSValue referrer, JSValue val) { + String string = key.toWTFString(globalObject); + return JSC::Identifier::fromString(globalObject->vm(), string ); +} +JSInternalPromise* DefaultGlobal::moduleLoaderImportModule(JSGlobalObject* globalObject, JSModuleLoader*, JSString* specifierValue, JSValue, const SourceOrigin& sourceOrigin) { + return nullptr; +} +JSInternalPromise* DefaultGlobal::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader*, JSValue key, JSValue, JSValue) { + return nullptr; +} +JSC::JSObject* DefaultGlobal::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, JSModuleLoader*loader, JSValue key, JSModuleRecord* record, JSValue value) { + return nullptr; +} +JSValue DefaultGlobal::moduleLoaderEvaluate(JSGlobalObject* globalObject, JSModuleLoader* moduleLoader, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher, JSValue sentValue, JSValue resumeMode) { + return jsNull(); +} + +using namespace JSC; + + +JSC::ObjectPrototype* DefaultGlobal__objectPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->objectPrototype(); +} +JSC::FunctionPrototype* DefaultGlobal__functionPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->functionPrototype(); +} +JSC::ArrayPrototype* DefaultGlobal__arrayPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->arrayPrototype(); +} +JSC::JSObject* DefaultGlobal__booleanPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->booleanPrototype(); +} +JSC::StringPrototype* DefaultGlobal__stringPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->stringPrototype(); +} +JSC::JSObject* DefaultGlobal__numberPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->numberPrototype(); +} +JSC::BigIntPrototype* DefaultGlobal__bigIntPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->bigIntPrototype(); +} +JSC::JSObject* DefaultGlobal__datePrototype(Wundle::DefaultGlobal* arg0) { + return arg0->datePrototype(); +} +JSC::JSObject* DefaultGlobal__symbolPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->symbolPrototype(); +} +JSC::RegExpPrototype* DefaultGlobal__regExpPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->regExpPrototype(); +} +JSC::JSObject* DefaultGlobal__errorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->errorPrototype(); +} +JSC::IteratorPrototype* DefaultGlobal__iteratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->iteratorPrototype(); +} +JSC::AsyncIteratorPrototype* DefaultGlobal__asyncIteratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->asyncIteratorPrototype(); +} +JSC::GeneratorFunctionPrototype* DefaultGlobal__generatorFunctionPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->generatorFunctionPrototype(); +} +JSC::GeneratorPrototype* DefaultGlobal__generatorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->generatorPrototype(); +} +JSC::AsyncFunctionPrototype* DefaultGlobal__asyncFunctionPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->asyncFunctionPrototype(); +} +JSC::ArrayIteratorPrototype* DefaultGlobal__arrayIteratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->arrayIteratorPrototype(); +} +JSC::MapIteratorPrototype* DefaultGlobal__mapIteratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->mapIteratorPrototype(); +} +JSC::SetIteratorPrototype* DefaultGlobal__setIteratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->setIteratorPrototype(); +} +JSC::JSObject* DefaultGlobal__mapPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->mapPrototype(); +} +JSC::JSObject* DefaultGlobal__jsSetPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->jsSetPrototype(); +} +JSC::JSPromisePrototype* DefaultGlobal__promisePrototype(Wundle::DefaultGlobal* arg0) { + return arg0->promisePrototype(); +} +JSC::AsyncGeneratorPrototype* DefaultGlobal__asyncGeneratorPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->asyncGeneratorPrototype(); +} +JSC::AsyncGeneratorFunctionPrototype* DefaultGlobal__asyncGeneratorFunctionPrototype(Wundle::DefaultGlobal* arg0) { + return arg0->asyncGeneratorFunctionPrototype(); +} + +} diff --git a/src/javascript/jsc/bindings/DefaultGlobal.h b/src/javascript/jsc/bindings/DefaultGlobal.h new file mode 100644 index 000000000..6bc5eb0c9 --- /dev/null +++ b/src/javascript/jsc/bindings/DefaultGlobal.h @@ -0,0 +1,65 @@ +#pragma once + +namespace JSC { + class Structure; + class Identifier; + +} + +#include "root.h" +#include <JavaScriptCore/JSGlobalObject.h> +#include "JSCInlines.h" + +using namespace JSC; + + +namespace Wundle { + +class Script; + +class DefaultGlobal final : public JSC::JSGlobalObject { +public: + using Base = JSC::JSGlobalObject; + + DECLARE_EXPORT_INFO; + static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; + + static constexpr bool needsDestruction = true; + template<typename CellType, SubspaceAccess mode> + static JSC::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return vm.apiGlobalObjectSpace<mode>(); + } + + static DefaultGlobal* create(JSC::VM& vm, JSC::Structure* structure) + { + auto* object = new (NotNull, allocateCell<DefaultGlobal>(vm.heap)) DefaultGlobal(vm, structure); + object->finishCreation(vm); + return object; + } + + static Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype) + { + auto* result = Structure::create(vm, nullptr, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); + result->setTransitionWatchpointIsLikelyToBeFired(true); + return result; + } + + static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, Exception*); + + static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSModuleLoader*, JSC::JSString* moduleNameValue, JSValue parameters, const SourceOrigin&); + static JSC::Identifier moduleLoaderResolve(JSGlobalObject*, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue); + static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue); + static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue); + static JSValue moduleLoaderEvaluate(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue, JSValue, JSValue); + + +private: + DefaultGlobal(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, &s_globalObjectMethodTable) + { } +}; + + +} + diff --git a/src/javascript/jsc/bindings/DefaultGlobal.zig b/src/javascript/jsc/bindings/DefaultGlobal.zig new file mode 100644 index 000000000..dfc931efb --- /dev/null +++ b/src/javascript/jsc/bindings/DefaultGlobal.zig @@ -0,0 +1,272 @@ +usingnamespace @import("./imports.zig"); + +const std = @import("std"); +const main = @import("root"); +const is_bindgen = std.meta.trait.hasDecls(main, .{"bindgen"}); + +fn Shimmer(comptime name: []const u8, comptime Parent: type) type { + return struct { + pub inline fn cppFn(comptime typeName: []const u8, args: anytype) (@typeInfo(@TypeOf(@field(Parent.C, typeName))).Fn.return_type orelse void) { + if (comptime is_bindgen) { + return .{}; + } else { + const func = @field(Parent, typeName); + const Func = @TypeOf(func); + // const Func: std.builtin.TypeInfo = brk: { + // var FuncType: std.builtin.TypeInfo = @typeInfo(@TypeOf(func)); + // var decl = std.meta.declarationInfo(Parent, name); + // var argument_field_list: [function_info.args.len]std.builtin.TypeInfo.StructField = undefined; + // inline for (function_info.args) |arg, i| { + // const T = arg.arg_type.?; + // @setEvalBranchQuota(10_000); + // var num_buf: [128]u8 = undefined; + // argument_field_list[i] = std.builtin.TypeInfo.StructField{ + // .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable, + // .field_type = T, + // .default_value = @as(?T, null), + // .is_comptime = false, + // .alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0, + // }; + // } + + // std.builtin.TypeInfo{ + // .Struct = std.builtin.TypeInfo.Struct{ + // .is_tuple = true, + // .layout = .Auto, + // .decls = &[_]std.builtin.TypeInfo.Declaration{}, + // .fields = &argument_field_list, + // }, + // }); + // }; + + const identifier = comptime std.fmt.comptimePrint("{s}__{s}", .{ name, typeName }); + const Outgoing = comptime @extern(Func, std.builtin.ExternOptions{ .name = identifier }); + const Decl: std.builtin.TypeInfo.Fn = @typeInfo(Func).Fn; + if (comptime Decl.return_type) |ReturnType| { + if (comptime @typeInfo(ReturnType) == .Pointer) { + const Ptr: std.builtin.TypeInfo.Pointer = comptime @typeInfo(ReturnType).Pointer; + const ChildType: type = brk: { + if (@typeInfo(ChildType) == .Struct) { + const Struct: std.builtin.TypeInfo.Struct = ChildType.Struct; + for (Struct.fields) |field| { + if (std.mem.eql(u8, field.name, "ref")) { + break :brk field.field_type; + } + } + } + break :brk Ptr.child; + }; + + if (comptime Ptr.is_const) { + const return_type = @call(.{}, comptime Outgoing, args); + return @ptrCast(*const ChildType, @alignCast(alignment, return_type)); + } else { + var return_type = @call(.{}, comptime Outgoing, args); + return @ptrCast(*ChildType, @alignCast(alignment, return_type)); + } + } + + return @as(ReturnType, @call(.{}, comptime Outgoing, args)); + } else { + @call(.{}, comptime Outgoing, args); + } + } + } + }; +} + +pub const JSCell = packed struct { + ref: Type, + pub const shim = Shimmer("JSCell", @This()); + const cppFn = shim.cppFn; + pub const include = "\"GenericBindings.h\""; + pub const name = "JSC::JSCell"; + + pub const Type = *c_void; + + pub fn getObject(this: *const JSCell) ?JSObject { + return shim.cppFn("getObject", .{this.ref}); + } + + pub fn getString(this: *const JSCell, globalObject: *DefaultGlobal) ?String { + return shim.cppFn("getString", .{ this.ref, globalObject.ref }); + } + + pub fn getType(this: *const JSCell) u8 { + return @intCast(CellType, shim.cppFn("getType", .{ + this.ref, + })); + } +}; + +pub const JSString = packed struct { + ref: Type, + pub const shim = Shimmer("JSString", @This()); + const cppFn = shim.cppFn; + pub const include = "\"GenericBindings.h\""; + pub const name = "JSC::JSString"; + + pub const Type = *c_void; + + pub fn getObject(this: *const JSCell) ?JSObject { + + return shim.cppFn("getObject", .{this.ref}); + } + + pub fn getString(this: *const JSCell, globalObject: *DefaultGlobal) ?String { + return shim.cppFn("getString", .{ this.ref, globalObject.ref }); + } + + +}; + +pub const DefaultGlobal = struct { + pub const shim = Shimmer("DefaultGlobal", @This()); + + ref: Type, + pub const Type = *c_void; + + pub const include = "\"DefaultGlobal.h\""; + pub const name = "Wundle::DefaultGlobal"; + + const cppFn = shim.cppFn; + + pub fn objectPrototype(instance: *DefaultGlobal) ObjectPrototype { + return cppFn("objectPrototype", .{instance.ref}); + } + pub fn functionPrototype(instance: *DefaultGlobal) FunctionPrototype { + return cppFn("functionPrototype", .{instance.ref}); + } + pub fn arrayPrototype(instance: *DefaultGlobal) ArrayPrototype { + return cppFn("arrayPrototype", .{instance.ref}); + } + pub fn booleanPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("booleanPrototype", .{instance.ref}); + } + pub fn stringPrototype(instance: *DefaultGlobal) StringPrototype { + return cppFn("stringPrototype", .{instance.ref}); + } + pub fn numberPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("numberPrototype", .{instance.ref}); + } + pub fn bigIntPrototype(instance: *DefaultGlobal) BigIntPrototype { + return cppFn("bigIntPrototype", .{instance.ref}); + } + pub fn datePrototype(instance: *DefaultGlobal) JSObject { + return cppFn("datePrototype", .{instance.ref}); + } + pub fn symbolPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("symbolPrototype", .{instance.ref}); + } + pub fn regExpPrototype(instance: *DefaultGlobal) RegExpPrototype { + return cppFn("regExpPrototype", .{instance.ref}); + } + pub fn errorPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("errorPrototype", .{instance.ref}); + } + pub fn iteratorPrototype(instance: *DefaultGlobal) IteratorPrototype { + return cppFn("iteratorPrototype", .{instance.ref}); + } + pub fn asyncIteratorPrototype(instance: *DefaultGlobal) AsyncIteratorPrototype { + return cppFn("asyncIteratorPrototype", .{instance.ref}); + } + pub fn generatorFunctionPrototype(instance: *DefaultGlobal) GeneratorFunctionPrototype { + return cppFn("generatorFunctionPrototype", .{instance.ref}); + } + pub fn generatorPrototype(instance: *DefaultGlobal) GeneratorPrototype { + return cppFn("generatorPrototype", .{instance.ref}); + } + pub fn asyncFunctionPrototype(instance: *DefaultGlobal) AsyncFunctionPrototype { + return cppFn("asyncFunctionPrototype", .{instance.ref}); + } + pub fn arrayIteratorPrototype(instance: *DefaultGlobal) ArrayIteratorPrototype { + return cppFn("arrayIteratorPrototype", .{instance.ref}); + } + pub fn mapIteratorPrototype(instance: *DefaultGlobal) MapIteratorPrototype { + return cppFn("mapIteratorPrototype", .{instance.ref}); + } + pub fn setIteratorPrototype(instance: *DefaultGlobal) SetIteratorPrototype { + return cppFn("setIteratorPrototype", .{instance.ref}); + } + pub fn mapPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("mapPrototype", .{instance.ref}); + } + pub fn jsSetPrototype(instance: *DefaultGlobal) JSObject { + return cppFn("jsSetPrototype", .{instance.ref}); + } + pub fn promisePrototype(instance: *DefaultGlobal) JSPromisePrototype { + return cppFn("promisePrototype", .{instance.ref}); + } + pub fn asyncGeneratorPrototype(instance: *DefaultGlobal) AsyncGeneratorPrototype { + return cppFn("asyncGeneratorPrototype", .{instance.ref}); + } + pub fn asyncGeneratorFunctionPrototype(instance: *DefaultGlobal) AsyncGeneratorFunctionPrototype { + return cppFn("asyncGeneratorFunctionPrototype", .{instance.ref}); + } +}; + +fn _JSCellStub(comptime str: []const u8) type { + if (is_bindgen) { + return struct { + pub const C = struct { + pub const name = "JSC::" ++ str ++ "*"; + ref: ?*c_void = null, + }; + }; + } else { + return struct { + pub const C = *c_void; + }; + } +} + +fn _Wundle(comptime str: []const u8) type { + if (is_bindgen) { + return struct { + pub const C = struct { + pub const name = "Wundle::" ++ str ++ "*"; + ref: ?*c_void = null, + }; + }; + } else { + return struct { + pub const C = *c_void; + }; + } +} + +fn _WTF(comptime str: []const u8) type { + if (is_bindgen) { + return struct { + pub const C = struct { + pub const name = "WTF::" ++ str ++ "*"; + ref: ?*c_void = null, + }; + }; + } else { + return struct { + pub const C = *c_void; + }; + } +} + +const _DefaultGlobal = _Wundle("DefaultGlobal"); +const ObjectPrototype = _JSCellStub("ObjectPrototype"); +const FunctionPrototype = _JSCellStub("FunctionPrototype"); +const ArrayPrototype = _JSCellStub("ArrayPrototype"); +const JSObject = _JSCellStub("JSObject"); +const StringPrototype = _JSCellStub("StringPrototype"); +const BigIntPrototype = _JSCellStub("BigIntPrototype"); +const RegExpPrototype = _JSCellStub("RegExpPrototype"); +const IteratorPrototype = _JSCellStub("IteratorPrototype"); +const AsyncIteratorPrototype = _JSCellStub("AsyncIteratorPrototype"); +const GeneratorFunctionPrototype = _JSCellStub("GeneratorFunctionPrototype"); +const GeneratorPrototype = _JSCellStub("GeneratorPrototype"); +const AsyncFunctionPrototype = _JSCellStub("AsyncFunctionPrototype"); +const ArrayIteratorPrototype = _JSCellStub("ArrayIteratorPrototype"); +const MapIteratorPrototype = _JSCellStub("MapIteratorPrototype"); +const SetIteratorPrototype = _JSCellStub("SetIteratorPrototype"); +const JSPromisePrototype = _JSCellStub("JSPromisePrototype"); +const AsyncGeneratorPrototype = _JSCellStub("AsyncGeneratorPrototype"); +const AsyncGeneratorFunctionPrototype = _JSCellStub("AsyncGeneratorFunctionPrototype"); +const String = _WTF("String"); diff --git a/src/javascript/jsc/bindings/JSCInlines.h b/src/javascript/jsc/bindings/JSCInlines.h new file mode 100644 index 000000000..f45088ecc --- /dev/null +++ b/src/javascript/jsc/bindings/JSCInlines.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +// This file's only purpose is to collect commonly used *Inlines.h files, so that you don't +// have to include all of them in every .cpp file. Instead you just include this. It's good +// style to make sure that every .cpp file includes JSCInlines.h. +// +// JSC should never include this file, or any *Inline.h file, from interface headers, since +// this could lead to a circular dependency. +// +// WebCore, or any other downstream client of JSC, is allowed to include this file in headers. +// In fact, it can make a lot of sense: outside of JSC, this file becomes a kind of umbrella +// header that pulls in most (all?) of the interesting things in JSC. + +#include <JavaScriptCore/ExceptionHelpers.h> +#include <JavaScriptCore/GCIncomingRefCountedInlines.h> +#include <JavaScriptCore/HeapInlines.h> +#include <JavaScriptCore/IdentifierInlines.h> +#include <JavaScriptCore/JSArrayBufferViewInlines.h> +#include <JavaScriptCore/JSCJSValueInlines.h> +#include <JavaScriptCore/JSCellInlines.h> +#include <JavaScriptCore/JSFunctionInlines.h> +#include <JavaScriptCore/JSGlobalObjectInlines.h> +#include <JavaScriptCore/JSObjectInlines.h> +#include <JavaScriptCore/JSProxy.h> +#include <JavaScriptCore/JSString.h> +#include <JavaScriptCore/Operations.h> +#include <JavaScriptCore/SlotVisitorInlines.h> +#include <JavaScriptCore/StrongInlines.h> +#include <JavaScriptCore/StructureInlines.h> +#include <JavaScriptCore/ThrowScope.h> +#include <JavaScriptCore/WeakGCMapInlines.h> +#include <JavaScriptCore/WeakGCSetInlines.h> diff --git a/src/javascript/jsc/bindings/JSValue.zig b/src/javascript/jsc/bindings/JSValue.zig new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/javascript/jsc/bindings/JSValue.zig diff --git a/src/javascript/jsc/bindings/bindings-generator.zig b/src/javascript/jsc/bindings/bindings-generator.zig new file mode 100644 index 000000000..ac6fbe738 --- /dev/null +++ b/src/javascript/jsc/bindings/bindings-generator.zig @@ -0,0 +1,32 @@ +const Bindings = @import("bindings.zig"); +const HeaderGen = @import("./header-gen.zig").HeaderGen; + +const std = @import("std"); +const builtin = std.builtin; +const io = std.io; +const fs = std.fs; +const process = std.process; +const ChildProcess = std.ChildProcess; +const Progress = std.Progress; +const print = std.debug.print; +const mem = std.mem; +const testing = std.testing; +const Allocator = std.mem.Allocator; + +pub const bindgen = true; + +pub fn main() anyerror!void { + var allocator = std.heap.c_allocator; + var stdout = std.io.getStdOut(); + var writer = stdout.writer(); + const src: std.builtin.SourceLocation = @src(); + const paths = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "headers.h" }; + const file = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths), .{}); + + const HeaderGenerator = HeaderGen( + Bindings, + "src/javascript/jsc/bindings/bindings.zig", + ); + + HeaderGenerator.exec(HeaderGenerator{}, file); +} diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp new file mode 100644 index 000000000..ad35863e2 --- /dev/null +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -0,0 +1,10 @@ +#include "root.h" + + +// namespace Bundler { +// class CustomGlobalObject : public JSC::JSGlobalObject { + +// }; + +// } + diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig new file mode 100644 index 000000000..016de2ab9 --- /dev/null +++ b/src/javascript/jsc/bindings/bindings.zig @@ -0,0 +1,2 @@ +pub usingnamespace @import("./JSValue.zig"); +pub usingnamespace @import("./DefaultGlobal.zig"); diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig new file mode 100644 index 000000000..e0ea96a21 --- /dev/null +++ b/src/javascript/jsc/bindings/header-gen.zig @@ -0,0 +1,368 @@ +const std = @import("std"); +const Dir = std.fs.Dir; +const FnMeta = std.builtin.TypeInfo.Fn; +const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; +const StructMeta = std.builtin.TypeInfo.Struct; +const EnumMeta = std.builtin.TypeInfo.Enum; +const UnionMeta = std.builtin.TypeInfo.Union; +const warn = std.debug.warn; + +pub const C_Generator = struct { + file: std.fs.File, + filebase: []const u8, + const Self = @This(); + + pub fn init(comptime src_file: []const u8, file: std.fs.File) Self { + var res = Self{ .file = file, .filebase = src_file }; + + file.writeAll("\n/**** " ++ src_file ++ " /*****/\n\n") catch unreachable; + return res; + } + + pub fn deinit(self: *Self) void { + self.file.writeAll("\n/***** ") catch unreachable; + self.file.writeAll(self.filebase) catch unreachable; + self.file.writeAll(" *****/") catch unreachable; + } + + pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta, comptime arg_names: []const []const u8) void { + switch (meta.calling_convention) { + .Naked => self.write("__attribute__((naked)) "), + .Stdcall => self.write("__attribute__((stdcall)) "), + .Fastcall => self.write("__attribute__((fastcall)) "), + .Thiscall => self.write("__attribute__((thiscall)) "), + else => {}, + } + + self.write("extern \"C\" "); + self.writeType(func.return_type); + self.write(" " ++ name ++ "("); + + inline for (meta.args) |arg, i| { + self.writeType(arg.arg_type.?); + if (func.arg_names.len > i) { + self.write(comptime arg_names[i]); + } else { + self.write(comptime std.fmt.comptimePrint(" arg{d}", .{i})); + } + + //TODO: Figure out how to get arg names; for now just do arg0..argN + if (i != meta.args.len - 1) + self.write(", "); + } + + self.write(");\n"); + } + + pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { + self.write("typedef struct "); + + if (meta.layout == .Packed) + self.write("__attribute__((__packed__)) "); + + self.write(name ++ " {\n"); + + inline for (meta.fields) |field| { + self.write(" "); + + const info = @typeInfo(field.field_type); + + if (info == .Array) { + self.writeType(info.Array.child); + } else { + self.writeType(field.field_type); + } + + self.write(" " ++ field.name); + + if (info == .Array) { + _ = self.file.writer().print("[{}]", .{info.Array.len}) catch unreachable; + } + + self.write(";\n"); + } + self.write("} " ++ name ++ "_t;\n\n"); + } + + pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { + self.write("enum " ++ name ++ " {\n"); + + comptime var last = 0; + inline for (meta.fields) |field, i| { + self.write(" " ++ field.name); + + // if field value is unexpected/custom, manually define it + if ((i == 0 and field.value != 0) or (i > 0 and field.value > last + 1)) { + _ = self.file.writer().print(" = {}", .{field.value}) catch unreachable; + } + + self.write(",\n"); + + last = field.value; + } + + self.write("};\n\n"); + } + + pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { + self.write("typedef union "); + + self.write(name ++ " {\n"); + + inline for (meta.fields) |field| { + self.write(" "); + self.writeType(field.field_type); + self.write(" " ++ field.name ++ ";\n"); + } + self.write("} " ++ name ++ "_t;\n\n"); + } + + fn writeType(self: *Self, comptime T: type) void { + const TT = if (@typeInfo(T) == .Pointer) @typeInfo(T).Pointer.child else T; + + if (comptime std.meta.trait.hasDecls(TT, .{"C"}) and std.meta.trait.hasDecls(TT.C, .{"name"})) { + writeType(self, TT.C); + if (std.meta.trait.isSingleItemPtr(T)) { + write(self, "*"); + } + return; + } + + if (comptime std.meta.trait.hasDecls(TT, .{"name"})) { + self.write(comptime T.name); + if (std.meta.trait.isSingleItemPtr(T)) { + write(self, "*"); + } + return; + } + + switch (T) { + void => self.write("void"), + bool => self.write("bool"), + usize => self.write("size_t"), + isize => self.write("int"), + u8 => self.write("uint8_t"), + u16 => self.write("uint16_t"), + u32 => self.write("uint32_t"), + u64 => self.write("uint64_t"), + i8 => self.write("int8_t"), + i16 => self.write("int16_t"), + i24 => self.write("int24_t"), + i32 => self.write("int32_t"), + i64 => self.write("int64_t"), + [*]bool => self.write("bool*"), + [*]usize => self.write("size_t*"), + [*]isize => self.write("int*"), + [*]u8 => self.write("uint8_t*"), + [*]u16 => self.write("uint16_t*"), + [*]u32 => self.write("uint32_t*"), + [*]u64 => self.write("uint64_t*"), + [*]i8 => self.write("int8_t*"), + [*]i16 => self.write("int16_t*"), + [*]i32 => self.write("int32_t*"), + [*]i64 => self.write("int64_t*"), + else => { + const meta = @typeInfo(T); + switch (meta) { + .Pointer => { + const child = meta.Pointer.child; + const childmeta = @typeInfo(child); + // if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { + // self.write("void"); + // } else { + self.writeType(child); + // } + self.write("*"); + }, + .Optional => self.writeType(meta.Optional.child), + .Array => @compileError("Handle goofy looking C Arrays in the calling function"), + else => self.write(@typeName(T) ++ "_t"), + } + }, + } + } + + fn write(self: *Self, comptime str: []const u8) void { + _ = self.file.writeAll(str) catch {}; + } +}; + +const builtin = std.builtin; +const TypeInfo = builtin.TypeInfo; +const Declaration = TypeInfo.Declaration; + +const GeneratorInterface = struct { + fn init() void {} + fn deinit() void {} + fn gen_func() void {} + fn gen_struct() void {} + fn gen_enum() void {} + fn gen_union() void {} +}; + +fn validateGenerator(comptime Generator: type) void { + comptime { + const interface = @typeInfo(GeneratorInterface).Struct.decls; + + for (interface) |decl| { + if (@hasDecl(Generator, decl.name) == false) { + @compileError("Generator: '" ++ + @typeName(Generator) ++ + "' is missing function: " ++ + decl.name); + } + } + } +} + +const NamedStruct = struct { + name: []const u8, + Type: type, +}; + +pub fn getCStruct(comptime T: type) ?NamedStruct { + if (!std.meta.trait.isContainer(T) or (std.meta.trait.isSingleItemPtr(T) and !std.meta.trait.isContainer(std.meta.Child(T)))) { + return null; + } + + inline for (std.meta.declarations(T)) |decl| { + if (std.mem.eql(u8, decl.name, "C")) { + switch (decl.data) { + .Type => |TT| { + return NamedStruct{ .Type = TT, .name = @typeName(T) }; + }, + else => {}, + } + } + } + + return null; +} + +pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type { + const all_decls = std.meta.declarations(import); + + return struct { + source_file: []const u8 = fname, + + const Self = @This(); + + pub fn init() Self { + return Self{}; + } + + pub fn processDecls( + comptime self: Self, + file: std.fs.File, + comptime Parent: type, + comptime Type: type, + comptime prefix: []const u8, + ) void { + const decls = std.meta.declarations(Type); + var gen = C_Generator.init(prefix, file); + defer gen.deinit(); + + if (comptime std.meta.trait.hasDecls(Type, .{"include"})) { + comptime var new_name = std.mem.zeroes([Type.include.len]u8); + + comptime { + _ = std.mem.replace(u8, Type.include, "/", "_", std.mem.span(&new_name)); + _ = std.mem.replace(u8, &new_name, ".", "_", std.mem.span(&new_name)); + } + const inner_name = comptime std.mem.trim(u8, &new_name, "<>\""); + file.writeAll("#ifndef BINDINGS__decls__" ++ inner_name ++ "\n") catch {}; + file.writeAll("#define BINDINGS__decls__" ++ inner_name ++ "\n") catch {}; + file.writeAll("#include " ++ Type.include ++ "\n") catch {}; + file.writeAll("namespace Wundle {\n class " ++ prefix ++ ";\n}\n") catch {}; + file.writeAll("#endif\n\n") catch {}; + } + + // iterate exported enums + // do this first in case target lang needs enums defined before use + inline for (decls) |decl| { + if (decl.is_pub and decl.data == .Type and comptime std.ascii.isUpper(decl.name[0])) { + const T = decl.data.Type; + const info = @typeInfo(T); + if (info == .Enum and decl.is_pub) { + const layout = info.Enum.layout; + gen.gen_enum(prefix ++ "__" ++ decl.name, info.Enum); + } + } + } + + // iterate exported structs + inline for (decls) |decl| { + if (decl.is_pub and decl.data == .Type and decl.is_pub and comptime std.ascii.isUpper(decl.name[0])) { + const T = decl.data.Type; + const info = @typeInfo(T); + if (info == .Struct and decl.is_pub) { + gen.gen_struct(decl.name, @typeInfo(T).Struct); + } + } + } + + inline for (decls) |decl| { + if (decl.is_pub and decl.data == .Type and decl.is_pub) { + const T = decl.data.Type; + const info = @typeInfo(T); + if (info == .Union and comptime std.ascii.isUpper(decl.name[0])) { + const layout = info.Union.layout; + gen.gen_union(prefix ++ "__" ++ decl.name, info.Union); + } + } + } + + // iterate exported fns + inline for (decls) |decl, decl_i| { + if (decl.is_pub and decl.data == .Fn and decl.is_pub) { + const func = decl.data.Fn; + // if (func.) { + const fn_meta = @typeInfo(func.fn_type).Fn; + const info = @typeInfo(Type); + const struct_decl = info.Struct.decls[decl_i]; + // blocked by https://github.com/ziglang/zig/issues/8259 + gen.gen_func( + prefix ++ "__" ++ decl.name, + func, + fn_meta, + struct_decl.data.Fn.arg_names, + ); + // } + } + } + } + + pub fn exec(comptime self: Self, file: std.fs.File) void { + const Generator = C_Generator; + validateGenerator(Generator); + + file.writeAll("#pragma once\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n") catch {}; + + inline for (all_decls) |_decls| { + if (comptime _decls.is_pub) { + switch (_decls.data) { + .Type => |Type| { + if (getCStruct(Type)) |CStruct| { + processDecls( + self, + file, + Type, + CStruct.Type, + CStruct.name, + ); + } + }, + else => {}, + } + } + } + + // processDecls( + // self, + // file, + // import, + // "Bindings", + // ); + } + }; +} diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h new file mode 100644 index 000000000..231c6697e --- /dev/null +++ b/src/javascript/jsc/bindings/headers.h @@ -0,0 +1,42 @@ +#pragma once +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + + +/**** DefaultGlobal /*****/ + +#ifndef BINDINGS__decls__DefaultGlobal_h +#define BINDINGS__decls__DefaultGlobal_h +#include "DefaultGlobal.h" +namespace Wundle { + class DefaultGlobal; +} +#endif + +extern "C" JSC::ObjectPrototype* DefaultGlobal__objectPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::FunctionPrototype* DefaultGlobal__functionPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::ArrayPrototype* DefaultGlobal__arrayPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__booleanPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::StringPrototype* DefaultGlobal__stringPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__numberPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::BigIntPrototype* DefaultGlobal__bigIntPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__datePrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__symbolPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::RegExpPrototype* DefaultGlobal__regExpPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__errorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::IteratorPrototype* DefaultGlobal__iteratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::AsyncIteratorPrototype* DefaultGlobal__asyncIteratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::GeneratorFunctionPrototype* DefaultGlobal__generatorFunctionPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::GeneratorPrototype* DefaultGlobal__generatorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::AsyncFunctionPrototype* DefaultGlobal__asyncFunctionPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::ArrayIteratorPrototype* DefaultGlobal__arrayIteratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::MapIteratorPrototype* DefaultGlobal__mapIteratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::SetIteratorPrototype* DefaultGlobal__setIteratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__mapPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSObject* DefaultGlobal__jsSetPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::JSPromisePrototype* DefaultGlobal__promisePrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::AsyncGeneratorPrototype* DefaultGlobal__asyncGeneratorPrototype(Wundle::DefaultGlobal* arg0); +extern "C" JSC::AsyncGeneratorFunctionPrototype* DefaultGlobal__asyncGeneratorFunctionPrototype(Wundle::DefaultGlobal* arg0); + +/***** DefaultGlobal *****/
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/imports.zig b/src/javascript/jsc/bindings/imports.zig new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/javascript/jsc/bindings/imports.zig @@ -0,0 +1 @@ + diff --git a/src/javascript/jsc/bindings/inlines.cpp b/src/javascript/jsc/bindings/inlines.cpp new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/javascript/jsc/bindings/inlines.cpp diff --git a/src/javascript/jsc/bindings/root.h b/src/javascript/jsc/bindings/root.h new file mode 100644 index 000000000..2ac4c15bc --- /dev/null +++ b/src/javascript/jsc/bindings/root.h @@ -0,0 +1,71 @@ +#pragma once + +/* + * Copyright (C) 2006-2021 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ +#define HAVE_CONFIG_H 1 +#define BUILDING_WITH_CMAKE 1 + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE) +#include "cmakeconfig.h" +#endif + +#define JSC_API_AVAILABLE(...) +#define JSC_CLASS_AVAILABLE(...) JS_EXPORT +#define JSC_API_DEPRECATED(...) +// Use zero since it will be less than any possible version number. +#define JSC_MAC_VERSION_TBA 0 +#define JSC_IOS_VERSION_TBA 0 + +#include <wtf/ExportMacros.h> + +#if !defined(JS_EXPORT_PRIVATE) + +#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) +#define JS_EXPORT_PRIVATE WTF_EXPORT_DECLARATION +#else +#define JS_EXPORT_PRIVATE WTF_IMPORT_DECLARATION +#endif + +#endif + + +#ifdef __cplusplus +#undef new +#undef delete +#include <wtf/FastMalloc.h> +#endif + +#include <wtf/DisallowCType.h> + +/* Disabling warning C4206: nonstandard extension used: translation unit is empty. + By design, we rely on #define flags to make some translation units empty. + Make sure this warning does not turn into an error. +*/ +#if COMPILER(MSVC) +#pragma warning(disable:4206) +#endif + +#ifdef USE_FOUNDATION +#include <CoreFoundation/CoreFoundation.h> +#endif + + +#include <JavaScriptCore/Heap.h>
\ No newline at end of file diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 416897ccf..e984ccbb1 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -163,6 +163,10 @@ pub const VirtualMachine = struct { log = try allocator.create(logger.Log); } + if (FeatureFlags.remote_inspector) { + js.JSRemoteInspectorSetInspectionEnabledByDefault(true); + } + var vm = try allocator.create(VirtualMachine); var global = try allocator.create(GlobalObject); vm.* = .{ @@ -188,10 +192,9 @@ pub const VirtualMachine = struct { global.* = GlobalObject{ .vm = vm }; try vm.global.boot(); vm.ctx = vm.global.ctx; - + Properties.init(); Module.boot(vm); - Properties.init(); if (vm.bundler.options.node_modules_bundle) |bundle| { vm.node_modules = bundle; vm.node_module_list = try allocator.create(Module.NodeModuleList); @@ -201,6 +204,47 @@ pub const VirtualMachine = struct { return vm; } + + pub fn require( + vm: *VirtualMachine, + ctx: js.JSContextRef, + source_dir: string, + import_path: string, + exception: js.ExceptionRef, + ) js.JSObjectRef { + if (vm.bundler.linker.resolver.resolve(source_dir, import_path, .require)) |resolved| { + var load_result = Module.loadFromResolveResult(vm, ctx, resolved, exception) catch |err| { + return null; + }; + + switch (load_result) { + .Module => |new_module| { + return new_module.internalGetExports(js.JSContextGetGlobalContext(ctx)); + }, + .Path => |path| { + return js.JSValueMakeString(ctx, js.JSStringCreateWithUTF8CString(path.text.ptr)); + }, + } + } else |err| { + Output.prettyErrorln( + "<r><red>RequireError<r>: Failed to load module <b>\"{s}\"<r> at \"{s}\": <red>{s}<r>", + .{ import_path, source_dir, @errorName(err) }, + ); + Output.flush(); + JSError( + getAllocator(ctx), + "{s}: failed to load module \"{s}\" from \"{s}\"", + .{ + @errorName(err), + import_path, + source_dir, + }, + ctx, + exception, + ); + return null; + } + } }; pub const Object = struct { @@ -517,7 +561,8 @@ pub const Module = struct { ); if (this.console == null) { - this.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), this.vm.global.console_class, this.vm.global); + this.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), GlobalObject.ConsoleClass.get().*, this.vm.global); + js.JSValueProtect(ctx, this.console); } return this.console; @@ -611,8 +656,7 @@ pub const Module = struct { var node_module_global_class_def = js.kJSClassDefinitionEmpty; node_module_global_class_def.staticValues = static_properties.ptr; node_module_global_class_def.className = node_module_global_class_name[0.. :0]; - node_module_global_class_def.staticFunctions = GlobalObject.GlobalClass.definition.staticFunctions; - // node_module_global_class_def.parentClass = vm.global.global_class; + node_module_global_class_def.parentClass = GlobalObject.GlobalClass.get().*; var property_getters = try vm.allocator.alloc(js.JSObjectRef, bundle.bundle.modules.len); std.mem.set(js.JSObjectRef, property_getters, null); @@ -637,7 +681,6 @@ pub const Module = struct { // .callAsFunction = To.JS.Callback(NodeModuleList, initializeNodeModule), // }; // node_module_global_class_def.staticFunctions = &node_module_list.static_functions; - node_module_list.node_module_global_class_def = node_module_global_class_def; node_module_list.node_module_global_class = js.JSClassRetain(js.JSClassCreate(&node_module_list.node_module_global_class_def)); node_module_list.bundle_ctx = js.JSGlobalContextRetain(js.JSGlobalContextCreateInGroup(vm.group, node_module_list.node_module_global_class)); _ = js.JSObjectSetPrivate(js.JSContextGetGlobalObject(node_module_list.bundle_ctx), node_module_list); @@ -708,45 +751,7 @@ pub const Module = struct { return ref; } - if (this.vm.bundler.linker.resolver.resolve(module.path.name.dirWithTrailingSlash(), import_path, .require)) |resolved| { - var load_result = Module.loadFromResolveResult(this.vm, ctx, resolved, exception) catch |err| { - return null; - }; - - switch (load_result) { - .Module => |new_module| { - // if (isDebug) { - // Output.prettyln( - // "Input: {s}\nOutput: {s}", - // .{ import_path, load_result.Module.path.text }, - // ); - // Output.flush(); - // } - return new_module.internalGetExports(js.JSContextGetGlobalContext(ctx)); - }, - .Path => |path| { - return js.JSStringCreateWithUTF8CString(path.text.ptr); - }, - } - } else |err| { - Output.prettyErrorln( - "<r><red>RequireError<r>: Failed to load module <b>\"{s}\"<r> at \"{s}\": <red>{s}<r>", - .{ import_path, module.path.name.dirWithTrailingSlash(), @errorName(err) }, - ); - Output.flush(); - JSError( - getAllocator(ctx), - "{s}: failed to load module \"{s}\" from \"{s}\"", - .{ - @errorName(err), - import_path, - module.path.name.dirWithTrailingSlash(), - }, - ctx, - exception, - ); - return null; - } + return this.vm.require(ctx, module.path.name.dirWithTrailingSlash(), import_path, exception); } pub fn requireFirst( @@ -853,9 +858,9 @@ pub const Module = struct { return null; } - const ModuleClass = NewClass( + pub const ModuleClass = NewClass( Module, - .{ .name = "Module" }, + .{ .name = Properties.UTF8.module }, .{ .@"require" = require, .@"requireFirst" = requireFirst, @@ -888,6 +893,7 @@ pub const Module = struct { // ExportsClass.callAsConstructor = To.JS.Callback(Module, callExportsAsConstructor); exports_class_ref = js.JSClassRetain(js.JSClassCreate(&ExportsClass)); + _ = Module.ModuleClass.get().*; } pub const LoadResult = union(Tag) { @@ -907,13 +913,26 @@ pub const Module = struct { threadlocal var module_wrapper_params: [2]js.JSStringRef = undefined; threadlocal var module_wrapper_loaded = false; - pub fn load(module: *Module, vm: *VirtualMachine, allocator: *std.mem.Allocator, log: *logger.Log, source: [:0]u8, path: Fs.Path, global_ctx: js.JSContextRef, call_ctx: js.JSContextRef, function_ctx: js.JSContextRef, exception: js.ExceptionRef, comptime is_reload: bool) !void { - var source_code_ref = js.JSStringCreateWithUTF8CString(source.ptr); - defer js.JSStringRelease(source_code_ref); - var source_url = try allocator.dupeZ(u8, path.text); - defer allocator.free(source_url); - var source_url_ref = js.JSStringCreateWithUTF8CString(source_url.ptr); - defer js.JSStringRelease(source_url_ref); + pub fn load( + module: *Module, + vm: *VirtualMachine, + allocator: *std.mem.Allocator, + log: *logger.Log, + source: string, + path: Fs.Path, + global_ctx: js.JSContextRef, + call_ctx: js.JSContextRef, + function_ctx: js.JSContextRef, + exception: js.ExceptionRef, + comptime is_reload: bool, + ) !void { + var source_code_ref = js.JSStringCreateStatic(source.ptr, source.len - 1); + var source_url_raw = try std.fmt.allocPrintZ(allocator, "file://{s}", .{path.text}); + var source_url = js.JSStringCreateStatic(source_url_raw.ptr, source_url_raw.len); + + if (FeatureFlags.remote_inspector) { + js.JSGlobalContextSetName(js.JSContextGetGlobalContext(global_ctx), source_url); + } if (isDebug) { Output.print("// {s}\n{s}", .{ path.pretty, source }); @@ -926,16 +945,16 @@ pub const Module = struct { .ref = undefined, .vm = vm, }; - module.ref = js.JSObjectMake(global_ctx, Module.ModuleClass.get(), module); + module.ref = js.JSObjectMake(global_ctx, Module.ModuleClass.get().*, module); js.JSValueProtect(global_ctx, module.ref); } else { js.JSValueUnprotect(global_ctx, module.exports.?); } // if (!module_wrapper_loaded) { - module_wrapper_params[0] = js.JSStringRetain(js.JSStringCreateWithUTF8CString(Properties.UTF8.module[0.. :0])); - module_wrapper_params[1] = js.JSStringRetain(js.JSStringCreateWithUTF8CString(Properties.UTF8.exports[0.. :0])); - // module_wrapper_loaded = true; + module_wrapper_params[0] = js.JSStringCreateStatic(Properties.UTF8.module.ptr, Properties.UTF8.module.len); + module_wrapper_params[1] = js.JSStringCreateStatic(Properties.UTF8.exports.ptr, Properties.UTF8.exports.len); + // module_wrapper_loaded = true; // } var module_wrapper_args: [2]js.JSValueRef = undefined; @@ -951,7 +970,7 @@ pub const Module = struct { @truncate(c_uint, module_wrapper_params.len), &module_wrapper_params, source_code_ref, - null, + source_url, 1, &except, ); @@ -1140,7 +1159,7 @@ pub const Module = struct { vm, vm.allocator, vm.log, - source_code_printer.ctx.sentinel, + source_code_printer.ctx.written, path, js.JSContextGetGlobalContext(ctx), ctx, @@ -1154,7 +1173,7 @@ pub const Module = struct { vm, vm.allocator, vm.log, - source_code_printer.ctx.sentinel, + source_code_printer.ctx.written, path, js.JSContextGetGlobalContext(ctx), ctx, @@ -1245,7 +1264,7 @@ pub const Module = struct { exception: js.ExceptionRef, ) callconv(.C) js.JSValueRef { if (this.id == null) { - this.id = js.JSStringCreateWithUTF8CString(this.path.text.ptr); + this.id = js.JSStringCreateStatic(this.path.text.ptr, this.path.text.len); } return this.id; @@ -1475,9 +1494,7 @@ pub const GlobalObject = struct { ref: js.JSObjectRef = undefined, vm: *VirtualMachine, ctx: js.JSGlobalContextRef = undefined, - console_class: js.JSClassRef = undefined, - console: js.JSObjectRef = undefined, - console_definition: js.JSClassDefinition = undefined, + console: js.JSObjectRef = null, global_class_def: js.JSClassDefinition = undefined, global_class: js.JSClassRef = undefined, @@ -1530,12 +1547,12 @@ pub const GlobalObject = struct { obj: js.JSObjectRef, exception: js.ExceptionRef, ) js.JSValueRef { - // if (global.console == null) { - // global.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), global.console_class, global); - // js.JSValueProtect(js.JSContextGetGlobalContext(ctx), global.console); - // } + if (global.console == null) { + global.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), ConsoleClass.get().*, global); + js.JSValueProtect(ctx, global.console); + } - return js.JSObjectMake(js.JSContextGetGlobalContext(ctx), ConsoleClass.get().*, global); + return global.console; } pub fn boot(global: *GlobalObject) !void { diff --git a/src/javascript/jsc/typescript.zig b/src/javascript/jsc/typescript.zig index da22fc88c..e10df2b2f 100644 --- a/src/javascript/jsc/typescript.zig +++ b/src/javascript/jsc/typescript.zig @@ -27,43 +27,66 @@ const hidden_globals = [_]d.ts.decl{ const global = JavaScript.GlobalObject.GlobalClass.typescriptDeclaration(); pub fn main() anyerror!void { + var allocator = std.heap.c_allocator; var argv = std.mem.span(std.os.argv); - var dest = [_]string{ argv[argv.len - 2], argv[argv.len - 1] }; - - var dir_path = resolve_path.joinAbs(std.process.getCwdAlloc(allocator), .auto, &dest); + var dest = [_]string{ std.mem.span(argv[argv.len - 2]), std.mem.span(argv[argv.len - 1]) }; + var stdout = std.io.getStdOut(); + var writer = stdout.writer(); + try writer.print("{s}/{s}\n", .{ dest[0], dest[1] }); + var dir_path = resolve_path.joinAbsString(try std.process.getCwdAlloc(allocator), &dest, .auto); std.debug.assert(dir_path.len > 0 and strings.eqlComptime(std.fs.path.basename(dir_path), "types")); - try std.fs.deleteTreeAbsolute(dir_path); + std.fs.deleteTreeAbsolute(dir_path) catch {}; try std.fs.makeDirAbsolute(dir_path); var dir = try std.fs.openDirAbsolute(dir_path, std.fs.Dir.OpenDirOptions{}); + var index_file = try dir.createFile("index.d.ts", .{}); + try index_file.writeAll( + \\/// <reference no-default-lib="true" /> + \\/// <reference lib="esnext" /> + \\/// <reference types="speedy.js/types/globals" /> + \\/// <reference types="speedy.js/types/modules" /> + \\ + ); + + var global_file = try dir.createFile("globals.d.ts", .{}); + try global_file.writeAll( + \\// Speedy.js v + \\ + \\ + ); + try global_file.writeAll(comptime d.ts.class.Printer.printDecl(global, 0)); - var index_file = dir.openFile("index.d.ts", .{ .write = true }); - try index_file.writeAll(comptime d.ts.class.Printer.printDecl(global, 0)); + var module_file = try dir.createFile("modules.d.ts", .{}); + try module_file.writeAll( + \\// Speedy.js v + \\ + \\ + ); - try index_file.writeAll("\n"); + try global_file.writeAll("\n"); - try index_file.writeAll("declare global {\n"); + try global_file.writeAll("declare global {\n"); inline for (hidden_globals) |module, i| { if (i > 0) { - try index_file.writeAll("\n"); + try global_file.writeAll("\n"); } - try index_file.writeAll(comptime d.ts.class.Printer.printDecl(module, 2)); + try global_file.writeAll(comptime d.ts.class.Printer.printDecl(module, 2)); } - try index_file.writeAll("}\n"); - var stdout = std.io.getStdOut(); - try stdout.writeAll("✔️ index.d.ts"); + try global_file.writeAll("}\n\n"); + try stdout.writeAll(" ✔️ index.d.ts\n"); inline for (modules) |decl| { - var module: d.ts.module = comptime decl.module; + comptime var module: d.ts.module = decl.module; const basepath = comptime module.path["speedy.js/".len..]; if (std.fs.path.dirname(basepath)) |dirname| { - dir.makePath(dirname); + try dir.makePath(dirname); } - var file = try dir.openFile(comptime basepath ++ ".d.ts", .{ .write = true }); - try file.writeAll(comptime d.ts.class.Printer.printDecl(module, 0)); - try stdout.writeAll(comptime "✔️ " ++ basepath); + try module_file.writeAll(comptime d.ts.class.Printer.printDecl(decl, 0)); + try stdout.writeAll(comptime " ✔️ " ++ basepath ++ " - modules.d.ts\n"); } + + try global_file.writeAll("export {};\n"); } diff --git a/src/js_printer.zig b/src/js_printer.zig index 6cbd1a931..fbdff279a 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -3790,6 +3790,7 @@ pub const BufferWriter = struct { ) anyerror!void { if (ctx.append_null_byte) { ctx.sentinel = ctx.buffer.toOwnedSentinelLeaky(); + ctx.written = ctx.buffer.toOwnedSliceLeaky(); } else { ctx.written = ctx.buffer.toOwnedSliceLeaky(); } diff --git a/src/router.zig b/src/router.zig index 67a203d09..40deb4349 100644 --- a/src/router.zig +++ b/src/router.zig @@ -180,6 +180,7 @@ const TinyPtr = packed struct { const Param = struct { key: string, + kind: RoutePart.Tag, value: string, pub const List = std.MultiArrayList(Param); @@ -302,25 +303,6 @@ pub const RouteMap = struct { return written; } - pub const MatchedRoute = struct { - /// normalized url path from the request - path: string, - /// raw url path from the request - pathname: string, - /// absolute filesystem path to the entry point - file_path: string, - /// route name, like `"posts/[id]"` - name: string, - - /// basename of the route in the file system, including file extension - basename: string, - - hash: u32, - params: *Param.List, - redirect_path: ?string = null, - query_string: string = "", - }; - const MatchContext = struct { params: *Param.List, segments: []string, @@ -339,7 +321,7 @@ pub const RouteMap = struct { this: *MatchContext, head_i: u16, segment_i: u16, - ) ?MatchedRoute { + ) ?Match { var match = this._matchDynamicRoute(head_i, segment_i) orelse return null; this.matched_route_name.append("/"); this.matched_route_name.append(match.name); @@ -350,7 +332,7 @@ pub const RouteMap = struct { this: *MatchContext, head_i: u16, segment_i: u16, - ) ?MatchedRoute { + ) ?Match { const start_len = this.params.len; var head = this.map.routes.get(head_i); const segment = this.segments[segment_i]; @@ -369,7 +351,7 @@ pub const RouteMap = struct { else => {}, } - var match_result: MatchedRoute = undefined; + var match_result: Match = undefined; if (head.children.len > 0 and remaining.len > 0) { var child_i = head.children.offset; const last = child_i + head.children.len; @@ -391,7 +373,7 @@ pub const RouteMap = struct { this.params.shrinkRetainingCapacity(start_len); return null; } else { - match_result = MatchedRoute{ + match_result = Match{ .path = head.path, .name = head.name, .params = this.params, @@ -412,9 +394,10 @@ pub const RouteMap = struct { .param => { this.params.append( this.allocator, - .{ + Param{ .key = head.part.str(head.name), .value = segment, + .kind = head.part.tag, }, ) catch unreachable; }, @@ -427,7 +410,7 @@ pub const RouteMap = struct { // This makes many passes over the list of routes // However, most of those passes are basically array.indexOf(number) and then smallerArray.indexOf(number) - pub fn matchPage(this: *RouteMap, url_path: URLPath, params: *Param.List) ?MatchedRoute { + pub fn matchPage(this: *RouteMap, url_path: URLPath, params: *Param.List) ?Match { // Trim trailing slash var path = url_path.path; var redirect = false; @@ -454,7 +437,7 @@ pub const RouteMap = struct { if (path.len == 0) { if (this.index) |index| { - return MatchedRoute{ + return Match{ .params = params, .name = "index", .path = this.routes.items(.path)[index], @@ -479,7 +462,7 @@ pub const RouteMap = struct { const children = this.routes.items(.hash)[route.children.offset .. route.children.offset + route.children.len]; for (children) |child_hash, i| { if (child_hash == index_route_hash) { - return MatchedRoute{ + return Match{ .params = params, .name = this.routes.items(.name)[i], .path = this.routes.items(.path)[i], @@ -492,7 +475,7 @@ pub const RouteMap = struct { // It's an exact route, there are no params // /foo/bar => /foo/bar.js } else { - return MatchedRoute{ + return Match{ .params = params, .name = route.name, .path = route.path, @@ -642,3 +625,22 @@ pub fn match(app: *Router, comptime RequestContextType: type, ctx: *RequestConte try ctx.handleRequest(); } + +pub const Match = struct { + /// normalized url path from the request + path: string, + /// raw url path from the request + pathname: string, + /// absolute filesystem path to the entry point + file_path: string, + /// route name, like `"posts/[id]"` + name: string, + + /// basename of the route in the file system, including file extension + basename: string, + + hash: u32, + params: *Param.List, + redirect_path: ?string = null, + query_string: string = "", +}; diff --git a/src/test/fixtures/console.log.js b/src/test/fixtures/console.log.js index cb95413ed..3088f90d5 100644 --- a/src/test/fixtures/console.log.js +++ b/src/test/fixtures/console.log.js @@ -1,3 +1 @@ -import React from "react"; - -console.log("Is this JavaScriptCore?", JSON.stringify(<div>hello</div>)); +console.log("Waiting for debugger."); |