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); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy