From af4d2612f49838e3f05f727e10e09eed61169f1e Mon Sep 17 00:00:00 2001 From: Joel Mun Date: Sun, 1 Dec 2019 01:21:02 +0900 Subject: [PATCH] Implement emission of warning upon generic function/class export (#570) --- NOTICE | 1 + src/compiler.ts | 16 +- src/diagnosticMessages.generated.ts | 2 + src/diagnosticMessages.json | 1 + tests/compiler.js | 52 +- tests/compiler/generic-export.json | 10 + tests/compiler/generic-export.optimized.wat | 161 ++ tests/compiler/generic-export.ts | 31 + tests/compiler/generic-export.untouched.wat | 1491 +++++++++++++++++++ 9 files changed, 1742 insertions(+), 23 deletions(-) create mode 100644 tests/compiler/generic-export.json create mode 100644 tests/compiler/generic-export.optimized.wat create mode 100644 tests/compiler/generic-export.ts create mode 100644 tests/compiler/generic-export.untouched.wat diff --git a/NOTICE b/NOTICE index ec157dab57..c74474413b 100644 --- a/NOTICE +++ b/NOTICE @@ -18,6 +18,7 @@ under the licensing terms detailed in LICENSE: * Emil Laine * Stephen Paul Weber * Jay Phelps +* Joel Mun Portions of this software are derived from third-party works licensed under the following terms: diff --git a/src/compiler.ts b/src/compiler.ts index a5eeaa8329..30102c6fdc 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -680,13 +680,23 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.FUNCTION_PROTOTYPE: { - if (!element.is(CommonFlags.GENERIC)) { + if (element.is(CommonFlags.GENERIC)) { + this.warning( + DiagnosticCode.Generic_functions_or_classes_cannot_be_compiled_to_wasm, + (element).identifierNode.range, + ); + } else { this.compileFunctionUsingTypeArguments(element, []); } break; } case ElementKind.CLASS_PROTOTYPE: { - if (!element.is(CommonFlags.GENERIC)) { + if (element.is(CommonFlags.GENERIC)) { + this.warning( + DiagnosticCode.Generic_functions_or_classes_cannot_be_compiled_to_wasm, + (element).identifierNode.range, + ); + } else { this.compileClassUsingTypeArguments(element, []); } break; @@ -712,7 +722,7 @@ export class Compiler extends DiagnosticEmitter { } /** Compiles an element's members. */ - compileMembers(element: Element): void { + compileMembers(element: Element,): void { var members = element.members; if (members) for (let element of members.values()) this.compileElement(element); } diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index abe278a10f..26500f51e6 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -99,6 +99,7 @@ export enum DiagnosticCode { Module_0_has_no_exported_member_1 = 2305, Generic_type_0_requires_1_type_argument_s = 2314, Type_0_is_not_generic = 2315, + Generic_functions_or_classes_cannot_be_compiled_to_wasm = 2316, Type_0_is_not_assignable_to_type_1 = 2322, Index_signature_is_missing_in_type_0 = 2329, _this_cannot_be_referenced_in_current_location = 2332, @@ -242,6 +243,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 2305: return "Module '{0}' has no exported member '{1}'."; case 2314: return "Generic type '{0}' requires {1} type argument(s)."; case 2315: return "Type '{0}' is not generic."; + case 2316: return "Generic functions or classes cannot be compiled to wasm"; case 2322: return "Type '{0}' is not assignable to type '{1}'."; case 2329: return "Index signature is missing in type '{0}'."; case 2332: return "'this' cannot be referenced in current location."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 8ee257ddb0..129006bc80 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -94,6 +94,7 @@ "Module '{0}' has no exported member '{1}'.": 2305, "Generic type '{0}' requires {1} type argument(s).": 2314, "Type '{0}' is not generic.": 2315, + "Generic functions or classes cannot be compiled to wasm": 2316, "Type '{0}' is not assignable to type '{1}'.": 2322, "Index signature is missing in type '{0}'.": 2329, "'this' cannot be referenced in current location.": 2332, diff --git a/tests/compiler.js b/tests/compiler.js index 3f286b89df..fa190d5263 100644 --- a/tests/compiler.js +++ b/tests/compiler.js @@ -156,32 +156,44 @@ function runTest(basename) { }, err => { console.log(); - // check expected stderr patterns in order + // check expected stderr and stdout patterns in order let expectStderr = config.stderr; - if (expectStderr) { - const stderrString = stderr.toString(); - if (typeof expectStderr === "string") expectStderr = [ expectStderr ]; - let lastIndex = 0; - let failed = false; - expectStderr.forEach((substr, i) => { - var index = stderrString.indexOf(substr, lastIndex); - if (index < 0) { - console.log("Missing pattern #" + (i + 1) + " '" + substr + "' in stderr at " + lastIndex + "+."); + let expectStdout = config.stdout; + let hasExpected = false; + [ + { expected: expectStderr, text: 'stderr' }, + { expected: expectStdout, text: 'stdout' } + ].forEach((stdPatterns) => { + let expected = stdPatterns.expected; + if (expected) { + hasExpected = true; + const stderrString = stderr.toString(); + if (typeof expected === "string") expected = [ expected ]; + let lastIndex = 0; + let failed = false; + expected.forEach((substr, i) => { + var index = stderrString.indexOf(substr, lastIndex); + if (index < 0) { + console.log("Missing pattern #" + (i + 1) + " '" + substr + "' in stderr at " + lastIndex + "+."); + failedTests.add(basename); + failed = true; + } else { + lastIndex = index + substr.length; + } + }); + let text = stdPatterns.text; + if (failed) { failedTests.add(basename); - failed = true; + failedMessages.set(basename, + text + " mismatch"); + console.log("\n- " + colorsUtil.red(text + " MISMATCH") + "\n"); } else { - lastIndex = index + substr.length; + console.log("- " + colorsUtil.green(text + " MATCH") + "\n"); } - }); - if (failed) { - failedTests.add(basename); - failedMessages.set(basename, "stderr mismatch"); - console.log("\n- " + colorsUtil.red("stderr MISMATCH") + "\n"); - } else { - console.log("- " + colorsUtil.green("stderr MATCH") + "\n"); + return; } + }) + if (hasExpected) return; - } if (err) stderr.write(err + os.EOL); diff --git a/tests/compiler/generic-export.json b/tests/compiler/generic-export.json new file mode 100644 index 0000000000..1113c08f93 --- /dev/null +++ b/tests/compiler/generic-export.json @@ -0,0 +1,10 @@ +{ + "asc_flags": [ + "--runtime none" + ], + "stdout": [ + "TS2316: Generic functions or classes cannot be compiled to wasm", "export function genericExample(a: T, b: T): Array {", + "TS2316: Generic functions or classes cannot be compiled to wasm", "export class GenericNumber {", + "TS2316: Generic functions or classes cannot be compiled to wasm", "export class GenericNumber2 {" + ] +} \ No newline at end of file diff --git a/tests/compiler/generic-export.optimized.wat b/tests/compiler/generic-export.optimized.wat new file mode 100644 index 0000000000..1d790bd9fa --- /dev/null +++ b/tests/compiler/generic-export.optimized.wat @@ -0,0 +1,161 @@ +(module + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$v (func)) + (memory $0 0) + (global $generic-export/okVariable i32 (i32.const 1)) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $generic-export/OkClass i32 (i32.const 4)) + (export "memory" (memory $0)) + (export "genericExample" (func $generic-export/okFunction)) + (export "okFunction" (func $generic-export/okFunction)) + (export "OkClass" (global $generic-export/OkClass)) + (export "OkClass#one" (func $generic-export/OkClass#one)) + (export "okVariable" (global $generic-export/okVariable)) + (export "functionThatUsesGenericFunction" (func $generic-export/functionThatUsesGenericFunction)) + (start $start) + (func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + local.get $0 + memory.size + local.tee $2 + i32.const 16 + i32.shl + local.tee $1 + i32.gt_u + if + local.get $2 + local.get $0 + local.get $1 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $1 + local.get $2 + local.get $1 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $1 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.tee $3 + local.get $0 + i32.const 15 + i32.add + i32.const -16 + i32.and + local.tee $2 + i32.const 16 + local.get $2 + i32.const 16 + i32.gt_u + select + local.tee $4 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $3 + i32.const 16 + i32.sub + local.tee $2 + local.get $4 + i32.store + local.get $2 + i32.const -1 + i32.store offset=4 + local.get $2 + local.get $1 + i32.store offset=8 + local.get $2 + local.get $0 + i32.store offset=12 + local.get $3 + ) + (func $~lib/rt/__allocArray (; 2 ;) (type $FUNCSIG$i) (result i32) + (local $0 i32) + (local $1 i32) + i32.const 16 + i32.const 3 + call $~lib/rt/stub/__alloc + local.tee $0 + i32.const 8 + i32.const 0 + call $~lib/rt/stub/__alloc + local.tee $1 + i32.store + local.get $0 + local.get $1 + i32.store offset=4 + local.get $0 + i32.const 8 + i32.store offset=8 + local.get $0 + i32.const 2 + i32.store offset=12 + local.get $0 + ) + (func $generic-export/okFunction (; 3 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + call $~lib/rt/__allocArray + local.tee $2 + i32.load offset=4 + local.tee $3 + local.get $0 + i32.store + local.get $3 + local.get $1 + i32.store offset=4 + local.get $2 + ) + (func $generic-export/OkClass#one (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 1 + ) + (func $generic-export/functionThatUsesGenericFunction (; 5 ;) (type $FUNCSIG$i) (result i32) + i32.const 1 + i32.const 1 + call $generic-export/okFunction + ) + (func $start (; 6 ;) (type $FUNCSIG$v) + i32.const 16 + global.set $~lib/rt/stub/startOffset + i32.const 16 + global.set $~lib/rt/stub/offset + ) + (func $null (; 7 ;) (type $FUNCSIG$v) + nop + ) +) diff --git a/tests/compiler/generic-export.ts b/tests/compiler/generic-export.ts new file mode 100644 index 0000000000..604abf155a --- /dev/null +++ b/tests/compiler/generic-export.ts @@ -0,0 +1,31 @@ +export function genericExample(a: T, b: T): Array { + return [a, b]; +} + +export function okFunction(a: i32, b: i32): Array { + return [a, b]; +} + +export class OkClass { + one(): i32 { + return 1; + } +} + +export class GenericNumber { + zeroValue: T; + add: (x: T, y: T) => T; +} + +export namespace GenericNumberNamespace { + export class GenericNumber2 { + zeroValue: T; + add: (x: T, y: T) => T; + } +} + +export const okVariable: i32 = 1; + +export function functionThatUsesGenericFunction(): Array { + return genericExample(1, 1); +} diff --git a/tests/compiler/generic-export.untouched.wat b/tests/compiler/generic-export.untouched.wat new file mode 100644 index 0000000000..e7ae366312 --- /dev/null +++ b/tests/compiler/generic-export.untouched.wat @@ -0,0 +1,1491 @@ +(module + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$ii (func (param i32) (result i32))) + (type $FUNCSIG$viii (func (param i32 i32 i32))) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$v (func)) + (memory $0 0) + (table $0 1 funcref) + (elem (i32.const 0) $null) + (global $generic-export/okVariable i32 (i32.const 1)) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $~lib/ASC_SHRINK_LEVEL i32 (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 8)) + (global $generic-export/OkClass i32 (i32.const 4)) + (export "memory" (memory $0)) + (export "genericExample" (func $generic-export/genericExample)) + (export "okFunction" (func $generic-export/okFunction)) + (export "OkClass" (global $generic-export/OkClass)) + (export "OkClass#one" (func $generic-export/OkClass#one)) + (export "okVariable" (global $generic-export/okVariable)) + (export "functionThatUsesGenericFunction" (func $generic-export/functionThatUsesGenericFunction)) + (start $start) + (func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + local.get $6 + i32.const -1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/rt/stub/__retain (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + ) + (func $~lib/util/memory/memcpy (; 3 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + block $break|0 + loop $continue|0 + local.get $2 + if (result i32) + local.get $1 + i32.const 3 + i32.and + else + i32.const 0 + end + i32.eqz + br_if $break|0 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 1 + i32.sub + local.set $2 + br $continue|0 + end + unreachable + end + local.get $0 + i32.const 3 + i32.and + i32.const 0 + i32.eq + if + block $break|1 + loop $continue|1 + local.get $2 + i32.const 16 + i32.ge_u + i32.eqz + br_if $break|1 + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.get $1 + i32.const 4 + i32.add + i32.load + i32.store + local.get $0 + i32.const 8 + i32.add + local.get $1 + i32.const 8 + i32.add + i32.load + i32.store + local.get $0 + i32.const 12 + i32.add + local.get $1 + i32.const 12 + i32.add + i32.load + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|1 + end + unreachable + end + local.get $2 + i32.const 8 + i32.and + if + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.get $1 + i32.const 4 + i32.add + i32.load + i32.store + local.get $0 + i32.const 8 + i32.add + local.set $0 + local.get $1 + i32.const 8 + i32.add + local.set $1 + end + local.get $2 + i32.const 4 + i32.and + if + local.get $0 + local.get $1 + i32.load + i32.store + local.get $0 + i32.const 4 + i32.add + local.set $0 + local.get $1 + i32.const 4 + i32.add + local.set $1 + end + local.get $2 + i32.const 2 + i32.and + if + local.get $0 + local.get $1 + i32.load16_u + i32.store16 + local.get $0 + i32.const 2 + i32.add + local.set $0 + local.get $1 + i32.const 2 + i32.add + local.set $1 + end + local.get $2 + i32.const 1 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + return + end + local.get $2 + i32.const 32 + i32.ge_u + if + block $break|2 + block $case2|2 + block $case1|2 + block $case0|2 + local.get $0 + i32.const 3 + i32.and + local.set $5 + local.get $5 + i32.const 1 + i32.eq + br_if $case0|2 + local.get $5 + i32.const 2 + i32.eq + br_if $case1|2 + local.get $5 + i32.const 3 + i32.eq + br_if $case2|2 + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 3 + i32.sub + local.set $2 + block $break|3 + loop $continue|3 + local.get $2 + i32.const 17 + i32.ge_u + i32.eqz + br_if $break|3 + local.get $1 + i32.const 1 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 24 + i32.shr_u + local.get $4 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 5 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 24 + i32.shr_u + local.get $3 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 9 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 24 + i32.shr_u + local.get $4 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 13 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 24 + i32.shr_u + local.get $3 + i32.const 8 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|3 + end + unreachable + end + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 2 + i32.sub + local.set $2 + block $break|4 + loop $continue|4 + local.get $2 + i32.const 18 + i32.ge_u + i32.eqz + br_if $break|4 + local.get $1 + i32.const 2 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 16 + i32.shr_u + local.get $4 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 6 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 16 + i32.shr_u + local.get $3 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 10 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 16 + i32.shr_u + local.get $4 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 14 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 16 + i32.shr_u + local.get $3 + i32.const 16 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|4 + end + unreachable + end + br $break|2 + end + local.get $1 + i32.load + local.set $3 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $2 + i32.const 1 + i32.sub + local.set $2 + block $break|5 + loop $continue|5 + local.get $2 + i32.const 19 + i32.ge_u + i32.eqz + br_if $break|5 + local.get $1 + i32.const 3 + i32.add + i32.load + local.set $4 + local.get $0 + local.get $3 + i32.const 8 + i32.shr_u + local.get $4 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 7 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 4 + i32.add + local.get $4 + i32.const 8 + i32.shr_u + local.get $3 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 11 + i32.add + i32.load + local.set $4 + local.get $0 + i32.const 8 + i32.add + local.get $3 + i32.const 8 + i32.shr_u + local.get $4 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 15 + i32.add + i32.load + local.set $3 + local.get $0 + i32.const 12 + i32.add + local.get $4 + i32.const 8 + i32.shr_u + local.get $3 + i32.const 24 + i32.shl + i32.or + i32.store + local.get $1 + i32.const 16 + i32.add + local.set $1 + local.get $0 + i32.const 16 + i32.add + local.set $0 + local.get $2 + i32.const 16 + i32.sub + local.set $2 + br $continue|5 + end + unreachable + end + br $break|2 + end + end + local.get $2 + i32.const 16 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 8 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 4 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 2 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + local.get $2 + i32.const 1 + i32.and + if + local.get $0 + local.tee $5 + i32.const 1 + i32.add + local.set $0 + local.get $5 + local.get $1 + local.tee $5 + i32.const 1 + i32.add + local.set $1 + local.get $5 + i32.load8_u + i32.store8 + end + ) + (func $~lib/memory/memory.copy (; 4 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + block $~lib/util/memory/memmove|inlined.0 + local.get $0 + local.set $5 + local.get $1 + local.set $4 + local.get $2 + local.set $3 + local.get $5 + local.get $4 + i32.eq + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $4 + local.get $3 + i32.add + local.get $5 + i32.le_u + if (result i32) + i32.const 1 + else + local.get $5 + local.get $3 + i32.add + local.get $4 + i32.le_u + end + if + local.get $5 + local.get $4 + local.get $3 + call $~lib/util/memory/memcpy + br $~lib/util/memory/memmove|inlined.0 + end + local.get $5 + local.get $4 + i32.lt_u + if + local.get $4 + i32.const 7 + i32.and + local.get $5 + i32.const 7 + i32.and + i32.eq + if + block $break|0 + loop $continue|0 + local.get $5 + i32.const 7 + i32.and + i32.eqz + br_if $break|0 + local.get $3 + i32.eqz + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $3 + i32.const 1 + i32.sub + local.set $3 + local.get $5 + local.tee $6 + i32.const 1 + i32.add + local.set $5 + local.get $6 + local.get $4 + local.tee $6 + i32.const 1 + i32.add + local.set $4 + local.get $6 + i32.load8_u + i32.store8 + br $continue|0 + end + unreachable + end + block $break|1 + loop $continue|1 + local.get $3 + i32.const 8 + i32.ge_u + i32.eqz + br_if $break|1 + local.get $5 + local.get $4 + i64.load + i64.store + local.get $3 + i32.const 8 + i32.sub + local.set $3 + local.get $5 + i32.const 8 + i32.add + local.set $5 + local.get $4 + i32.const 8 + i32.add + local.set $4 + br $continue|1 + end + unreachable + end + end + block $break|2 + loop $continue|2 + local.get $3 + i32.eqz + br_if $break|2 + local.get $5 + local.tee $6 + i32.const 1 + i32.add + local.set $5 + local.get $6 + local.get $4 + local.tee $6 + i32.const 1 + i32.add + local.set $4 + local.get $6 + i32.load8_u + i32.store8 + local.get $3 + i32.const 1 + i32.sub + local.set $3 + br $continue|2 + end + unreachable + end + else + local.get $4 + i32.const 7 + i32.and + local.get $5 + i32.const 7 + i32.and + i32.eq + if + block $break|3 + loop $continue|3 + local.get $5 + local.get $3 + i32.add + i32.const 7 + i32.and + i32.eqz + br_if $break|3 + local.get $3 + i32.eqz + if + br $~lib/util/memory/memmove|inlined.0 + end + local.get $5 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $4 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|3 + end + unreachable + end + block $break|4 + loop $continue|4 + local.get $3 + i32.const 8 + i32.ge_u + i32.eqz + br_if $break|4 + local.get $3 + i32.const 8 + i32.sub + local.set $3 + local.get $5 + local.get $3 + i32.add + local.get $4 + local.get $3 + i32.add + i64.load + i64.store + br $continue|4 + end + unreachable + end + end + block $break|5 + loop $continue|5 + local.get $3 + i32.eqz + br_if $break|5 + local.get $5 + local.get $3 + i32.const 1 + i32.sub + local.tee $3 + i32.add + local.get $4 + local.get $3 + i32.add + i32.load8_u + i32.store8 + br $continue|5 + end + unreachable + end + end + end + ) + (func $~lib/rt/__allocArray (; 5 ;) (type $FUNCSIG$iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + i32.const 16 + local.get $2 + call $~lib/rt/stub/__alloc + local.set $4 + local.get $0 + local.get $1 + i32.shl + local.set $5 + local.get $5 + i32.const 0 + call $~lib/rt/stub/__alloc + local.set $6 + local.get $4 + local.get $6 + call $~lib/rt/stub/__retain + i32.store + local.get $4 + local.get $6 + i32.store offset=4 + local.get $4 + local.get $5 + i32.store offset=8 + local.get $4 + local.get $0 + i32.store offset=12 + local.get $3 + if + local.get $6 + local.get $3 + local.get $5 + call $~lib/memory/memory.copy + end + local.get $4 + ) + (func $generic-export/okFunction (; 6 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + i32.const 2 + i32.const 2 + i32.const 3 + i32.const 0 + call $~lib/rt/__allocArray + local.set $2 + local.get $2 + i32.load offset=4 + local.set $3 + local.get $3 + local.get $0 + i32.store + local.get $3 + local.get $1 + i32.store offset=4 + local.get $2 + call $~lib/rt/stub/__retain + ) + (func $generic-export/OkClass#one (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 1 + ) + (func $generic-export/genericExample (; 8 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + i32.const 2 + i32.const 2 + i32.const 3 + i32.const 0 + call $~lib/rt/__allocArray + local.set $2 + local.get $2 + i32.load offset=4 + local.set $3 + local.get $3 + local.get $0 + i32.store + local.get $3 + local.get $1 + i32.store offset=4 + local.get $2 + call $~lib/rt/stub/__retain + ) + (func $generic-export/functionThatUsesGenericFunction (; 9 ;) (type $FUNCSIG$i) (result i32) + i32.const 1 + i32.const 1 + call $generic-export/genericExample + ) + (func $start (; 10 ;) (type $FUNCSIG$v) + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + ) + (func $null (; 11 ;) (type $FUNCSIG$v) + ) +)