From f0ae1fcfa89eb7aea70893e417cad52c31188767 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 19 Apr 2023 19:25:43 +0200 Subject: [PATCH 1/9] Implement stringref operations --- .github/workflows/test.yml | 6 +- src/builtins.ts | 682 ++++++++++ src/common.ts | 4 + src/module.ts | 280 ++++- src/program.ts | 6 + std/assembly/builtins.ts | 168 +++ std/assembly/index.d.ts | 90 ++ std/assembly/reference.ts | 16 + tests/compiler.js | 3 +- tests/compiler/features/stringref.debug.wat | 1096 +++++++++++++++++ tests/compiler/features/stringref.json | 7 + tests/compiler/features/stringref.release.wat | 846 +++++++++++++ tests/compiler/features/stringref.ts | 111 ++ tests/compiler/simd.json | 4 +- tests/features.json | 10 + 15 files changed, 3315 insertions(+), 14 deletions(-) create mode 100644 tests/compiler/features/stringref.debug.wat create mode 100644 tests/compiler/features/stringref.json create mode 100644 tests/compiler/features/stringref.release.wat create mode 100644 tests/compiler/features/stringref.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e46805377..0bb81e6ffc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -74,16 +74,16 @@ jobs: - uses: dcodeIO/setup-node-nvm@master with: node-mirror: https://nodejs.org/download/v8-canary/ - node-version: 19.0.0-v8-canary202209029fc5a9347b + node-version: 21.0.0-v8-canary20230419061e93e884 - name: Install dependencies run: npm ci --no-audit - name: Build run: npm run build - name: Test experimental features env: - ASC_FEATURES: threads,reference-types,gc,exception-handling + ASC_FEATURES: threads,reference-types,gc,exception-handling,stringref run: | - npm run test:compiler features/threads features/reference-types features/gc features/exception-handling + npm run test:compiler features/threads features/reference-types features/gc features/exception-handling features/stringref runtimes: name: "Runtimes" runs-on: ubuntu-latest diff --git a/src/builtins.ts b/src/builtins.ts index 20cf2e044d..6924da14aa 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -715,6 +715,49 @@ export namespace BuiltinNames { export const i31_new = "~lib/builtins/i31.new"; export const i31_get = "~lib/builtins/i31.get"; + export const string_const = "~lib/builtins/string.const_"; + export const string_new_utf8 = "~lib/builtins/string.new_utf8"; + export const string_new_utf8_array = "~lib/builtins/string.new_utf8_array"; + export const string_new_lossy_utf8 = "~lib/builtins/string.new_lossy_utf8"; + export const string_new_lossy_utf8_array = "~lib/builtins/string.new_lossy_utf8_array"; + export const string_new_wtf8 = "~lib/builtins/string.new_wtf8"; + export const string_new_wtf8_array = "~lib/builtins/string.new_wtf8_array"; + export const string_new_wtf16 = "~lib/builtins/string.new_wtf16"; + export const string_new_wtf16_array = "~lib/builtins/string.new_wtf16_array"; + export const string_from_code_point = "~lib/builtins/string.from_code_point"; + export const string_hash = "~lib/builtins/string.hash"; + export const string_measure_utf8 = "~lib/builtins/string.measure_utf8"; + export const string_measure_wtf8 = "~lib/builtins/string.measure_wtf8"; + export const string_measure_wtf16 = "~lib/builtins/string.measure_wtf16"; + export const string_is_usv_sequence = "~lib/builtins/string.is_usv_sequence"; + export const string_encode_utf8 = "~lib/builtins/string.encode_utf8"; + export const string_encode_utf8_array = "~lib/builtins/string.encode_utf8_array"; + // TODO: string_encode_lossy_utf8 + // TODO: string_encode_lossy_utf8_array + export const string_encode_wtf8 = "~lib/builtins/string.encode_wtf8"; + export const string_encode_wtf8_array = "~lib/builtins/string.encode_wtf8_array"; + export const string_encode_wtf16 = "~lib/builtins/string.encode_wtf16"; + export const string_encode_wtf16_array = "~lib/builtins/string.encode_wtf16_array"; + export const string_concat = "~lib/builtins/string.concat"; + export const string_eq = "~lib/builtins/string.eq"; + export const string_compare = "~lib/builtins/string.compare"; + export const string_as_wtf8 = "~lib/builtins/string.as_wtf8"; + export const string_as_wtf16 = "~lib/builtins/string.as_wtf16"; + export const string_as_iter = "~lib/builtins/string.as_iter"; + export const stringview_wtf8_advance = "~lib/builtins/stringview_wtf8.advance"; + // TODO: stringview_wtf8_encode_utf8 + // TODO: stringview_wtf8_encode_lossy_utf8 + // TODO: stringview_wtf8_encode_wtf8 + export const stringview_wtf8_slice = "~lib/builtins/stringview_wtf8.slice"; + export const stringview_wtf16_length = "~lib/builtins/stringview_wtf16.length"; + export const stringview_wtf16_slice = "~lib/builtins/stringview_wtf16.slice"; + export const stringview_wtf16_get_codeunit = "~lib/builtins/stringview_wtf16.get_codeunit"; + // TODO: stringview_wtf16_encode + export const stringview_iter_next = "~lib/builtins/stringview_iter.next"; + export const stringview_iter_advance = "~lib/builtins/stringview_iter.advance"; + export const stringview_iter_rewind = "~lib/builtins/stringview_iter.rewind"; + export const stringview_iter_slice = "~lib/builtins/stringview_iter.slice"; + // internals export const data_end = "~lib/memory/__data_end"; export const stack_pointer = "~lib/memory/__stack_pointer"; @@ -10826,6 +10869,645 @@ function builtin_i32x4_relaxed_dot_i8x16_i7x16_add_s(ctx: BuiltinFunctionContext } builtinFunctions.set(BuiltinNames.i32x4_relaxed_dot_i8x16_i7x16_add_s, builtin_i32x4_relaxed_dot_i8x16_i7x16_add_s); +// === Stringref ============================================================================== + +// string.const(str: string) -> stringref +function builtin_string_const(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let node = operands[0]; + if (node.kind == NodeKind.Literal) { + let literal = node; + if (literal.literalKind == LiteralKind.String) { + compiler.currentType = Type.stringref; + return module.string_const((literal).value); + } + } + compiler.error( + DiagnosticCode.String_literal_expected, + node.range + ); + compiler.currentType = Type.stringref; + return module.unreachable(); +} +builtinFunctions.set(BuiltinNames.string_const, builtin_string_const); + +// string.new_utf8(ptr: usize, bytes: i32, immMemory?: i32) -> stringref +function builtin_string_new_utf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.stringref; + return module.string_new_utf8(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_new_utf8, builtin_string_new_utf8); + +// string.new_utf8_array(arr: array, start: i32, end: i32) -> stringref +function builtin_string_new_utf8_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.arrayref, Constraints.ConvImplicit); // TODO + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_new_utf8_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_new_utf8_array, builtin_string_new_utf8_array); + +// string.new_lossy_utf8(ptr: usize, bytes: i32, immMemory?: i32) -> stringref +function builtin_string_new_lossy_utf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.stringref; + return module.string_new_lossy_utf8(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_new_lossy_utf8, builtin_string_new_lossy_utf8); + +// string.new_lossy_utf8_array(arr: array, start: i32, end: i32) -> stringref +function builtin_string_new_lossy_utf8_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.arrayref, Constraints.ConvImplicit); // TODO + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_new_lossy_utf8_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_new_lossy_utf8_array, builtin_string_new_lossy_utf8_array); + +// string.new_wtf8(ptr: usize, bytes: i32, immMemory?: i32) -> stringref +function builtin_string_new_wtf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.stringref; + return module.string_new_wtf8(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_new_wtf8, builtin_string_new_wtf8); + +// string.new_wtf8_array(arr: array, start: i32, end: i32) -> stringref +function builtin_string_new_wtf8_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.arrayref, Constraints.ConvImplicit); // TODO + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_new_wtf8_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_new_wtf8_array, builtin_string_new_wtf8_array); + +// string.new_wtf16(ptr: usize, bytes: i32, immMemory?: i32) -> stringref +function builtin_string_new_wtf16(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.stringref; + return module.string_new_wtf16(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_new_wtf16, builtin_string_new_wtf16); + +// string.new_wtf16_array(arr: array, start: i32, end: i32) -> stringref +function builtin_string_new_wtf16_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.arrayref, Constraints.ConvImplicit); // TODO + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_new_wtf16_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_new_wtf16_array, builtin_string_new_wtf16_array); + +// string.from_code_point(codepoint: i32) -> stringref +function builtin_string_from_code_point(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_from_code_point(arg0); +} +builtinFunctions.set(BuiltinNames.string_from_code_point, builtin_string_from_code_point); + +// string.hash(str: stringref) -> i32 +function builtin_string_hash(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_hash(arg0); +} +builtinFunctions.set(BuiltinNames.string_hash, builtin_string_hash); + +// string.measure_utf8(str: stringref) -> i32 +function builtin_string_measure_utf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_measure_utf8(arg0); +} +builtinFunctions.set(BuiltinNames.string_measure_utf8, builtin_string_measure_utf8); + +// string.measure_wtf8(str: stringref) -> i32 +function builtin_string_measure_wtf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_measure_wtf8(arg0); +} +builtinFunctions.set(BuiltinNames.string_measure_wtf8, builtin_string_measure_wtf8); + +// string.measure_wtf16(str: stringref) -> i32 +function builtin_string_measure_wtf16(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_measure_wtf16(arg0); +} +builtinFunctions.set(BuiltinNames.string_measure_wtf16, builtin_string_measure_wtf16); + +// string.is_usv_sequence(str: stringref) -> bool +function builtin_string_is_usv_sequence(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.bool; + return module.string_is_usv_sequence(arg0); +} +builtinFunctions.set(BuiltinNames.string_is_usv_sequence, builtin_string_is_usv_sequence); + +// string.encode_utf8(str: stringref, ptr: usize) -> i32 +function builtin_string_encode_utf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], compiler.options.usizeType, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.i32; + return module.string_encode_utf8(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_encode_utf8, builtin_string_encode_utf8); + +// string.encode_utf8_array(str: stringref, arr: array, start: i32) -> i32 +function builtin_string_encode_utf8_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.arrayref, Constraints.ConvImplicit); // TODO: array + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_encode_utf8_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_encode_utf8_array, builtin_string_encode_utf8_array); + +// TOOD: string.encode_lossy_utf8(str: stringref, ptr: usize) -> i32 +// TODO: string.encode_lossy_utf8_array(str: stringref, arr: array, start: i32) -> i32 + +// string.encode_wtf8(str: stringref, ptr: usize) -> i32 +function builtin_string_encode_wtf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], compiler.options.usizeType, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.i32; + return module.string_encode_wtf8(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_encode_wtf8, builtin_string_encode_wtf8); + +// string.encode_wtf8_array(str: stringref, arr: array, start: i32) -> i32 +function builtin_string_encode_wtf8_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.arrayref, Constraints.ConvImplicit); // TODO: array + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_encode_wtf8_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_encode_wtf8_array, builtin_string_encode_wtf8_array); + +// string.encode_wtf16(str: stringref, ptr: usize) -> i32 +function builtin_string_encode_wtf16(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], compiler.options.usizeType, Constraints.ConvImplicit); + // TODO: immMemory + compiler.currentType = Type.i32; + return module.string_encode_wtf16(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_encode_wtf16, builtin_string_encode_wtf16); + +// string.encode_wtf16_array(str: stringref, arr: array, start: i32) -> i32 +function builtin_string_encode_wtf16_array(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.arrayref, Constraints.ConvImplicit); // TODO: array + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_encode_wtf16_array(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.string_encode_wtf16_array, builtin_string_encode_wtf16_array); + +// string.concat(left: stringref, right: stringref) -> stringref +function builtin_string_concat(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.string_concat(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_concat, builtin_string_concat); + +// string.eq(left: stringref, right: stringref) -> bool +function builtin_string_eq(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.bool; + return module.string_eq(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_eq, builtin_string_eq); + +// string.compare(left: stringref, right: stringref) -> i32 +function builtin_string_compare(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.string_compare(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.string_compare, builtin_string_compare); + +// string.as_wtf8(str: stringref) -> stringview_wtf8 +function builtin_string_as_wtf8(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.stringview_wtf8; + return module.string_as_wtf8(arg0); +} +builtinFunctions.set(BuiltinNames.string_as_wtf8, builtin_string_as_wtf8); + +// string.as_wtf16(str: stringref) -> stringview_wtf16 +function builtin_string_as_wtf16(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.stringview_wtf16; + return module.string_as_wtf16(arg0); +} +builtinFunctions.set(BuiltinNames.string_as_wtf16, builtin_string_as_wtf16); + +// string.as_iter(str: stringref) -> stringview_iter +function builtin_string_as_iter(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringref, Constraints.ConvImplicit); + compiler.currentType = Type.stringview_iter; + return module.string_as_iter(arg0); +} +builtinFunctions.set(BuiltinNames.string_as_iter, builtin_string_as_iter); + +// stringview_wtf8.advance(view: stringview_wtf8, pos: i32, bytes: i32) -> i32 +function builtin_stringview_wtf8_advance(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_wtf8, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_wtf8_advance(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.stringview_wtf8_advance, builtin_stringview_wtf8_advance); + +// TODO: stringview_wtf8.encode_utf8 +// TODO: stringview_wtf8.encode_lossy_utf8 +// TODO: stringview_wtf8.encode_wtf8 + +// stringview_wtf8.slice(view: stringview_wtf8, start: i32, end: i32) -> stringview_wtf8 +function builtin_stringview_wtf8_slice(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_wtf8, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.stringview_wtf8_slice(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.stringview_wtf8_slice, builtin_stringview_wtf8_slice); + +// stringview_wtf16.length(view: stringview_wtf8) -> i32 +function builtin_stringview_wtf16_length(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_wtf16, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_wtf16_length(arg0); +} +builtinFunctions.set(BuiltinNames.stringview_wtf16_length, builtin_stringview_wtf16_length); + +// stringview_wtf16.slice(view: stringview_wtf16, start: i32, end: i32) -> stringref +function builtin_stringview_wtf16_slice(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_wtf16, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + let arg2 = compiler.compileExpression(operands[2], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.stringview_wtf16_slice(arg0, arg1, arg2); +} +builtinFunctions.set(BuiltinNames.stringview_wtf16_slice, builtin_stringview_wtf16_slice); + +// stringview_wtf16.get_codeunit(view: stringview_wtf16, pos: i32) -> i32 +function builtin_stringview_wtf16_get_codeunit(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_wtf16, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_wtf16_get_codeunit(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.stringview_wtf16_get_codeunit, builtin_stringview_wtf16_get_codeunit); + +// TODO: stringview_wtf16.encode + +// stringview_iter.next(view: stringview_iter) -> i32 +function builtin_stringview_iter_next(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_iter, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_iter_next(arg0); +} +builtinFunctions.set(BuiltinNames.stringview_iter_next, builtin_stringview_iter_next); + +// stringview_iter.advance(view: stringview_iter, count: i32) -> i32 +function builtin_stringview_iter_advance(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_iter, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_iter_advance(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.stringview_iter_advance, builtin_stringview_iter_advance); + +// stringview_iter.rewind(view: stringview_iter, count: i32) -> i32 +function builtin_stringview_iter_rewind(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_iter, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.i32; + return module.stringview_iter_rewind(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.stringview_iter_rewind, builtin_stringview_iter_rewind); + +// stringview_iter.slice(view: stringview_iter, count: i32) -> stringref +function builtin_stringview_iter_slice(ctx: BuiltinFunctionContext): ExpressionRef { + let compiler = ctx.compiler; + let module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.Stringref) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + let operands = ctx.operands; + let arg0 = compiler.compileExpression(operands[0], Type.stringview_iter, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.ConvImplicit); + compiler.currentType = Type.stringref; + return module.stringview_iter_slice(arg0, arg1); +} +builtinFunctions.set(BuiltinNames.stringview_iter_slice, builtin_stringview_iter_slice); + // === Internal helpers ======================================================================= /** Compiles the `visit_globals` function. */ diff --git a/src/common.ts b/src/common.ts index 8e03684d05..545567388d 100644 --- a/src/common.ts +++ b/src/common.ts @@ -214,6 +214,10 @@ export namespace CommonNames { export const Structref = "Structref"; export const Arrayref = "Arrayref"; export const I31ref = "I31ref"; + export const Stringref = "Stringref"; + export const StringviewWTF8 = "StringviewWTF8"; + export const StringviewWTF16 = "StringviewWTF16"; + export const StringviewIter = "StringviewIter"; export const String = "String"; export const RegExp = "RegExp"; export const Object = "Object"; diff --git a/src/module.ts b/src/module.ts index 6c9d527cb0..eae482a1d3 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1298,7 +1298,9 @@ export const enum StringMeasureOp { /** string.is_usv_sequence */ IsUSV = 3 /* _BinaryenStringMeasureIsUSV */, /** stringview_wtf16.length */ - WTF16View = 4 /* _BinaryenStringMeasureWTF16View */ + WTF16View = 4 /* _BinaryenStringMeasureWTF16View */, + /** string.hash */ + Hash = 5 /* TODO_BinaryenStringMeasureHash */ } /** Binaryen StringEncode operation constants. */ @@ -1472,14 +1474,6 @@ export class Module { return binaryen._BinaryenRefEq(this.ref, left, right); } - string_eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef { - return binaryen._BinaryenStringEq(this.ref, StringEqOp.Equal, left, right); - } - - string_compare(left: ExpressionRef, right: ExpressionRef): ExpressionRef { - return binaryen._BinaryenStringEq(this.ref, StringEqOp.Compare, left, right); - } - // expressions unary( @@ -2136,6 +2130,274 @@ export class Module { return binaryen._BinaryenI31Get(this.ref, expr, signed); } + // stringref + + string_const( + str: string + ): ExpressionRef { + return binaryen._BinaryenStringConst(this.ref, this.allocStringCached(str)); + } + + string_new_utf8( + ptr: ExpressionRef, + length: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.UTF8, ptr, length, 0, 0, false); + } + + string_new_utf8_array( + arr: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.UTF8Array, arr, 0, start, end, false); + } + + string_new_lossy_utf8( + ptr: ExpressionRef, + length: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.Replace, ptr, length, 0, 0, false); + } + + string_new_lossy_utf8_array( + arr: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.ReplaceArray, arr, 0, start, end, false); + } + + string_new_wtf8( + ptr: ExpressionRef, + length: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF8, ptr, length, 0, 0, false); + } + + string_new_wtf8_array( + arr: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF8Array, arr, 0, start, end, false); + } + + string_new_wtf16( + ptr: ExpressionRef, + length: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF16, ptr, length, 0, 0, false); + } + + string_new_wtf16_array( + arr: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF16Array, arr, 0, start, end, false); + } + + string_from_code_point( + codepoint: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringNew(this.ref, StringNewOp.FromCodePoint, codepoint, 0, 0, 0, false); + } + + string_hash( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.Hash, str); + } + + string_measure_utf8( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.UTF8, str); + } + + string_measure_wtf8( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF8, str); + } + + string_measure_wtf16( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF16, str); + } + + string_is_usv_sequence( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.IsUSV, str); + } + + string_encode_utf8( + str: ExpressionRef, + ptr: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.UTF8, str, ptr, 0); + } + + string_encode_utf8_array( + str: ExpressionRef, + arr: ExpressionRef, + start: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.UTF8Array, str, arr, start); + } + + // TOOD: string_encode_lossy_utf8 + // TODO: string_encode_lossy_utf8_array + + string_encode_wtf8( + str: ExpressionRef, + ptr: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF8, str, ptr, 0); + } + + string_encode_wtf8_array( + str: ExpressionRef, + arr: ExpressionRef, + start: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF8Array, str, arr, start); + } + + string_encode_wtf16( + str: ExpressionRef, + ptr: ExpressionRef, + memory: string = CommonNames.DefaultMemory // TODO + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF16, str, ptr, 0); + } + + string_encode_wtf16_array( + str: ExpressionRef, + arr: ExpressionRef, + start: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF16Array, str, arr, start); + } + + string_concat( + left: ExpressionRef, + right: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringConcat(this.ref, left, right); + } + + string_eq( + left: ExpressionRef, + right: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringEq(this.ref, StringEqOp.Equal, left, right); + } + + string_compare( + left: ExpressionRef, + right: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringEq(this.ref, StringEqOp.Compare, left, right); + } + + string_as_wtf8( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringAs(this.ref, StringAsOp.WTF8, str); + } + + string_as_wtf16( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringAs(this.ref, StringAsOp.WTF16, str); + } + + string_as_iter( + str: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringAs(this.ref, StringAsOp.Iter, str); + } + + stringview_wtf8_advance( + view: ExpressionRef, + pos: ExpressionRef, + bytes: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringWTF8Advance(this.ref, view, pos, bytes); + } + + // TODO: stringview_wtf8_encode_utf8 + // TODO: stringview_wtf8_encode_lossy_utf8 + // TODO: stringview_wtf8_encode_wtf8 + + stringview_wtf8_slice( + view: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringSliceWTF(this.ref, StringSliceWTFOp.WTF8, view, start, end); + } + + stringview_wtf16_length( + view: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF16View, view); + } + + stringview_wtf16_slice( + view: ExpressionRef, + start: ExpressionRef, + end: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringSliceWTF(this.ref, StringSliceWTFOp.WTF16, view, start, end); + } + + stringview_wtf16_get_codeunit( + view: ExpressionRef, + pos: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringWTF16Get(this.ref, view, pos); + } + + // TODO: stringview_wtf16_encode + + stringview_iter_next( + view: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringIterNext(this.ref, view); + } + + stringview_iter_advance( + view: ExpressionRef, + count: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringIterMove(this.ref, StringIterMoveOp.Advance, view, count); + } + + stringview_iter_rewind( + view: ExpressionRef, + count: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringIterMove(this.ref, StringIterMoveOp.Rewind, view, count); + } + + stringview_iter_slice( + view: ExpressionRef, + count: ExpressionRef + ): ExpressionRef { + return binaryen._BinaryenStringSliceIter(this.ref, view, count); + } + // globals addGlobal( diff --git a/src/program.ts b/src/program.ts index 18ebd57a6d..e04e6153de 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1297,6 +1297,12 @@ export class Program extends DiagnosticEmitter { this.registerWrapperClass(Type.arrayref, CommonNames.Arrayref); this.registerWrapperClass(Type.i31ref, CommonNames.I31ref); } + if (options.hasFeature(Feature.Stringref)) { + this.registerWrapperClass(Type.stringref, CommonNames.Stringref); + this.registerWrapperClass(Type.stringview_wtf8, CommonNames.StringviewWTF8); + this.registerWrapperClass(Type.stringview_wtf16, CommonNames.StringviewWTF16); + this.registerWrapperClass(Type.stringview_iter, CommonNames.StringviewIter); + } } // resolve prototypes of extended classes or interfaces diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 12f0dfd574..a41e3ae4ff 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -2596,6 +2596,174 @@ export abstract class i31 { // FIXME: usage of 'new' requires a class :( static get(i31expr: i31ref): i32 { return unreachable(); } } +export namespace string { + + // @ts-ignore: decorator + @builtin + export declare function const_(str: string): stringref; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function new_utf8(ptr: usize, bytes: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function new_utf8_array(array: arrayref, start: i32, end: i32): stringref; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function new_lossy_utf8(ptr: usize, bytes: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function new_lossy_utf8_array(array: arrayref, start: i32, end: i32): stringref; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function new_wtf8(ptr: usize, bytes: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function new_wtf8_array(arr: arrayref, start: i32, end: i32): stringref; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function new_wtf16(ptr: usize, units: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function new_wtf16_array(arr: arrayref, start: i32, end: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function from_code_point(codepoint: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function hash(str: stringref): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_utf8(str: stringref): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_wtf8(str: stringref): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_wtf16(str: stringref): i32; + + // @ts-ignore: decorator + @builtin + export declare function is_usv_sequence(str: stringref): i32; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function encode_utf8(str: stringref, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + export declare function encode_utf8_array(str: stringref, arr: arrayref, start: i32): i32; + + // TODO: encode_lossy_utf8 + + // TODO: encode_lossy_utf8_array + + // @ts-ignore: decorator + @unsafe @builtin + export declare function encode_wtf8(str: stringref, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + export declare function encode_wtf8_array(str: stringref, arr: arrayref, start: i32): i32; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function encode_wtf16(str: stringref, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + export declare function encode_wtf16_array(str: stringref, arr: arrayref, start: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function concat(left: stringref, right: stringref): stringref; + + // @ts-ignore: decorator + @builtin + export declare function eq(left: stringref, right: stringref): bool; + + // @ts-ignore: decorator + @builtin + export declare function compare(left: stringref, right: stringref): i32; + + // @ts-ignore: decorator + @builtin + export declare function as_wtf8(str: stringref): stringview_wtf8; + + // @ts-ignore: decorator + @builtin + export declare function as_wtf16(str: stringref): stringview_wtf16; + + // @ts-ignore: decorator + @builtin + export declare function as_iter(str: stringref): stringview_iter; +} + +export namespace stringview_wtf8 { + + // @ts-ignore: decorator + @builtin + export declare function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_wtf8, start: i32, end: i32): stringref; + + // TODO: encode_utf8 + + // TODO: encode_lossy_utf8 + + // TODO: encode_wtf8 +} + +export namespace stringview_wtf16 { + + // @ts-ignore: decorator + @builtin + export declare function length(view: stringview_wtf16): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_wtf16, start: i32, end: i32): stringref; + + // @ts-ignore: decorator + @builtin + export declare function get_codeunit(view: stringview_wtf16, pos: i32): i32; + + // TODO: encode +} + +export namespace stringview_iter { + + // @ts-ignore: decorator + @builtin + export declare function next(view: stringview_iter): i32; + + // @ts-ignore: decorator + @builtin + export declare function advance(view: stringview_iter, count: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function rewind(view: stringview_iter, count: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_iter, count: i32): stringref; +} + /* eslint-disable @typescript-eslint/no-unused-vars */ // @ts-ignore: decorator diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 13e59d0886..3c3ad6faf2 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -1646,6 +1646,96 @@ declare abstract class i31 { static get(i31expr: i31ref): i32; } +declare namespace string { + /** Constructs a string reference from a string literal. Temporary! */ + export function const_(str: string): stringref; + /** Creates a new string from memory using a strict UTF-8 decoder, decoding `bytes` bytes starting at `ptr`. */ + export function new_utf8(ptr: usize, bytes: i32): stringref; + /** Creates a new string from `array` using a strict UTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ + export function new_utf8_array(array: arrayref, start: i32, end: i32): stringref; + /** Creates a new string from memory using a lossy UTF-8 decoder, decoding `bytes` bytes starting at `ptr`. */ + export function new_lossy_utf8(ptr: usize, bytes: i32): stringref; + /** Creates a new string from `array` using a lossy UTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ + export function new_lossy_utf8_array(array: arrayref, start: i32, end: i32): stringref; + /** Creates a new string from memory using a strict WTF-8 decoder, decodiing `bytes` bytes starting at `ptr`. */ + export function new_wtf8(ptr: usize, bytes: i32): stringref; + /** Creates a new string from `array` using a strict WTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ + export function new_wtf8_array(array: arrayref, start: i32, end: i32): stringref; + /** Creates a new string from memory assuming WTF-16 encoding, reading `codeunits` code units starting at `ptr`. `ptr` must be two-byte aligned. */ + export function new_wtf16(ptr: usize, codeunits: i32): stringref; + /** Creates a new string from `array` assuming WTF-16 encoding, reading from `start` inclusive to `end` exclusive. */ + export function new_wtf16_array(array: arrayref, start: i32, end: i32): stringref; + /** Creates a new string from the given `codepoint`. */ + export function from_code_point(codepoint: i32): stringref; + /** Obtains an implementation-defined 32-bit hash value of `str`. */ + export function hash(str: stringref): i32; + /** Measures the number of bytes required to encode `str` to UTF-8. Returns `-1` if the string contains an isolated surrogate. */ + export function measure_utf8(str: stringref): i32; + /** Measures the number of bytes required to encode `str` to WTF-8. */ + export function measure_wtf8(str: stringref): i32; + /** Measures the number of 16-bit code units required to encode `str` to WTF-16. */ + export function measure_wtf16(str: stringref): i32; + /** Tests whether `str` is a sequence of Unicode scalar values, i.e. does not contain isolated surrogates. */ + export function is_usv_sequence(str: stringref): bool; + /** Encodes `str` to memory at `ptr` using a strict UTF-8 encoder. */ + export function encode_utf8(str: stringref, ptr: usize): i32; + /** Encodes `str` to `arr` at `start` using a strict UTF-8 encoder. */ + export function encode_utf8_array(str: stringref, arr: arrayref, start: i32): i32; + // TODO: encode_lossy_utf8 + // TODO: encode_lossy_utf8_array + /** Encodes `str` to memory at `ptr` using a WTF-8 encoder. */ + export function encode_wtf8(str: stringref, ptr: usize): i32; + /** Encodes `str` to `arr` at `start` using a WTF-8 encoder. */ + export function encode_wtf8_array(str: stringref, arr: arrayref, start: i32): i32; + /** Encodes `str` to memory at `ptr` using a WTF-16 encoder. */ + export function encode_wtf16(str: stringref, ptr: usize): i32; + /** Encodes `str` to `arr` at `start` using a WTF-16 encoder. */ + export function encode_wtf16_array(str: stringref, arr: arrayref, start: i32): i32; + /** Concatenates `left` and `right` in this order. Traps if either operand is `null`. */ + export function concat(left: stringref, right: stringref): stringref; + /** Tests whether `left` and `right` are equal, including if both are `null`. */ + export function eq(left: stringref, right: stringref): bool; + /** Compares the contents of `left` and `right`, returning `-1` if `left < right`, `0` if `left == right` or `1` if `left > right`. Traps if either operand is `null`. */ + export function compare(left: stringref, right: stringref): i32; + /** Obtains a WTF-8 view on `str`. */ + export function as_wtf8(str: stringref): stringview_wtf8; + /** Obtains a WTF-16 view on `str`. */ + export function as_wtf16(str: stringref): stringview_wtf16; + /** Obtains an iterator view on `str`. */ + export function as_iter(str: stringref): stringview_iter; +} + +declare namespace stringview_wtf8 { + /** Obtains the highest code point offset in `view` that is not greater than `pos + bytes`. If `pos` does not match the start of a code point, it is advanced to the next code point. */ + export function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; + /** Returns a substring of `view` from `start` inclusive to `end` exclusive. If `start` or `end` do not match the start of a code point, these are advanced to the next code point. */ + export function slice(view: stringview_wtf8, start: i32, end: i32): stringref; + // TODO: encode_utf8 + // TODO: encode_lossy_utf8 + // TODO: encode_wtf8 +} + +declare namespace stringview_wtf16 { + /** Obtains the number of 16-bit code units in `view`. */ + export function length(view: stringview_wtf16): i32; + /** Returns a substring of `view` from `start` inclusive to `end` exclusive. */ + export function slice(view: stringview_wtf16, start: i32, end: i32): stringref; + /** Obtains the 16-bit code unit at `pos` in `view`. Traps if `pos` is greater than or equal to the view's WTF-16 length. */ + export function get_codeunit(view: stringview_wtf16, pos: i32): i32; + // TODO: encode +} + +declare namespace stringview_iter { + /** Obtains the code point at the iterator's current position, advancing the iterator by one code point. Returns `-1` if already at the end. */ + export function next(view: stringview_iter): i32; + /** Advances the iterator by up to `count` code points, returning the number of code points consumed. */ + export function advance(view: stringview_iter, count: i32): i32; + /** Rewinds the iterator by up to `count` code points, returning the number of coode points consumed. */ + export function rewind(view: stringview_iter, count: i32): i32; + /** Returns a substring of `view`, starting at the current position for up to `count` code points. */ + export function slice(view: stringview_iter, count: i32): stringref; +} + /** Macro type evaluating to the underlying native WebAssembly type. */ declare type native = T; /** Special type evaluating the indexed access index type. */ diff --git a/std/assembly/reference.ts b/std/assembly/reference.ts index 1c7b85cb13..57cccca2b4 100644 --- a/std/assembly/reference.ts +++ b/std/assembly/reference.ts @@ -29,3 +29,19 @@ export abstract class Structref extends Ref { @final @unmanaged export abstract class Arrayref extends Ref { } + +@final @unmanaged +export abstract class Stringref extends Ref { +} + +@final @unmanaged +export abstract class StringviewWTF8 extends Ref { +} + +@final @unmanaged +export abstract class StringviewWTF16 extends Ref { +} + +@final @unmanaged +export abstract class StringviewIter extends Ref { +} diff --git a/tests/compiler.js b/tests/compiler.js index 1095bc4e4c..fcf12ade97 100644 --- a/tests/compiler.js +++ b/tests/compiler.js @@ -410,7 +410,8 @@ async function testInstantiate(binaryBuffer, glue, stderr) { return new Date().getTimezoneOffset(); }, ...toEnv("Date", Date), - ...toEnv("Math", Math) + ...toEnv("Math", Math), + ...toEnv("console", console) }) }); diff --git a/tests/compiler/features/stringref.debug.wat b/tests/compiler/features/stringref.debug.wat new file mode 100644 index 0000000000..8e3aac79b6 --- /dev/null +++ b/tests/compiler/features/stringref.debug.wat @@ -0,0 +1,1096 @@ +(module + (type $none_=>_none (func)) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $features/stringref/utf8_data i32 (i32.const 8)) + (global $features/stringref/wtf16_data i32 (i32.const 12)) + (global $features/stringref/temp_data i32 (i32.const 32)) + (global $~lib/native/ASC_SHRINK_LEVEL i32 (i32.const 0)) + (global $~lib/memory/__data_end i32 (i32.const 124)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 32892)) + (global $~lib/memory/__heap_base i32 (i32.const 32892)) + (memory $0 1) + (data $0 (i32.const 8) "abc") + (data $1 (i32.const 12) "a\00b\00c\00") + (data $2 (i32.const 32) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $3 (i32.const 60) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00*\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00s\00t\00r\00i\00n\00g\00r\00e\00f\00.\00t\00s\00\00\00") + (table $0 1 1 funcref) + (elem $0 (i32.const 1)) + (export "memory" (memory $0)) + (start $~start) + (func $features/stringref/test_utf8 + nop + ) + (func $features/stringref/test_lossy_utf8 + nop + ) + (func $features/stringref/test_wtf8 + (local $str stringref) + (local $vl i32) + (local $vr i32) + (local $n i32) + (local $vl|4 i32) + (local $vr|5 i32) + (local $n|6 i32) + (local $a i32) + (local $b i32) + (local $9 i32) + (local $a|10 i32) + (local $b|11 i32) + (local $view stringview_wtf8) + global.get $features/stringref/utf8_data + i32.const 3 + string.new_wtf8 wtf8 + local.set $str + local.get $str + string.measure_wtf8 wtf8 + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 29 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.hash + drop + local.get $str + string.is_usv_sequence + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 31 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $str + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 32 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "abc" + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 33 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $str + string.compare + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 34 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "b" + string.compare + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 35 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "`" + string.compare + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 36 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + global.get $features/stringref/temp_data + string.encode_wtf8 wtf8 + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 37 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + block $~lib/memory/memory.compare|inlined.0 (result i32) + global.get $features/stringref/utf8_data + local.set $vl + global.get $features/stringref/temp_data + local.set $vr + i32.const 3 + local.set $n + block $~lib/util/memory/memcmp|inlined.0 (result i32) + local.get $vl + local.set $vl|4 + local.get $vr + local.set $vr|5 + local.get $n + local.set $n|6 + local.get $vl|4 + local.get $vr|5 + i32.eq + if + i32.const 0 + br $~lib/util/memory/memcmp|inlined.0 + end + i32.const 0 + i32.const 2 + i32.lt_s + drop + local.get $vl|4 + i32.const 7 + i32.and + local.get $vr|5 + i32.const 7 + i32.and + i32.eq + if + loop $while-continue|0 + local.get $vl|4 + i32.const 7 + i32.and + if + local.get $n|6 + i32.eqz + if + i32.const 0 + br $~lib/util/memory/memcmp|inlined.0 + end + local.get $vl|4 + i32.load8_u $0 + local.set $a + local.get $vr|5 + i32.load8_u $0 + local.set $b + local.get $a + local.get $b + i32.ne + if + local.get $a + local.get $b + i32.sub + br $~lib/util/memory/memcmp|inlined.0 + end + local.get $n|6 + i32.const 1 + i32.sub + local.set $n|6 + local.get $vl|4 + i32.const 1 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 1 + i32.add + local.set $vr|5 + br $while-continue|0 + end + end + block $while-break|1 + loop $while-continue|1 + local.get $n|6 + i32.const 8 + i32.ge_u + if + local.get $vl|4 + i64.load $0 + local.get $vr|5 + i64.load $0 + i64.ne + if + br $while-break|1 + end + local.get $vl|4 + i32.const 8 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 8 + i32.add + local.set $vr|5 + local.get $n|6 + i32.const 8 + i32.sub + local.set $n|6 + br $while-continue|1 + end + end + end + end + loop $while-continue|2 + local.get $n|6 + local.tee $9 + i32.const 1 + i32.sub + local.set $n|6 + local.get $9 + if + local.get $vl|4 + i32.load8_u $0 + local.set $a|10 + local.get $vr|5 + i32.load8_u $0 + local.set $b|11 + local.get $a|10 + local.get $b|11 + i32.ne + if + local.get $a|10 + local.get $b|11 + i32.sub + br $~lib/util/memory/memcmp|inlined.0 + end + local.get $vl|4 + i32.const 1 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 1 + i32.add + local.set $vr|5 + br $while-continue|2 + end + end + i32.const 0 + br $~lib/util/memory/memcmp|inlined.0 + end + br $~lib/memory/memory.compare|inlined.0 + end + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 38 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.as_wtf8 + local.set $view + local.get $view + i32.const 0 + i32.const 0 + stringview_wtf8.advance + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 41 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 0 + i32.const 1 + stringview_wtf8.advance + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 42 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 0 + i32.const 2 + stringview_wtf8.advance + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 43 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 0 + i32.const 3 + stringview_wtf8.advance + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 44 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 0 + i32.const 4 + stringview_wtf8.advance + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 45 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const -1 + i32.const 0 + stringview_wtf8.advance + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 46 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $view + i32.const 0 + i32.const 3 + stringview_wtf8.slice + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 47 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_wtf16 + (local $str stringref) + (local $vl i32) + (local $vr i32) + (local $n i32) + (local $vl|4 i32) + (local $vr|5 i32) + (local $n|6 i32) + (local $a i32) + (local $b i32) + (local $9 i32) + (local $a|10 i32) + (local $b|11 i32) + (local $view stringview_wtf16) + global.get $features/stringref/wtf16_data + i32.const 3 + string.new_wtf16 + local.set $str + local.get $str + string.measure_wtf16 + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 55 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.hash + drop + local.get $str + string.is_usv_sequence + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 57 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $str + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 58 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "abc" + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 59 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $str + string.compare + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 60 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "b" + string.compare + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 61 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.const "`" + string.compare + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 62 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + global.get $features/stringref/temp_data + string.encode_wtf16 + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 63 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + block $~lib/memory/memory.compare|inlined.1 (result i32) + global.get $features/stringref/wtf16_data + local.set $vl + global.get $features/stringref/temp_data + local.set $vr + i32.const 6 + local.set $n + block $~lib/util/memory/memcmp|inlined.1 (result i32) + local.get $vl + local.set $vl|4 + local.get $vr + local.set $vr|5 + local.get $n + local.set $n|6 + local.get $vl|4 + local.get $vr|5 + i32.eq + if + i32.const 0 + br $~lib/util/memory/memcmp|inlined.1 + end + i32.const 0 + i32.const 2 + i32.lt_s + drop + local.get $vl|4 + i32.const 7 + i32.and + local.get $vr|5 + i32.const 7 + i32.and + i32.eq + if + loop $while-continue|0 + local.get $vl|4 + i32.const 7 + i32.and + if + local.get $n|6 + i32.eqz + if + i32.const 0 + br $~lib/util/memory/memcmp|inlined.1 + end + local.get $vl|4 + i32.load8_u $0 + local.set $a + local.get $vr|5 + i32.load8_u $0 + local.set $b + local.get $a + local.get $b + i32.ne + if + local.get $a + local.get $b + i32.sub + br $~lib/util/memory/memcmp|inlined.1 + end + local.get $n|6 + i32.const 1 + i32.sub + local.set $n|6 + local.get $vl|4 + i32.const 1 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 1 + i32.add + local.set $vr|5 + br $while-continue|0 + end + end + block $while-break|1 + loop $while-continue|1 + local.get $n|6 + i32.const 8 + i32.ge_u + if + local.get $vl|4 + i64.load $0 + local.get $vr|5 + i64.load $0 + i64.ne + if + br $while-break|1 + end + local.get $vl|4 + i32.const 8 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 8 + i32.add + local.set $vr|5 + local.get $n|6 + i32.const 8 + i32.sub + local.set $n|6 + br $while-continue|1 + end + end + end + end + loop $while-continue|2 + local.get $n|6 + local.tee $9 + i32.const 1 + i32.sub + local.set $n|6 + local.get $9 + if + local.get $vl|4 + i32.load8_u $0 + local.set $a|10 + local.get $vr|5 + i32.load8_u $0 + local.set $b|11 + local.get $a|10 + local.get $b|11 + i32.ne + if + local.get $a|10 + local.get $b|11 + i32.sub + br $~lib/util/memory/memcmp|inlined.1 + end + local.get $vl|4 + i32.const 1 + i32.add + local.set $vl|4 + local.get $vr|5 + i32.const 1 + i32.add + local.set $vr|5 + br $while-continue|2 + end + end + i32.const 0 + br $~lib/util/memory/memcmp|inlined.1 + end + br $~lib/memory/memory.compare|inlined.1 + end + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 64 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + string.as_wtf16 + local.set $view + local.get $view + stringview_wtf16.length + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 67 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $str + local.get $view + i32.const 0 + i32.const 3 + stringview_wtf16.slice + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 68 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 0 + stringview_wtf16.get_codeunit + i32.const 97 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 69 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 1 + stringview_wtf16.get_codeunit + i32.const 98 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 70 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 2 + stringview_wtf16.get_codeunit + i32.const 99 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 71 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_iter + (local $str stringref) + (local $view stringview_iter) + global.get $features/stringref/wtf16_data + i32.const 3 + string.new_wtf16 + local.set $str + local.get $str + string.as_iter + local.set $view + local.get $view + stringview_iter.next + i32.const 97 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 80 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const 98 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 81 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const 99 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 82 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 83 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 1 + stringview_iter.rewind + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 84 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const 99 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 85 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 86 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const -1 + stringview_iter.rewind + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 87 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 2 + stringview_iter.advance + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 88 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const 99 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 89 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 90 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const -1 + stringview_iter.rewind + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 91 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 1 + stringview_iter.slice + i32.const 97 + string.from_code_point + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 92 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 2 + stringview_iter.slice + i32.const 97 + string.from_code_point + i32.const 98 + string.from_code_point + string.concat + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 93 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 3 + stringview_iter.slice + local.get $str + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 94 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const -1 + stringview_iter.slice + local.get $str + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 95 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + stringview_iter.next + drop + local.get $view + i32.const 1 + stringview_iter.slice + i32.const 98 + string.from_code_point + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 97 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const 2 + stringview_iter.slice + i32.const 98 + string.from_code_point + i32.const 99 + string.from_code_point + string.concat + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 98 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $view + i32.const -1 + stringview_iter.slice + i32.const 98 + string.from_code_point + i32.const 99 + string.from_code_point + string.concat + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 99 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $start:features/stringref + call $features/stringref/test_utf8 + call $features/stringref/test_lossy_utf8 + call $features/stringref/test_wtf8 + call $features/stringref/test_wtf16 + call $features/stringref/test_iter + ) + (func $~start + call $start:features/stringref + ) +) diff --git a/tests/compiler/features/stringref.json b/tests/compiler/features/stringref.json new file mode 100644 index 0000000000..4cbf3f3730 --- /dev/null +++ b/tests/compiler/features/stringref.json @@ -0,0 +1,7 @@ +{ + "asc_flags": [ + ], + "features": [ + "stringref" + ] +} diff --git a/tests/compiler/features/stringref.release.wat b/tests/compiler/features/stringref.release.wat new file mode 100644 index 0000000000..7ef5123561 --- /dev/null +++ b/tests/compiler/features/stringref.release.wat @@ -0,0 +1,846 @@ +(module + (type $none_=>_none (func)) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data $0 (i32.const 1024) "abc") + (data $1 (i32.const 1028) "a\00b\00c") + (data $3 (i32.const 1068) "<") + (data $3.1 (i32.const 1080) "\02\00\00\00*\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00s\00t\00r\00i\00n\00g\00r\00e\00f\00.\00t\00s") + (export "memory" (memory $0)) + (start $~start) + (func $features/stringref/test_wtf8 + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 stringview_wtf8) + (local $4 i32) + (local $5 i32) + (local $6 stringref) + (local $7 i32) + i32.const 1024 + i32.const 3 + string.new_wtf8 wtf8 + local.tee $6 + string.measure_wtf8 wtf8 + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 29 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.hash + drop + local.get $6 + string.is_usv_sequence + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 31 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $6 + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 32 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "abc" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 33 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $6 + string.compare + if + i32.const 0 + i32.const 1088 + i32.const 34 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "b" + string.compare + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 35 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "`" + string.compare + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 36 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + i32.const 1040 + string.encode_wtf8 wtf8 + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 37 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + i32.const 3 + local.set $1 + i32.const 1024 + local.set $5 + i32.const 1040 + local.set $4 + block $~lib/util/memory/memcmp|inlined.0 + loop $while-continue|0 + local.get $5 + i32.const 7 + i32.and + if + i32.const 0 + local.set $7 + local.get $1 + i32.eqz + br_if $~lib/util/memory/memcmp|inlined.0 + local.get $5 + i32.load8_u $0 + local.tee $2 + local.get $4 + i32.load8_u $0 + local.tee $0 + i32.sub + local.set $7 + local.get $0 + local.get $2 + i32.ne + br_if $~lib/util/memory/memcmp|inlined.0 + local.get $1 + i32.const 1 + i32.sub + local.set $1 + local.get $5 + i32.const 1 + i32.add + local.set $5 + local.get $4 + i32.const 1 + i32.add + local.set $4 + br $while-continue|0 + end + end + loop $while-continue|1 + local.get $1 + i32.const 8 + i32.ge_u + if + local.get $5 + i64.load $0 + local.get $4 + i64.load $0 + i64.eq + if + local.get $5 + i32.const 8 + i32.add + local.set $5 + local.get $4 + i32.const 8 + i32.add + local.set $4 + local.get $1 + i32.const 8 + i32.sub + local.set $1 + br $while-continue|1 + end + end + end + loop $while-continue|2 + local.get $1 + local.tee $0 + i32.const 1 + i32.sub + local.set $1 + local.get $0 + if + local.get $5 + i32.load8_u $0 + local.tee $2 + local.get $4 + i32.load8_u $0 + local.tee $0 + i32.sub + local.set $7 + local.get $0 + local.get $2 + i32.ne + br_if $~lib/util/memory/memcmp|inlined.0 + local.get $5 + i32.const 1 + i32.add + local.set $5 + local.get $4 + i32.const 1 + i32.add + local.set $4 + br $while-continue|2 + end + end + i32.const 0 + local.set $7 + end + local.get $7 + if + i32.const 0 + i32.const 1088 + i32.const 38 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.as_wtf8 + local.tee $3 + i32.const 0 + i32.const 0 + stringview_wtf8.advance + if + i32.const 0 + i32.const 1088 + i32.const 41 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const 0 + i32.const 1 + stringview_wtf8.advance + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 42 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const 0 + i32.const 2 + stringview_wtf8.advance + i32.const 2 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 43 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const 0 + i32.const 3 + stringview_wtf8.advance + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 44 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const 0 + i32.const 4 + stringview_wtf8.advance + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 45 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const -1 + i32.const 0 + stringview_wtf8.advance + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 46 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $3 + i32.const 0 + i32.const 3 + stringview_wtf8.slice + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 47 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_wtf16 + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 stringview_wtf16) + (local $6 stringref) + (local $7 i32) + i32.const 1028 + i32.const 3 + string.new_wtf16 + local.tee $6 + string.measure_wtf16 + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 55 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.hash + drop + local.get $6 + string.is_usv_sequence + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 57 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $6 + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 58 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "abc" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 59 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $6 + string.compare + if + i32.const 0 + i32.const 1088 + i32.const 60 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "b" + string.compare + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 61 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.const "`" + string.compare + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 62 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + i32.const 1040 + string.encode_wtf16 + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 63 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + i32.const 6 + local.set $1 + i32.const 1028 + local.set $4 + i32.const 1040 + local.set $3 + block $~lib/util/memory/memcmp|inlined.1 + loop $while-continue|2 + local.get $1 + local.tee $0 + i32.const 1 + i32.sub + local.set $1 + local.get $0 + if + local.get $4 + i32.load8_u $0 + local.tee $2 + local.get $3 + i32.load8_u $0 + local.tee $0 + i32.sub + local.set $7 + local.get $0 + local.get $2 + i32.ne + br_if $~lib/util/memory/memcmp|inlined.1 + local.get $4 + i32.const 1 + i32.add + local.set $4 + local.get $3 + i32.const 1 + i32.add + local.set $3 + br $while-continue|2 + end + end + i32.const 0 + local.set $7 + end + local.get $7 + if + i32.const 0 + i32.const 1088 + i32.const 64 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + string.as_wtf16 + local.tee $5 + stringview_wtf16.length + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 67 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $6 + local.get $5 + i32.const 0 + i32.const 3 + stringview_wtf16.slice + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 68 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $5 + i32.const 0 + stringview_wtf16.get_codeunit + i32.const 97 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 69 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $5 + i32.const 1 + stringview_wtf16.get_codeunit + i32.const 98 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 70 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $5 + i32.const 2 + stringview_wtf16.get_codeunit + i32.const 99 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 71 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_iter + (local $0 stringview_iter) + (local $1 stringref) + i32.const 1028 + i32.const 3 + string.new_wtf16 + local.tee $1 + string.as_iter + local.tee $0 + stringview_iter.next + i32.const 97 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 80 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const 98 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 81 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const 99 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 82 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 83 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 1 + stringview_iter.rewind + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 84 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const 99 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 85 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 86 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const -1 + stringview_iter.rewind + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 87 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 2 + stringview_iter.advance + i32.const 2 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 88 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const 99 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 89 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + i32.const -1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 90 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const -1 + stringview_iter.rewind + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 91 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 1 + stringview_iter.slice + i32.const 97 + string.from_code_point + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 92 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 2 + stringview_iter.slice + i32.const 97 + string.from_code_point + i32.const 98 + string.from_code_point + string.concat + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 93 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 3 + stringview_iter.slice + local.get $1 + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 94 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const -1 + stringview_iter.slice + local.get $1 + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 95 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + stringview_iter.next + drop + local.get $0 + i32.const 1 + stringview_iter.slice + i32.const 98 + string.from_code_point + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 97 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 2 + stringview_iter.slice + i32.const 98 + string.from_code_point + i32.const 99 + string.from_code_point + string.concat + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 98 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const -1 + stringview_iter.slice + i32.const 98 + string.from_code_point + i32.const 99 + string.from_code_point + string.concat + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 99 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $~start + call $features/stringref/test_wtf8 + call $features/stringref/test_wtf16 + call $features/stringref/test_iter + ) +) diff --git a/tests/compiler/features/stringref.ts b/tests/compiler/features/stringref.ts new file mode 100644 index 0000000000..e2df0c18be --- /dev/null +++ b/tests/compiler/features/stringref.ts @@ -0,0 +1,111 @@ +@external("env", "console.log") +declare function log_s(s: stringref): void; +@external("env", "console.log") +declare function log_i(i: i32): void; + +const utf8_data = memory.data([0x61, 0x62, 0x63]); +const wtf16_data = memory.data([0x61, 0x62, 0x63]); +const temp_data = memory.data(16); + +function test_utf8(): void { + // TODO: RuntimeError: unreachable - not yet implemented in Node? + // string.new_utf8 + // string.measure_utf8 + // string.encode_utf8 +} +test_utf8(); + +function test_lossy_utf8(): void { + // TODO: RuntimeError: unreachable - not yet implemented in Node? + // string.new_lossy_utf8 + // string.encode_lossy_utf8 + // stringview_wtf8.encode_utf8 + // stringview_wtf8.encode_lossy_utf8 +} +test_lossy_utf8(); + +function test_wtf8(): void { + let str = string.new_wtf8(utf8_data, 3); + assert(string.measure_wtf8(str) == 3); + string.hash(str); + assert(string.is_usv_sequence(str)); + assert(string.eq(str, str)); + assert(string.eq(str, string.const_("abc"))); + assert(string.compare(str, str) == 0); + assert(string.compare(str, string.const_("b")) == -1); + assert(string.compare(str, string.const_("`")) == 1); + assert(string.encode_wtf8(str, temp_data) == 3); + assert(memory.compare(utf8_data, temp_data, 3) == 0); + + let view = string.as_wtf8(str); + assert(stringview_wtf8.advance(view, 0, 0) == 0); // ^a + assert(stringview_wtf8.advance(view, 0, 1) == 1); // a^b + assert(stringview_wtf8.advance(view, 0, 2) == 2); // ab^c + assert(stringview_wtf8.advance(view, 0, 3) == 3); // abc^ + assert(stringview_wtf8.advance(view, 0, 4) == 3); // abc^ + assert(stringview_wtf8.advance(view, -1, 0) == 3); // abc^ + assert(string.eq(str, stringview_wtf8.slice(view, 0, 3))); + + // TODO: stringview_wtf8.encode_wtf8 +} +test_wtf8(); + +function test_wtf16(): void { + let str = string.new_wtf16(wtf16_data, 3); + assert(string.measure_wtf16(str) == 3); + string.hash(str); + assert(string.is_usv_sequence(str)); + assert(string.eq(str, str)); + assert(string.eq(str, string.const_("abc"))); + assert(string.compare(str, str) == 0); + assert(string.compare(str, string.const_("b")) == -1); + assert(string.compare(str, string.const_("`")) == 1); + assert(string.encode_wtf16(str, temp_data) == 3); + assert(memory.compare(wtf16_data, temp_data, 6) == 0); + + let view = string.as_wtf16(str); + assert(stringview_wtf16.length(view) == 3); + assert(string.eq(str, stringview_wtf16.slice(view, 0, 3))); + assert(stringview_wtf16.get_codeunit(view, 0) == 0x61); // a + assert(stringview_wtf16.get_codeunit(view, 1) == 0x62); // b + assert(stringview_wtf16.get_codeunit(view, 2) == 0x63); // c + + // TODO: stringview_wtf16.encode +} +test_wtf16(); + +function test_iter(): void { + let str = string.new_wtf16(wtf16_data, 3); + let view = string.as_iter(str); + assert(stringview_iter.next(view) == 0x61); + assert(stringview_iter.next(view) == 0x62); + assert(stringview_iter.next(view) == 0x63); + assert(stringview_iter.next(view) == -1); + assert(stringview_iter.rewind(view, 1) == 1); + assert(stringview_iter.next(view) == 0x63); + assert(stringview_iter.next(view) == -1); + assert(stringview_iter.rewind(view, -1) == 3); + assert(stringview_iter.advance(view, 2) == 2); + assert(stringview_iter.next(view) == 0x63); + assert(stringview_iter.next(view) == -1); + assert(stringview_iter.rewind(view, -1) == 3); + assert(string.eq(stringview_iter.slice(view, 1), string.from_code_point(0x61))); + assert(string.eq(stringview_iter.slice(view, 2), string.concat(string.from_code_point(0x61), string.from_code_point(0x62)))); + assert(string.eq(stringview_iter.slice(view, 3), str)); + assert(string.eq(stringview_iter.slice(view, -1), str)); + stringview_iter.next(view); + assert(string.eq(stringview_iter.slice(view, 1), string.from_code_point(0x62))); + assert(string.eq(stringview_iter.slice(view, 2), string.concat(string.from_code_point(0x62), string.from_code_point(0x63)))); + assert(string.eq(stringview_iter.slice(view, -1), string.concat(string.from_code_point(0x62), string.from_code_point(0x63)))); +} +test_iter(); + +// TODO: Test combined Stringref+GC instructions (needs GC types) +// string.new_utf8_array +// string.new_lossy_utf8_array +// string.new_wtf8_array +// string.new_wtf16_array +// string.encode_utf8_array +// string.encode_lossy_utf8_array +// string.encode_wtf8_array +// string.encode_wtf16_array diff --git a/tests/compiler/simd.json b/tests/compiler/simd.json index 0a393fd610..1861d3626f 100644 --- a/tests/compiler/simd.json +++ b/tests/compiler/simd.json @@ -1,5 +1,7 @@ { "asc_flags": [ - "--enable", "simd" + ], + "features": [ + "simd" ] } diff --git a/tests/features.json b/tests/features.json index 4ba0c0b4c5..f6110c2613 100644 --- a/tests/features.json +++ b/tests/features.json @@ -48,5 +48,15 @@ "v8_flags": [ "--experimental-wasm-relaxed-simd" ] + }, + "stringref": { + "asc_flags": [ + "--enable reference-types", + "--enable stringref" + ], + "v8_flags": [ + "--experimental-wasm-gc", + "--experimental-wasm-stringref" + ] } } From 84012539dea35af5f2939fee69d0335a53e89177 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 22 Apr 2023 19:31:24 +0200 Subject: [PATCH 2/9] clean --- src/common.ts | 3 -- std/assembly/builtins.ts | 62 ++++++++++++++++++++-------------------- tests/features.json | 1 - 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/common.ts b/src/common.ts index 2bd3cc8266..f5d6675edd 100644 --- a/src/common.ts +++ b/src/common.ts @@ -217,9 +217,6 @@ export namespace CommonNames { export const RefArray = "RefArray"; export const RefI31 = "RefI31"; export const RefString = "RefString"; - export const StringviewWTF8 = "StringviewWTF8"; - export const StringviewWTF16 = "StringviewWTF16"; - export const StringviewIter = "StringviewIter"; export const String = "String"; export const RegExp = "RegExp"; export const Object = "Object"; diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index a41e3ae4ff..3876ac96f7 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -2713,55 +2713,55 @@ export namespace string { export namespace stringview_wtf8 { - // @ts-ignore: decorator - @builtin - export declare function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; + // @ts-ignore: decorator + @builtin + export declare function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; - // @ts-ignore: decorator - @builtin - export declare function slice(view: stringview_wtf8, start: i32, end: i32): stringref; + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_wtf8, start: i32, end: i32): stringref; - // TODO: encode_utf8 + // TODO: encode_utf8 - // TODO: encode_lossy_utf8 + // TODO: encode_lossy_utf8 - // TODO: encode_wtf8 + // TODO: encode_wtf8 } export namespace stringview_wtf16 { - // @ts-ignore: decorator - @builtin - export declare function length(view: stringview_wtf16): i32; + // @ts-ignore: decorator + @builtin + export declare function length(view: stringview_wtf16): i32; - // @ts-ignore: decorator - @builtin - export declare function slice(view: stringview_wtf16, start: i32, end: i32): stringref; + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_wtf16, start: i32, end: i32): stringref; - // @ts-ignore: decorator - @builtin - export declare function get_codeunit(view: stringview_wtf16, pos: i32): i32; + // @ts-ignore: decorator + @builtin + export declare function get_codeunit(view: stringview_wtf16, pos: i32): i32; - // TODO: encode + // TODO: encode } export namespace stringview_iter { - // @ts-ignore: decorator - @builtin - export declare function next(view: stringview_iter): i32; + // @ts-ignore: decorator + @builtin + export declare function next(view: stringview_iter): i32; - // @ts-ignore: decorator - @builtin - export declare function advance(view: stringview_iter, count: i32): i32; + // @ts-ignore: decorator + @builtin + export declare function advance(view: stringview_iter, count: i32): i32; - // @ts-ignore: decorator - @builtin - export declare function rewind(view: stringview_iter, count: i32): i32; + // @ts-ignore: decorator + @builtin + export declare function rewind(view: stringview_iter, count: i32): i32; - // @ts-ignore: decorator - @builtin - export declare function slice(view: stringview_iter, count: i32): stringref; + // @ts-ignore: decorator + @builtin + export declare function slice(view: stringview_iter, count: i32): stringref; } /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/tests/features.json b/tests/features.json index 51ace09f97..f2e525e6f2 100644 --- a/tests/features.json +++ b/tests/features.json @@ -46,7 +46,6 @@ }, "stringref": { "asc_flags": [ - "--enable reference-types", "--enable stringref" ], "v8_flags": [ From d1e8dbd51a25468b2bbd5f38a1ede235c798d2a3 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 22 Apr 2023 19:49:07 +0200 Subject: [PATCH 3/9] update types --- std/assembly/builtins.ts | 72 +++++----- std/assembly/index.d.ts | 72 +++++----- tests/compiler/features/stringref.debug.wat | 125 +++++++++++------- tests/compiler/features/stringref.release.wat | 98 +++++++------- tests/compiler/features/stringref.ts | 19 ++- 5 files changed, 215 insertions(+), 171 deletions(-) diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 3876ac96f7..b59fb0746f 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -2600,71 +2600,71 @@ export namespace string { // @ts-ignore: decorator @builtin - export declare function const_(str: string): stringref; + export declare function const_(str: string): ref_string; // @ts-ignore: decorator @unsafe @builtin - export declare function new_utf8(ptr: usize, bytes: i32): stringref; + export declare function new_utf8(ptr: usize, bytes: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function new_utf8_array(array: arrayref, start: i32, end: i32): stringref; + export declare function new_utf8_array(array: arrayref, start: i32, end: i32): ref_string; // @ts-ignore: decorator @unsafe @builtin - export declare function new_lossy_utf8(ptr: usize, bytes: i32): stringref; + export declare function new_lossy_utf8(ptr: usize, bytes: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function new_lossy_utf8_array(array: arrayref, start: i32, end: i32): stringref; + export declare function new_lossy_utf8_array(array: ref_array, start: i32, end: i32): ref_string; // @ts-ignore: decorator @unsafe @builtin - export declare function new_wtf8(ptr: usize, bytes: i32): stringref; + export declare function new_wtf8(ptr: usize, bytes: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function new_wtf8_array(arr: arrayref, start: i32, end: i32): stringref; + export declare function new_wtf8_array(arr: ref_array, start: i32, end: i32): ref_string; // @ts-ignore: decorator @unsafe @builtin - export declare function new_wtf16(ptr: usize, units: i32): stringref; + export declare function new_wtf16(ptr: usize, units: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function new_wtf16_array(arr: arrayref, start: i32, end: i32): stringref; + export declare function new_wtf16_array(arr: ref_array, start: i32, end: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function from_code_point(codepoint: i32): stringref; + export declare function from_code_point(codepoint: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function hash(str: stringref): i32; + export declare function hash(str: ref_string): i32; // @ts-ignore: decorator @builtin - export declare function measure_utf8(str: stringref): i32; + export declare function measure_utf8(str: ref_string): i32; // @ts-ignore: decorator @builtin - export declare function measure_wtf8(str: stringref): i32; + export declare function measure_wtf8(str: ref_string): i32; // @ts-ignore: decorator @builtin - export declare function measure_wtf16(str: stringref): i32; + export declare function measure_wtf16(str: ref_string): i32; // @ts-ignore: decorator @builtin - export declare function is_usv_sequence(str: stringref): i32; + export declare function is_usv_sequence(str: ref_string): i32; // @ts-ignore: decorator @unsafe @builtin - export declare function encode_utf8(str: stringref, ptr: usize): i32; + export declare function encode_utf8(str: ref_string, ptr: usize): i32; // @ts-ignore: decorator @builtin - export declare function encode_utf8_array(str: stringref, arr: arrayref, start: i32): i32; + export declare function encode_utf8_array(str: ref_string, arr: arrayref, start: i32): i32; // TODO: encode_lossy_utf8 @@ -2672,54 +2672,54 @@ export namespace string { // @ts-ignore: decorator @unsafe @builtin - export declare function encode_wtf8(str: stringref, ptr: usize): i32; + export declare function encode_wtf8(str: ref_string, ptr: usize): i32; // @ts-ignore: decorator @builtin - export declare function encode_wtf8_array(str: stringref, arr: arrayref, start: i32): i32; + export declare function encode_wtf8_array(str: ref_string, arr: ref_array, start: i32): i32; // @ts-ignore: decorator @unsafe @builtin - export declare function encode_wtf16(str: stringref, ptr: usize): i32; + export declare function encode_wtf16(str: ref_string, ptr: usize): i32; // @ts-ignore: decorator @builtin - export declare function encode_wtf16_array(str: stringref, arr: arrayref, start: i32): i32; + export declare function encode_wtf16_array(str: ref_string, arr: ref_array, start: i32): i32; // @ts-ignore: decorator @builtin - export declare function concat(left: stringref, right: stringref): stringref; + export declare function concat(left: ref_string, right: ref_string): ref_string; // @ts-ignore: decorator @builtin - export declare function eq(left: stringref, right: stringref): bool; + export declare function eq(left: ref_string | null, right: ref_string | null): bool; // @ts-ignore: decorator @builtin - export declare function compare(left: stringref, right: stringref): i32; + export declare function compare(left: ref_string, right: ref_string): i32; // @ts-ignore: decorator @builtin - export declare function as_wtf8(str: stringref): stringview_wtf8; + export declare function as_wtf8(str: ref_string): ref_stringview_wtf8; // @ts-ignore: decorator @builtin - export declare function as_wtf16(str: stringref): stringview_wtf16; + export declare function as_wtf16(str: ref_string): ref_stringview_wtf16; // @ts-ignore: decorator @builtin - export declare function as_iter(str: stringref): stringview_iter; + export declare function as_iter(str: ref_string): ref_stringview_iter; } export namespace stringview_wtf8 { // @ts-ignore: decorator @builtin - export declare function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; + export declare function advance(view: ref_stringview_wtf8, pos: i32, bytes: i32): i32; // @ts-ignore: decorator @builtin - export declare function slice(view: stringview_wtf8, start: i32, end: i32): stringref; + export declare function slice(view: ref_stringview_wtf8, start: i32, end: i32): ref_string; // TODO: encode_utf8 @@ -2732,15 +2732,15 @@ export namespace stringview_wtf16 { // @ts-ignore: decorator @builtin - export declare function length(view: stringview_wtf16): i32; + export declare function length(view: ref_stringview_wtf16): i32; // @ts-ignore: decorator @builtin - export declare function slice(view: stringview_wtf16, start: i32, end: i32): stringref; + export declare function slice(view: ref_stringview_wtf16, start: i32, end: i32): ref_string; // @ts-ignore: decorator @builtin - export declare function get_codeunit(view: stringview_wtf16, pos: i32): i32; + export declare function get_codeunit(view: ref_stringview_wtf16, pos: i32): i32; // TODO: encode } @@ -2749,19 +2749,19 @@ export namespace stringview_iter { // @ts-ignore: decorator @builtin - export declare function next(view: stringview_iter): i32; + export declare function next(view: ref_stringview_iter): i32; // @ts-ignore: decorator @builtin - export declare function advance(view: stringview_iter, count: i32): i32; + export declare function advance(view: ref_stringview_iter, count: i32): i32; // @ts-ignore: decorator @builtin - export declare function rewind(view: stringview_iter, count: i32): i32; + export declare function rewind(view: ref_stringview_iter, count: i32): i32; // @ts-ignore: decorator @builtin - export declare function slice(view: stringview_iter, count: i32): stringref; + export declare function slice(view: ref_stringview_iter, count: i32): ref_string; } /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index ac0a91b1d0..3d4304eee2 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -1670,68 +1670,68 @@ declare abstract class i31 { declare namespace string { /** Constructs a string reference from a string literal. Temporary! */ - export function const_(str: string): stringref; + export function const_(str: string): ref_string; /** Creates a new string from memory using a strict UTF-8 decoder, decoding `bytes` bytes starting at `ptr`. */ - export function new_utf8(ptr: usize, bytes: i32): stringref; + export function new_utf8(ptr: usize, bytes: i32): ref_string; /** Creates a new string from `array` using a strict UTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ - export function new_utf8_array(array: arrayref, start: i32, end: i32): stringref; + export function new_utf8_array(array: ref_array, start: i32, end: i32): ref_string; /** Creates a new string from memory using a lossy UTF-8 decoder, decoding `bytes` bytes starting at `ptr`. */ - export function new_lossy_utf8(ptr: usize, bytes: i32): stringref; + export function new_lossy_utf8(ptr: usize, bytes: i32): ref_string; /** Creates a new string from `array` using a lossy UTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ - export function new_lossy_utf8_array(array: arrayref, start: i32, end: i32): stringref; + export function new_lossy_utf8_array(array: ref_array, start: i32, end: i32): ref_string; /** Creates a new string from memory using a strict WTF-8 decoder, decodiing `bytes` bytes starting at `ptr`. */ - export function new_wtf8(ptr: usize, bytes: i32): stringref; + export function new_wtf8(ptr: usize, bytes: i32): ref_string; /** Creates a new string from `array` using a strict WTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ - export function new_wtf8_array(array: arrayref, start: i32, end: i32): stringref; + export function new_wtf8_array(array: ref_array, start: i32, end: i32): ref_string; /** Creates a new string from memory assuming WTF-16 encoding, reading `codeunits` code units starting at `ptr`. `ptr` must be two-byte aligned. */ - export function new_wtf16(ptr: usize, codeunits: i32): stringref; + export function new_wtf16(ptr: usize, codeunits: i32): ref_string; /** Creates a new string from `array` assuming WTF-16 encoding, reading from `start` inclusive to `end` exclusive. */ - export function new_wtf16_array(array: arrayref, start: i32, end: i32): stringref; + export function new_wtf16_array(array: ref_array, start: i32, end: i32): ref_string; /** Creates a new string from the given `codepoint`. */ - export function from_code_point(codepoint: i32): stringref; + export function from_code_point(codepoint: i32): ref_string; /** Obtains an implementation-defined 32-bit hash value of `str`. */ - export function hash(str: stringref): i32; + export function hash(str: ref_string): i32; /** Measures the number of bytes required to encode `str` to UTF-8. Returns `-1` if the string contains an isolated surrogate. */ - export function measure_utf8(str: stringref): i32; + export function measure_utf8(str: ref_string): i32; /** Measures the number of bytes required to encode `str` to WTF-8. */ - export function measure_wtf8(str: stringref): i32; + export function measure_wtf8(str: ref_string): i32; /** Measures the number of 16-bit code units required to encode `str` to WTF-16. */ - export function measure_wtf16(str: stringref): i32; + export function measure_wtf16(str: ref_string): i32; /** Tests whether `str` is a sequence of Unicode scalar values, i.e. does not contain isolated surrogates. */ - export function is_usv_sequence(str: stringref): bool; + export function is_usv_sequence(str: ref_string): bool; /** Encodes `str` to memory at `ptr` using a strict UTF-8 encoder. */ - export function encode_utf8(str: stringref, ptr: usize): i32; + export function encode_utf8(str: ref_string, ptr: usize): i32; /** Encodes `str` to `arr` at `start` using a strict UTF-8 encoder. */ - export function encode_utf8_array(str: stringref, arr: arrayref, start: i32): i32; + export function encode_utf8_array(str: ref_string, arr: ref_array, start: i32): i32; // TODO: encode_lossy_utf8 // TODO: encode_lossy_utf8_array /** Encodes `str` to memory at `ptr` using a WTF-8 encoder. */ - export function encode_wtf8(str: stringref, ptr: usize): i32; + export function encode_wtf8(str: ref_string, ptr: usize): i32; /** Encodes `str` to `arr` at `start` using a WTF-8 encoder. */ - export function encode_wtf8_array(str: stringref, arr: arrayref, start: i32): i32; + export function encode_wtf8_array(str: ref_string, arr: ref_array, start: i32): i32; /** Encodes `str` to memory at `ptr` using a WTF-16 encoder. */ - export function encode_wtf16(str: stringref, ptr: usize): i32; + export function encode_wtf16(str: ref_string, ptr: usize): i32; /** Encodes `str` to `arr` at `start` using a WTF-16 encoder. */ - export function encode_wtf16_array(str: stringref, arr: arrayref, start: i32): i32; + export function encode_wtf16_array(str: ref_string, arr: arrayref, start: i32): i32; /** Concatenates `left` and `right` in this order. Traps if either operand is `null`. */ - export function concat(left: stringref, right: stringref): stringref; + export function concat(left: ref_string, right: ref_string): ref_string; /** Tests whether `left` and `right` are equal, including if both are `null`. */ - export function eq(left: stringref, right: stringref): bool; + export function eq(left: ref_string | null, right: ref_string | null): bool; /** Compares the contents of `left` and `right`, returning `-1` if `left < right`, `0` if `left == right` or `1` if `left > right`. Traps if either operand is `null`. */ - export function compare(left: stringref, right: stringref): i32; + export function compare(left: ref_string, right: ref_string): i32; /** Obtains a WTF-8 view on `str`. */ - export function as_wtf8(str: stringref): stringview_wtf8; + export function as_wtf8(str: ref_string): ref_stringview_wtf8; /** Obtains a WTF-16 view on `str`. */ - export function as_wtf16(str: stringref): stringview_wtf16; + export function as_wtf16(str: ref_string): ref_stringview_wtf16; /** Obtains an iterator view on `str`. */ - export function as_iter(str: stringref): stringview_iter; + export function as_iter(str: ref_string): ref_stringview_iter; } declare namespace stringview_wtf8 { /** Obtains the highest code point offset in `view` that is not greater than `pos + bytes`. If `pos` does not match the start of a code point, it is advanced to the next code point. */ - export function advance(view: stringview_wtf8, pos: i32, bytes: i32): i32; + export function advance(view: ref_stringview_wtf8, pos: i32, bytes: i32): i32; /** Returns a substring of `view` from `start` inclusive to `end` exclusive. If `start` or `end` do not match the start of a code point, these are advanced to the next code point. */ - export function slice(view: stringview_wtf8, start: i32, end: i32): stringref; + export function slice(view: ref_stringview_wtf8, start: i32, end: i32): ref_string; // TODO: encode_utf8 // TODO: encode_lossy_utf8 // TODO: encode_wtf8 @@ -1739,23 +1739,23 @@ declare namespace stringview_wtf8 { declare namespace stringview_wtf16 { /** Obtains the number of 16-bit code units in `view`. */ - export function length(view: stringview_wtf16): i32; + export function length(view: ref_stringview_wtf16): i32; /** Returns a substring of `view` from `start` inclusive to `end` exclusive. */ - export function slice(view: stringview_wtf16, start: i32, end: i32): stringref; + export function slice(view: ref_stringview_wtf16, start: i32, end: i32): ref_string; /** Obtains the 16-bit code unit at `pos` in `view`. Traps if `pos` is greater than or equal to the view's WTF-16 length. */ - export function get_codeunit(view: stringview_wtf16, pos: i32): i32; + export function get_codeunit(view: ref_stringview_wtf16, pos: i32): i32; // TODO: encode } declare namespace stringview_iter { /** Obtains the code point at the iterator's current position, advancing the iterator by one code point. Returns `-1` if already at the end. */ - export function next(view: stringview_iter): i32; + export function next(view: ref_stringview_iter): i32; /** Advances the iterator by up to `count` code points, returning the number of code points consumed. */ - export function advance(view: stringview_iter, count: i32): i32; + export function advance(view: ref_stringview_iter, count: i32): i32; /** Rewinds the iterator by up to `count` code points, returning the number of coode points consumed. */ - export function rewind(view: stringview_iter, count: i32): i32; + export function rewind(view: ref_stringview_iter, count: i32): i32; /** Returns a substring of `view`, starting at the current position for up to `count` code points. */ - export function slice(view: stringview_iter, count: i32): stringref; + export function slice(view: ref_stringview_iter, count: i32): ref_string; } /** Macro type evaluating to the underlying native WebAssembly type. */ diff --git a/tests/compiler/features/stringref.debug.wat b/tests/compiler/features/stringref.debug.wat index 2cb5b1a1c8..4e071d3059 100644 --- a/tests/compiler/features/stringref.debug.wat +++ b/tests/compiler/features/stringref.debug.wat @@ -2,6 +2,10 @@ (type $none_=>_none (func)) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $features/stringref/stringGlobal (mut stringref) (ref.null none)) + (global $features/stringref/stringviewWtf8Global (mut stringview_wtf8) (ref.null none)) + (global $features/stringref/stringviewWtf16Global (mut stringview_wtf16) (ref.null none)) + (global $features/stringref/stringviewIterGlobal (mut stringview_iter) (ref.null none)) (global $features/stringref/utf8_data i32 (i32.const 8)) (global $features/stringref/wtf16_data i32 (i32.const 12)) (global $features/stringref/temp_data i32 (i32.const 32)) @@ -18,6 +22,28 @@ (elem $0 (i32.const 1)) (export "memory" (memory $0)) (start $~start) + (func $features/stringref/test_locals (type $none_=>_none) + (local $stringLocal stringref) + (local $stringviewWtf8Local stringview_wtf8) + (local $stringviewWtf16Local stringview_wtf16) + (local $stringviewIterLocal stringview_iter) + ref.null none + local.set $stringLocal + ref.null none + local.set $stringLocal + ref.null none + local.set $stringviewWtf8Local + ref.null none + local.set $stringviewWtf8Local + ref.null none + local.set $stringviewWtf16Local + ref.null none + local.set $stringviewWtf16Local + ref.null none + local.set $stringviewIterLocal + ref.null none + local.set $stringviewIterLocal + ) (func $features/stringref/test_utf8 (type $none_=>_none) nop ) @@ -50,7 +76,7 @@ if i32.const 0 i32.const 80 - i32.const 29 + i32.const 46 i32.const 3 call $~lib/builtins/abort unreachable @@ -66,7 +92,7 @@ if i32.const 0 i32.const 80 - i32.const 31 + i32.const 48 i32.const 3 call $~lib/builtins/abort unreachable @@ -80,7 +106,7 @@ if i32.const 0 i32.const 80 - i32.const 32 + i32.const 49 i32.const 3 call $~lib/builtins/abort unreachable @@ -94,7 +120,7 @@ if i32.const 0 i32.const 80 - i32.const 33 + i32.const 50 i32.const 3 call $~lib/builtins/abort unreachable @@ -108,7 +134,7 @@ if i32.const 0 i32.const 80 - i32.const 34 + i32.const 51 i32.const 3 call $~lib/builtins/abort unreachable @@ -122,7 +148,7 @@ if i32.const 0 i32.const 80 - i32.const 35 + i32.const 52 i32.const 3 call $~lib/builtins/abort unreachable @@ -136,7 +162,7 @@ if i32.const 0 i32.const 80 - i32.const 36 + i32.const 53 i32.const 3 call $~lib/builtins/abort unreachable @@ -150,7 +176,7 @@ if i32.const 0 i32.const 80 - i32.const 37 + i32.const 54 i32.const 3 call $~lib/builtins/abort unreachable @@ -305,7 +331,7 @@ if i32.const 0 i32.const 80 - i32.const 38 + i32.const 55 i32.const 3 call $~lib/builtins/abort unreachable @@ -323,7 +349,7 @@ if i32.const 0 i32.const 80 - i32.const 41 + i32.const 58 i32.const 3 call $~lib/builtins/abort unreachable @@ -338,7 +364,7 @@ if i32.const 0 i32.const 80 - i32.const 42 + i32.const 59 i32.const 3 call $~lib/builtins/abort unreachable @@ -353,7 +379,7 @@ if i32.const 0 i32.const 80 - i32.const 43 + i32.const 60 i32.const 3 call $~lib/builtins/abort unreachable @@ -368,7 +394,7 @@ if i32.const 0 i32.const 80 - i32.const 44 + i32.const 61 i32.const 3 call $~lib/builtins/abort unreachable @@ -383,7 +409,7 @@ if i32.const 0 i32.const 80 - i32.const 45 + i32.const 62 i32.const 3 call $~lib/builtins/abort unreachable @@ -398,7 +424,7 @@ if i32.const 0 i32.const 80 - i32.const 46 + i32.const 63 i32.const 3 call $~lib/builtins/abort unreachable @@ -415,7 +441,7 @@ if i32.const 0 i32.const 80 - i32.const 47 + i32.const 64 i32.const 3 call $~lib/builtins/abort unreachable @@ -447,7 +473,7 @@ if i32.const 0 i32.const 80 - i32.const 55 + i32.const 72 i32.const 3 call $~lib/builtins/abort unreachable @@ -463,7 +489,7 @@ if i32.const 0 i32.const 80 - i32.const 57 + i32.const 74 i32.const 3 call $~lib/builtins/abort unreachable @@ -477,7 +503,7 @@ if i32.const 0 i32.const 80 - i32.const 58 + i32.const 75 i32.const 3 call $~lib/builtins/abort unreachable @@ -491,7 +517,7 @@ if i32.const 0 i32.const 80 - i32.const 59 + i32.const 76 i32.const 3 call $~lib/builtins/abort unreachable @@ -505,7 +531,7 @@ if i32.const 0 i32.const 80 - i32.const 60 + i32.const 77 i32.const 3 call $~lib/builtins/abort unreachable @@ -519,7 +545,7 @@ if i32.const 0 i32.const 80 - i32.const 61 + i32.const 78 i32.const 3 call $~lib/builtins/abort unreachable @@ -533,7 +559,7 @@ if i32.const 0 i32.const 80 - i32.const 62 + i32.const 79 i32.const 3 call $~lib/builtins/abort unreachable @@ -547,7 +573,7 @@ if i32.const 0 i32.const 80 - i32.const 63 + i32.const 80 i32.const 3 call $~lib/builtins/abort unreachable @@ -702,7 +728,7 @@ if i32.const 0 i32.const 80 - i32.const 64 + i32.const 81 i32.const 3 call $~lib/builtins/abort unreachable @@ -718,7 +744,7 @@ if i32.const 0 i32.const 80 - i32.const 67 + i32.const 84 i32.const 3 call $~lib/builtins/abort unreachable @@ -735,7 +761,7 @@ if i32.const 0 i32.const 80 - i32.const 68 + i32.const 85 i32.const 3 call $~lib/builtins/abort unreachable @@ -749,7 +775,7 @@ if i32.const 0 i32.const 80 - i32.const 69 + i32.const 86 i32.const 3 call $~lib/builtins/abort unreachable @@ -763,7 +789,7 @@ if i32.const 0 i32.const 80 - i32.const 70 + i32.const 87 i32.const 3 call $~lib/builtins/abort unreachable @@ -777,7 +803,7 @@ if i32.const 0 i32.const 80 - i32.const 71 + i32.const 88 i32.const 3 call $~lib/builtins/abort unreachable @@ -801,7 +827,7 @@ if i32.const 0 i32.const 80 - i32.const 80 + i32.const 97 i32.const 3 call $~lib/builtins/abort unreachable @@ -814,7 +840,7 @@ if i32.const 0 i32.const 80 - i32.const 81 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -827,7 +853,7 @@ if i32.const 0 i32.const 80 - i32.const 82 + i32.const 99 i32.const 3 call $~lib/builtins/abort unreachable @@ -840,7 +866,7 @@ if i32.const 0 i32.const 80 - i32.const 83 + i32.const 100 i32.const 3 call $~lib/builtins/abort unreachable @@ -854,7 +880,7 @@ if i32.const 0 i32.const 80 - i32.const 84 + i32.const 101 i32.const 3 call $~lib/builtins/abort unreachable @@ -867,7 +893,7 @@ if i32.const 0 i32.const 80 - i32.const 85 + i32.const 102 i32.const 3 call $~lib/builtins/abort unreachable @@ -880,7 +906,7 @@ if i32.const 0 i32.const 80 - i32.const 86 + i32.const 103 i32.const 3 call $~lib/builtins/abort unreachable @@ -894,7 +920,7 @@ if i32.const 0 i32.const 80 - i32.const 87 + i32.const 104 i32.const 3 call $~lib/builtins/abort unreachable @@ -908,7 +934,7 @@ if i32.const 0 i32.const 80 - i32.const 88 + i32.const 105 i32.const 3 call $~lib/builtins/abort unreachable @@ -921,7 +947,7 @@ if i32.const 0 i32.const 80 - i32.const 89 + i32.const 106 i32.const 3 call $~lib/builtins/abort unreachable @@ -934,7 +960,7 @@ if i32.const 0 i32.const 80 - i32.const 90 + i32.const 107 i32.const 3 call $~lib/builtins/abort unreachable @@ -948,7 +974,7 @@ if i32.const 0 i32.const 80 - i32.const 91 + i32.const 108 i32.const 3 call $~lib/builtins/abort unreachable @@ -965,7 +991,7 @@ if i32.const 0 i32.const 80 - i32.const 92 + i32.const 109 i32.const 3 call $~lib/builtins/abort unreachable @@ -985,7 +1011,7 @@ if i32.const 0 i32.const 80 - i32.const 93 + i32.const 110 i32.const 3 call $~lib/builtins/abort unreachable @@ -1001,7 +1027,7 @@ if i32.const 0 i32.const 80 - i32.const 94 + i32.const 111 i32.const 3 call $~lib/builtins/abort unreachable @@ -1017,7 +1043,7 @@ if i32.const 0 i32.const 80 - i32.const 95 + i32.const 112 i32.const 3 call $~lib/builtins/abort unreachable @@ -1037,7 +1063,7 @@ if i32.const 0 i32.const 80 - i32.const 97 + i32.const 114 i32.const 3 call $~lib/builtins/abort unreachable @@ -1057,7 +1083,7 @@ if i32.const 0 i32.const 80 - i32.const 98 + i32.const 115 i32.const 3 call $~lib/builtins/abort unreachable @@ -1077,13 +1103,14 @@ if i32.const 0 i32.const 80 - i32.const 99 + i32.const 116 i32.const 3 call $~lib/builtins/abort unreachable end ) (func $start:features/stringref (type $none_=>_none) + call $features/stringref/test_locals call $features/stringref/test_utf8 call $features/stringref/test_lossy_utf8 call $features/stringref/test_wtf8 diff --git a/tests/compiler/features/stringref.release.wat b/tests/compiler/features/stringref.release.wat index f83d2517a3..ae0208937d 100644 --- a/tests/compiler/features/stringref.release.wat +++ b/tests/compiler/features/stringref.release.wat @@ -28,7 +28,7 @@ if i32.const 0 i32.const 1088 - i32.const 29 + i32.const 46 i32.const 3 call $~lib/builtins/abort unreachable @@ -42,7 +42,7 @@ if i32.const 0 i32.const 1088 - i32.const 31 + i32.const 48 i32.const 3 call $~lib/builtins/abort unreachable @@ -54,7 +54,7 @@ if i32.const 0 i32.const 1088 - i32.const 32 + i32.const 49 i32.const 3 call $~lib/builtins/abort unreachable @@ -66,7 +66,7 @@ if i32.const 0 i32.const 1088 - i32.const 33 + i32.const 50 i32.const 3 call $~lib/builtins/abort unreachable @@ -77,7 +77,7 @@ if i32.const 0 i32.const 1088 - i32.const 34 + i32.const 51 i32.const 3 call $~lib/builtins/abort unreachable @@ -90,7 +90,7 @@ if i32.const 0 i32.const 1088 - i32.const 35 + i32.const 52 i32.const 3 call $~lib/builtins/abort unreachable @@ -103,7 +103,7 @@ if i32.const 0 i32.const 1088 - i32.const 36 + i32.const 53 i32.const 3 call $~lib/builtins/abort unreachable @@ -116,7 +116,7 @@ if i32.const 0 i32.const 1088 - i32.const 37 + i32.const 54 i32.const 3 call $~lib/builtins/abort unreachable @@ -230,7 +230,7 @@ if i32.const 0 i32.const 1088 - i32.const 38 + i32.const 55 i32.const 3 call $~lib/builtins/abort unreachable @@ -244,7 +244,7 @@ if i32.const 0 i32.const 1088 - i32.const 41 + i32.const 58 i32.const 3 call $~lib/builtins/abort unreachable @@ -258,7 +258,7 @@ if i32.const 0 i32.const 1088 - i32.const 42 + i32.const 59 i32.const 3 call $~lib/builtins/abort unreachable @@ -272,7 +272,7 @@ if i32.const 0 i32.const 1088 - i32.const 43 + i32.const 60 i32.const 3 call $~lib/builtins/abort unreachable @@ -286,7 +286,7 @@ if i32.const 0 i32.const 1088 - i32.const 44 + i32.const 61 i32.const 3 call $~lib/builtins/abort unreachable @@ -300,7 +300,7 @@ if i32.const 0 i32.const 1088 - i32.const 45 + i32.const 62 i32.const 3 call $~lib/builtins/abort unreachable @@ -314,7 +314,7 @@ if i32.const 0 i32.const 1088 - i32.const 46 + i32.const 63 i32.const 3 call $~lib/builtins/abort unreachable @@ -329,7 +329,7 @@ if i32.const 0 i32.const 1088 - i32.const 47 + i32.const 64 i32.const 3 call $~lib/builtins/abort unreachable @@ -354,7 +354,7 @@ if i32.const 0 i32.const 1088 - i32.const 55 + i32.const 72 i32.const 3 call $~lib/builtins/abort unreachable @@ -368,7 +368,7 @@ if i32.const 0 i32.const 1088 - i32.const 57 + i32.const 74 i32.const 3 call $~lib/builtins/abort unreachable @@ -380,7 +380,7 @@ if i32.const 0 i32.const 1088 - i32.const 58 + i32.const 75 i32.const 3 call $~lib/builtins/abort unreachable @@ -392,7 +392,7 @@ if i32.const 0 i32.const 1088 - i32.const 59 + i32.const 76 i32.const 3 call $~lib/builtins/abort unreachable @@ -403,7 +403,7 @@ if i32.const 0 i32.const 1088 - i32.const 60 + i32.const 77 i32.const 3 call $~lib/builtins/abort unreachable @@ -416,7 +416,7 @@ if i32.const 0 i32.const 1088 - i32.const 61 + i32.const 78 i32.const 3 call $~lib/builtins/abort unreachable @@ -429,7 +429,7 @@ if i32.const 0 i32.const 1088 - i32.const 62 + i32.const 79 i32.const 3 call $~lib/builtins/abort unreachable @@ -442,7 +442,7 @@ if i32.const 0 i32.const 1088 - i32.const 63 + i32.const 80 i32.const 3 call $~lib/builtins/abort unreachable @@ -492,7 +492,7 @@ if i32.const 0 i32.const 1088 - i32.const 64 + i32.const 81 i32.const 3 call $~lib/builtins/abort unreachable @@ -506,7 +506,7 @@ if i32.const 0 i32.const 1088 - i32.const 67 + i32.const 84 i32.const 3 call $~lib/builtins/abort unreachable @@ -521,7 +521,7 @@ if i32.const 0 i32.const 1088 - i32.const 68 + i32.const 85 i32.const 3 call $~lib/builtins/abort unreachable @@ -534,7 +534,7 @@ if i32.const 0 i32.const 1088 - i32.const 69 + i32.const 86 i32.const 3 call $~lib/builtins/abort unreachable @@ -547,7 +547,7 @@ if i32.const 0 i32.const 1088 - i32.const 70 + i32.const 87 i32.const 3 call $~lib/builtins/abort unreachable @@ -560,7 +560,7 @@ if i32.const 0 i32.const 1088 - i32.const 71 + i32.const 88 i32.const 3 call $~lib/builtins/abort unreachable @@ -581,7 +581,7 @@ if i32.const 0 i32.const 1088 - i32.const 80 + i32.const 97 i32.const 3 call $~lib/builtins/abort unreachable @@ -593,7 +593,7 @@ if i32.const 0 i32.const 1088 - i32.const 81 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -605,7 +605,7 @@ if i32.const 0 i32.const 1088 - i32.const 82 + i32.const 99 i32.const 3 call $~lib/builtins/abort unreachable @@ -617,7 +617,7 @@ if i32.const 0 i32.const 1088 - i32.const 83 + i32.const 100 i32.const 3 call $~lib/builtins/abort unreachable @@ -630,7 +630,7 @@ if i32.const 0 i32.const 1088 - i32.const 84 + i32.const 101 i32.const 3 call $~lib/builtins/abort unreachable @@ -642,7 +642,7 @@ if i32.const 0 i32.const 1088 - i32.const 85 + i32.const 102 i32.const 3 call $~lib/builtins/abort unreachable @@ -654,7 +654,7 @@ if i32.const 0 i32.const 1088 - i32.const 86 + i32.const 103 i32.const 3 call $~lib/builtins/abort unreachable @@ -667,7 +667,7 @@ if i32.const 0 i32.const 1088 - i32.const 87 + i32.const 104 i32.const 3 call $~lib/builtins/abort unreachable @@ -680,7 +680,7 @@ if i32.const 0 i32.const 1088 - i32.const 88 + i32.const 105 i32.const 3 call $~lib/builtins/abort unreachable @@ -692,7 +692,7 @@ if i32.const 0 i32.const 1088 - i32.const 89 + i32.const 106 i32.const 3 call $~lib/builtins/abort unreachable @@ -704,7 +704,7 @@ if i32.const 0 i32.const 1088 - i32.const 90 + i32.const 107 i32.const 3 call $~lib/builtins/abort unreachable @@ -717,7 +717,7 @@ if i32.const 0 i32.const 1088 - i32.const 91 + i32.const 108 i32.const 3 call $~lib/builtins/abort unreachable @@ -732,7 +732,7 @@ if i32.const 0 i32.const 1088 - i32.const 92 + i32.const 109 i32.const 3 call $~lib/builtins/abort unreachable @@ -750,7 +750,7 @@ if i32.const 0 i32.const 1088 - i32.const 93 + i32.const 110 i32.const 3 call $~lib/builtins/abort unreachable @@ -764,7 +764,7 @@ if i32.const 0 i32.const 1088 - i32.const 94 + i32.const 111 i32.const 3 call $~lib/builtins/abort unreachable @@ -778,7 +778,7 @@ if i32.const 0 i32.const 1088 - i32.const 95 + i32.const 112 i32.const 3 call $~lib/builtins/abort unreachable @@ -796,7 +796,7 @@ if i32.const 0 i32.const 1088 - i32.const 97 + i32.const 114 i32.const 3 call $~lib/builtins/abort unreachable @@ -814,7 +814,7 @@ if i32.const 0 i32.const 1088 - i32.const 98 + i32.const 115 i32.const 3 call $~lib/builtins/abort unreachable @@ -832,7 +832,7 @@ if i32.const 0 i32.const 1088 - i32.const 99 + i32.const 116 i32.const 3 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/features/stringref.ts b/tests/compiler/features/stringref.ts index e2df0c18be..996a79b9cc 100644 --- a/tests/compiler/features/stringref.ts +++ b/tests/compiler/features/stringref.ts @@ -1,8 +1,25 @@ @external("env", "console.log") -declare function log_s(s: stringref): void; +declare function log_s(s: ref_string | null): void; @external("env", "console.log") declare function log_i(i: i32): void; +let stringGlobal: ref_string | null = null; +let stringviewWtf8Global: ref_stringview_wtf8 | null = null; +let stringviewWtf16Global: ref_stringview_wtf16 | null = null; +let stringviewIterGlobal: ref_stringview_iter | null = null; + +function test_locals(): void { + let stringLocal: ref_string | null = null; + stringLocal = null; + let stringviewWtf8Local: ref_stringview_wtf8 | null = null; + stringviewWtf8Local = null; + let stringviewWtf16Local: ref_stringview_wtf16 | null = null; + stringviewWtf16Local = null; + let stringviewIterLocal: ref_stringview_iter | null = null; + stringviewIterLocal = null; +} +test_locals(); + const utf8_data = memory.data([0x61, 0x62, 0x63]); const wtf16_data = memory.data([0x61, 0x62, 0x63]); const temp_data = memory.data(16); From a9e874aba8d15d032119285ed38f5d7d9517c873 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 22 Apr 2023 20:08:54 +0200 Subject: [PATCH 4/9] constant string.const, more global/local tests --- src/module.ts | 3 +- tests/compiler/features/stringref.debug.wat | 150 +++++++++++------- tests/compiler/features/stringref.release.wat | 107 +++++++------ tests/compiler/features/stringref.ts | 38 +++-- 4 files changed, 175 insertions(+), 123 deletions(-) diff --git a/src/module.ts b/src/module.ts index 0d4ac44da4..f5f27cf7c3 100644 --- a/src/module.ts +++ b/src/module.ts @@ -3221,7 +3221,8 @@ export class Module { case ExpressionId.Const: case ExpressionId.RefNull: case ExpressionId.RefFunc: - case ExpressionId.I31New: return true; + case ExpressionId.I31New: + case ExpressionId.StringConst: return true; case ExpressionId.Binary: { if (this.getFeatures() & FeatureFlags.ExtendedConst) { switch (getBinaryOp(expr)) { diff --git a/tests/compiler/features/stringref.debug.wat b/tests/compiler/features/stringref.debug.wat index 4e071d3059..572600ffd1 100644 --- a/tests/compiler/features/stringref.debug.wat +++ b/tests/compiler/features/stringref.debug.wat @@ -2,7 +2,11 @@ (type $none_=>_none (func)) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) - (global $features/stringref/stringGlobal (mut stringref) (ref.null none)) + (global $features/stringref/stringGlobalNull (mut stringref) (ref.null none)) + (global $features/stringref/stringviewWtf8GlobalNull (mut stringview_wtf8) (ref.null none)) + (global $features/stringref/stringviewWtf16GlobalNull (mut stringview_wtf16) (ref.null none)) + (global $features/stringref/stringviewIterGlobalNull (mut stringview_iter) (ref.null none)) + (global $features/stringref/stringGlobal (mut (ref string)) (string.const "")) (global $features/stringref/stringviewWtf8Global (mut stringview_wtf8) (ref.null none)) (global $features/stringref/stringviewWtf16Global (mut stringview_wtf16) (ref.null none)) (global $features/stringref/stringviewIterGlobal (mut stringview_iter) (ref.null none)) @@ -23,25 +27,40 @@ (export "memory" (memory $0)) (start $~start) (func $features/stringref/test_locals (type $none_=>_none) - (local $stringLocal stringref) - (local $stringviewWtf8Local stringview_wtf8) - (local $stringviewWtf16Local stringview_wtf16) - (local $stringviewIterLocal stringview_iter) + (local $stringLocalNull stringref) + (local $stringviewWtf8LocalNull stringview_wtf8) + (local $stringviewWtf16LocalNull stringview_wtf16) + (local $stringviewIterLocalNull stringview_iter) + (local $stringLocal (ref string)) + (local $stringviewWtf8Local (ref stringview_wtf8)) + (local $stringviewWtf16Local (ref stringview_wtf16)) + (local $stringviewIterLocal (ref stringview_iter)) ref.null none - local.set $stringLocal + local.set $stringLocalNull ref.null none - local.set $stringLocal + local.set $stringLocalNull ref.null none - local.set $stringviewWtf8Local + local.set $stringviewWtf8LocalNull ref.null none - local.set $stringviewWtf8Local + local.set $stringviewWtf8LocalNull ref.null none - local.set $stringviewWtf16Local + local.set $stringviewWtf16LocalNull ref.null none - local.set $stringviewWtf16Local + local.set $stringviewWtf16LocalNull ref.null none - local.set $stringviewIterLocal + local.set $stringviewIterLocalNull ref.null none + local.set $stringviewIterLocalNull + string.const "" + local.set $stringLocal + local.get $stringLocal + string.as_wtf8 + local.set $stringviewWtf8Local + local.get $stringLocal + string.as_wtf16 + local.set $stringviewWtf16Local + local.get $stringLocal + string.as_iter local.set $stringviewIterLocal ) (func $features/stringref/test_utf8 (type $none_=>_none) @@ -76,7 +95,7 @@ if i32.const 0 i32.const 80 - i32.const 46 + i32.const 60 i32.const 3 call $~lib/builtins/abort unreachable @@ -92,7 +111,7 @@ if i32.const 0 i32.const 80 - i32.const 48 + i32.const 62 i32.const 3 call $~lib/builtins/abort unreachable @@ -106,7 +125,7 @@ if i32.const 0 i32.const 80 - i32.const 49 + i32.const 63 i32.const 3 call $~lib/builtins/abort unreachable @@ -120,7 +139,7 @@ if i32.const 0 i32.const 80 - i32.const 50 + i32.const 64 i32.const 3 call $~lib/builtins/abort unreachable @@ -134,7 +153,7 @@ if i32.const 0 i32.const 80 - i32.const 51 + i32.const 65 i32.const 3 call $~lib/builtins/abort unreachable @@ -148,7 +167,7 @@ if i32.const 0 i32.const 80 - i32.const 52 + i32.const 66 i32.const 3 call $~lib/builtins/abort unreachable @@ -162,7 +181,7 @@ if i32.const 0 i32.const 80 - i32.const 53 + i32.const 67 i32.const 3 call $~lib/builtins/abort unreachable @@ -176,7 +195,7 @@ if i32.const 0 i32.const 80 - i32.const 54 + i32.const 68 i32.const 3 call $~lib/builtins/abort unreachable @@ -331,7 +350,7 @@ if i32.const 0 i32.const 80 - i32.const 55 + i32.const 69 i32.const 3 call $~lib/builtins/abort unreachable @@ -349,7 +368,7 @@ if i32.const 0 i32.const 80 - i32.const 58 + i32.const 72 i32.const 3 call $~lib/builtins/abort unreachable @@ -364,7 +383,7 @@ if i32.const 0 i32.const 80 - i32.const 59 + i32.const 73 i32.const 3 call $~lib/builtins/abort unreachable @@ -379,7 +398,7 @@ if i32.const 0 i32.const 80 - i32.const 60 + i32.const 74 i32.const 3 call $~lib/builtins/abort unreachable @@ -394,7 +413,7 @@ if i32.const 0 i32.const 80 - i32.const 61 + i32.const 75 i32.const 3 call $~lib/builtins/abort unreachable @@ -409,7 +428,7 @@ if i32.const 0 i32.const 80 - i32.const 62 + i32.const 76 i32.const 3 call $~lib/builtins/abort unreachable @@ -424,7 +443,7 @@ if i32.const 0 i32.const 80 - i32.const 63 + i32.const 77 i32.const 3 call $~lib/builtins/abort unreachable @@ -441,7 +460,7 @@ if i32.const 0 i32.const 80 - i32.const 64 + i32.const 78 i32.const 3 call $~lib/builtins/abort unreachable @@ -473,7 +492,7 @@ if i32.const 0 i32.const 80 - i32.const 72 + i32.const 86 i32.const 3 call $~lib/builtins/abort unreachable @@ -489,7 +508,7 @@ if i32.const 0 i32.const 80 - i32.const 74 + i32.const 88 i32.const 3 call $~lib/builtins/abort unreachable @@ -503,7 +522,7 @@ if i32.const 0 i32.const 80 - i32.const 75 + i32.const 89 i32.const 3 call $~lib/builtins/abort unreachable @@ -517,7 +536,7 @@ if i32.const 0 i32.const 80 - i32.const 76 + i32.const 90 i32.const 3 call $~lib/builtins/abort unreachable @@ -531,7 +550,7 @@ if i32.const 0 i32.const 80 - i32.const 77 + i32.const 91 i32.const 3 call $~lib/builtins/abort unreachable @@ -545,7 +564,7 @@ if i32.const 0 i32.const 80 - i32.const 78 + i32.const 92 i32.const 3 call $~lib/builtins/abort unreachable @@ -559,7 +578,7 @@ if i32.const 0 i32.const 80 - i32.const 79 + i32.const 93 i32.const 3 call $~lib/builtins/abort unreachable @@ -573,7 +592,7 @@ if i32.const 0 i32.const 80 - i32.const 80 + i32.const 94 i32.const 3 call $~lib/builtins/abort unreachable @@ -728,7 +747,7 @@ if i32.const 0 i32.const 80 - i32.const 81 + i32.const 95 i32.const 3 call $~lib/builtins/abort unreachable @@ -744,7 +763,7 @@ if i32.const 0 i32.const 80 - i32.const 84 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -761,7 +780,7 @@ if i32.const 0 i32.const 80 - i32.const 85 + i32.const 99 i32.const 3 call $~lib/builtins/abort unreachable @@ -775,7 +794,7 @@ if i32.const 0 i32.const 80 - i32.const 86 + i32.const 100 i32.const 3 call $~lib/builtins/abort unreachable @@ -789,7 +808,7 @@ if i32.const 0 i32.const 80 - i32.const 87 + i32.const 101 i32.const 3 call $~lib/builtins/abort unreachable @@ -803,7 +822,7 @@ if i32.const 0 i32.const 80 - i32.const 88 + i32.const 102 i32.const 3 call $~lib/builtins/abort unreachable @@ -827,7 +846,7 @@ if i32.const 0 i32.const 80 - i32.const 97 + i32.const 111 i32.const 3 call $~lib/builtins/abort unreachable @@ -840,7 +859,7 @@ if i32.const 0 i32.const 80 - i32.const 98 + i32.const 112 i32.const 3 call $~lib/builtins/abort unreachable @@ -853,7 +872,7 @@ if i32.const 0 i32.const 80 - i32.const 99 + i32.const 113 i32.const 3 call $~lib/builtins/abort unreachable @@ -866,7 +885,7 @@ if i32.const 0 i32.const 80 - i32.const 100 + i32.const 114 i32.const 3 call $~lib/builtins/abort unreachable @@ -880,7 +899,7 @@ if i32.const 0 i32.const 80 - i32.const 101 + i32.const 115 i32.const 3 call $~lib/builtins/abort unreachable @@ -893,7 +912,7 @@ if i32.const 0 i32.const 80 - i32.const 102 + i32.const 116 i32.const 3 call $~lib/builtins/abort unreachable @@ -906,7 +925,7 @@ if i32.const 0 i32.const 80 - i32.const 103 + i32.const 117 i32.const 3 call $~lib/builtins/abort unreachable @@ -920,7 +939,7 @@ if i32.const 0 i32.const 80 - i32.const 104 + i32.const 118 i32.const 3 call $~lib/builtins/abort unreachable @@ -934,7 +953,7 @@ if i32.const 0 i32.const 80 - i32.const 105 + i32.const 119 i32.const 3 call $~lib/builtins/abort unreachable @@ -947,7 +966,7 @@ if i32.const 0 i32.const 80 - i32.const 106 + i32.const 120 i32.const 3 call $~lib/builtins/abort unreachable @@ -960,7 +979,7 @@ if i32.const 0 i32.const 80 - i32.const 107 + i32.const 121 i32.const 3 call $~lib/builtins/abort unreachable @@ -974,7 +993,7 @@ if i32.const 0 i32.const 80 - i32.const 108 + i32.const 122 i32.const 3 call $~lib/builtins/abort unreachable @@ -991,7 +1010,7 @@ if i32.const 0 i32.const 80 - i32.const 109 + i32.const 123 i32.const 3 call $~lib/builtins/abort unreachable @@ -1011,7 +1030,7 @@ if i32.const 0 i32.const 80 - i32.const 110 + i32.const 124 i32.const 3 call $~lib/builtins/abort unreachable @@ -1027,7 +1046,7 @@ if i32.const 0 i32.const 80 - i32.const 111 + i32.const 125 i32.const 3 call $~lib/builtins/abort unreachable @@ -1043,7 +1062,7 @@ if i32.const 0 i32.const 80 - i32.const 112 + i32.const 126 i32.const 3 call $~lib/builtins/abort unreachable @@ -1063,7 +1082,7 @@ if i32.const 0 i32.const 80 - i32.const 114 + i32.const 128 i32.const 3 call $~lib/builtins/abort unreachable @@ -1083,7 +1102,7 @@ if i32.const 0 i32.const 80 - i32.const 115 + i32.const 129 i32.const 3 call $~lib/builtins/abort unreachable @@ -1103,13 +1122,22 @@ if i32.const 0 i32.const 80 - i32.const 116 + i32.const 130 i32.const 3 call $~lib/builtins/abort unreachable end ) (func $start:features/stringref (type $none_=>_none) + global.get $features/stringref/stringGlobal + string.as_wtf8 + global.set $features/stringref/stringviewWtf8Global + global.get $features/stringref/stringGlobal + string.as_wtf16 + global.set $features/stringref/stringviewWtf16Global + global.get $features/stringref/stringGlobal + string.as_iter + global.set $features/stringref/stringviewIterGlobal call $features/stringref/test_locals call $features/stringref/test_utf8 call $features/stringref/test_lossy_utf8 diff --git a/tests/compiler/features/stringref.release.wat b/tests/compiler/features/stringref.release.wat index ae0208937d..d367025606 100644 --- a/tests/compiler/features/stringref.release.wat +++ b/tests/compiler/features/stringref.release.wat @@ -28,7 +28,7 @@ if i32.const 0 i32.const 1088 - i32.const 46 + i32.const 60 i32.const 3 call $~lib/builtins/abort unreachable @@ -42,7 +42,7 @@ if i32.const 0 i32.const 1088 - i32.const 48 + i32.const 62 i32.const 3 call $~lib/builtins/abort unreachable @@ -54,7 +54,7 @@ if i32.const 0 i32.const 1088 - i32.const 49 + i32.const 63 i32.const 3 call $~lib/builtins/abort unreachable @@ -66,7 +66,7 @@ if i32.const 0 i32.const 1088 - i32.const 50 + i32.const 64 i32.const 3 call $~lib/builtins/abort unreachable @@ -77,7 +77,7 @@ if i32.const 0 i32.const 1088 - i32.const 51 + i32.const 65 i32.const 3 call $~lib/builtins/abort unreachable @@ -90,7 +90,7 @@ if i32.const 0 i32.const 1088 - i32.const 52 + i32.const 66 i32.const 3 call $~lib/builtins/abort unreachable @@ -103,7 +103,7 @@ if i32.const 0 i32.const 1088 - i32.const 53 + i32.const 67 i32.const 3 call $~lib/builtins/abort unreachable @@ -116,7 +116,7 @@ if i32.const 0 i32.const 1088 - i32.const 54 + i32.const 68 i32.const 3 call $~lib/builtins/abort unreachable @@ -230,7 +230,7 @@ if i32.const 0 i32.const 1088 - i32.const 55 + i32.const 69 i32.const 3 call $~lib/builtins/abort unreachable @@ -244,7 +244,7 @@ if i32.const 0 i32.const 1088 - i32.const 58 + i32.const 72 i32.const 3 call $~lib/builtins/abort unreachable @@ -258,7 +258,7 @@ if i32.const 0 i32.const 1088 - i32.const 59 + i32.const 73 i32.const 3 call $~lib/builtins/abort unreachable @@ -272,7 +272,7 @@ if i32.const 0 i32.const 1088 - i32.const 60 + i32.const 74 i32.const 3 call $~lib/builtins/abort unreachable @@ -286,7 +286,7 @@ if i32.const 0 i32.const 1088 - i32.const 61 + i32.const 75 i32.const 3 call $~lib/builtins/abort unreachable @@ -300,7 +300,7 @@ if i32.const 0 i32.const 1088 - i32.const 62 + i32.const 76 i32.const 3 call $~lib/builtins/abort unreachable @@ -314,7 +314,7 @@ if i32.const 0 i32.const 1088 - i32.const 63 + i32.const 77 i32.const 3 call $~lib/builtins/abort unreachable @@ -329,7 +329,7 @@ if i32.const 0 i32.const 1088 - i32.const 64 + i32.const 78 i32.const 3 call $~lib/builtins/abort unreachable @@ -354,7 +354,7 @@ if i32.const 0 i32.const 1088 - i32.const 72 + i32.const 86 i32.const 3 call $~lib/builtins/abort unreachable @@ -368,7 +368,7 @@ if i32.const 0 i32.const 1088 - i32.const 74 + i32.const 88 i32.const 3 call $~lib/builtins/abort unreachable @@ -380,7 +380,7 @@ if i32.const 0 i32.const 1088 - i32.const 75 + i32.const 89 i32.const 3 call $~lib/builtins/abort unreachable @@ -392,7 +392,7 @@ if i32.const 0 i32.const 1088 - i32.const 76 + i32.const 90 i32.const 3 call $~lib/builtins/abort unreachable @@ -403,7 +403,7 @@ if i32.const 0 i32.const 1088 - i32.const 77 + i32.const 91 i32.const 3 call $~lib/builtins/abort unreachable @@ -416,7 +416,7 @@ if i32.const 0 i32.const 1088 - i32.const 78 + i32.const 92 i32.const 3 call $~lib/builtins/abort unreachable @@ -429,7 +429,7 @@ if i32.const 0 i32.const 1088 - i32.const 79 + i32.const 93 i32.const 3 call $~lib/builtins/abort unreachable @@ -442,7 +442,7 @@ if i32.const 0 i32.const 1088 - i32.const 80 + i32.const 94 i32.const 3 call $~lib/builtins/abort unreachable @@ -492,7 +492,7 @@ if i32.const 0 i32.const 1088 - i32.const 81 + i32.const 95 i32.const 3 call $~lib/builtins/abort unreachable @@ -506,7 +506,7 @@ if i32.const 0 i32.const 1088 - i32.const 84 + i32.const 98 i32.const 3 call $~lib/builtins/abort unreachable @@ -521,7 +521,7 @@ if i32.const 0 i32.const 1088 - i32.const 85 + i32.const 99 i32.const 3 call $~lib/builtins/abort unreachable @@ -534,7 +534,7 @@ if i32.const 0 i32.const 1088 - i32.const 86 + i32.const 100 i32.const 3 call $~lib/builtins/abort unreachable @@ -547,7 +547,7 @@ if i32.const 0 i32.const 1088 - i32.const 87 + i32.const 101 i32.const 3 call $~lib/builtins/abort unreachable @@ -560,7 +560,7 @@ if i32.const 0 i32.const 1088 - i32.const 88 + i32.const 102 i32.const 3 call $~lib/builtins/abort unreachable @@ -581,7 +581,7 @@ if i32.const 0 i32.const 1088 - i32.const 97 + i32.const 111 i32.const 3 call $~lib/builtins/abort unreachable @@ -593,7 +593,7 @@ if i32.const 0 i32.const 1088 - i32.const 98 + i32.const 112 i32.const 3 call $~lib/builtins/abort unreachable @@ -605,7 +605,7 @@ if i32.const 0 i32.const 1088 - i32.const 99 + i32.const 113 i32.const 3 call $~lib/builtins/abort unreachable @@ -617,7 +617,7 @@ if i32.const 0 i32.const 1088 - i32.const 100 + i32.const 114 i32.const 3 call $~lib/builtins/abort unreachable @@ -630,7 +630,7 @@ if i32.const 0 i32.const 1088 - i32.const 101 + i32.const 115 i32.const 3 call $~lib/builtins/abort unreachable @@ -642,7 +642,7 @@ if i32.const 0 i32.const 1088 - i32.const 102 + i32.const 116 i32.const 3 call $~lib/builtins/abort unreachable @@ -654,7 +654,7 @@ if i32.const 0 i32.const 1088 - i32.const 103 + i32.const 117 i32.const 3 call $~lib/builtins/abort unreachable @@ -667,7 +667,7 @@ if i32.const 0 i32.const 1088 - i32.const 104 + i32.const 118 i32.const 3 call $~lib/builtins/abort unreachable @@ -680,7 +680,7 @@ if i32.const 0 i32.const 1088 - i32.const 105 + i32.const 119 i32.const 3 call $~lib/builtins/abort unreachable @@ -692,7 +692,7 @@ if i32.const 0 i32.const 1088 - i32.const 106 + i32.const 120 i32.const 3 call $~lib/builtins/abort unreachable @@ -704,7 +704,7 @@ if i32.const 0 i32.const 1088 - i32.const 107 + i32.const 121 i32.const 3 call $~lib/builtins/abort unreachable @@ -717,7 +717,7 @@ if i32.const 0 i32.const 1088 - i32.const 108 + i32.const 122 i32.const 3 call $~lib/builtins/abort unreachable @@ -732,7 +732,7 @@ if i32.const 0 i32.const 1088 - i32.const 109 + i32.const 123 i32.const 3 call $~lib/builtins/abort unreachable @@ -750,7 +750,7 @@ if i32.const 0 i32.const 1088 - i32.const 110 + i32.const 124 i32.const 3 call $~lib/builtins/abort unreachable @@ -764,7 +764,7 @@ if i32.const 0 i32.const 1088 - i32.const 111 + i32.const 125 i32.const 3 call $~lib/builtins/abort unreachable @@ -778,7 +778,7 @@ if i32.const 0 i32.const 1088 - i32.const 112 + i32.const 126 i32.const 3 call $~lib/builtins/abort unreachable @@ -796,7 +796,7 @@ if i32.const 0 i32.const 1088 - i32.const 114 + i32.const 128 i32.const 3 call $~lib/builtins/abort unreachable @@ -814,7 +814,7 @@ if i32.const 0 i32.const 1088 - i32.const 115 + i32.const 129 i32.const 3 call $~lib/builtins/abort unreachable @@ -832,13 +832,22 @@ if i32.const 0 i32.const 1088 - i32.const 116 + i32.const 130 i32.const 3 call $~lib/builtins/abort unreachable end ) (func $~start (type $none_=>_none) + string.const "" + string.as_wtf8 + drop + string.const "" + string.as_wtf16 + drop + string.const "" + string.as_iter + drop call $features/stringref/test_wtf8 call $features/stringref/test_wtf16 call $features/stringref/test_iter diff --git a/tests/compiler/features/stringref.ts b/tests/compiler/features/stringref.ts index 996a79b9cc..5054d666b4 100644 --- a/tests/compiler/features/stringref.ts +++ b/tests/compiler/features/stringref.ts @@ -3,20 +3,34 @@ declare function log_s(s: ref_string | null): void; @external("env", "console.log") declare function log_i(i: i32): void; -let stringGlobal: ref_string | null = null; -let stringviewWtf8Global: ref_stringview_wtf8 | null = null; -let stringviewWtf16Global: ref_stringview_wtf16 | null = null; -let stringviewIterGlobal: ref_stringview_iter | null = null; +let stringGlobalNull: ref_string | null = null; +let stringviewWtf8GlobalNull: ref_stringview_wtf8 | null = null; +let stringviewWtf16GlobalNull: ref_stringview_wtf16 | null = null; +let stringviewIterGlobalNull: ref_stringview_iter | null = null; + +let stringGlobal: ref_string = string.const_(""); +let stringviewWtf8Global: ref_stringview_wtf8 = string.as_wtf8(stringGlobal); // internally nullable +let stringviewWtf16Global: ref_stringview_wtf16 = string.as_wtf16(stringGlobal); // internally nullable +let stringviewIterGlobal: ref_stringview_iter = string.as_iter(stringGlobal); // internally nullable function test_locals(): void { - let stringLocal: ref_string | null = null; - stringLocal = null; - let stringviewWtf8Local: ref_stringview_wtf8 | null = null; - stringviewWtf8Local = null; - let stringviewWtf16Local: ref_stringview_wtf16 | null = null; - stringviewWtf16Local = null; - let stringviewIterLocal: ref_stringview_iter | null = null; - stringviewIterLocal = null; + let stringLocalNull: ref_string | null = null; + stringLocalNull = null; + let stringviewWtf8LocalNull: ref_stringview_wtf8 | null = null; + stringviewWtf8LocalNull = null; + let stringviewWtf16LocalNull: ref_stringview_wtf16 | null = null; + stringviewWtf16LocalNull = null; + let stringviewIterLocalNull: ref_stringview_iter | null = null; + stringviewIterLocalNull = null; + + let stringLocal: ref_string; + stringLocal = string.const_(""); + let stringviewWtf8Local: ref_stringview_wtf8; + stringviewWtf8Local = string.as_wtf8(stringLocal); + let stringviewWtf16Local: ref_stringview_wtf16; + stringviewWtf16Local = string.as_wtf16(stringLocal); + let stringviewIterLocal: ref_stringview_iter; + stringviewIterLocal = string.as_iter(stringLocal); } test_locals(); From d6b3187612c71126233c0b56cd13e5ff027dbe8e Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Apr 2023 13:03:15 +0200 Subject: [PATCH 5/9] propagate ref nonnull state --- src/flow.ts | 9 +++++++++ src/module.ts | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/flow.ts b/src/flow.ts index 3f4838ab3d..2ff37ea6f6 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -70,6 +70,7 @@ import { getUnaryValue, getCallOperandAt, getCallOperandCount, + getRefIsNullValue, isConstZero, isConstNonZero } from "./module"; @@ -1049,6 +1050,10 @@ export class Flow { } break; } + case ExpressionId.RefIsNull: { + this.inheritNonnullIfFalse(getRefIsNullValue(expr), iff); // value == null -> value must have been null + break; + } } } @@ -1140,6 +1145,10 @@ export class Flow { } break; } + case ExpressionId.RefIsNull: { + this.inheritNonnullIfTrue(getRefIsNullValue(expr), iff); // value == null -> value must have been non-null + break; + } } } diff --git a/src/module.ts b/src/module.ts index f5f27cf7c3..c7853b025f 100644 --- a/src/module.ts +++ b/src/module.ts @@ -3553,6 +3553,10 @@ export function getMemoryGrowDelta(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenMemoryGrowGetDelta(expr); } +export function getRefIsNullValue(expr: ExpressionRef): ExpressionRef { + return binaryen._BinaryenRefIsNullGetValue(expr); +} + // functions export function getFunctionBody(func: FunctionRef): ExpressionRef { From 13214ba17cd5ba8edfc5e40c51babbe094b6e845 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Apr 2023 13:06:04 +0200 Subject: [PATCH 6/9] remove string.const_, accept string literal in context instead --- src/builtins.ts | 28 ---------------------------- src/compiler.ts | 5 +++++ std/assembly/builtins.ts | 4 ---- std/assembly/index.d.ts | 4 +--- 4 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index d4043d9196..14b620a39c 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -715,7 +715,6 @@ export namespace BuiltinNames { export const i31_new = "~lib/builtins/i31.new"; export const i31_get = "~lib/builtins/i31.get"; - export const string_const = "~lib/builtins/string.const_"; export const string_new_utf8 = "~lib/builtins/string.new_utf8"; export const string_new_utf8_array = "~lib/builtins/string.new_utf8_array"; export const string_new_lossy_utf8 = "~lib/builtins/string.new_lossy_utf8"; @@ -10871,33 +10870,6 @@ builtinFunctions.set(BuiltinNames.i32x4_relaxed_dot_i8x16_i7x16_add_s, builtin_i // === Stringref ============================================================================== -// string.const(str: string) -> stringref -function builtin_string_const(ctx: BuiltinFunctionContext): ExpressionRef { - let compiler = ctx.compiler; - let module = compiler.module; - if ( - checkFeatureEnabled(ctx, Feature.Stringref) | - checkTypeAbsent(ctx) | - checkArgsRequired(ctx, 1) - ) return module.unreachable(); - let operands = ctx.operands; - let node = operands[0]; - if (node.kind == NodeKind.Literal) { - let literal = node; - if (literal.literalKind == LiteralKind.String) { - compiler.currentType = Type.string; - return module.string_const((literal).value); - } - } - compiler.error( - DiagnosticCode.String_literal_expected, - node.range - ); - compiler.currentType = Type.string; - return module.unreachable(); -} -builtinFunctions.set(BuiltinNames.string_const, builtin_string_const); - // string.new_utf8(ptr: usize, bytes: i32, immMemory?: i32) -> stringref function builtin_string_new_utf8(ctx: BuiltinFunctionContext): ExpressionRef { let compiler = ctx.compiler; diff --git a/src/compiler.ts b/src/compiler.ts index 7703f5de18..e2b37b9958 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -7923,6 +7923,11 @@ export class Compiler extends DiagnosticEmitter { } case LiteralKind.String: { assert(!implicitlyNegate); + // Emit a stringref if context indicates + if (contextualType.kind == TypeKind.String) { + this.currentType = Type.string; + return module.string_const((expression).value); + } return this.compileStringLiteral(expression, constraints); } case LiteralKind.Template: { diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index b59fb0746f..e672b08912 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -2598,10 +2598,6 @@ export abstract class i31 { // FIXME: usage of 'new' requires a class :( export namespace string { - // @ts-ignore: decorator - @builtin - export declare function const_(str: string): ref_string; - // @ts-ignore: decorator @unsafe @builtin export declare function new_utf8(ptr: usize, bytes: i32): ref_string; diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 3d4304eee2..6255df2afe 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -64,7 +64,7 @@ declare type ref_i31 = object; /** Canonical nullable 31-bit integer reference. */ declare type i31ref = ref_i31 | null; /** Non-nullable string reference. */ -declare type ref_string = object; +declare type ref_string = string; /** Canonical nullable string reference. */ declare type stringref = ref_string | null; /** Non-nullable WTF-8 string view. */ @@ -1669,8 +1669,6 @@ declare abstract class i31 { } declare namespace string { - /** Constructs a string reference from a string literal. Temporary! */ - export function const_(str: string): ref_string; /** Creates a new string from memory using a strict UTF-8 decoder, decoding `bytes` bytes starting at `ptr`. */ export function new_utf8(ptr: usize, bytes: i32): ref_string; /** Creates a new string from `array` using a strict UTF-8 decoder, decoding from `start` inclusive to `end` exclusive. */ From e927b04e2b163b792e7418dd46035992cae0520f Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Apr 2023 13:09:56 +0200 Subject: [PATCH 7/9] sync with resolver --- src/program.ts | 8 ++++++++ src/resolver.ts | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/program.ts b/src/program.ts index 829cffee05..8f0e805020 100644 --- a/src/program.ts +++ b/src/program.ts @@ -633,6 +633,14 @@ export class Program extends DiagnosticEmitter { } private _stringInstance: Class | null = null; + /** Gets the standard `RefString` instance. */ + get refStringInstance(): Class { + let cached = this._refStringInstance; + if (!cached) this._refStringInstance = cached = this.requireClass(CommonNames.RefString); + return cached; + } + private _refStringInstance: Class | null = null; + /** Gets the standard `RegExp` instance. */ get regexpInstance(): Class { let cached = this._regexpInstance; diff --git a/src/resolver.ts b/src/resolver.ts index 16bd967847..b097e743fa 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2343,6 +2343,8 @@ export class Resolver extends DiagnosticEmitter { } case LiteralKind.String: case LiteralKind.Template: { + // Resolve to stringref if context indicates + if (ctxType.kind == TypeKind.String) return this.program.refStringInstance; return this.program.stringInstance; } case LiteralKind.RegExp: { From 82800a50f065ff75c58a0d753462d566deca475f Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Apr 2023 13:11:14 +0200 Subject: [PATCH 8/9] skip template literals for now --- src/resolver.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/resolver.ts b/src/resolver.ts index b097e743fa..e2d9c7167d 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2341,10 +2341,12 @@ export class Resolver extends DiagnosticEmitter { let fltType = ctxType == Type.f32 ? Type.f32 : Type.f64; return assert(fltType.getClassOrWrapper(this.program)); } - case LiteralKind.String: - case LiteralKind.Template: { + case LiteralKind.String: { // Resolve to stringref if context indicates if (ctxType.kind == TypeKind.String) return this.program.refStringInstance; + // fall-through + } + case LiteralKind.Template: { return this.program.stringInstance; } case LiteralKind.RegExp: { From a1ff14d3f8da58ee7e833c836511c85c46e57f97 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Apr 2023 13:13:00 +0200 Subject: [PATCH 9/9] update test, add POC --- std/assembly/reference.ts | 144 +++- tests/compiler/features/stringref.debug.wat | 726 +++++++++++++++++- tests/compiler/features/stringref.release.wat | 483 +++++++++++- tests/compiler/features/stringref.ts | 37 +- 4 files changed, 1375 insertions(+), 15 deletions(-) diff --git a/std/assembly/reference.ts b/std/assembly/reference.ts index 148f456799..fb5f927597 100644 --- a/std/assembly/reference.ts +++ b/std/assembly/reference.ts @@ -7,9 +7,11 @@ export type i31ref = ref_i31 | null; export type structref = ref_struct | null; export type arrayref = ref_array | null; export type stringref = ref_string | null; -export type stringview_wtf8 = ref_stringview_wtf8 | null; -export type stringview_wtf16 = ref_stringview_wtf16 | null; -export type stringview_iter = ref_stringview_iter | null; + +// TODO: Conflict with the instruction namespaces +// export type stringview_wtf8 = ref_stringview_wtf8 | null; +// export type stringview_wtf16 = ref_stringview_wtf16 | null; +// export type stringview_iter = ref_stringview_iter | null; @unmanaged abstract class Ref { @@ -43,6 +45,142 @@ export abstract class RefStruct extends Ref { export abstract class RefArray extends Ref { } +import { E_INDEXOUTOFRANGE } from "util/error"; + @final @unmanaged export abstract class RefString extends Ref { + + @lazy static readonly MAX_LENGTH: i32 = (1 << 30) - 1; + + static fromCharCode(unit: i32, surr: i32 = -1): ref_string { + if (~surr) unit = 0x10000 + ((unit & 0x3FF) << 10) | (surr & 0x3FF); + return string.from_code_point(unit); + } + + static fromCodePoint(cp: i32): ref_string { + if (cp > 0x10ffff) throw new Error("Invalid code point"); + return string.from_code_point(cp); + } + + // @ts-ignore: this on getter + get length(this: ref_string): i32 { + return string.measure_wtf16(this); + } + + at(this: ref_string, pos: i32): stringref { + let len = string.measure_wtf16(this); + pos += select(0, len, pos >= 0); + if (pos >= len) throw new RangeError(E_INDEXOUTOFRANGE); + return string.from_code_point(stringview_wtf16.get_codeunit(string.as_wtf16(this), pos)); + } + + @operator("[]") charAt(this: ref_string, pos: i32): stringref { + if (pos >= string.measure_wtf16(this)) return ""; + return string.from_code_point(stringview_wtf16.get_codeunit(string.as_wtf16(this), pos)); + } + + charCodeAt(this: ref_string, pos: i32): i32 { + if (pos >= string.measure_wtf16(this)) return -1; // (NaN) + return stringview_wtf16.get_codeunit(string.as_wtf16(this), pos); + } + + codePointAt(this: ref_string, pos: i32): i32 { + let len = string.measure_wtf16(this); + if (pos >= len) return -1; // (undefined) + let view = string.as_wtf16(this); + let first = stringview_wtf16.get_codeunit(view, pos); + if ((first & 0xFC00) != 0xD800 || pos + 1 == len) return first; + let second = stringview_wtf16.get_codeunit(view, pos + 1); + if ((second & 0xFC00) != 0xDC00) return first; + return (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000; + } + + @operator("+") + concat(this: ref_string, other: ref_string): ref_string { + return string.concat(this, other); + } + + endsWith(this: ref_string, search: ref_string, end: i32 = RefString.MAX_LENGTH): bool { + end = min(max(end, 0), string.measure_wtf16(this)); + let searchLength = string.measure_wtf16(search); + let searchStart = end - searchLength; + if (searchStart < 0) return false; + return string.eq( + stringview_wtf16.slice(string.as_wtf16(this), searchStart, searchStart + searchLength), + search + ); + } + + @operator("==") private static __eq(left: ref_string | null, right: ref_string | null): bool { + return string.eq(left, right); + } + + @operator.prefix("!") + private static __not(str: ref_string | null): bool { + return str == null; + } + + @operator("!=") + private static __ne(left: ref_string | null, right: ref_string | null): bool { + return !string.eq(left, right); + } + + @operator(">") private static __gt(left: ref_string, right: ref_string): bool { + return string.compare(left, right) > 0; + } + + @operator(">=") private static __gte(left: ref_string, right: ref_string): bool { + return string.compare(left, right) >= 0; + } + + @operator("<") private static __lt(left: ref_string, right: ref_string): bool { + return string.compare(left, right) < 0; + } + + @operator("<=") private static __lte(left: ref_string, right: ref_string): bool { + return string.compare(left, right) <= 0; + } + + includes(this: ref_string, search: ref_string, start: i32 = 0): bool { + return this.indexOf(search, start) != -1; + } + + indexOf(this: ref_string, search: ref_string, start: i32 = 0): i32 { + let searchLen = string.measure_wtf16(search); + if (!searchLen) return 0; + let len = string.measure_wtf16(this); + if (!len) return -1; + let searchStart = min(max(start, 0), len); + let view = string.as_wtf16(this); + for (len -= searchLen; searchStart <= len; ++searchStart) { + // FIXME: slice is suboptimal + if (string.eq( + stringview_wtf16.slice(view, searchStart, searchStart + searchLen), + search + )) { + return searchStart; + } + } + return -1; + } + + lastIndexOf(this: ref_string, search: ref_string, start: i32 = i32.MAX_VALUE): i32 { + let searchLen = string.measure_wtf16(search); + if (!searchLen) return string.measure_wtf16(this); + let len = string.measure_wtf16(this); + if (!len) return -1; + let searchStart = min(max(start, 0), len - searchLen); + for (; searchStart >= 0; --searchStart) { + // FIXME: slice is suboptimal + if (string.eq( + stringview_wtf16.slice(string.as_wtf16(this), searchStart, searchStart + searchLen), + search + )) { + return searchStart; + } + } + return -1; + } + + // TODO: port more } diff --git a/tests/compiler/features/stringref.debug.wat b/tests/compiler/features/stringref.debug.wat index 572600ffd1..3795771c70 100644 --- a/tests/compiler/features/stringref.debug.wat +++ b/tests/compiler/features/stringref.debug.wat @@ -1,6 +1,15 @@ (module (type $none_=>_none (func)) + (type $ref|string|_ref|string|_i32_=>_i32 (func (param (ref string) (ref string) i32) (result i32))) + (type $ref|string|_ref|string|_=>_i32 (func (param (ref string) (ref string)) (result i32))) + (type $ref|string|_i32_=>_stringref (func (param (ref string) i32) (result stringref))) + (type $ref|string|_i32_=>_i32 (func (param (ref string) i32) (result i32))) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (type $i32_=>_ref|string| (func (param i32) (result (ref string)))) + (type $stringref_stringref_=>_i32 (func (param stringref stringref) (result i32))) + (type $ref|string|_=>_i32 (func (param (ref string)) (result i32))) + (type $ref|string|_ref|string|_=>_ref|string| (func (param (ref string) (ref string)) (result (ref string)))) + (type $stringref_=>_i32 (func (param stringref) (result i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (global $features/stringref/stringGlobalNull (mut stringref) (ref.null none)) (global $features/stringref/stringviewWtf8GlobalNull (mut stringview_wtf8) (ref.null none)) @@ -14,14 +23,21 @@ (global $features/stringref/wtf16_data i32 (i32.const 12)) (global $features/stringref/temp_data i32 (i32.const 32)) (global $~lib/native/ASC_SHRINK_LEVEL i32 (i32.const 0)) - (global $~lib/memory/__data_end i32 (i32.const 124)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 32892)) - (global $~lib/memory/__heap_base i32 (i32.const 32892)) + (global $features/stringref/str (mut (ref string)) (string.const "abc")) + (global $~lib/reference/RefString.MAX_LENGTH i32 (i32.const 1073741823)) + (global $~argumentsLength (mut i32) (i32.const 0)) + (global $~lib/builtins/i32.MAX_VALUE i32 (i32.const 2147483647)) + (global $~lib/memory/__data_end i32 (i32.const 316)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 33084)) + (global $~lib/memory/__heap_base i32 (i32.const 33084)) (memory $0 1) (data $0 (i32.const 8) "abc") (data $1 (i32.const 12) "a\00b\00c\00") (data $2 (i32.const 32) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") (data $3 (i32.const 60) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00*\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00s\00t\00r\00i\00n\00g\00r\00e\00f\00.\00t\00s\00\00\00") + (data $4 (i32.const 124) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00$\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00c\00o\00d\00e\00 \00p\00o\00i\00n\00t\00\00\00\00\00\00\00\00\00") + (data $5 (i32.const 188) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\"\00\00\00~\00l\00i\00b\00/\00r\00e\00f\00e\00r\00e\00n\00c\00e\00.\00t\00s\00\00\00\00\00\00\00\00\00\00\00") + (data $6 (i32.const 252) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00$\00\00\00I\00n\00d\00e\00x\00 \00o\00u\00t\00 \00o\00f\00 \00r\00a\00n\00g\00e\00\00\00\00\00\00\00\00\00") (table $0 1 1 funcref) (elem $0 (i32.const 1)) (export "memory" (memory $0)) @@ -1128,6 +1144,454 @@ unreachable end ) + (func $~lib/reference/RefString.fromCodePoint (type $i32_=>_ref|string|) (param $cp i32) (result (ref string)) + local.get $cp + i32.const 1114111 + i32.gt_u + if + i32.const 144 + i32.const 208 + i32.const 61 + i32.const 29 + call $~lib/builtins/abort + unreachable + end + local.get $cp + string.from_code_point + return + ) + (func $~lib/reference/RefString.__eq (type $stringref_stringref_=>_i32) (param $left stringref) (param $right stringref) (result i32) + local.get $left + local.get $right + string.eq + return + ) + (func $~lib/reference/RefString#get:length (type $ref|string|_=>_i32) (param $this (ref string)) (result i32) + local.get $this + string.measure_wtf16 + return + ) + (func $~lib/reference/RefString#at (type $ref|string|_i32_=>_stringref) (param $this (ref string)) (param $pos i32) (result stringref) + (local $len i32) + local.get $this + string.measure_wtf16 + local.set $len + local.get $pos + i32.const 0 + local.get $len + local.get $pos + i32.const 0 + i32.ge_s + select + i32.add + local.set $pos + local.get $pos + local.get $len + i32.ge_u + if + i32.const 272 + i32.const 208 + i32.const 73 + i32.const 31 + call $~lib/builtins/abort + unreachable + end + local.get $this + string.as_wtf16 + local.get $pos + stringview_wtf16.get_codeunit + string.from_code_point + return + ) + (func $~lib/reference/RefString#charAt (type $ref|string|_i32_=>_stringref) (param $this (ref string)) (param $pos i32) (result stringref) + local.get $pos + local.get $this + string.measure_wtf16 + i32.ge_u + if + string.const "" + return + end + local.get $this + string.as_wtf16 + local.get $pos + stringview_wtf16.get_codeunit + string.from_code_point + return + ) + (func $~lib/reference/RefString#charCodeAt (type $ref|string|_i32_=>_i32) (param $this (ref string)) (param $pos i32) (result i32) + local.get $pos + local.get $this + string.measure_wtf16 + i32.ge_u + if + i32.const -1 + return + end + local.get $this + string.as_wtf16 + local.get $pos + stringview_wtf16.get_codeunit + return + ) + (func $~lib/reference/RefString#codePointAt (type $ref|string|_i32_=>_i32) (param $this (ref string)) (param $pos i32) (result i32) + (local $len i32) + (local $view (ref stringview_wtf16)) + (local $first i32) + (local $second i32) + local.get $this + string.measure_wtf16 + local.set $len + local.get $pos + local.get $len + i32.ge_u + if + i32.const -1 + return + end + local.get $this + string.as_wtf16 + local.set $view + local.get $view + local.get $pos + stringview_wtf16.get_codeunit + local.set $first + local.get $first + i32.const 64512 + i32.and + i32.const 55296 + i32.ne + if (result i32) + i32.const 1 + else + local.get $pos + i32.const 1 + i32.add + local.get $len + i32.eq + end + if + local.get $first + return + end + local.get $view + local.get $pos + i32.const 1 + i32.add + stringview_wtf16.get_codeunit + local.set $second + local.get $second + i32.const 64512 + i32.and + i32.const 56320 + i32.ne + if + local.get $first + return + end + local.get $first + i32.const 55296 + i32.sub + i32.const 10 + i32.shl + local.get $second + i32.const 56320 + i32.sub + i32.add + i32.const 65536 + i32.add + return + ) + (func $~lib/reference/RefString#concat (type $ref|string|_ref|string|_=>_ref|string|) (param $this (ref string)) (param $other (ref string)) (result (ref string)) + local.get $this + local.get $other + string.concat + return + ) + (func $~lib/reference/RefString#endsWith (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $end i32) (result i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $searchLength i32) + (local $searchStart i32) + local.get $end + local.tee $3 + i32.const 0 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_s + select + local.tee $5 + local.get $this + string.measure_wtf16 + local.tee $6 + local.get $5 + local.get $6 + i32.lt_s + select + local.set $end + local.get $search + string.measure_wtf16 + local.set $searchLength + local.get $end + local.get $searchLength + i32.sub + local.set $searchStart + local.get $searchStart + i32.const 0 + i32.lt_s + if + i32.const 0 + return + end + local.get $this + string.as_wtf16 + local.get $searchStart + local.get $searchStart + local.get $searchLength + i32.add + stringview_wtf16.slice + local.get $search + string.eq + return + ) + (func $~lib/reference/RefString#endsWith@varargs (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $end i32) (result i32) + block $1of1 + block $0of1 + block $outOfRange + global.get $~argumentsLength + i32.const 1 + i32.sub + br_table $0of1 $1of1 $outOfRange + end + unreachable + end + global.get $~lib/reference/RefString.MAX_LENGTH + local.set $end + end + local.get $this + local.get $search + local.get $end + call $~lib/reference/RefString#endsWith + ) + (func $~lib/reference/RefString.__not (type $stringref_=>_i32) (param $str stringref) (result i32) + local.get $str + ref.null none + string.eq + return + ) + (func $~lib/reference/RefString.__gt (type $ref|string|_ref|string|_=>_i32) (param $left (ref string)) (param $right (ref string)) (result i32) + local.get $left + local.get $right + string.compare + i32.const 0 + i32.gt_s + return + ) + (func $~lib/reference/RefString.__gte (type $ref|string|_ref|string|_=>_i32) (param $left (ref string)) (param $right (ref string)) (result i32) + local.get $left + local.get $right + string.compare + i32.const 0 + i32.ge_s + return + ) + (func $~lib/reference/RefString.__lt (type $ref|string|_ref|string|_=>_i32) (param $left (ref string)) (param $right (ref string)) (result i32) + local.get $left + local.get $right + string.compare + i32.const 0 + i32.lt_s + return + ) + (func $~lib/reference/RefString.__lte (type $ref|string|_ref|string|_=>_i32) (param $left (ref string)) (param $right (ref string)) (result i32) + local.get $left + local.get $right + string.compare + i32.const 0 + i32.le_s + return + ) + (func $~lib/reference/RefString#indexOf (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $start i32) (result i32) + (local $searchLen i32) + (local $len i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $searchStart i32) + (local $view (ref stringview_wtf16)) + local.get $search + string.measure_wtf16 + local.set $searchLen + local.get $searchLen + i32.eqz + if + i32.const 0 + return + end + local.get $this + string.measure_wtf16 + local.set $len + local.get $len + i32.eqz + if + i32.const -1 + return + end + local.get $start + local.tee $5 + i32.const 0 + local.tee $6 + local.get $5 + local.get $6 + i32.gt_s + select + local.tee $7 + local.get $len + local.tee $8 + local.get $7 + local.get $8 + i32.lt_s + select + local.set $searchStart + local.get $this + string.as_wtf16 + local.set $view + local.get $len + local.get $searchLen + i32.sub + local.set $len + loop $for-loop|0 + local.get $searchStart + local.get $len + i32.le_s + if + local.get $view + local.get $searchStart + local.get $searchStart + local.get $searchLen + i32.add + stringview_wtf16.slice + local.get $search + string.eq + if + local.get $searchStart + return + end + local.get $searchStart + i32.const 1 + i32.add + local.set $searchStart + br $for-loop|0 + end + end + i32.const -1 + return + ) + (func $~lib/reference/RefString#includes (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $start i32) (result i32) + local.get $this + local.get $search + local.get $start + call $~lib/reference/RefString#indexOf + i32.const -1 + i32.ne + return + ) + (func $~lib/reference/RefString#lastIndexOf (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $start i32) (result i32) + (local $searchLen i32) + (local $len i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $searchStart i32) + local.get $search + string.measure_wtf16 + local.set $searchLen + local.get $searchLen + i32.eqz + if + local.get $this + string.measure_wtf16 + return + end + local.get $this + string.measure_wtf16 + local.set $len + local.get $len + i32.eqz + if + i32.const -1 + return + end + local.get $start + local.tee $5 + i32.const 0 + local.tee $6 + local.get $5 + local.get $6 + i32.gt_s + select + local.tee $7 + local.get $len + local.get $searchLen + i32.sub + local.tee $8 + local.get $7 + local.get $8 + i32.lt_s + select + local.set $searchStart + loop $for-loop|0 + local.get $searchStart + i32.const 0 + i32.ge_s + if + local.get $this + string.as_wtf16 + local.get $searchStart + local.get $searchStart + local.get $searchLen + i32.add + stringview_wtf16.slice + local.get $search + string.eq + if + local.get $searchStart + return + end + local.get $searchStart + i32.const 1 + i32.sub + local.set $searchStart + br $for-loop|0 + end + end + i32.const -1 + return + ) + (func $~lib/reference/RefString#lastIndexOf@varargs (type $ref|string|_ref|string|_i32_=>_i32) (param $this (ref string)) (param $search (ref string)) (param $start i32) (result i32) + block $1of1 + block $0of1 + block $outOfRange + global.get $~argumentsLength + i32.const 1 + i32.sub + br_table $0of1 $1of1 $outOfRange + end + unreachable + end + global.get $~lib/builtins/i32.MAX_VALUE + local.set $start + end + local.get $this + local.get $search + local.get $start + call $~lib/reference/RefString#lastIndexOf + ) (func $start:features/stringref (type $none_=>_none) global.get $features/stringref/stringGlobal string.as_wtf8 @@ -1144,6 +1608,262 @@ call $features/stringref/test_wtf8 call $features/stringref/test_wtf16 call $features/stringref/test_iter + i32.const 97 + call $~lib/reference/RefString.fromCodePoint + string.const "a" + call $~lib/reference/RefString.__eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 145 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + call $~lib/reference/RefString#get:length + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 147 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + i32.const 1 + call $~lib/reference/RefString#at + string.const "b" + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 148 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + i32.const 0 + call $~lib/reference/RefString#charAt + string.const "a" + string.eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 149 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + i32.const 0 + call $~lib/reference/RefString#charCodeAt + i32.const 97 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 150 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + i32.const 0 + call $~lib/reference/RefString#codePointAt + i32.const 97 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 151 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + global.get $features/stringref/str + call $~lib/reference/RefString#concat + string.const "abcabc" + call $~lib/reference/RefString.__eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 152 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "abc" + i32.const 1 + global.set $~argumentsLength + i32.const 0 + call $~lib/reference/RefString#endsWith@varargs + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 153 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + global.get $features/stringref/str + call $~lib/reference/RefString.__eq + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 154 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + call $~lib/reference/RefString.__not + i32.const 0 + i32.ne + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 155 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "" + string.eq + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 156 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "ab" + call $~lib/reference/RefString.__gt + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 157 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "ab" + call $~lib/reference/RefString.__gte + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 158 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "abcd" + call $~lib/reference/RefString.__lt + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 159 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "abcd" + call $~lib/reference/RefString.__lte + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 160 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "b" + i32.const 0 + call $~lib/reference/RefString#includes + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 161 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "b" + i32.const 0 + call $~lib/reference/RefString#indexOf + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 162 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $features/stringref/str + string.const "b" + i32.const 1 + global.set $~argumentsLength + i32.const 0 + call $~lib/reference/RefString#lastIndexOf@varargs + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 163 + i32.const 1 + call $~lib/builtins/abort + unreachable + end ) (func $~start (type $none_=>_none) call $start:features/stringref diff --git a/tests/compiler/features/stringref.release.wat b/tests/compiler/features/stringref.release.wat index d367025606..89f7aeedb0 100644 --- a/tests/compiler/features/stringref.release.wat +++ b/tests/compiler/features/stringref.release.wat @@ -7,6 +7,12 @@ (data $1 (i32.const 1028) "a\00b\00c") (data $3 (i32.const 1068) "<") (data $3.1 (i32.const 1080) "\02\00\00\00*\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00s\00t\00r\00i\00n\00g\00r\00e\00f\00.\00t\00s") + (data $4 (i32.const 1132) "<") + (data $4.1 (i32.const 1144) "\02\00\00\00$\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00c\00o\00d\00e\00 \00p\00o\00i\00n\00t") + (data $5 (i32.const 1196) "<") + (data $5.1 (i32.const 1208) "\02\00\00\00\"\00\00\00~\00l\00i\00b\00/\00r\00e\00f\00e\00r\00e\00n\00c\00e\00.\00t\00s") + (data $6 (i32.const 1260) "<") + (data $6.1 (i32.const 1272) "\02\00\00\00$\00\00\00I\00n\00d\00e\00x\00 \00o\00u\00t\00 \00o\00f\00 \00r\00a\00n\00g\00e") (export "memory" (memory $0)) (start $~start) (func $features/stringref/test_wtf8 (type $none_=>_none) @@ -838,7 +844,11 @@ unreachable end ) - (func $~start (type $none_=>_none) + (func $start:features/stringref (type $none_=>_none) + (local $0 i32) + (local $1 (ref stringview_wtf16)) + (local $2 i32) + (local $3 i32) string.const "" string.as_wtf8 drop @@ -851,5 +861,476 @@ call $features/stringref/test_wtf8 call $features/stringref/test_wtf16 call $features/stringref/test_iter + i32.const 97 + string.from_code_point + string.const "a" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 145 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.measure_wtf16 + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 147 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.measure_wtf16 + i32.const 1 + i32.le_u + if + i32.const 1280 + i32.const 1216 + i32.const 73 + i32.const 31 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.as_wtf16 + i32.const 1 + stringview_wtf16.get_codeunit + string.from_code_point + string.const "b" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 148 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.measure_wtf16 + if (result (ref string)) + string.const "abc" + string.as_wtf16 + i32.const 0 + stringview_wtf16.get_codeunit + string.from_code_point + else + string.const "" + end + string.const "a" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 149 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.measure_wtf16 + if (result i32) + string.const "abc" + string.as_wtf16 + i32.const 0 + stringview_wtf16.get_codeunit + else + i32.const -1 + end + i32.const 97 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 150 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const -1 + local.set $0 + block $__inlined_func$~lib/reference/RefString#codePointAt + string.const "abc" + string.measure_wtf16 + local.tee $2 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#codePointAt + local.get $2 + i32.const 1 + i32.eq + string.const "abc" + string.as_wtf16 + local.tee $1 + i32.const 0 + stringview_wtf16.get_codeunit + local.tee $0 + i32.const 64512 + i32.and + i32.const 55296 + i32.ne + i32.or + br_if $__inlined_func$~lib/reference/RefString#codePointAt + local.get $1 + i32.const 1 + stringview_wtf16.get_codeunit + local.tee $2 + i32.const 64512 + i32.and + i32.const 56320 + i32.ne + br_if $__inlined_func$~lib/reference/RefString#codePointAt + local.get $0 + i32.const 10 + i32.shl + local.get $2 + i32.add + i32.const 56613888 + i32.sub + local.set $0 + end + local.get $0 + i32.const 97 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 151 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "abc" + string.concat + string.const "abcabc" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 152 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 1073741823 + string.const "abc" + string.measure_wtf16 + local.tee $0 + local.get $0 + i32.const 1073741823 + i32.gt_s + select + local.get $0 + i32.sub + local.tee $2 + i32.const 0 + i32.lt_s + if (result i32) + i32.const 0 + else + string.const "abc" + string.as_wtf16 + local.get $2 + local.get $0 + local.get $2 + i32.add + stringview_wtf16.slice + string.const "abc" + string.eq + end + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 153 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "abc" + string.eq + i32.eqz + if + i32.const 0 + i32.const 1088 + i32.const 154 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + ref.null none + string.eq + if + i32.const 0 + i32.const 1088 + i32.const 155 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "" + string.eq + if + i32.const 0 + i32.const 1088 + i32.const 156 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "ab" + string.compare + i32.const 0 + i32.le_s + if + i32.const 0 + i32.const 1088 + i32.const 157 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "ab" + string.compare + i32.const 0 + i32.lt_s + if + i32.const 0 + i32.const 1088 + i32.const 158 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "abcd" + string.compare + i32.const 0 + i32.ge_s + if + i32.const 0 + i32.const 1088 + i32.const 159 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + string.const "abc" + string.const "abcd" + string.compare + i32.const 0 + i32.gt_s + if + i32.const 0 + i32.const 1088 + i32.const 160 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + local.set $0 + block $__inlined_func$~lib/reference/RefString#indexOf + string.const "b" + string.measure_wtf16 + local.tee $2 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#indexOf + i32.const -1 + local.set $0 + string.const "abc" + string.measure_wtf16 + local.tee $3 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#indexOf + local.get $3 + i32.const 0 + local.get $3 + i32.const 0 + i32.le_s + select + local.set $0 + string.const "abc" + string.as_wtf16 + local.set $1 + local.get $3 + local.get $2 + i32.sub + local.set $3 + loop $for-loop|0 + local.get $0 + local.get $3 + i32.le_s + if + local.get $1 + local.get $0 + local.get $0 + local.get $2 + i32.add + stringview_wtf16.slice + string.const "b" + string.eq + br_if $__inlined_func$~lib/reference/RefString#indexOf + local.get $0 + i32.const 1 + i32.add + local.set $0 + br $for-loop|0 + end + end + i32.const -1 + local.set $0 + end + local.get $0 + i32.const -1 + i32.eq + if + i32.const 0 + i32.const 1088 + i32.const 161 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + local.set $0 + block $__inlined_func$~lib/reference/RefString#indexOf0 + string.const "b" + string.measure_wtf16 + local.tee $2 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#indexOf0 + i32.const -1 + local.set $0 + string.const "abc" + string.measure_wtf16 + local.tee $3 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#indexOf0 + local.get $3 + i32.const 0 + local.get $3 + i32.const 0 + i32.le_s + select + local.set $0 + string.const "abc" + string.as_wtf16 + local.set $1 + local.get $3 + local.get $2 + i32.sub + local.set $3 + loop $for-loop|01 + local.get $0 + local.get $3 + i32.le_s + if + local.get $1 + local.get $0 + local.get $0 + local.get $2 + i32.add + stringview_wtf16.slice + string.const "b" + string.eq + br_if $__inlined_func$~lib/reference/RefString#indexOf0 + local.get $0 + i32.const 1 + i32.add + local.set $0 + br $for-loop|01 + end + end + i32.const -1 + local.set $0 + end + local.get $0 + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 162 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + block $__inlined_func$~lib/reference/RefString#lastIndexOf + string.const "b" + string.measure_wtf16 + local.tee $2 + i32.eqz + if + string.const "abc" + string.measure_wtf16 + local.set $0 + br $__inlined_func$~lib/reference/RefString#lastIndexOf + end + i32.const -1 + local.set $0 + string.const "abc" + string.measure_wtf16 + local.tee $3 + i32.eqz + br_if $__inlined_func$~lib/reference/RefString#lastIndexOf + local.get $3 + local.get $2 + i32.sub + local.set $0 + loop $for-loop|03 + local.get $0 + i32.const 0 + i32.ge_s + if + string.const "abc" + string.as_wtf16 + local.get $0 + local.get $0 + local.get $2 + i32.add + stringview_wtf16.slice + string.const "b" + string.eq + br_if $__inlined_func$~lib/reference/RefString#lastIndexOf + local.get $0 + i32.const 1 + i32.sub + local.set $0 + br $for-loop|03 + end + end + i32.const -1 + local.set $0 + end + local.get $0 + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1088 + i32.const 163 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~start (type $none_=>_none) + call $start:features/stringref ) ) diff --git a/tests/compiler/features/stringref.ts b/tests/compiler/features/stringref.ts index 5054d666b4..f25f9f04d0 100644 --- a/tests/compiler/features/stringref.ts +++ b/tests/compiler/features/stringref.ts @@ -8,7 +8,7 @@ let stringviewWtf8GlobalNull: ref_stringview_wtf8 | null = null; let stringviewWtf16GlobalNull: ref_stringview_wtf16 | null = null; let stringviewIterGlobalNull: ref_stringview_iter | null = null; -let stringGlobal: ref_string = string.const_(""); +let stringGlobal: ref_string = ""; let stringviewWtf8Global: ref_stringview_wtf8 = string.as_wtf8(stringGlobal); // internally nullable let stringviewWtf16Global: ref_stringview_wtf16 = string.as_wtf16(stringGlobal); // internally nullable let stringviewIterGlobal: ref_stringview_iter = string.as_iter(stringGlobal); // internally nullable @@ -24,7 +24,7 @@ function test_locals(): void { stringviewIterLocalNull = null; let stringLocal: ref_string; - stringLocal = string.const_(""); + stringLocal = ""; let stringviewWtf8Local: ref_stringview_wtf8; stringviewWtf8Local = string.as_wtf8(stringLocal); let stringviewWtf16Local: ref_stringview_wtf16; @@ -61,10 +61,10 @@ function test_wtf8(): void { string.hash(str); assert(string.is_usv_sequence(str)); assert(string.eq(str, str)); - assert(string.eq(str, string.const_("abc"))); + assert(string.eq(str, "abc")); assert(string.compare(str, str) == 0); - assert(string.compare(str, string.const_("b")) == -1); - assert(string.compare(str, string.const_("`")) == 1); + assert(string.compare(str, "b") == -1); + assert(string.compare(str, "`") == 1); assert(string.encode_wtf8(str, temp_data) == 3); assert(memory.compare(utf8_data, temp_data, 3) == 0); @@ -87,10 +87,10 @@ function test_wtf16(): void { string.hash(str); assert(string.is_usv_sequence(str)); assert(string.eq(str, str)); - assert(string.eq(str, string.const_("abc"))); + assert(string.eq(str, "abc")); assert(string.compare(str, str) == 0); - assert(string.compare(str, string.const_("b")) == -1); - assert(string.compare(str, string.const_("`")) == 1); + assert(string.compare(str, "b") == -1); + assert(string.compare(str, "`") == 1); assert(string.encode_wtf16(str, temp_data) == 3); assert(memory.compare(wtf16_data, temp_data, 6) == 0); @@ -140,3 +140,24 @@ test_iter(); // string.encode_lossy_utf8_array // string.encode_wtf8_array // string.encode_wtf16_array + +// POC +assert(RefString.fromCodePoint(0x61) == "a"); +let str: ref_string = "abc"; +assert(str.length == 3); +assert(str.at(1) == "b"); +assert(str.charAt(0) == "a"); +assert(str.charCodeAt(0) == 0x61); +assert(str.codePointAt(0) == 0x61); +assert(str.concat(str) == "abcabc"); +assert(str.endsWith("abc")); +assert(str == str); +assert(!str == false); +assert(str != ""); +assert(str > "ab"); +assert(str >= "ab"); +assert(str < "abcd"); +assert(str <= "abcd"); +assert(str.includes("b")); +assert(str.indexOf("b") == 1); +assert(str.lastIndexOf("b") == 1);