From c64e160130e6b1070ef430ab65a4234695e33e3d Mon Sep 17 00:00:00 2001 From: Nick Benton Date: Wed, 17 May 2023 03:59:29 -0700 Subject: [PATCH] Translate await bytecode into call to builtin Summary: Add translation of hhbc await instruction (we previously only called the builtin for awaits on function calls and panicked on `await $a`). This supports inferhack unawaited awaitable analysis (D45861645) Reviewed By: aorenste Differential Revision: D45863376 fbshipit-source-id: f9ecffa176e4dbb97ee7ca7da35e4032a6c00b18 --- .../src/hackc/ir/conversions/textual/func.rs | 2 +- .../src/hackc/ir/conversions/textual/hack.rs | 5 ++-- .../ir/conversions/textual/lower/instrs.rs | 1 + hphp/hack/src/hackc/test/infer/async.hack | 29 ++++++++++++++----- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/hphp/hack/src/hackc/ir/conversions/textual/func.rs b/hphp/hack/src/hackc/ir/conversions/textual/func.rs index da472bb0c01a68..ce4c728118bcb0 100644 --- a/hphp/hack/src/hackc/ir/conversions/textual/func.rs +++ b/hphp/hack/src/hackc/ir/conversions/textual/func.rs @@ -968,7 +968,7 @@ fn write_call(state: &mut FuncState<'_, '_, '_>, iid: InstrId, call: &ir::Call) }; if is_async { - output = state.call_builtin(hack::Builtin::Await, [output])?; + output = state.call_builtin(hack::Builtin::Hhbc(hack::Hhbc::Await), [output])?; } state.set_iid(iid, output); diff --git a/hphp/hack/src/hackc/ir/conversions/textual/hack.rs b/hphp/hack/src/hackc/ir/conversions/textual/hack.rs index d6397c94a5363d..a976795cbd5cac 100644 --- a/hphp/hack/src/hackc/ir/conversions/textual/hack.rs +++ b/hphp/hack/src/hackc/ir/conversions/textual/hack.rs @@ -46,6 +46,8 @@ pub(crate) enum Hhbc { AddElemC, #[decl(fn hhbc_add_new_elem_c(*HackMixed, *HackMixed) -> *HackMixed)] AddNewElemC, + #[decl(fn hhbc_await(*HackMixed) -> *HackMixed)] + Await, #[decl(fn hhbc_await_all(...) -> *HackMixed)] AwaitAll, #[decl(fn hhbc_cast_keyset(*HackMixed) -> *HackMixed)] @@ -209,9 +211,6 @@ pub(crate) enum Builtin { /// pointer-sized value). #[decl(fn alloc_words(int) -> *void)] AllocWords, - /// Await for a value returned by an async function. - #[decl(fn await(*HackMixed) -> *HackMixed)] - Await, /// Get the superglobal as a base. #[decl(fn hack_base_get_superglobal(name: *HackMixed) -> **HackMixed)] BaseGetSuperglobal, diff --git a/hphp/hack/src/hackc/ir/conversions/textual/lower/instrs.rs b/hphp/hack/src/hackc/ir/conversions/textual/lower/instrs.rs index fdb0781f18685b..fa6fb45d8e0f8d 100644 --- a/hphp/hack/src/hackc/ir/conversions/textual/lower/instrs.rs +++ b/hphp/hack/src/hackc/ir/conversions/textual/lower/instrs.rs @@ -97,6 +97,7 @@ impl LowerInstrs<'_> { Hhbc::Add(..) => hack::Hhbc::Add, Hhbc::AddElemC(..) => hack::Hhbc::AddElemC, Hhbc::AddNewElemC(..) => hack::Hhbc::AddNewElemC, + Hhbc::Await(..) => hack::Hhbc::Await, Hhbc::AwaitAll(..) => hack::Hhbc::AwaitAll, Hhbc::CastKeyset(..) => hack::Hhbc::CastKeyset, Hhbc::CastVec(..) => hack::Hhbc::CastVec, diff --git a/hphp/hack/src/hackc/test/infer/async.hack b/hphp/hack/src/hackc/test/infer/async.hack index 7f60950f3847d5..804f8d4c8cd528 100644 --- a/hphp/hack/src/hackc/test/infer/async.hack +++ b/hphp/hack/src/hackc/test/infer/async.hack @@ -2,23 +2,38 @@ // TEST-CHECK-BAL: define $root.test_async // CHECK: define $root.test_async($this: *void) : *HackInt { -// CHECK: local $a: *void, $b: *void +// CHECK: local $a: *void, $a2: *void, $b: *void // CHECK: #b0: // CHECK: n0 = $root.bar(null) -// CHECK: n1 = $builtins.await(n0) +// CHECK: n1 = $builtins.hhbc_await(n0) // CHECK: store &$a <- n1: *HackMixed // CHECK: n2: *HackMixed = load &$a // CHECK: n3 = $root.baz(null, n2) -// CHECK: n4 = $builtins.await(n3) +// CHECK: n4 = $builtins.hhbc_await(n3) // CHECK: store &$b <- n4: *HackMixed -// CHECK: n5: *HackMixed = load &$b -// CHECK: n6 = $builtins.hhbc_is_type_int(n5) -// CHECK: n7 = $builtins.hhbc_verify_type_pred(n5, n6) -// CHECK: ret n5 +// CHECK: n5 = $root.bar(null) +// CHECK: store &$a2 <- n5: *HackMixed +// CHECK: n6: *HackMixed = load &$a2 +// CHECK: n7 = $builtins.hhbc_is_type_null(n6) +// CHECK: jmp b1, b2 +// CHECK: #b1: +// CHECK: prune $builtins.hack_is_true(n7) +// CHECK: jmp b3(n6) +// CHECK: #b2: +// CHECK: prune ! $builtins.hack_is_true(n7) +// CHECK: n8 = $builtins.hhbc_await(n6) +// CHECK: jmp b3(n8) +// CHECK: #b3(n9: *HackMixed): +// CHECK: n10: *HackMixed = load &$b +// CHECK: n11 = $builtins.hhbc_is_type_int(n10) +// CHECK: n12 = $builtins.hhbc_verify_type_pred(n10, n11) +// CHECK: ret n10 // CHECK: } async function test_async(): Awaitable { $a = await bar(); $b = await baz($a); + $a2 = bar(); + await $a2; return $b; }