Rename directory hhbc to hackc
[hiphop-php.git] / hphp / hack / src / hackc / emitter / emit_adata.rs
blob098b79cf455b35a2e3d64ec1627566557cc39ea4
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 adata_state::AdataState;
7 use env::emitter::Emitter;
8 use ffi::Str;
9 use hhas_adata::{HhasAdata, DARRAY_PREFIX, DICT_PREFIX, KEYSET_PREFIX, VARRAY_PREFIX, VEC_PREFIX};
10 use hhbc_ast::*;
11 use hhbc_string_utils as string_utils;
12 use instruction_sequence::{Error, InstrSeq};
13 use options::HhvmFlags;
14 use runtime::TypedValue;
16 pub fn rewrite_typed_values<'arena, 'decl>(
17     emitter: &mut Emitter<'arena, 'decl>,
18     instrseq: &mut InstrSeq<'arena>,
19 ) -> std::result::Result<(), instruction_sequence::Error> {
20     instrseq.map_result_mut(&mut |instr| rewrite_typed_value(emitter, instr))
23 fn rewrite_typed_value<'arena, 'decl>(
24     e: &mut Emitter<'arena, 'decl>,
25     instr: &mut Instruct<'arena>,
26 ) -> std::result::Result<(), instruction_sequence::Error> {
27     if let Instruct::ILitConst(InstructLitConst::TypedValue(tv)) = instr {
28         *instr = Instruct::ILitConst(match &tv {
29             TypedValue::Uninit => {
30                 return Err(Error::Unrecoverable("rewrite_typed_value: uninit".into()));
31             }
32             TypedValue::Null => InstructLitConst::Null,
33             TypedValue::Bool(true) => InstructLitConst::True,
34             TypedValue::Bool(false) => InstructLitConst::False,
35             TypedValue::Int(i) => InstructLitConst::Int(*i),
36             TypedValue::String(s) => InstructLitConst::String(*s),
37             TypedValue::LazyClass(s) => {
38                 let classid: hhbc_ast::ClassId<'arena> =
39                     hhbc_id::class::ClassType::from_ast_name_and_mangle(e.alloc, s.unsafe_as_str());
40                 InstructLitConst::LazyClass(classid)
41             }
42             TypedValue::Float(f) => {
43                 let fstr = bumpalo::collections::String::from_str_in(
44                     string_utils::float::to_string(*f).as_str(),
45                     e.alloc,
46                 )
47                 .into_bump_str();
48                 InstructLitConst::Double(Str::from(fstr))
49             }
50             TypedValue::Keyset(_) => {
51                 let arrayid = Str::from(get_array_identifier(e, tv));
52                 InstructLitConst::Keyset(arrayid)
53             }
54             TypedValue::Vec(_) => {
55                 let arrayid = Str::from(get_array_identifier(e, tv));
56                 InstructLitConst::Vec(arrayid)
57             }
58             TypedValue::Dict(_) => {
59                 let arrayid = Str::from(get_array_identifier(e, tv));
60                 InstructLitConst::Dict(arrayid)
61             }
62             TypedValue::HhasAdata(d) if d.is_empty() => {
63                 return Err(Error::Unrecoverable("HhasAdata may not be empty".into()));
64             }
65             TypedValue::HhasAdata(d) => {
66                 let arrayid = Str::from(get_array_identifier(e, tv));
67                 let d = d.unsafe_as_str();
68                 match &d[..1] {
69                     VARRAY_PREFIX | VEC_PREFIX => InstructLitConst::Vec(arrayid),
70                     DARRAY_PREFIX | DICT_PREFIX => InstructLitConst::Dict(arrayid),
71                     KEYSET_PREFIX => InstructLitConst::Keyset(arrayid),
72                     _ => {
73                         return Err(Error::Unrecoverable(format!(
74                             "Unknown HhasAdata data: {}",
75                             d,
76                         )));
77                     }
78                 }
79             }
80         })
81     };
82     Ok(())
85 pub fn get_array_identifier<'arena, 'decl>(
86     e: &mut Emitter<'arena, 'decl>,
87     tv: &TypedValue<'arena>,
88 ) -> &'arena str {
89     if e.options().hhvm.flags.contains(HhvmFlags::ARRAY_PROVENANCE) {
90         next_adata_id(e, tv)
91     } else {
92         match e.emit_adata_state_mut().array_identifier_map.get(tv) {
93             None => {
94                 let id = next_adata_id(e, tv);
95                 e.emit_adata_state_mut()
96                     .array_identifier_map
97                     .insert(tv.clone(), id);
98                 id
99             }
100             Some(id) => id,
101         }
102     }
105 fn next_adata_id<'arena, 'decl>(
106     e: &mut Emitter<'arena, 'decl>,
107     value: &TypedValue<'arena>,
108 ) -> &'arena str {
109     let alloc = e.alloc;
110     let mut state = e.emit_adata_state_mut();
111     let id: &str = alloc.alloc_str(format!("A_{}", state.array_identifier_counter).as_str());
112     state.array_identifier_counter += 1;
113     state.adata.push(HhasAdata {
114         id: id.into(),
115         value: value.clone(),
116     });
117     id
120 pub fn take<'arena, 'decl>(e: &mut Emitter<'arena, 'decl>) -> AdataState<'arena> {
121     let state = e.emit_adata_state_mut();
122     std::mem::take(state)
125 #[cfg(test)]
126 mod tests {
127     use super::*;
129     // verify it compiles (no test attribute)
130     #[allow(dead_code)]
131     #[allow(clippy::needless_lifetimes)]
132     fn ref_state_from_emiter<'arena, 'decl>(e: &Emitter<'arena, 'decl>) {
133         let _: &AdataState<'_> = e.emit_adata_state();
134     }
136     // verify it compiles (no test attribute)
137     #[allow(dead_code)]
138     #[allow(clippy::needless_lifetimes)]
139     fn mut_state_from_emiter<'arena, 'decl>(e: &mut Emitter<'arena, 'decl>) {
140         let _: &mut AdataState<'_> = e.emit_adata_state_mut();
141     }