goscript 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +8 -8
  2. package/cmd/go_js_wasm_exec/main.go +1 -1
  3. package/cmd/go_js_wasm_exec/main_test.go +1 -1
  4. package/cmd/goscript/cmd-compile.go +9 -1
  5. package/cmd/goscript/cmd-test.go +1 -1
  6. package/cmd/goscript/cmd_compile_test.go +44 -0
  7. package/cmd/goscript/deps.go +1 -1
  8. package/cmd/goscript-wasm/main.go +2 -2
  9. package/compiler/compile-request.go +19 -0
  10. package/compiler/compile_bench_test.go +121 -0
  11. package/compiler/compliance_test.go +17 -1
  12. package/compiler/config.go +2 -0
  13. package/compiler/gotest/result.go +1 -1
  14. package/compiler/gotest/runner.go +2 -2
  15. package/compiler/gotest/runner_test.go +4 -7
  16. package/compiler/index.test.ts +28 -0
  17. package/compiler/index.ts +32 -16
  18. package/compiler/lowering.go +1238 -194
  19. package/compiler/lowering_bench_test.go +4 -0
  20. package/compiler/override-facts.go +1 -1
  21. package/compiler/package-graph.go +92 -0
  22. package/compiler/package-graph_test.go +113 -0
  23. package/compiler/runtime-contract.go +1 -1
  24. package/compiler/semantic-model.go +32 -0
  25. package/compiler/skeleton_test.go +241 -15
  26. package/compiler/wasm/compile.go +1 -1
  27. package/compiler/wasm/compile_test.go +1 -1
  28. package/dist/compiler/index.d.ts +4 -0
  29. package/dist/compiler/index.js +26 -15
  30. package/dist/compiler/index.js.map +1 -1
  31. package/dist/gs/database/sql/driver/index.d.ts +165 -0
  32. package/dist/gs/database/sql/driver/index.js +432 -0
  33. package/dist/gs/database/sql/driver/index.js.map +1 -0
  34. package/dist/gs/encoding/binary/index.d.ts +71 -0
  35. package/dist/gs/encoding/binary/index.js +778 -0
  36. package/dist/gs/encoding/binary/index.js.map +1 -0
  37. package/dist/gs/fmt/fmt.js +156 -57
  38. package/dist/gs/fmt/fmt.js.map +1 -1
  39. package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
  40. package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
  41. package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
  42. package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
  43. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  44. package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
  45. package/dist/gs/github.com/pkg/errors/index.js +1 -1
  46. package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
  47. package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
  48. package/dist/gs/github.com/pkg/errors/stack.js +26 -61
  49. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  50. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
  51. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
  52. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
  53. package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
  54. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
  55. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
  56. package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
  57. package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
  58. package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
  59. package/dist/gs/runtime/runtime.d.ts +6 -1
  60. package/dist/gs/runtime/runtime.js +15 -8
  61. package/dist/gs/runtime/runtime.js.map +1 -1
  62. package/dist/gs/runtime/trace/index.d.ts +8 -5
  63. package/dist/gs/runtime/trace/index.js +324 -23
  64. package/dist/gs/runtime/trace/index.js.map +1 -1
  65. package/dist/gs/slices/slices.d.ts +2 -1
  66. package/dist/gs/slices/slices.js +9 -3
  67. package/dist/gs/slices/slices.js.map +1 -1
  68. package/dist/gs/sort/search.gs.d.ts +3 -1
  69. package/dist/gs/sort/search.gs.js +18 -53
  70. package/dist/gs/sort/search.gs.js.map +1 -1
  71. package/dist/gs/sync/sync.d.ts +1 -1
  72. package/dist/gs/sync/sync.js +3 -0
  73. package/dist/gs/sync/sync.js.map +1 -1
  74. package/dist/gs/time/time.d.ts +22 -29
  75. package/dist/gs/time/time.js +111 -32
  76. package/dist/gs/time/time.js.map +1 -1
  77. package/dist/gs/unsafe/unsafe.d.ts +3 -2
  78. package/dist/gs/unsafe/unsafe.js.map +1 -1
  79. package/go.mod +7 -5
  80. package/go.sum +12 -26
  81. package/gs/database/sql/driver/index.test.ts +88 -0
  82. package/gs/database/sql/driver/index.ts +675 -0
  83. package/gs/database/sql/driver/meta.json +3 -0
  84. package/gs/database/sql/driver/parity.json +144 -0
  85. package/gs/encoding/binary/index.test.ts +239 -0
  86. package/gs/encoding/binary/index.ts +999 -0
  87. package/gs/encoding/binary/meta.json +9 -0
  88. package/gs/encoding/binary/parity.json +72 -0
  89. package/gs/fmt/fmt.test.ts +28 -0
  90. package/gs/fmt/fmt.ts +198 -61
  91. package/gs/fmt/meta.json +2 -1
  92. package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
  93. package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
  94. package/gs/github.com/pkg/errors/errors.ts +1 -2
  95. package/gs/github.com/pkg/errors/index.ts +2 -1
  96. package/gs/github.com/pkg/errors/stack.ts +34 -62
  97. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
  98. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
  99. package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
  100. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
  101. package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
  102. package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
  103. package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
  104. package/gs/runtime/runtime.test.ts +16 -0
  105. package/gs/runtime/runtime.ts +17 -9
  106. package/gs/runtime/trace/index.test.ts +113 -14
  107. package/gs/runtime/trace/index.ts +384 -34
  108. package/gs/runtime/trace/meta.json +1 -0
  109. package/gs/slices/slices.test.ts +24 -1
  110. package/gs/slices/slices.ts +14 -4
  111. package/gs/sort/meta.json +1 -0
  112. package/gs/sort/search.gs.ts +20 -5
  113. package/gs/sync/sync.ts +4 -1
  114. package/gs/time/time.test.ts +79 -2
  115. package/gs/time/time.ts +133 -33
  116. package/gs/unsafe/unsafe.ts +4 -2
  117. package/package.json +2 -2
