From 05004fa127defbceebb2f5cbd7a9f370fd3186f1 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 20 Aug 2021 19:38:16 +0200 Subject: [PATCH] Handle nulls in runtime upcast checks --- src/compiler.ts | 31 +++- tests/compiler/managed-cast.optimized.wat | 173 +++++++++++----------- tests/compiler/managed-cast.untouched.wat | 21 ++- 3 files changed, 127 insertions(+), 98 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 0e0e06d405..5efd2fba16 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -10565,14 +10565,31 @@ export class Compiler extends DiagnosticEmitter { var temp = flow.getTempLocal(type); var instanceofInstance = this.program.instanceofInstance; assert(this.compileFunction(instanceofInstance)); - expr = module.if( - module.call(instanceofInstance.internalName, [ + if (!toType.isNullableReference || flow.isNonnull(expr, type)) { + // Simplify if the value cannot be `null`. If toType is non-nullable, a + // null-check would have been emitted separately so is not necessary here. + expr = module.if( + module.call(instanceofInstance.internalName, [ + module.local_tee(temp.index, expr, type.isManaged), + module.i32(toType.classReference!.id) + ], TypeRef.I32), + module.local_get(temp.index, type.toRef()), + this.makeStaticAbort(this.ensureStaticString("unexpected upcast"), reportNode) // TODO: throw + ); + } else { + expr = module.if( module.local_tee(temp.index, expr, type.isManaged), - module.i32(toType.classReference!.id) - ], TypeRef.I32), - module.local_get(temp.index, type.toRef()), - this.makeStaticAbort(this.ensureStaticString("unexpected upcast"), reportNode) // TODO: throw - ); + module.if( + module.call(instanceofInstance.internalName, [ + module.local_get(temp.index, type.toRef()), + module.i32(toType.classReference!.id) + ], TypeRef.I32), + module.local_get(temp.index, type.toRef()), + this.makeStaticAbort(this.ensureStaticString("unexpected upcast"), reportNode) // TODO: throw + ), + module.usize(0) + ); + } flow.freeTempLocal(temp); this.currentType = toType; return expr; diff --git a/tests/compiler/managed-cast.optimized.wat b/tests/compiler/managed-cast.optimized.wat index 65555741cf..cd7df977b2 100644 --- a/tests/compiler/managed-cast.optimized.wat +++ b/tests/compiler/managed-cast.optimized.wat @@ -1468,17 +1468,17 @@ i32.const 1344 global.set $~lib/rt/itcms/fromSpace call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $1 + local.get $0 i32.store call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.sub global.set $~lib/memory/__stack_pointer @@ -1489,7 +1489,7 @@ global.get $~lib/memory/__stack_pointer i32.const 0 i32.store - local.get $1 + local.get $0 i32.eqz if i32.const 1456 @@ -1500,30 +1500,30 @@ unreachable end global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.add global.set $~lib/memory/__stack_pointer call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $1 + local.get $0 i32.store call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $1 + local.get $0 i32.store call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.sub global.set $~lib/memory/__stack_pointer @@ -1535,29 +1535,29 @@ i32.const 0 i32.store block $__inlined_func$~lib/rt/__instanceof (result i32) - local.get $1 + local.get $0 i32.const 20 i32.sub i32.load offset=12 - local.tee $0 + local.tee $1 i32.const 1632 i32.load i32.le_u if loop $do-continue|0 i32.const 1 - local.get $0 + local.get $1 i32.const 3 i32.eq br_if $__inlined_func$~lib/rt/__instanceof drop - local.get $0 + local.get $1 i32.const 3 i32.shl i32.const 1636 i32.add i32.load offset=4 - local.tee $0 + local.tee $1 br_if $do-continue|0 end end @@ -1573,20 +1573,20 @@ unreachable end global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.add global.set $~lib/memory/__stack_pointer call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 8 i32.sub global.set $~lib/memory/__stack_pointer @@ -1595,10 +1595,10 @@ i32.lt_s br_if $folding-inner0 global.get $~lib/memory/__stack_pointer - local.tee $0 + local.tee $1 i64.const 0 i64.store - local.get $1 + local.get $0 i32.eqz if i32.const 1456 @@ -1608,11 +1608,12 @@ call $~lib/builtins/abort unreachable end - local.get $0 local.get $1 + local.get $0 + local.tee $1 i32.store offset=4 block $__inlined_func$~lib/rt/__instanceof11 (result i32) - local.get $1 + local.get $0 i32.const 20 i32.sub i32.load offset=12 @@ -1658,12 +1659,12 @@ i32.add global.set $~lib/memory/__stack_pointer call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.sub global.set $~lib/memory/__stack_pointer @@ -1676,29 +1677,29 @@ i32.const 0 i32.store block $__inlined_func$~lib/rt/__instanceof14 (result i32) - local.get $1 + local.get $0 i32.const 20 i32.sub i32.load offset=12 - local.tee $0 + local.tee $1 i32.const 1632 i32.load i32.le_u if loop $do-continue|015 i32.const 1 - local.get $0 + local.get $1 i32.const 3 i32.eq br_if $__inlined_func$~lib/rt/__instanceof14 drop - local.get $0 + local.get $1 i32.const 3 i32.shl i32.const 1636 i32.add i32.load offset=4 - local.tee $0 + local.tee $1 br_if $do-continue|015 end end @@ -1714,19 +1715,19 @@ unreachable end local.get $2 - local.get $1 + local.get $0 i32.store global.get $~lib/memory/__stack_pointer i32.const 4 i32.add global.set $~lib/memory/__stack_pointer call $managed-cast/Cat#constructor - local.set $1 + local.set $0 global.get $~lib/memory/__stack_pointer - local.tee $0 - local.get $1 - i32.store + local.tee $1 local.get $0 + i32.store + local.get $1 i32.const 4 i32.sub global.set $~lib/memory/__stack_pointer @@ -1738,46 +1739,52 @@ local.tee $2 i32.const 0 i32.store - block $__inlined_func$~lib/rt/__instanceof17 (result i32) - local.get $1 - i32.const 20 - i32.sub - i32.load offset=12 - local.tee $0 - i32.const 1632 - i32.load - i32.le_u - if - loop $do-continue|018 - i32.const 1 - local.get $0 - i32.const 3 - i32.eq - br_if $__inlined_func$~lib/rt/__instanceof17 - drop - local.get $0 - i32.const 3 - i32.shl - i32.const 1636 - i32.add - i32.load offset=4 - local.tee $0 - br_if $do-continue|018 + local.get $0 + if + block $__inlined_func$~lib/rt/__instanceof17 (result i32) + local.get $0 + i32.const 20 + i32.sub + i32.load offset=12 + local.tee $1 + i32.const 1632 + i32.load + i32.le_u + if + loop $do-continue|018 + i32.const 1 + local.get $1 + i32.const 3 + i32.eq + br_if $__inlined_func$~lib/rt/__instanceof17 + drop + local.get $1 + i32.const 3 + i32.shl + i32.const 1636 + i32.add + i32.load offset=4 + local.tee $1 + br_if $do-continue|018 + end end + i32.const 0 end + i32.eqz + if + i32.const 1584 + i32.const 1520 + i32.const 47 + i32.const 30 + call $~lib/builtins/abort + unreachable + end + else i32.const 0 - end - i32.eqz - if - i32.const 1584 - i32.const 1520 - i32.const 47 - i32.const 30 - call $~lib/builtins/abort - unreachable + local.set $0 end local.get $2 - local.get $1 + local.get $0 i32.store global.get $~lib/memory/__stack_pointer i32.const 4 diff --git a/tests/compiler/managed-cast.untouched.wat b/tests/compiler/managed-cast.untouched.wat index f5f059bbb6..d0a0bfe294 100644 --- a/tests/compiler/managed-cast.untouched.wat +++ b/tests/compiler/managed-cast.untouched.wat @@ -2469,17 +2469,22 @@ global.get $~lib/memory/__stack_pointer local.get $0 local.tee $1 - i32.const 3 - call $~lib/rt/__instanceof if (result i32) local.get $1 + i32.const 3 + call $~lib/rt/__instanceof + if (result i32) + local.get $1 + else + i32.const 560 + i32.const 496 + i32.const 47 + i32.const 30 + call $~lib/builtins/abort + unreachable + end else - i32.const 560 - i32.const 496 - i32.const 47 - i32.const 30 - call $~lib/builtins/abort - unreachable + i32.const 0 end local.tee $2 i32.store