Fix closure locals
[hiphop-php.git] / hphp / hack / src / hackc / ir / conversions / textual / lower / func.rs
blob1d0f88608b0c32605fe0748f9bc6b522ab742849
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use std::sync::Arc;
8 use ir::instr::Hhbc;
9 use ir::Func;
10 use ir::FuncBuilder;
11 use ir::Instr;
12 use ir::LocalId;
13 use ir::MemberOpBuilder;
14 use ir::MethodFlags;
15 use ir::StringInterner;
16 use log::trace;
18 use crate::func::MethodInfo;
20 pub(crate) fn lower_func<'a>(
21     mut func: Func<'a>,
22     method_info: Option<Arc<MethodInfo<'_>>>,
23     strings: Arc<StringInterner>,
24 ) -> Func<'a> {
25     trace!(
26         "Before Lower: {}",
27         ir::print::DisplayFunc::new(&func, true, &strings)
28     );
30     // In a closure we implicitly load all the properties as locals - so start
31     // with that as a prelude to all entrypoints.
32     if let Some(method_info) = method_info.as_ref() {
33         if method_info.flags.contains(MethodFlags::IS_CLOSURE_BODY) {
34             load_closure_vars(&mut func, method_info, &strings);
35         }
36     }
38     // Start by 'unasync'ing the Func.
39     ir::passes::unasync(&mut func);
40     trace!(
41         "After unasync: {}",
42         ir::print::DisplayFunc::new(&func, true, &strings)
43     );
45     let mut builder = FuncBuilder::with_func(func, Arc::clone(&strings));
47     // Simplify various Instrs.
48     super::instrs::lower_instrs(&mut builder, method_info);
50     // Write the complex constants out as a prelude to the function.
51     super::constants::write_constants(&mut builder);
53     let mut func = builder.finish();
55     ir::passes::split_critical_edges(&mut func, true);
57     ir::passes::clean::run(&mut func);
59     trace!(
60         "After Lower: {}",
61         ir::print::DisplayFunc::new(&func, true, &strings)
62     );
64     func
67 fn load_closure_vars(func: &mut Func<'_>, method_info: &MethodInfo<'_>, strings: &StringInterner) {
68     let mut instrs = Vec::new();
70     let loc = func.loc_id;
72     for prop in &method_info.class.properties {
73         // Property names are the variable names without the '$'.
74         let prop_str = strings.lookup_bstr(prop.name.id);
75         let mut var = prop_str.to_vec();
76         var.insert(0, b'$');
77         let lid = LocalId::Named(strings.intern_bytes(var));
79         let iid = func.alloc_instr(Instr::MemberOp(
80             MemberOpBuilder::base_h(loc).query_pt(prop.name),
81         ));
82         instrs.push(iid);
83         instrs.push(func.alloc_instr(Instr::Hhbc(Hhbc::SetL(iid.into(), lid, loc))));
84     }
86     func.block_mut(Func::ENTRY_BID).iids.splice(0..0, instrs);