Tweak `HhasTypeConstant` C++: Replace Option with Maybe
[hiphop-php.git] / hphp / hack / src / hhbc / hhbc_by_ref / emit_adata.rs
blob19cdcc1a606a49d5c9944fe0dbd46bdd5f09c8a2
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 decl_provider::DeclProvider;
7 use ffi::Str;
8 use hhbc_by_ref_adata_state::AdataState;
9 use hhbc_by_ref_env::emitter::Emitter;
10 use hhbc_by_ref_hhas_adata::{
11     HhasAdata, DARRAY_PREFIX, DICT_PREFIX, KEYSET_PREFIX, VARRAY_PREFIX, VEC_PREFIX,
13 use hhbc_by_ref_hhbc_ast::*;
14 use hhbc_by_ref_hhbc_string_utils as string_utils;
15 use hhbc_by_ref_instruction_sequence::{Error, InstrSeq};
16 use hhbc_by_ref_options::HhvmFlags;
17 use hhbc_by_ref_runtime::TypedValue;
19 pub fn rewrite_typed_values<'arena, 'decl, D: DeclProvider<'decl>>(
20     alloc: &'arena bumpalo::Bump,
21     emitter: &mut Emitter<'arena, 'decl, D>,
22     instrseq: &mut InstrSeq<'arena>,
23 ) -> std::result::Result<(), hhbc_by_ref_instruction_sequence::Error> {
24     instrseq.map_result_mut(&mut |instr| rewrite_typed_value(alloc, emitter, instr))
27 fn rewrite_typed_value<'arena, 'decl, D: DeclProvider<'decl>>(
28     alloc: &'arena bumpalo::Bump,
29     e: &mut Emitter<'arena, 'decl, D>,
30     instr: &mut Instruct<'arena>,
31 ) -> std::result::Result<(), hhbc_by_ref_instruction_sequence::Error> {
32     if let Instruct::ILitConst(InstructLitConst::TypedValue(tv)) = instr {
33         *instr = Instruct::ILitConst(match &tv {
34             TypedValue::Uninit => {
35                 return Err(Error::Unrecoverable("rewrite_typed_value: uninit".into()));
36             }
37             TypedValue::Null => InstructLitConst::Null,
38             TypedValue::Bool(true) => InstructLitConst::True,
39             TypedValue::Bool(false) => InstructLitConst::False,
40             TypedValue::Int(i) => InstructLitConst::Int(*i),
41             TypedValue::String(s) => InstructLitConst::String(*s),
42             TypedValue::LazyClass(s) => {
43                 let classid: hhbc_by_ref_hhbc_ast::ClassId<'arena> =
44                     hhbc_by_ref_hhbc_id::class::ClassType::from_ast_name_and_mangle(
45                         alloc,
46                         s.as_str(),
47                     );
48                 InstructLitConst::LazyClass(classid)
49             }
50             TypedValue::Float(f) => {
51                 let fstr = bumpalo::collections::String::from_str_in(
52                     string_utils::float::to_string(*f).as_str(),
53                     alloc,
54                 )
55                 .into_bump_str();
56                 InstructLitConst::Double(Str::from(fstr))
57             }
58             TypedValue::Keyset(_) => {
59                 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
60                 InstructLitConst::Keyset(arrayid)
61             }
62             TypedValue::Vec(_) => {
63                 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
64                 InstructLitConst::Vec(arrayid)
65             }
66             TypedValue::Dict(_) => {
67                 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
68                 InstructLitConst::Dict(arrayid)
69             }
70             TypedValue::HhasAdata(d) if d.is_empty() => {
71                 return Err(Error::Unrecoverable("HhasAdata may not be empty".into()));
72             }
73             TypedValue::HhasAdata(d) => {
74                 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
75                 let d = d.as_str();
76                 match &d[..1] {
77                     VARRAY_PREFIX | VEC_PREFIX => InstructLitConst::Vec(arrayid),
78                     DARRAY_PREFIX | DICT_PREFIX => InstructLitConst::Dict(arrayid),
79                     KEYSET_PREFIX => InstructLitConst::Keyset(arrayid),
80                     _ => {
81                         return Err(Error::Unrecoverable(format!(
82                             "Unknown HhasAdata data: {}",
83                             d,
84                         )));
85                     }
86                 }
87             }
88         })
89     };
90     Ok(())
93 pub fn get_array_identifier<'arena, 'decl, D: DeclProvider<'decl>>(
94     alloc: &'arena bumpalo::Bump,
95     e: &mut Emitter<'arena, 'decl, D>,
96     tv: &TypedValue<'arena>,
97 ) -> &'arena str {
98     if e.options().hhvm.flags.contains(HhvmFlags::ARRAY_PROVENANCE) {
99         next_adata_id(alloc, e, tv)
100     } else {
101         match e.emit_adata_state_mut(alloc).array_identifier_map.get(tv) {
102             None => {
103                 let id = next_adata_id(alloc, e, tv);
104                 e.emit_adata_state_mut(alloc)
105                     .array_identifier_map
106                     .insert(tv.clone(), id);
107                 id
108             }
109             Some(id) => id,
110         }
111     }
114 fn next_adata_id<'arena, 'decl, D: DeclProvider<'decl>>(
115     alloc: &'arena bumpalo::Bump,
116     e: &mut Emitter<'arena, 'decl, D>,
117     value: &TypedValue<'arena>,
118 ) -> &'arena str {
119     let mut state = e.emit_adata_state_mut(alloc);
120     let id: &str = alloc.alloc_str(format!("A_{}", state.array_identifier_counter).as_str());
121     state.array_identifier_counter += 1;
122     state.adata.push(HhasAdata {
123         id: id.into(),
124         value: value.clone(),
125     });
126     id
129 pub fn take<'arena, 'decl, D: DeclProvider<'decl>>(
130     alloc: &'arena bumpalo::Bump,
131     e: &mut Emitter<'arena, 'decl, D>,
132 ) -> AdataState<'arena> {
133     let state = e.emit_adata_state_mut(alloc);
134     std::mem::take(state)
137 #[cfg(test)]
138 mod tests {
139     use super::*;
141     // verify it compiles (no test attribute)
142     #[allow(dead_code)]
143     #[allow(clippy::needless_lifetimes)]
144     fn ref_state_from_emiter<'arena, 'decl, D: DeclProvider<'decl>>(e: &Emitter<'arena, 'decl, D>) {
145         let _: &AdataState = e.emit_adata_state();
146     }
148     // verify it compiles (no test attribute)
149     #[allow(dead_code)]
150     #[allow(clippy::needless_lifetimes)]
151     fn mut_state_from_emiter<'arena, 'decl, D: DeclProvider<'decl>>(
152         alloc: &'arena bumpalo::Bump,
153         e: &mut Emitter<'arena, 'decl, D>,
154     ) {
155         let _: &mut AdataState = e.emit_adata_state_mut(alloc);
156     }