@@ -0,0 +1,3 @@
1
+ {
2
+ "dependencies": ["time"]
3
+ }
@@ -0,0 +1,40 @@
1
+ import { describe, expect, test } from 'vitest'
2
+
3
+ import { AnyOverlap, InexactOverlap } from './index.js'
4
+
5
+ describe('crypto/internal/alias override', () => {
6
+ test('reports no overlap for distinct backings', () => {
7
+ const x = new Uint8Array([1, 2, 3, 4])
8
+ const y = new Uint8Array([1, 2, 3, 4])
9
+ expect(AnyOverlap(x, y)).toBe(false)
10
+ expect(InexactOverlap(x, y)).toBe(false)
11
+ })
12
+
13
+ test('reports no overlap when either slice is empty', () => {
14
+ const buf = new Uint8Array(8)
15
+ expect(AnyOverlap(buf, new Uint8Array(0))).toBe(false)
16
+ expect(AnyOverlap(new Uint8Array(0), buf)).toBe(false)
17
+ })
18
+
19
+ test('detects overlap of views over a shared backing', () => {
20
+ const buf = new Uint8Array(8)
21
+ const head = buf.subarray(0, 4)
22
+ const tail = buf.subarray(4, 8)
23
+ const straddle = buf.subarray(2, 6)
24
+ // Disjoint halves of the same buffer do not overlap.
25
+ expect(AnyOverlap(head, tail)).toBe(false)
26
+ // A straddling view overlaps both halves.
27
+ expect(AnyOverlap(head, straddle)).toBe(true)
28
+ expect(AnyOverlap(tail, straddle)).toBe(true)
29
+ })
30
+
31
+ test('InexactOverlap ignores exactly aligned identical starts', () => {
32
+ const buf = new Uint8Array(8)
33
+ const a = buf.subarray(0, 4)
34
+ const b = buf.subarray(0, 4)
35
+ // Same start address: exact overlap, so InexactOverlap is false.
36
+ expect(InexactOverlap(a, b)).toBe(false)
37
+ // But AnyOverlap still reports the shared memory.
38
+ expect(AnyOverlap(a, b)).toBe(true)
39
+ })
40
+ })
@@ -0,0 +1,40 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+
3
+ // AnyOverlap reports whether x and y share memory at any (not necessarily
4
+ // corresponding) index. The memory beyond the slice length is ignored.
5
+ //
6
+ // This mirrors the upstream pointer comparison without reflect or unsafe by
7
+ // using GoScript synthetic byte addresses. Those addresses are stride separated
8
+ // per backing array, so slices over distinct backings can never compare as
9
+ // overlapping and slices over a shared backing compare by element offset, which
10
+ // reproduces the Go semantics the crypto cipher modes rely on.
11
+ export function AnyOverlap(x: $.Bytes, y: $.Bytes): boolean {
12
+ const xLen = $.len(x)
13
+ const yLen = $.len(y)
14
+ if (xLen === 0 || yLen === 0) {
15
+ return false
16
+ }
17
+ const xFirst = $.indexByteAddress(x, 0, 1)
18
+ const xLast = $.indexByteAddress(x, xLen - 1, 1)
19
+ const yFirst = $.indexByteAddress(y, 0, 1)
20
+ const yLast = $.indexByteAddress(y, yLen - 1, 1)
21
+ return xFirst <= yLast && yFirst <= xLast
22
+ }
23
+
24
+ // InexactOverlap reports whether x and y share memory at any non-corresponding
25
+ // index. The memory beyond the slice length is ignored. Note that x and y can
26
+ // have different lengths and still not have any inexact overlap.
27
+ //
28
+ // InexactOverlap can be used to implement the requirements of the crypto/cipher
29
+ // AEAD, Block, BlockMode and Stream interfaces.
30
+ export function InexactOverlap(x: $.Bytes, y: $.Bytes): boolean {
31
+ const xLen = $.len(x)
32
+ const yLen = $.len(y)
33
+ if (xLen === 0 || yLen === 0) {
34
+ return false
35
+ }
36
+ if ($.indexByteAddress(x, 0, 1) === $.indexByteAddress(y, 0, 1)) {
37
+ return false
38
+ }
39
+ return AnyOverlap(x, y)
40
+ }
@@ -1,8 +1,12 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
+ import * as $ from '@goscript/builtin/index.js'
4
+
3
5
  import {
4
6
  Compiler,
5
7
  FuncForPC,
8
+ MemStats,
9
+ ReadMemStats,
6
10
  ReadTrace,
7
11
  SetFinalizer,
8
12
  StartTrace,
@@ -25,4 +29,16 @@ describe('runtime override', () => {
25
29
  expect(() => SetFinalizer(obj, () => {})).not.toThrow()
26
30
  expect(() => SetFinalizer(obj, null)).not.toThrow()
27
31
  })
32
+
33
+ it('exposes heap and stack MemStats fields', () => {
34
+ const stats = new MemStats()
35
+
36
+ ReadMemStats($.varRef(stats))
37
+
38
+ expect(stats.HeapAlloc).toBe(stats.Alloc)
39
+ expect(stats.HeapSys).toBe(stats.Sys)
40
+ expect(stats.HeapInuse).toBe(stats.Alloc)
41
+ expect(stats.StackInuse).toBe(0)
42
+ expect(stats.StackSys).toBe(0)
43
+ })
28
44
  })
@@ -170,6 +170,11 @@ export class MemStats {
170
170
  public Alloc: number = 0 // bytes allocated and not yet freed
171
171
  public TotalAlloc: number = 0 // bytes allocated (even if freed)
172
172
  public Sys: number = 0 // bytes obtained from system
173
+ public HeapAlloc: number = 0 // bytes allocated and not yet freed on the heap
174
+ public HeapSys: number = 0 // bytes obtained from system for the heap
175
+ public HeapInuse: number = 0 // bytes in in-use heap spans
176
+ public StackInuse: number = 0 // bytes in stack spans
177
+ public StackSys: number = 0 // bytes obtained from system for stacks
173
178
  public Lookups: number = 0 // number of pointer lookups
174
179
  public Mallocs: number = 0 // number of mallocs
175
180
  public Frees: number = 0 // number of frees
@@ -181,25 +186,28 @@ export class MemStats {
181
186
  }
182
187
 
183
188
  private updateMemoryStats(): void {
184
- // Use performance.memory if available (Chrome/Edge)
185
- if (typeof performance !== 'undefined' && (performance as any).memory) {
186
- const mem = (performance as any).memory
187
- this.Alloc = mem.usedJSHeapSize || 0
188
- this.Sys = mem.totalJSHeapSize || 0
189
- this.TotalAlloc = this.Alloc // Simplified
190
- }
189
+ updateMemoryStats(this)
191
190
  }
192
191
  }
