From cad9aaada79188dd73b42ba703cfc9dbd67434ef Mon Sep 17 00:00:00 2001 From: buke Date: Fri, 22 May 2026 14:57:25 +0800 Subject: [PATCH 1/4] feat(api): align uint64 constructor and dump flags - add NewUint64 and the deprecated Uint64 alias for JavaScript Number values - export Go dump flag constants that mirror the quickjs-ng runtime flags - cover the new constructor and dump flag constants in focused context and runtime tests --- context.go | 11 +++++++++++ context_deprecated_test.go | 31 ++++++++++++++++++------------- context_test.go | 32 +++++++++++++++++++------------- runtime.go | 23 +++++++++++++++++++++++ runtime_test.go | 13 +++++++++++++ 5 files changed, 84 insertions(+), 26 deletions(-) diff --git a/context.go b/context.go index bb13adb..bbe1b61 100644 --- a/context.go +++ b/context.go @@ -338,6 +338,17 @@ func (ctx *Context) Uint32(v uint32) *Value { return ctx.NewUint32(v) } +// NewUint64 returns a uint64 value as a JavaScript Number. +func (ctx *Context) NewUint64(v uint64) *Value { + return &Value{ctx: ctx, ref: C.JS_NewUint64(ctx.ref, C.uint64_t(v))} +} + +// Uint64 returns a uint64 value as a JavaScript Number. +// Deprecated: Use NewUint64() instead. +func (ctx *Context) Uint64(v uint64) *Value { + return ctx.NewUint64(v) +} + // NewBigInt64 returns a int64 value with given uint64. func (ctx *Context) NewBigInt64(v int64) *Value { return &Value{ctx: ctx, ref: C.JS_NewBigInt64(ctx.ref, C.int64_t(v))} diff --git a/context_deprecated_test.go b/context_deprecated_test.go index dae2c16..be971bc 100644 --- a/context_deprecated_test.go +++ b/context_deprecated_test.go @@ -52,33 +52,38 @@ func TestDeprecatedContextAPIs(t *testing.T) { defer val7.Free() require.True(t, val7.IsNumber()) - val8 := ctx.BigInt64(9223372036854775807) + val8 := ctx.Uint64(uint64(1) << 32) defer val8.Free() - require.True(t, val8.IsBigInt()) + require.True(t, val8.IsNumber()) + require.Equal(t, float64(uint64(1)<<32), val8.ToFloat64()) - val9 := ctx.BigUint64(18446744073709551615) + val9 := ctx.BigInt64(9223372036854775807) defer val9.Free() require.True(t, val9.IsBigInt()) - val10 := ctx.Float64(3.14159) + val10 := ctx.BigUint64(18446744073709551615) defer val10.Free() - require.True(t, val10.IsNumber()) + require.True(t, val10.IsBigInt()) - val11 := ctx.String("test") + val11 := ctx.Float64(3.14159) defer val11.Free() - require.True(t, val11.IsString()) + require.True(t, val11.IsNumber()) - val12 := ctx.Object() + val12 := ctx.String("test") defer val12.Free() - require.True(t, val12.IsObject()) + require.True(t, val12.IsString()) - val13 := ctx.ArrayBuffer([]byte{1, 2, 3}) + val13 := ctx.Object() defer val13.Free() - require.True(t, val13.IsByteArray()) + require.True(t, val13.IsObject()) - val14 := ctx.Error(errors.New("test error")) + val14 := ctx.ArrayBuffer([]byte{1, 2, 3}) defer val14.Free() - require.True(t, val14.IsError()) + require.True(t, val14.IsByteArray()) + + val15 := ctx.Error(errors.New("test error")) + defer val15.Free() + require.True(t, val15.IsError()) }) t.Run("DeprecatedTypedArrays", func(t *testing.T) { diff --git a/context_test.go b/context_test.go index 7e529d2..874a052 100644 --- a/context_test.go +++ b/context_test.go @@ -52,6 +52,7 @@ func TestContextBasics(t *testing.T) { {"Int32", func() *Value { return ctx.NewInt32(-42) }, func(v *Value) bool { return v.IsNumber() }}, {"Int64", func() *Value { return ctx.NewInt64(1234567890) }, func(v *Value) bool { return v.IsNumber() }}, {"Uint32", func() *Value { return ctx.NewUint32(42) }, func(v *Value) bool { return v.IsNumber() }}, + {"Uint64", func() *Value { return ctx.NewUint64(uint64(1) << 32) }, func(v *Value) bool { return v.IsNumber() && v.ToFloat64() == float64(uint64(1)<<32) }}, {"BigInt64", func() *Value { return ctx.NewBigInt64(9223372036854775807) }, func(v *Value) bool { return v.IsBigInt() }}, {"BigUint64", func() *Value { return ctx.NewBigUint64(18446744073709551615) }, func(v *Value) bool { return v.IsBigInt() }}, {"Float64", func() *Value { return ctx.NewFloat64(3.14159) }, func(v *Value) bool { return v.IsNumber() }}, @@ -2084,33 +2085,38 @@ func TestDeprecatedAPIs(t *testing.T) { defer val7.Free() require.True(t, val7.IsNumber()) - val8 := ctx.BigInt64(9223372036854775807) + val8 := ctx.Uint64(uint64(1) << 32) defer val8.Free() - require.True(t, val8.IsBigInt()) + require.True(t, val8.IsNumber()) + require.Equal(t, float64(uint64(1)<<32), val8.ToFloat64()) - val9 := ctx.BigUint64(18446744073709551615) + val9 := ctx.BigInt64(9223372036854775807) defer val9.Free() require.True(t, val9.IsBigInt()) - val10 := ctx.Float64(3.14159) + val10 := ctx.BigUint64(18446744073709551615) defer val10.Free() - require.True(t, val10.IsNumber()) + require.True(t, val10.IsBigInt()) - val11 := ctx.String("test") + val11 := ctx.Float64(3.14159) defer val11.Free() - require.True(t, val11.IsString()) + require.True(t, val11.IsNumber()) - val12 := ctx.Object() + val12 := ctx.String("test") defer val12.Free() - require.True(t, val12.IsObject()) + require.True(t, val12.IsString()) - val13 := ctx.ArrayBuffer([]byte{1, 2, 3}) + val13 := ctx.Object() defer val13.Free() - require.True(t, val13.IsByteArray()) + require.True(t, val13.IsObject()) - val14 := ctx.Error(errors.New("test error")) + val14 := ctx.ArrayBuffer([]byte{1, 2, 3}) defer val14.Free() - require.True(t, val14.IsError()) + require.True(t, val14.IsByteArray()) + + val15 := ctx.Error(errors.New("test error")) + defer val15.Free() + require.True(t, val15.IsError()) }) t.Run("DeprecatedTypedArrays", func(t *testing.T) { diff --git a/runtime.go b/runtime.go index 422bde9..4910e62 100644 --- a/runtime.go +++ b/runtime.go @@ -137,6 +137,29 @@ type MemoryUsage struct { BinaryObjectSize int64 } +const ( + DumpFlagBytecodeFinal uint64 = C.JS_DUMP_BYTECODE_FINAL + DumpFlagBytecodePass2 uint64 = C.JS_DUMP_BYTECODE_PASS2 + DumpFlagBytecodePass1 uint64 = C.JS_DUMP_BYTECODE_PASS1 + DumpFlagBytecodeHex uint64 = C.JS_DUMP_BYTECODE_HEX + DumpFlagBytecodePC2Line uint64 = C.JS_DUMP_BYTECODE_PC2LINE + DumpFlagBytecodeStack uint64 = C.JS_DUMP_BYTECODE_STACK + DumpFlagBytecodeStep uint64 = C.JS_DUMP_BYTECODE_STEP + DumpFlagReadObject uint64 = C.JS_DUMP_READ_OBJECT + DumpFlagFree uint64 = C.JS_DUMP_FREE + DumpFlagGC uint64 = C.JS_DUMP_GC + DumpFlagGCFree uint64 = C.JS_DUMP_GC_FREE + DumpFlagModuleResolve uint64 = C.JS_DUMP_MODULE_RESOLVE + DumpFlagPromise uint64 = C.JS_DUMP_PROMISE + DumpFlagLeaks uint64 = C.JS_DUMP_LEAKS + DumpFlagAtomLeaks uint64 = C.JS_DUMP_ATOM_LEAKS + DumpFlagMem uint64 = C.JS_DUMP_MEM + DumpFlagObjects uint64 = C.JS_DUMP_OBJECTS + DumpFlagAtoms uint64 = C.JS_DUMP_ATOMS + DumpFlagShapes uint64 = C.JS_DUMP_SHAPES + DumpFlagAbortOnLeaks uint64 = C.JS_ABORT_ON_LEAKS +) + // IntrinsicSet controls which QuickJS intrinsics are injected into a raw context. type IntrinsicSet struct { BaseObjects bool diff --git a/runtime_test.go b/runtime_test.go index ec5086d..b14cff6 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -185,6 +185,19 @@ func TestRuntimeDiagnosticsAndRawContext(t *testing.T) { require.True(t, selected.Eval) } +func TestRuntimeDumpFlagConstants(t *testing.T) { + rt := NewRuntime() + defer rt.Close() + + flags := DumpFlagBytecodeFinal | DumpFlagModuleResolve | DumpFlagPromise + rt.SetDumpFlags(flags) + require.EqualValues(t, flags, rt.DumpFlags()) + + require.NotZero(t, DumpFlagAbortOnLeaks) + require.EqualValues(t, DumpFlagLeaks, DumpFlagAbortOnLeaks&DumpFlagLeaks) + require.EqualValues(t, DumpFlagAtomLeaks, DumpFlagAbortOnLeaks&DumpFlagAtomLeaks) +} + func TestRuntimeStage3CoveragePaths(t *testing.T) { useStableOwnerHooksForLegacySubtests(t) From 907345f58baf923dcea4f9f53f5526f6744ab228 Mon Sep 17 00:00:00 2001 From: buke Date: Fri, 22 May 2026 15:19:21 +0800 Subject: [PATCH 2/4] docs(runtime): describe exported dump flag constants - document that DumpFlag* values mirror quickjs-ng runtime dump flags - note that the flags are combined with bitwise OR for Runtime.SetDumpFlags - clarify that DumpFlagAbortOnLeaks is intended for testing --- runtime.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime.go b/runtime.go index 4910e62..fa8cdfb 100644 --- a/runtime.go +++ b/runtime.go @@ -137,6 +137,8 @@ type MemoryUsage struct { BinaryObjectSize int64 } +// DumpFlag* constants mirror the quickjs-ng runtime dump flags and can be +// combined with bitwise OR for Runtime.SetDumpFlags. const ( DumpFlagBytecodeFinal uint64 = C.JS_DUMP_BYTECODE_FINAL DumpFlagBytecodePass2 uint64 = C.JS_DUMP_BYTECODE_PASS2 @@ -157,6 +159,7 @@ const ( DumpFlagObjects uint64 = C.JS_DUMP_OBJECTS DumpFlagAtoms uint64 = C.JS_DUMP_ATOMS DumpFlagShapes uint64 = C.JS_DUMP_SHAPES + // DumpFlagAbortOnLeaks aborts on atom/object/string leaks and is intended for testing. DumpFlagAbortOnLeaks uint64 = C.JS_ABORT_ON_LEAKS ) From 5987350129f7ed13240b18367448e4b897039bea Mon Sep 17 00:00:00 2001 From: buke Date: Fri, 22 May 2026 15:30:26 +0800 Subject: [PATCH 3/4] fix(context): guard uint64 number constructor - add a hasValidRef check before building a JavaScript Number from uint64 - document that NewUint64 and Uint64 return JavaScript Number values - warn about precision loss beyond 2^53 - 1 and point callers to NewBigUint64 --- context.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index bbe1b61..3bca08f 100644 --- a/context.go +++ b/context.go @@ -338,12 +338,19 @@ func (ctx *Context) Uint32(v uint32) *Value { return ctx.NewUint32(v) } -// NewUint64 returns a uint64 value as a JavaScript Number. +// NewUint64 returns a JavaScript Number from a uint64. +// Note: Precision loss occurs for values exceeding 2^53 - 1. Use NewBigUint64 +// for full 64-bit precision. func (ctx *Context) NewUint64(v uint64) *Value { + if !ctx.hasValidRef() { + return nil + } return &Value{ctx: ctx, ref: C.JS_NewUint64(ctx.ref, C.uint64_t(v))} } -// Uint64 returns a uint64 value as a JavaScript Number. +// Uint64 returns a JavaScript Number from a uint64. +// Note: Precision loss occurs for values exceeding 2^53 - 1. Use NewBigUint64 +// for full 64-bit precision. // Deprecated: Use NewUint64() instead. func (ctx *Context) Uint64(v uint64) *Value { return ctx.NewUint64(v) From b606674a2acc2d1dbffe4c3479287bc4db8087ff Mon Sep 17 00:00:00 2001 From: buke Date: Fri, 22 May 2026 15:37:30 +0800 Subject: [PATCH 4/4] test(context): cover NewUint64 fail-closed guard - add nil-context coverage for NewUint64 in the existing libc helper guard test - add closed-context coverage for NewUint64 in the same guard test - keep the coverage fix isolated to the existing guard test surface --- context_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/context_test.go b/context_test.go index 874a052..d357ad9 100644 --- a/context_test.go +++ b/context_test.go @@ -411,6 +411,7 @@ func TestContextLibcStage4HelpersNilAndClosedGuards(t *testing.T) { var nilCtx *Context require.Nil(t, nilCtx.NewDate(0)) + require.Nil(t, nilCtx.NewUint64(1)) require.Nil(t, nilCtx.NewSymbol("x")) require.Nil(t, nilCtx.NewGlobalSymbol("x")) require.False(t, nilCtx.SetImportMeta(nil, false, false)) @@ -430,6 +431,7 @@ func TestContextLibcStage4HelpersNilAndClosedGuards(t *testing.T) { ctx.Close() require.Nil(t, ctx.NewDate(0)) + require.Nil(t, ctx.NewUint64(1)) require.Nil(t, ctx.NewSymbol("x")) require.Nil(t, ctx.NewGlobalSymbol("x")) require.False(t, ctx.SetImportMeta(moduleFunc, false, false))