diff --git a/src/compiler.ts b/src/compiler.ts index 154b7006..304c5f38 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6665,34 +6665,135 @@ export class Compiler extends DiagnosticEmitter { var module = this.module; // NOTE that this differs from TypeScript in that the rhs is a type, not an expression. at the // time of implementation, this seemed more useful because dynamic rhs expressions are not - // possible in AS anyway. + // possible in AS anyway. also note that the code generated below must preserve side-effects of + // the LHS expression even when the result is a constant, i.e. return a block dropping `expr`. var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE); var actualType = this.currentType; - var expectedType = this.resolver.resolveType( - expression.isType, - this.currentFlow.actualFunction - ); + var expectedType = this.resolver.resolveType(expression.isType, this.currentFlow.actualFunction); this.currentType = Type.bool; if (!expectedType) return module.createUnreachable(); - // instanceof must be exact + // instanceof - must be exact if (!expectedType.is(TypeFlags.REFERENCE)) { - return module.createI32(actualType == expectedType ? 1 : 0); + return module.createBlock(null, [ + this.convertExpression(expr, actualType, Type.void, ConversionKind.EXPLICIT, WrapMode.NONE, expression.expression), + module.createI32(actualType == expectedType ? 1 : 0) + ], NativeType.I32); } - // instanceof must be != 0 - if ( - actualType.is(TypeFlags.NULLABLE) && !expectedType.is(TypeFlags.NULLABLE) && - actualType.nonNullableType.isAssignableTo(expectedType) - ) { - return module.createBinary( - actualType.is(TypeFlags.LONG) - ? BinaryOp.NeI64 - : BinaryOp.NeI32, - expr, - actualType.toNativeZero(module) - ); + + // instanceof - always false + if (!actualType.is(TypeFlags.REFERENCE)) { + return module.createBlock(null, [ + this.convertExpression(expr, actualType, Type.void, ConversionKind.EXPLICIT, WrapMode.NONE, expression.expression), + module.createI32(0) + ], NativeType.I32); } - return module.createI32(actualType.isAssignableTo(expectedType) ? 1 : 0); + + // both LHS and RHS are references now + var nativeSizeType = actualType.toNativeType(); + + // instanceof - LHS must be != 0 + if (actualType.is(TypeFlags.NULLABLE) && !expectedType.is(TypeFlags.NULLABLE)) { + + // downcast - check statically + if (actualType.nonNullableType.isAssignableTo(expectedType)) { + return module.createBinary( + nativeSizeType == NativeType.I64 + ? BinaryOp.NeI64 + : BinaryOp.NeI32, + expr, + actualType.toNativeZero(module) + ); + } + + // upcast - check dynamically + if (expectedType.isAssignableTo(actualType)) { + let program = this.program; + this.needsInstanceOf = true; + if (!(actualType.isUnmanaged || expectedType.isUnmanaged)) { + let flow = this.currentFlow; + let tempLocal = flow.getAndFreeTempLocal(actualType, false); + this.needsInstanceOf = true; + return module.createIf( + module.createUnary( + nativeSizeType == NativeType.I64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + module.createTeeLocal(tempLocal.index, expr), + ), + module.createI32(0), + module.createCall(BuiltinSymbols.runtime_instanceof, [ + module.createLoad(4, false, + module.createBinary(BinaryOp.SubI32, + module.createGetLocal(tempLocal.index, nativeSizeType), + module.createI32(program.runtimeHeaderSize) + ), + NativeType.I32 + ), + module.createI32(expectedType.classReference!.ensureId()) + ], NativeType.I32) + ); + } else { + this.error( + DiagnosticCode.Operation_not_supported, + expression.range + ); + } + } + + // either none or both nullable + } else { + + // downcast - check statically + if (actualType.isAssignableTo(expectedType)) { + return module.createBlock(null, [ + this.convertExpression(expr, actualType, Type.void, ConversionKind.EXPLICIT, WrapMode.NONE, expression.expression), + module.createI32(1) + ], NativeType.I32); + + // upcast - check dynamically + } else if (expectedType.isAssignableTo(actualType)) { + let program = this.program; + if (!(actualType.isUnmanaged || expectedType.isUnmanaged)) { + // FIXME: the temp local and the if can be removed here once flows + // perform null checking, which would error earlier when checking + // uninitialized (thus zero) `var a: A` to be an instance of something. + let flow = this.currentFlow; + let tempLocal = flow.getAndFreeTempLocal(actualType, false); + this.needsInstanceOf = true; + return module.createIf( + module.createUnary( + nativeSizeType == NativeType.I64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + module.createTeeLocal(tempLocal.index, expr), + ), + module.createI32(0), + module.createCall(BuiltinSymbols.runtime_instanceof, [ + module.createLoad(4, false, + module.createBinary(BinaryOp.SubI32, + module.createGetLocal(tempLocal.index, nativeSizeType), + module.createI32(program.runtimeHeaderSize) + ), + NativeType.I32 + ), + module.createI32(expectedType.classReference!.ensureId()) + ], NativeType.I32) + ); + } else { + this.error( + DiagnosticCode.Operation_not_supported, + expression.range + ); + } + } + } + + // false + return module.createBlock(null, [ + this.convertExpression(expr, actualType, Type.void, ConversionKind.EXPLICIT, WrapMode.NONE, expression.expression), + module.createI32(0) + ], NativeType.I32); } compileLiteralExpression( diff --git a/src/types.ts b/src/types.ts index 09b9e164..35551e1d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -160,6 +160,12 @@ export class Type { return false; } + /** Tests if this is a class type explicitly annotated as unmanaged. */ + get isUnmanaged(): bool { + var classReference = this.classReference; + return classReference !== null && classReference.hasDecorator(DecoratorFlags.UNMANAGED); + } + /** Computes the sign-extending shift in the target type. */ computeSmallIntegerShift(targetType: Type): u32 { return targetType.size - this.size; diff --git a/std/assembly/runtime.ts b/std/assembly/runtime.ts index bbdbf54f..0d167a78 100644 --- a/std/assembly/runtime.ts +++ b/std/assembly/runtime.ts @@ -128,4 +128,15 @@ export namespace runtime { if (source) memory.copy(buffer, source, bufferSize); return array; } + + // @ts-ignore: decorator + @unsafe + export function instanceOf(ref: usize, id: u32): bool { + return ref + ? __runtime_instanceof( + changetype
(ref - HEADER_SIZE).classId, + id + ) + : false; + } } diff --git a/tests/compiler/gc.optimized.wat b/tests/compiler/gc.optimized.wat index 14d0a109..959e4bd0 100644 --- a/tests/compiler/gc.optimized.wat +++ b/tests/compiler/gc.optimized.wat @@ -55,6 +55,7 @@ (export "runtime.register" (func $~lib/runtime/runtime.register)) (export ".setargc" (func $~lib/setargc)) (export "runtime.makeArray" (func $~lib/runtime/runtime.makeArray|trampoline)) + (export "runtime.instanceOf" (func $~lib/runtime/runtime.instanceOf)) (export "gc.implemented" (global $~lib/gc/gc.implemented)) (export "gc.collect" (func $~lib/gc/gc.collect)) (export "gc.retain" (func $~lib/gc/gc.retain)) @@ -2361,10 +2362,56 @@ end local.get $4 ) - (func $null (; 28 ;) (type $FUNCSIG$v) + (func $~lib/runtime/runtime.instanceOf (; 28 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + local.get $1 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + ) + (func $~lib/runtime/__runtime_instanceof (; 29 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + block $nope + block $~lib/arraybuffer/ArrayBuffer + block $~lib/set/Set + block $~lib/string/String + block $gc/Ref + local.get $0 + i32.const 1 + i32.sub + br_table $gc/Ref $~lib/string/String $~lib/set/Set $~lib/arraybuffer/ArrayBuffer $nope + end + local.get $1 + i32.const 1 + i32.eq + return + end + local.get $1 + i32.const 2 + i32.eq + return + end + local.get $1 + i32.const 3 + i32.eq + return + end + local.get $1 + i32.const 4 + i32.eq + return + end + i32.const 0 + ) + (func $null (; 30 ;) (type $FUNCSIG$v) nop ) - (func $~lib/runtime/runtime.makeArray|trampoline (; 29 ;) (type $FUNCSIG$iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32) + (func $~lib/runtime/runtime.makeArray|trampoline (; 31 ;) (type $FUNCSIG$iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32) block $1of1 block $0of1 block $outOfRange @@ -2384,7 +2431,7 @@ local.get $3 call $~lib/runtime/runtime.makeArray ) - (func $~lib/setargc (; 30 ;) (type $FUNCSIG$vi) (param $0 i32) + (func $~lib/setargc (; 32 ;) (type $FUNCSIG$vi) (param $0 i32) local.get $0 global.set $~lib/argc ) diff --git a/tests/compiler/gc.untouched.wat b/tests/compiler/gc.untouched.wat index 80ab5637..77b3114a 100644 --- a/tests/compiler/gc.untouched.wat +++ b/tests/compiler/gc.untouched.wat @@ -54,6 +54,7 @@ (export "runtime.register" (func $~lib/runtime/runtime.register)) (export ".setargc" (func $~lib/setargc)) (export "runtime.makeArray" (func $~lib/runtime/runtime.makeArray|trampoline)) + (export "runtime.instanceOf" (func $~lib/runtime/runtime.instanceOf)) (export "gc.implemented" (global $~lib/gc/gc.implemented)) (export "gc.collect" (func $~lib/gc/gc.collect)) (export "gc.retain" (func $~lib/gc/gc.retain)) @@ -2972,7 +2973,20 @@ end local.get $4 ) - (func $start (; 33 ;) (type $FUNCSIG$v) + (func $~lib/runtime/runtime.instanceOf (; 33 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + if (result i32) + local.get $0 + global.get $~lib/util/runtime/HEADER_SIZE + i32.sub + i32.load + local.get $1 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + ) + (func $start (; 34 ;) (type $FUNCSIG$v) global.get $~lib/memory/HEAP_BASE i32.const 7 i32.add @@ -2987,9 +3001,41 @@ call $~lib/set/Set#constructor global.set $~lib/gc/ROOT ) - (func $null (; 34 ;) (type $FUNCSIG$v) + (func $~lib/runtime/__runtime_instanceof (; 35 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + block $nope + block $~lib/arraybuffer/ArrayBuffer + block $~lib/set/Set + block $~lib/string/String + block $gc/Ref + local.get $0 + br_table $nope $gc/Ref $~lib/string/String $~lib/set/Set $~lib/arraybuffer/ArrayBuffer $nope + end + local.get $1 + i32.const 1 + i32.eq + return + end + local.get $1 + i32.const 2 + i32.eq + return + end + local.get $1 + i32.const 3 + i32.eq + return + end + local.get $1 + i32.const 4 + i32.eq + return + end + i32.const 0 + return ) - (func $~lib/runtime/runtime.makeArray|trampoline (; 35 ;) (type $FUNCSIG$iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32) + (func $null (; 36 ;) (type $FUNCSIG$v) + ) + (func $~lib/runtime/runtime.makeArray|trampoline (; 37 ;) (type $FUNCSIG$iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32) block $1of1 block $0of1 block $outOfRange @@ -3009,7 +3055,7 @@ local.get $3 call $~lib/runtime/runtime.makeArray ) - (func $~lib/setargc (; 36 ;) (type $FUNCSIG$vi) (param $0 i32) + (func $~lib/setargc (; 38 ;) (type $FUNCSIG$vi) (param $0 i32) local.get $0 global.set $~lib/argc ) diff --git a/tests/compiler/instanceof.ts b/tests/compiler/instanceof.ts index 64d96b03..b5b10329 100644 --- a/tests/compiler/instanceof.ts +++ b/tests/compiler/instanceof.ts @@ -15,7 +15,7 @@ assert(!(I instanceof A)); assert(!(f instanceof A)); assert(!(F instanceof A)); -assert(!(a instanceof B)); +// assert(!(a instanceof B)); // dynamic upcast, checked in runtime/instanceof assert( b instanceof B ); assert(!(i instanceof B)); assert(!(I instanceof B)); diff --git a/tests/compiler/instanceof.untouched.wat b/tests/compiler/instanceof.untouched.wat index ed9a4ef7..65e10c40 100644 --- a/tests/compiler/instanceof.untouched.wat +++ b/tests/compiler/instanceof.untouched.wat @@ -20,23 +20,75 @@ (export "table" (table $0)) (start $start) (func $instanceof/isI32 (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - i32.const 1 - return + block (result i32) + local.get $0 + drop + i32.const 1 + end + if + i32.const 1 + return + else + i32.const 0 + return + end + unreachable + unreachable ) (func $instanceof/isI32 (; 2 ;) (type $FUNCSIG$id) (param $0 f64) (result i32) - i32.const 0 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + else + i32.const 0 + return + end + unreachable + unreachable ) (func $instanceof/isI32 (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - i32.const 0 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + else + i32.const 0 + return + end + unreachable + unreachable ) (func $instanceof/isI32 (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) - i32.const 0 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + else + i32.const 0 + return + end + unreachable + unreachable ) (func $start:instanceof (; 5 ;) (type $FUNCSIG$v) - i32.const 1 + block (result i32) + global.get $instanceof/a + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -46,7 +98,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/b + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -56,7 +112,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/i + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -67,7 +127,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/I + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -78,7 +142,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/f + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -89,7 +157,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/F + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -100,18 +172,11 @@ call $~lib/env/abort unreachable end - i32.const 0 - i32.eqz - i32.eqz - if - i32.const 0 - i32.const 16 - i32.const 18 - i32.const 0 - call $~lib/env/abort - unreachable + block (result i32) + global.get $instanceof/b + drop + i32.const 1 end - i32.const 1 i32.eqz if i32.const 0 @@ -121,7 +186,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/i + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -132,7 +201,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/I + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -143,7 +216,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/f + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -154,7 +231,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/F + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -165,7 +246,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/a + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -176,7 +261,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/b + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -187,7 +276,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/i + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -197,7 +290,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/I + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -208,7 +305,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/f + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -219,7 +320,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/F + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -230,7 +335,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/a + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -241,7 +350,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/b + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -252,7 +365,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/i + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -263,7 +380,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/I + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -273,7 +394,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/f + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -284,7 +409,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/F + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -295,7 +424,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/a + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -306,7 +439,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/b + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -317,7 +454,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/i + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -328,7 +469,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/I + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -339,7 +484,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/f + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -349,7 +498,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/F + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -360,7 +513,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/a + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -371,7 +528,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/b + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -382,7 +543,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/i + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -393,7 +558,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/I + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -404,7 +573,11 @@ call $~lib/env/abort unreachable end - i32.const 0 + block (result i32) + global.get $instanceof/f + drop + i32.const 0 + end i32.eqz i32.eqz if @@ -415,7 +588,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/F + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -485,7 +662,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/an + drop + i32.const 1 + end i32.eqz if i32.const 0 @@ -509,7 +690,11 @@ call $~lib/env/abort unreachable end - i32.const 1 + block (result i32) + global.get $instanceof/an + drop + i32.const 1 + end i32.eqz if i32.const 0 diff --git a/tests/compiler/runtime/instanceof.optimized.wat b/tests/compiler/runtime/instanceof.optimized.wat index c3ece108..fe71599a 100644 --- a/tests/compiler/runtime/instanceof.optimized.wat +++ b/tests/compiler/runtime/instanceof.optimized.wat @@ -1,24 +1,212 @@ (module (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) - (type $FUNCSIG$v (func)) + (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viiddddd (func (param i32 i32 f64 f64 f64 f64 f64))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) + (import "env" "trace" (func $~lib/env/trace (param i32 i32 f64 f64 f64 f64 f64))) (memory $0 1) - (data (i32.const 8) "\02\00\00\00*\00\00\00r\00u\00n\00t\00i\00m\00e\00/\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s") + (data (i32.const 8) "\02\00\00\00*") + (data (i32.const 24) "r\00u\00n\00t\00i\00m\00e\00/\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s") + (data (i32.const 72) "\02\00\00\00\1e") + (data (i32.const 88) "~\00l\00i\00b\00/\00r\00u\00n\00t\00i\00m\00e\00.\00t\00s") + (data (i32.const 120) "\02\00\00\00\16") + (data (i32.const 136) "g\00c\00.\00r\00e\00g\00i\00s\00t\00e\00r") (table $0 1 funcref) (elem (i32.const 0) $null) + (global $gc/_dummy/register_count (mut i32) (i32.const 0)) + (global $gc/_dummy/register_ref (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (global $runtime/instanceof/animal (mut i32) (i32.const 0)) + (global $runtime/instanceof/cat (mut i32) (i32.const 0)) + (global $runtime/instanceof/blackcat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableAnimal (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableCat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableBlackcat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullAnimal (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullCat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullBlackcat (mut i32) (i32.const 0)) + (global $~lib/started (mut i32) (i32.const 0)) + (global $~lib/capabilities i32 (i32.const 2)) (export "memory" (memory $0)) (export "table" (table $0)) - (start $start) - (func $start:runtime/instanceof (; 1 ;) (type $FUNCSIG$v) + (export "main" (func $runtime/instanceof/main)) + (export ".capabilities" (global $~lib/capabilities)) + (func $~lib/allocator/arena/__mem_allocate (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + i32.const 1073741824 + i32.gt_u + if + unreachable + end + global.get $~lib/allocator/arena/offset + local.tee $1 + local.get $0 + i32.const 1 + local.get $0 + i32.const 1 + i32.gt_u + select + i32.add + i32.const 7 + i32.add + i32.const -8 + i32.and + local.tee $0 + current_memory + local.tee $2 + i32.const 16 + i32.shl + 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 $3 + local.get $2 + local.get $3 + i32.gt_s + select + grow_memory + i32.const 0 + i32.lt_s + if + local.get $3 + grow_memory + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/allocator/arena/offset + local.get $1 + ) + (func $~lib/runtime/runtime.allocate (; 3 ;) (type $FUNCSIG$i) (result i32) + (local $0 i32) + i32.const 16 + call $~lib/allocator/arena/__mem_allocate + local.tee $0 + i32.const -1520547049 + i32.store + local.get $0 + i32.const 0 + i32.store offset=4 + local.get $0 + i32.const 0 + i32.store offset=8 + local.get $0 + i32.const 0 + i32.store offset=12 + local.get $0 + i32.const 16 + i32.add + ) + (func $gc/_dummy/__ref_register (; 4 ;) (type $FUNCSIG$vi) (param $0 i32) + i32.const 136 + i32.const 1 + local.get $0 + f64.convert_i32_u + f64.const 0 + f64.const 0 + f64.const 0 + f64.const 0 + call $~lib/env/trace + global.get $gc/_dummy/register_count + i32.const 1 + i32.add + global.set $gc/_dummy/register_count + local.get $0 + global.set $gc/_dummy/register_ref + ) + (func $~lib/runtime/runtime.register (; 5 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $0 + i32.const 160 + i32.le_u + if + i32.const 0 + i32.const 88 + i32.const 107 + i32.const 6 + call $~lib/env/abort + unreachable + end + local.get $0 + i32.const 16 + i32.sub + local.tee $2 + i32.load + i32.const -1520547049 + i32.ne + if + i32.const 0 + i32.const 88 + i32.const 109 + i32.const 6 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i32.store + local.get $0 + call $gc/_dummy/__ref_register + local.get $0 + ) + (func $runtime/instanceof/Animal#constructor (; 6 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + if (result i32) + local.get $0 + else + call $~lib/runtime/runtime.allocate + i32.const 1 + call $~lib/runtime/runtime.register + end + ) + (func $runtime/instanceof/Cat#constructor (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + if (result i32) + local.get $0 + else + call $~lib/runtime/runtime.allocate + i32.const 3 + call $~lib/runtime/runtime.register + end + call $runtime/instanceof/Animal#constructor + ) + (func $runtime/instanceof/BlackCat#constructor (; 8 ;) (type $FUNCSIG$i) (result i32) + call $~lib/runtime/runtime.allocate + i32.const 4 + call $~lib/runtime/runtime.register + call $runtime/instanceof/Cat#constructor + ) + (func $start:runtime/instanceof (; 9 ;) (type $FUNCSIG$v) + (local $0 i32) i32.const 1 i32.const 1 call $~lib/runtime/__runtime_instanceof i32.eqz if i32.const 0 - i32.const 16 - i32.const 7 + i32.const 24 + i32.const 8 i32.const 0 call $~lib/env/abort unreachable @@ -29,8 +217,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 14 + i32.const 24 + i32.const 15 i32.const 0 call $~lib/env/abort unreachable @@ -41,8 +229,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 21 + i32.const 24 + i32.const 22 i32.const 0 call $~lib/env/abort unreachable @@ -53,8 +241,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 28 + i32.const 24 + i32.const 29 i32.const 0 call $~lib/env/abort unreachable @@ -65,8 +253,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 35 + i32.const 24 + i32.const 36 i32.const 0 call $~lib/env/abort unreachable @@ -76,8 +264,8 @@ call $~lib/runtime/__runtime_instanceof if i32.const 0 - i32.const 16 - i32.const 42 + i32.const 24 + i32.const 43 i32.const 0 call $~lib/env/abort unreachable @@ -87,8 +275,8 @@ call $~lib/runtime/__runtime_instanceof if i32.const 0 - i32.const 16 - i32.const 49 + i32.const 24 + i32.const 50 i32.const 0 call $~lib/env/abort unreachable @@ -98,17 +286,466 @@ call $~lib/runtime/__runtime_instanceof if i32.const 0 + i32.const 24 + i32.const 57 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 160 + global.set $~lib/allocator/arena/startOffset + global.get $~lib/allocator/arena/startOffset + global.set $~lib/allocator/arena/offset + i32.const 0 + call $runtime/instanceof/Animal#constructor + global.set $runtime/instanceof/animal + i32.const 0 + call $runtime/instanceof/Cat#constructor + global.set $runtime/instanceof/cat + call $runtime/instanceof/BlackCat#constructor + global.set $runtime/instanceof/blackcat + global.get $runtime/instanceof/animal + local.tee $0 + if (result i32) + local.get $0 i32.const 16 - i32.const 56 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 69 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/animal + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 70 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/cat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 73 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/cat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 74 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/blackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 77 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/blackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 78 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + call $runtime/instanceof/Animal#constructor + global.set $runtime/instanceof/nullableAnimal + i32.const 0 + call $runtime/instanceof/Cat#constructor + global.set $runtime/instanceof/nullableCat + call $runtime/instanceof/BlackCat#constructor + global.set $runtime/instanceof/nullableBlackcat + global.get $runtime/instanceof/nullableAnimal + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 84 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableAnimal + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 85 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableAnimal + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 86 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 88 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 89 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 90 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 92 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 93 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 94 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + if + i32.const 0 + i32.const 24 + i32.const 100 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 101 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 102 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + if + i32.const 0 + i32.const 24 + i32.const 104 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 105 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 106 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + if + i32.const 0 + i32.const 24 + i32.const 108 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 109 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + local.tee $0 + if (result i32) + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + else + i32.const 0 + end + if + i32.const 0 + i32.const 24 + i32.const 110 i32.const 0 call $~lib/env/abort unreachable end ) - (func $start (; 2 ;) (type $FUNCSIG$v) - call $start:runtime/instanceof + (func $runtime/instanceof/main (; 10 ;) (type $FUNCSIG$v) + global.get $~lib/started + i32.eqz + if + call $start:runtime/instanceof + i32.const 1 + global.set $~lib/started + end ) - (func $~lib/runtime/__runtime_instanceof (; 3 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/runtime/__runtime_instanceof (; 11 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) block $nope block $runtime/instanceof/BlackCat block $runtime/instanceof/Cat @@ -153,7 +790,7 @@ end i32.const 0 ) - (func $null (; 4 ;) (type $FUNCSIG$v) + (func $null (; 12 ;) (type $FUNCSIG$v) nop ) ) diff --git a/tests/compiler/runtime/instanceof.ts b/tests/compiler/runtime/instanceof.ts index 542d60a2..bb367bc4 100644 --- a/tests/compiler/runtime/instanceof.ts +++ b/tests/compiler/runtime/instanceof.ts @@ -1,4 +1,5 @@ import { __runtime_id, __runtime_instanceof } from "runtime"; +import "../gc/_dummy"; class Animal {} class Cat extends Animal {} @@ -59,3 +60,53 @@ assert(! // Cat isn't necessarily a BlackCat __runtime_id() ) ); + +var animal: Animal = new Animal(); +var cat: Animal = new Cat(); +var blackcat: Animal = new BlackCat(); + +assert(animal instanceof Animal); // static true +assert(!(animal instanceof Cat)); // dynamic false +assert(!(animal instanceof BlackCat)); // dynamic false + +assert(cat instanceof Animal); // static true +assert(cat instanceof Cat); // dynamic true +assert(!(cat instanceof BlackCat)); // dynamic false + +assert(blackcat instanceof Animal); // static true +assert(blackcat instanceof Cat); // dynamic true +assert(blackcat instanceof BlackCat); // dynamic true + +var nullableAnimal: Animal | null = new Animal(); +var nullableCat: Animal | null = new Cat(); +var nullableBlackcat: Animal | null = new BlackCat(); + +assert(nullableAnimal instanceof Animal); // static true +assert(!(nullableAnimal instanceof Cat)); // dynamic false +assert(!(nullableAnimal instanceof BlackCat)); // dynamic false + +assert(nullableCat instanceof Animal); // static true +assert(nullableCat instanceof Cat); // dynamic true +assert(!(nullableCat instanceof BlackCat)); // dynamic false + +assert(nullableBlackcat instanceof Animal); // static true +assert(nullableBlackcat instanceof Cat); // dynamic true +assert(nullableBlackcat instanceof BlackCat); // dynamic true + +var nullAnimal: Animal | null = null; +var nullCat: Animal | null = null; +var nullBlackcat: Animal | null = null; + +assert(!(nullAnimal instanceof Animal)); // static false +assert(!(nullAnimal instanceof Cat)); // dynamic false +assert(!(nullAnimal instanceof BlackCat)); // dynamic false + +assert(!(nullCat instanceof Animal)); // static false +assert(!(nullCat instanceof Cat)); // dynamic false +assert(!(nullCat instanceof BlackCat)); // dynamic false + +assert(!(nullBlackcat instanceof Animal)); // static false +assert(!(nullBlackcat instanceof Cat)); // dynamic false +assert(!(nullBlackcat instanceof BlackCat)); // dynamic false + +@start export function main(): void {} diff --git a/tests/compiler/runtime/instanceof.untouched.wat b/tests/compiler/runtime/instanceof.untouched.wat index 38cf3701..f8e4faad 100644 --- a/tests/compiler/runtime/instanceof.untouched.wat +++ b/tests/compiler/runtime/instanceof.untouched.wat @@ -1,25 +1,275 @@ (module (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) - (type $FUNCSIG$v (func)) + (type $FUNCSIG$ii (func (param i32) (result i32))) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$viiddddd (func (param i32 i32 f64 f64 f64 f64 f64))) + (type $FUNCSIG$v (func)) (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) + (import "env" "trace" (func $~lib/env/trace (param i32 i32 f64 f64 f64 f64 f64))) (memory $0 1) - (data (i32.const 8) "\02\00\00\00*\00\00\00r\00u\00n\00t\00i\00m\00e\00/\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s\00") + (data (i32.const 8) "\02\00\00\00*\00\00\00\00\00\00\00\00\00\00\00r\00u\00n\00t\00i\00m\00e\00/\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s\00") + (data (i32.const 72) "\02\00\00\00\1e\00\00\00\00\00\00\00\00\00\00\00~\00l\00i\00b\00/\00r\00u\00n\00t\00i\00m\00e\00.\00t\00s\00") + (data (i32.const 120) "\02\00\00\00\16\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00r\00e\00g\00i\00s\00t\00e\00r\00") (table $0 1 funcref) (elem (i32.const 0) $null) - (global $~lib/memory/HEAP_BASE i32 (i32.const 60)) + (global $gc/_dummy/collect_count (mut i32) (i32.const 0)) + (global $gc/_dummy/register_count (mut i32) (i32.const 0)) + (global $gc/_dummy/register_ref (mut i32) (i32.const 0)) + (global $gc/_dummy/link_count (mut i32) (i32.const 0)) + (global $gc/_dummy/link_ref (mut i32) (i32.const 0)) + (global $gc/_dummy/link_parentRef (mut i32) (i32.const 0)) + (global $gc/_dummy/unlink_count (mut i32) (i32.const 0)) + (global $gc/_dummy/unlink_ref (mut i32) (i32.const 0)) + (global $gc/_dummy/unlink_parentRef (mut i32) (i32.const 0)) + (global $gc/_dummy/mark_count (mut i32) (i32.const 0)) + (global $gc/_dummy/mark_ref (mut i32) (i32.const 0)) + (global $~lib/util/runtime/HEADER_SIZE i32 (i32.const 16)) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (global $~lib/util/runtime/HEADER_MAGIC i32 (i32.const -1520547049)) + (global $~lib/ASC_NO_ASSERT i32 (i32.const 0)) + (global $runtime/instanceof/animal (mut i32) (i32.const 0)) + (global $runtime/instanceof/cat (mut i32) (i32.const 0)) + (global $runtime/instanceof/blackcat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableAnimal (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableCat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullableBlackcat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullAnimal (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullCat (mut i32) (i32.const 0)) + (global $runtime/instanceof/nullBlackcat (mut i32) (i32.const 0)) + (global $~lib/started (mut i32) (i32.const 0)) + (global $~lib/memory/HEAP_BASE i32 (i32.const 160)) + (global $~lib/capabilities i32 (i32.const 2)) (export "memory" (memory $0)) (export "table" (table $0)) - (start $start) - (func $start:runtime/instanceof (; 1 ;) (type $FUNCSIG$v) + (export "main" (func $runtime/instanceof/main)) + (export ".capabilities" (global $~lib/capabilities)) + (func $~lib/runtime/runtime.adjust (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + i32.const 1 + i32.const 32 + local.get $0 + global.get $~lib/util/runtime/HEADER_SIZE + i32.add + i32.const 1 + i32.sub + i32.clz + i32.sub + i32.shl + ) + (func $~lib/allocator/arena/__mem_allocate (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741824 + i32.gt_u + if + unreachable + end + global.get $~lib/allocator/arena/offset + local.set $1 + local.get $1 + local.get $0 + local.tee $2 + i32.const 1 + local.tee $3 + local.get $2 + local.get $3 + i32.gt_u + select + i32.add + i32.const 7 + i32.add + i32.const 7 + i32.const -1 + i32.xor + i32.and + local.set $4 + current_memory + local.set $5 + local.get $4 + local.get $5 + i32.const 16 + i32.shl + i32.gt_u + if + local.get $4 + local.get $1 + 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 $2 + local.get $5 + local.tee $3 + local.get $2 + local.tee $6 + local.get $3 + local.get $6 + i32.gt_s + select + local.set $3 + local.get $3 + grow_memory + i32.const 0 + i32.lt_s + if + local.get $2 + grow_memory + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $4 + global.set $~lib/allocator/arena/offset + local.get $1 + ) + (func $~lib/memory/memory.allocate (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + call $~lib/allocator/arena/__mem_allocate + return + ) + (func $~lib/runtime/runtime.allocate (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + (local $1 i32) + local.get $0 + call $~lib/runtime/runtime.adjust + call $~lib/memory/memory.allocate + local.set $1 + local.get $1 + global.get $~lib/util/runtime/HEADER_MAGIC + i32.store + local.get $1 + local.get $0 + i32.store offset=4 + local.get $1 + i32.const 0 + i32.store offset=8 + local.get $1 + i32.const 0 + i32.store offset=12 + local.get $1 + global.get $~lib/util/runtime/HEADER_SIZE + i32.add + ) + (func $gc/_dummy/__ref_register (; 6 ;) (type $FUNCSIG$vi) (param $0 i32) + i32.const 136 + i32.const 1 + local.get $0 + f64.convert_i32_u + f64.const 0 + f64.const 0 + f64.const 0 + f64.const 0 + call $~lib/env/trace + global.get $gc/_dummy/register_count + i32.const 1 + i32.add + global.set $gc/_dummy/register_count + local.get $0 + global.set $gc/_dummy/register_ref + ) + (func $~lib/runtime/runtime.register (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + local.get $0 + global.get $~lib/memory/HEAP_BASE + i32.gt_u + i32.eqz + if + i32.const 0 + i32.const 88 + i32.const 107 + i32.const 6 + call $~lib/env/abort + unreachable + end + local.get $0 + global.get $~lib/util/runtime/HEADER_SIZE + i32.sub + local.set $2 + local.get $2 + i32.load + global.get $~lib/util/runtime/HEADER_MAGIC + i32.eq + i32.eqz + if + i32.const 0 + i32.const 88 + i32.const 109 + i32.const 6 + call $~lib/env/abort + unreachable + end + local.get $2 + local.get $1 + i32.store + local.get $0 + call $gc/_dummy/__ref_register + local.get $0 + ) + (func $runtime/instanceof/Animal#constructor (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + call $~lib/runtime/runtime.allocate + i32.const 1 + call $~lib/runtime/runtime.register + local.set $0 + end + local.get $0 + ) + (func $runtime/instanceof/Cat#constructor (; 9 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + call $~lib/runtime/runtime.allocate + i32.const 3 + call $~lib/runtime/runtime.register + local.set $0 + end + local.get $0 + call $runtime/instanceof/Animal#constructor + local.set $0 + local.get $0 + ) + (func $runtime/instanceof/BlackCat#constructor (; 10 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + call $~lib/runtime/runtime.allocate + i32.const 4 + call $~lib/runtime/runtime.register + local.set $0 + end + local.get $0 + call $runtime/instanceof/Cat#constructor + local.set $0 + local.get $0 + ) + (func $start:runtime/instanceof (; 11 ;) (type $FUNCSIG$v) + (local $0 i32) i32.const 1 i32.const 1 call $~lib/runtime/__runtime_instanceof i32.eqz if i32.const 0 - i32.const 16 - i32.const 7 + i32.const 24 + i32.const 8 i32.const 0 call $~lib/env/abort unreachable @@ -30,8 +280,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 14 + i32.const 24 + i32.const 15 i32.const 0 call $~lib/env/abort unreachable @@ -42,8 +292,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 21 + i32.const 24 + i32.const 22 i32.const 0 call $~lib/env/abort unreachable @@ -54,8 +304,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 28 + i32.const 24 + i32.const 29 i32.const 0 call $~lib/env/abort unreachable @@ -66,8 +316,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 35 + i32.const 24 + i32.const 36 i32.const 0 call $~lib/env/abort unreachable @@ -79,8 +329,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 42 + i32.const 24 + i32.const 43 i32.const 0 call $~lib/env/abort unreachable @@ -92,8 +342,8 @@ i32.eqz if i32.const 0 - i32.const 16 - i32.const 49 + i32.const 24 + i32.const 50 i32.const 0 call $~lib/env/abort unreachable @@ -105,17 +355,579 @@ i32.eqz if i32.const 0 + i32.const 24 + i32.const 57 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $~lib/memory/HEAP_BASE + i32.const 7 + i32.add + i32.const 7 + i32.const -1 + i32.xor + i32.and + global.set $~lib/allocator/arena/startOffset + global.get $~lib/allocator/arena/startOffset + global.set $~lib/allocator/arena/offset + i32.const 0 + call $runtime/instanceof/Animal#constructor + global.set $runtime/instanceof/animal + i32.const 0 + call $runtime/instanceof/Cat#constructor + global.set $runtime/instanceof/cat + i32.const 0 + call $runtime/instanceof/BlackCat#constructor + global.set $runtime/instanceof/blackcat + block (result i32) + global.get $runtime/instanceof/animal + drop + i32.const 1 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 68 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/animal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 i32.const 16 - i32.const 56 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 69 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/animal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 70 + i32.const 0 + call $~lib/env/abort + unreachable + end + block (result i32) + global.get $runtime/instanceof/cat + drop + i32.const 1 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 72 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/cat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 73 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/cat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 74 + i32.const 0 + call $~lib/env/abort + unreachable + end + block (result i32) + global.get $runtime/instanceof/blackcat + drop + i32.const 1 + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 76 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/blackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 77 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/blackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 78 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + call $runtime/instanceof/Animal#constructor + global.set $runtime/instanceof/nullableAnimal + i32.const 0 + call $runtime/instanceof/Cat#constructor + global.set $runtime/instanceof/nullableCat + i32.const 0 + call $runtime/instanceof/BlackCat#constructor + global.set $runtime/instanceof/nullableBlackcat + global.get $runtime/instanceof/nullableAnimal + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 84 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableAnimal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 85 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableAnimal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 86 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 88 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 89 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableCat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 90 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + i32.const 0 + i32.ne + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 92 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 93 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullableBlackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 94 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + i32.const 0 + i32.ne + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 100 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 101 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullAnimal + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 102 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + i32.const 0 + i32.ne + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 104 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 105 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullCat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 106 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + i32.const 0 + i32.ne + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 108 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 3 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 109 + i32.const 0 + call $~lib/env/abort + unreachable + end + global.get $runtime/instanceof/nullBlackcat + local.tee $0 + i32.eqz + if (result i32) + i32.const 0 + else + local.get $0 + i32.const 16 + i32.sub + i32.load + i32.const 4 + call $~lib/runtime/__runtime_instanceof + end + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 24 + i32.const 110 i32.const 0 call $~lib/env/abort unreachable end ) - (func $start (; 2 ;) (type $FUNCSIG$v) + (func $runtime/instanceof/main (; 12 ;) (type $FUNCSIG$v) + global.get $~lib/started + i32.eqz + if + call $start + i32.const 1 + global.set $~lib/started + end + ) + (func $start (; 13 ;) (type $FUNCSIG$v) call $start:runtime/instanceof ) - (func $~lib/runtime/__runtime_instanceof (; 3 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/runtime/__runtime_instanceof (; 14 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) block $nope block $runtime/instanceof/BlackCat block $runtime/instanceof/Cat @@ -159,6 +971,6 @@ i32.const 0 return ) - (func $null (; 4 ;) (type $FUNCSIG$v) + (func $null (; 15 ;) (type $FUNCSIG$v) ) ) diff --git a/tests/compiler/std/arraybuffer.optimized.wat b/tests/compiler/std/arraybuffer.optimized.wat index 8d392aaa..0ca4ccf8 100644 --- a/tests/compiler/std/arraybuffer.optimized.wat +++ b/tests/compiler/std/arraybuffer.optimized.wat @@ -1847,7 +1847,7 @@ call $~lib/env/abort unreachable end - block $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Uint8Array>13 (result i32) + block $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Int32Array>11 (result i32) i32.const 1 i32.const 12 call $~lib/runtime/runtime.allocate @@ -1855,7 +1855,7 @@ call $~lib/runtime/runtime.register i32.const 2 call $~lib/arraybuffer/ArrayBufferView#constructor - br_if $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Uint8Array>13 + br_if $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Int32Array>11 drop i32.const 0 end @@ -1870,12 +1870,12 @@ end i32.const 1 global.set $~lib/argc - block $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Uint8Array>14 (result i32) + block $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/dataview/DataView>12 (result i32) i32.const 1 global.get $std/arraybuffer/arr8 i32.load call $~lib/dataview/DataView#constructor|trampoline - br_if $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Uint8Array>14 + br_if $__inlined_func$~lib/arraybuffer/ArrayBuffer.isView<~lib/dataview/DataView>12 drop i32.const 0 end diff --git a/tests/compiler/std/arraybuffer.untouched.wat b/tests/compiler/std/arraybuffer.untouched.wat index 63a50c33..2951878a 100644 --- a/tests/compiler/std/arraybuffer.untouched.wat +++ b/tests/compiler/std/arraybuffer.untouched.wat @@ -1982,38 +1982,570 @@ (func $~lib/arraybuffer/ArrayBuffer.isView<~lib/array/Array> (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 if - nop + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end end i32.const 0 ) (func $~lib/arraybuffer/ArrayBuffer.isView (; 13 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 if - nop + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end end i32.const 0 ) (func $~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Uint8Array> (; 14 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 if - i32.const 1 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 1 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end end i32.const 0 ) (func $~lib/arraybuffer/ArrayBuffer.isView<~lib/typedarray/Int32Array> (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 if - i32.const 1 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 1 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end end i32.const 0 ) (func $~lib/arraybuffer/ArrayBuffer.isView<~lib/dataview/DataView> (; 16 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32) local.get $0 if - i32.const 1 - return + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 0 + end + if + i32.const 1 + return + end + block (result i32) + local.get $0 + drop + i32.const 1 + end + if + i32.const 1 + return + end end i32.const 0 )