193
192
 
194
193
  // ReadMemStats populates m with memory allocator statistics
195
- export function ReadMemStats(m: MemStats): void {
196
- // Update the provided MemStats object with current values
194
+ export function ReadMemStats(m: MemStats | $.VarRef<MemStats> | null): void {
195
+ m = $.pointerValue<MemStats>(m)
196
+ updateMemoryStats(m)
197
+ }
198
+
199
+ function updateMemoryStats(m: MemStats): void {
197
200
  if (typeof performance !== 'undefined' && (performance as any).memory) {
198
201
  const mem = (performance as any).memory
199
202
  m.Alloc = mem.usedJSHeapSize || 0
200
203
  m.Sys = mem.totalJSHeapSize || 0
201
204
  m.TotalAlloc = m.Alloc // Simplified
202
205
  }
206
+ m.HeapAlloc = m.Alloc
207
+ m.HeapSys = m.Sys
208
+ m.HeapInuse = m.Alloc
209
+ m.StackInuse = 0
210
+ m.StackSys = 0
203
211
  }
204
212
 
205
213
  // Error interface for runtime errors
@@ -12,8 +12,69 @@ import {
12
12
  WithRegion,
13
13
  } from './index.js'
14
14
 
15
+ function captureWriter(): { chunks: Uint8Array[]; bytes(): Uint8Array } {
16
+ const chunks: Uint8Array[] = []
17
+ return {
18
+ chunks,
19
+ bytes(): Uint8Array {
20
+ const total = chunks.reduce((n, c) => n + c.length, 0)
21
+ const out = new Uint8Array(total)
22
+ let off = 0
23
+ for (const c of chunks) {
24
+ out.set(c, off)
25
+ off += c.length
26
+ }
27
+ return out
28
+ },
29
+ }
30
+ }
31
+
32
+ const writerOf = (chunks: Uint8Array[]) => ({
33
+ Write(p: Uint8Array): [number, null] {
34
+ chunks.push(new Uint8Array(p))
35
+ return [p.length, null]
36
+ },
37
+ })
38
+
39
+ // maxBatchSize mirrors the trace v2 reader limit (tracev2.MaxBatchSize, 64<<10).
40
+ // A batch whose declared data length exceeds this is rejected with "invalid
41
+ // batch size", so the encoder must split large captures across batches.
42
+ const maxBatchSize = 64 * 1024
43
+
44
+ // batchSizes walks the trace v2 stream past the 16-byte header and returns the
45
+ // declared data length of every EvEventBatch frame. Each frame is the batch
46
+ // kind byte (1), then uvarints for generation, M id, base timestamp, and data
47
+ // length, then the data block.
48
+ function batchSizes(bytes: Uint8Array): number[] {
49
+ const sizes: number[] = []
50
+ let i = 16 // header: "go 1.22 trace\x00\x00\x00"
51
+ const readUvarint = (): number => {
52
+ let value = 0
53
+ let shift = 0
54
+ for (;;) {
55
+ const b = bytes[i++]
56
+ value += (b & 0x7f) * 2 ** shift
57
+ if ((b & 0x80) === 0) {
58
+ break
59
+ }
60
+ shift += 7
61
+ }
62
+ return value
63
+ }
64
+ while (i < bytes.length) {
65
+ i++ // EvEventBatch kind byte
66
+ readUvarint() // generation
67
+ readUvarint() // M id
68
+ readUvarint() // base timestamp
69
+ const size = readUvarint()
70
+ sizes.push(size)
71
+ i += size
72
+ }
73
+ return sizes
74
+ }
75
+
15
76
  describe('runtime/trace override', () => {
16
- it('creates no-op tasks from nil context', () => {
77
+ it('creates no-op tasks when tracing is disabled', () => {
17
78
  const [ctx, task] = NewTask(null, 'task')
18
79
 
19
80
  expect(ctx).not.toBeNull()
@@ -23,7 +84,7 @@ describe('runtime/trace override', () => {
23
84
  expect(IsEnabled()).toBe(false)
24
85
  })
25
86
 
26
- it('runs no-op regions', () => {
87
+ it('runs regions', () => {
27
88
  const [ctx] = NewTask(context.Background(), 'task')
28
89
  const called = { value: false }
29
90
 
@@ -35,21 +96,59 @@ describe('runtime/trace override', () => {
35
96
  expect(called.value).toBe(true)
36
97
  })
37
98
 
38
- it('reports execution tracing as unsupported', () => {
39
- const chunks: Uint8Array[] = []
40
- const writer = {
41
- Write(p: Uint8Array): [number, null] {
42
- chunks.push(new Uint8Array(p))
43
- return [p.length, null]
44
- },
99
+ it('rejects a nil trace writer', () => {
100
+ expect(Start(null)?.Error()).toBe('runtime/trace: nil trace writer')
101
+ })
102
+
103
+ it('emits a trace v2 stream for user tasks', () => {
104
+ const capture = captureWriter()
105
+
106
+ expect(Start(writerOf(capture.chunks))).toBeNull()
107
+ expect(IsEnabled()).toBe(true)
108
+
109
+ const [ctx, task] = NewTask(context.Background(), 'proof-task')
110
+ WithRegion(ctx, 'proof-region', () => {
111
+ Log(ctx, 'proof-key', 'proof-value')
112
+ })
113
+ task.End()
114
+
115
+ Stop()
116
+ expect(IsEnabled()).toBe(false)
117
+
118
+ const bytes = capture.bytes()
119
+ expect(bytes.length).toBeGreaterThan(0)
120
+
121
+ const header = new TextDecoder().decode(bytes.slice(0, 13))
122
+ expect(header).toBe('go 1.22 trace')
123
+
124
+ // The interned task and region names appear in the string batch.
125
+ const text = new TextDecoder('latin1').decode(bytes)
126
+ expect(text).toContain('proof-task')
127
+ expect(text).toContain('proof-region')
128
+ expect(text).toContain('proof-value')
129
+ })
130
+
131
+ it('splits a large capture into batches under the size limit', () => {
132
+ const capture = captureWriter()
133
+
134
+ expect(Start(writerOf(capture.chunks))).toBeNull()
135
+
136
+ // Record enough distinct tasks and logs to overflow the single-batch ceiling
137
+ // in both the string dictionary and the event stream.
138
+ const eventCount = 4000
139
+ for (let i = 0; i < eventCount; i++) {
140
+ const [ctx, task] = NewTask(context.Background(), `multibatch-task-${i}`)
141
+ Log(ctx, 'multibatch-key', `multibatch-message-${i}`)
142
+ task.End()
45
143
  }
46
144
 
47
- expect(Start(writer)?.Error()).toBe(
48
- 'runtime/trace: execution tracing is unsupported in GoScript',
49
- )
50
- Log(context.Background(), 'category', 'message')
51
145
  Stop()
52
146
 
53
- expect(chunks).toHaveLength(0)
147
+ const sizes = batchSizes(capture.bytes())
148
+ // Frequency, plus several string and event batches.
149
+ expect(sizes.length).toBeGreaterThan(3)
150
+ for (const size of sizes) {
151
+ expect(size).toBeLessThanOrEqual(maxBatchSize)
152
+ }
54
153
  })
55
154
  })