diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79091199fd..0bb81e6ffc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,9 +81,9 @@ jobs: 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 492b186600..14b620a39c 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -715,6 +715,48 @@ export namespace BuiltinNames { export const i31_new = "~lib/builtins/i31.new"; export const i31_get = "~lib/builtins/i31.get"; + 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 +10868,619 @@ 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.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.string; + 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.array, 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.string; + 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.string; + 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.array, 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.string; + 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.string; + 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.array, 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.string; + 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.string; + 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.array, 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.string; + 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.string; + 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.string, 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.string, 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.string, 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.string, 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.string, 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.string, 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.string, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.array, 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.string, 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.string, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.array, 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.string, 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.string, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.array, 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.string, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.string, Constraints.ConvImplicit); + compiler.currentType = Type.string; + 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 nullableString = Type.string.asNullable(); + let arg0 = compiler.compileExpression(operands[0], nullableString, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], nullableString, 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.string, Constraints.ConvImplicit); + let arg1 = compiler.compileExpression(operands[1], Type.string, 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.string, 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.string, 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.string, 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.string; + 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.string; + 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.string; + 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/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/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 705750ec4a..c7853b025f 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( @@ -2959,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)) { @@ -3290,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 { 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..e2d9c7167d 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -2341,7 +2341,11 @@ 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.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; } diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 12f0dfd574..e672b08912 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -2596,6 +2596,170 @@ export abstract class i31 { // FIXME: usage of 'new' requires a class :( static get(i31expr: i31ref): i32 { return unreachable(); } } +export namespace string { + + // @ts-ignore: decorator + @unsafe @builtin + 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): ref_string; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function new_lossy_utf8(ptr: usize, bytes: i32): ref_string; + + // @ts-ignore: decorator + @builtin + 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): ref_string; + + // @ts-ignore: decorator + @builtin + 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): ref_string; + + // @ts-ignore: decorator + @builtin + 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): ref_string; + + // @ts-ignore: decorator + @builtin + export declare function hash(str: ref_string): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_utf8(str: ref_string): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_wtf8(str: ref_string): i32; + + // @ts-ignore: decorator + @builtin + export declare function measure_wtf16(str: ref_string): i32; + + // @ts-ignore: decorator + @builtin + export declare function is_usv_sequence(str: ref_string): i32; + + // @ts-ignore: decorator + @unsafe @builtin + export declare function encode_utf8(str: ref_string, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + export declare function encode_utf8_array(str: ref_string, 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: ref_string, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + 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: ref_string, ptr: usize): i32; + + // @ts-ignore: decorator + @builtin + export declare function encode_wtf16_array(str: ref_string, arr: ref_array, start: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function concat(left: ref_string, right: ref_string): ref_string; + + // @ts-ignore: decorator + @builtin + export declare function eq(left: ref_string | null, right: ref_string | null): bool; + + // @ts-ignore: decorator + @builtin + export declare function compare(left: ref_string, right: ref_string): i32; + + // @ts-ignore: decorator + @builtin + export declare function as_wtf8(str: ref_string): ref_stringview_wtf8; + + // @ts-ignore: decorator + @builtin + export declare function as_wtf16(str: ref_string): ref_stringview_wtf16; + + // @ts-ignore: decorator + @builtin + export declare function as_iter(str: ref_string): ref_stringview_iter; +} + +export namespace stringview_wtf8 { + + // @ts-ignore: decorator + @builtin + export declare function advance(view: ref_stringview_wtf8, pos: i32, bytes: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: ref_stringview_wtf8, start: i32, end: i32): ref_string; + + // TODO: encode_utf8 + + // TODO: encode_lossy_utf8 + + // TODO: encode_wtf8 +} + +export namespace stringview_wtf16 { + + // @ts-ignore: decorator + @builtin + export declare function length(view: ref_stringview_wtf16): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: ref_stringview_wtf16, start: i32, end: i32): ref_string; + + // @ts-ignore: decorator + @builtin + export declare function get_codeunit(view: ref_stringview_wtf16, pos: i32): i32; + + // TODO: encode +} + +export namespace stringview_iter { + + // @ts-ignore: decorator + @builtin + export declare function next(view: ref_stringview_iter): i32; + + // @ts-ignore: decorator + @builtin + export declare function advance(view: ref_stringview_iter, count: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function rewind(view: ref_stringview_iter, count: i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function slice(view: ref_stringview_iter, count: i32): ref_string; +} + /* 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 cbba3592aa..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. */ @@ -1668,6 +1668,94 @@ declare abstract class i31 { static get(i31expr: ref_i31 | null): i32; } +declare namespace 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. */ + 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): 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: 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): 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: 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): 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: ref_array, start: i32, end: i32): ref_string; + /** Creates a new string from the given `codepoint`. */ + export function from_code_point(codepoint: i32): ref_string; + /** Obtains an implementation-defined 32-bit hash value of `str`. */ + 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: ref_string): i32; + /** Measures the number of bytes required to encode `str` to WTF-8. */ + 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: 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: ref_string): bool; + /** Encodes `str` to memory at `ptr` using a strict UTF-8 encoder. */ + 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: 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: ref_string, ptr: usize): i32; + /** Encodes `str` to `arr` at `start` using a WTF-8 encoder. */ + 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: ref_string, ptr: usize): i32; + /** Encodes `str` to `arr` at `start` using a WTF-16 encoder. */ + 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: ref_string, right: ref_string): ref_string; + /** Tests whether `left` and `right` are equal, including if both are `null`. */ + 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: ref_string, right: ref_string): i32; + /** Obtains a WTF-8 view on `str`. */ + export function as_wtf8(str: ref_string): ref_stringview_wtf8; + /** Obtains a WTF-16 view on `str`. */ + export function as_wtf16(str: ref_string): ref_stringview_wtf16; + /** Obtains an iterator view on `str`. */ + 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: 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: ref_stringview_wtf8, start: i32, end: i32): ref_string; + // 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: ref_stringview_wtf16): i32; + /** Returns a substring of `view` from `start` inclusive to `end` exclusive. */ + 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: 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: ref_stringview_iter): i32; + /** Advances the iterator by up to `count` code points, returning the number of code points consumed. */ + 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: 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: ref_stringview_iter, count: i32): ref_string; +} + /** 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 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.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..3795771c70 --- /dev/null +++ b/tests/compiler/features/stringref.debug.wat @@ -0,0 +1,1871 @@ +(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)) + (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)) + (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 $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)) + (start $~start) + (func $features/stringref/test_locals (type $none_=>_none) + (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 $stringLocalNull + ref.null none + local.set $stringLocalNull + ref.null none + local.set $stringviewWtf8LocalNull + ref.null none + local.set $stringviewWtf8LocalNull + ref.null none + local.set $stringviewWtf16LocalNull + ref.null none + local.set $stringviewWtf16LocalNull + ref.null none + 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) + nop + ) + (func $features/stringref/test_lossy_utf8 (type $none_=>_none) + nop + ) + (func $features/stringref/test_wtf8 (type $none_=>_none) + (local $str (ref string)) + (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 (ref 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 60 + 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 62 + 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 63 + 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 64 + 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 65 + 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 66 + 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 67 + 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 68 + 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 69 + 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 72 + 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 73 + 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 74 + 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 75 + 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 76 + 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 77 + 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 78 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_wtf16 (type $none_=>_none) + (local $str (ref string)) + (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 (ref 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 86 + 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 88 + 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 89 + 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 90 + 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 91 + 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 92 + 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 93 + 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 94 + 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 95 + 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 98 + 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 99 + 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 100 + 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 101 + 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 102 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_iter (type $none_=>_none) + (local $str (ref string)) + (local $view (ref 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 111 + 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 112 + 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 113 + 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 114 + 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 115 + 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 116 + 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 117 + 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 118 + 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 119 + 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 120 + 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 121 + 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 122 + 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 123 + 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 124 + 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 125 + 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 126 + 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 128 + 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 129 + 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 130 + i32.const 3 + call $~lib/builtins/abort + 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 + 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 + 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.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..89f7aeedb0 --- /dev/null +++ b/tests/compiler/features/stringref.release.wat @@ -0,0 +1,1336 @@ +(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") + (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) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 (ref stringview_wtf8)) + (local $4 i32) + (local $5 i32) + (local $6 (ref string)) + (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 60 + 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 62 + 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 63 + 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 64 + 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 65 + 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 66 + 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 67 + 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 68 + 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 69 + 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 72 + 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 73 + 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 74 + 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 75 + 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 76 + 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 77 + 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 78 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_wtf16 (type $none_=>_none) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 (ref stringview_wtf16)) + (local $6 (ref string)) + (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 86 + 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 88 + 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 89 + 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 90 + 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 91 + 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 92 + 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 93 + 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 94 + 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 95 + 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 98 + 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 99 + 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 100 + 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 101 + 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 102 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (func $features/stringref/test_iter (type $none_=>_none) + (local $0 (ref stringview_iter)) + (local $1 (ref string)) + 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 111 + 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 112 + 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 113 + 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 114 + 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 115 + 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 116 + 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 117 + 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 118 + 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 119 + 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 120 + 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 121 + 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 122 + 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 123 + 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 124 + 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 125 + 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 126 + 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 128 + 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 129 + 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 130 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + ) + (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 + 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 + 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 new file mode 100644 index 0000000000..f25f9f04d0 --- /dev/null +++ b/tests/compiler/features/stringref.ts @@ -0,0 +1,163 @@ +@external("env", "console.log") +declare function log_s(s: ref_string | null): void; +@external("env", "console.log") +declare function log_i(i: i32): void; + +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 = ""; +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 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 = ""; + 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(); + +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, "abc")); + assert(string.compare(str, str) == 0); + 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); + + 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, "abc")); + assert(string.compare(str, str) == 0); + 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); + + 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 + +// 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); 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 5c47772500..f2e525e6f2 100644 --- a/tests/features.json +++ b/tests/features.json @@ -43,5 +43,14 @@ "v8_flags": [ "--experimental-wasm-relaxed-simd" ] + }, + "stringref": { + "asc_flags": [ + "--enable stringref" + ], + "v8_flags": [ + "--experimental-wasm-gc", + "--experimental-wasm-stringref" + ] } } 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