1 // Copyright (c) Facebook, Inc. and its affiliates.
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;
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()));
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(
48 InstructLitConst::LazyClass(classid)
50 TypedValue::Float(f) => {
51 let fstr = bumpalo::collections::String::from_str_in(
52 string_utils::float::to_string(*f).as_str(),
56 InstructLitConst::Double(Str::from(fstr))
58 TypedValue::Keyset(_) => {
59 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
60 InstructLitConst::Keyset(arrayid)
62 TypedValue::Vec(_) => {
63 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
64 InstructLitConst::Vec(arrayid)
66 TypedValue::Dict(_) => {
67 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
68 InstructLitConst::Dict(arrayid)
70 TypedValue::HhasAdata(d) if d.is_empty() => {
71 return Err(Error::Unrecoverable("HhasAdata may not be empty".into()));
73 TypedValue::HhasAdata(d) => {
74 let arrayid = Str::from(get_array_identifier(alloc, e, tv));
77 VARRAY_PREFIX | VEC_PREFIX => InstructLitConst::Vec(arrayid),
78 DARRAY_PREFIX | DICT_PREFIX => InstructLitConst::Dict(arrayid),
79 KEYSET_PREFIX => InstructLitConst::Keyset(arrayid),
81 return Err(Error::Unrecoverable(format!(
82 "Unknown HhasAdata data: {}",
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>,
98 if e.options().hhvm.flags.contains(HhvmFlags::ARRAY_PROVENANCE) {
99 next_adata_id(alloc, e, tv)
101 match e.emit_adata_state_mut(alloc).array_identifier_map.get(tv) {
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);
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>,
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 {
124 value: value.clone(),
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)
141 // verify it compiles (no test attribute)
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();
148 // verify it compiles (no test attribute)
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>,
155 let _: &mut AdataState = e.emit_adata_state_mut(alloc);