Support for some missing instructions
[hiphop-php.git] / hphp / hack / src / hackc / ir / conversions / textual / hack.rs
blobc87660bcf62828b395f76d2b4140c1e6de847d68
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::fmt;
8 use anyhow::Error;
9 use once_cell::sync::OnceCell;
10 use strum::EnumProperty as _;
11 use strum_macros::EnumIter;
12 use strum_macros::EnumProperty;
14 use crate::mangle::MangleWithClass as _;
15 use crate::textual;
16 use crate::textual::Sid;
18 const BUILTINS_CLASS: ir::ClassName<'static> = ir::ClassName::new(ffi::Str::new(b"$builtins"));
20 type Result<T = (), E = Error> = std::result::Result<T, E>;
22 /// These represent builtins for handling HHVM bytecode instructions. In general
23 /// the names should match the HHBC name except when they are compound bytecodes
24 /// (like Cmp with a parameter of Eq becoming CmpEq). Documentation can be found
25 /// in hphp/doc/bytecode.specification.
26 #[derive(Copy, Clone, EnumIter, EnumProperty)]
27 pub(crate) enum Hhbc {
28     #[strum(props(Function = "hhbc_add"))]
29     Add,
30     #[strum(props(Function = "hhbc_cmp_eq"))]
31     CmpEq,
32     #[strum(props(Function = "hhbc_cmp_gt"))]
33     CmpGt,
34     #[strum(props(Function = "hhbc_cmp_gte"))]
35     CmpGte,
36     #[strum(props(Function = "hhbc_cmp_lt"))]
37     CmpLt,
38     #[strum(props(Function = "hhbc_cmp_lte"))]
39     CmpLte,
40     #[strum(props(Function = "hhbc_cmp_nsame"))]
41     CmpNSame,
42     #[strum(props(Function = "hhbc_cmp_neq"))]
43     CmpNeq,
44     #[strum(props(Function = "hhbc_cmp_same"))]
45     CmpSame,
46     #[strum(props(Function = "hhbc_exit"))]
47     Exit,
48     #[strum(props(Function = "hhbc_is_type_int"))]
49     IsTypeInt,
50     #[strum(props(Function = "hhbc_is_type_null"))]
51     IsTypeNull,
52     #[strum(props(Function = "hhbc_is_type_str"))]
53     IsTypeStr,
54     #[strum(props(Function = "hhbc_modulo"))]
55     Modulo,
56     #[strum(props(Function = "hhbc_new_obj"))]
57     NewObj,
58     #[strum(props(Function = "hhbc_new_vec"))]
59     NewVec,
60     #[strum(props(Function = "hhbc_not"))]
61     Not,
62     #[strum(props(Function = "hhbc_print"))]
63     Print,
64     #[strum(props(Function = "hhbc_sub"))]
65     Sub,
66     #[strum(props(Function = "hhbc_verify_failed"))]
67     VerifyFailed,
70 // Need Default for EnumIter on Builtin
71 impl std::default::Default for Hhbc {
72     fn default() -> Self {
73         Hhbc::Add
74     }
77 #[derive(EnumIter, EnumProperty)]
78 pub(crate) enum Builtin {
79     /// Allocate an array with the given number of words (a word is a
80     /// pointer-sized value).
81     ///   AllocWords(int) -> *void
82     #[strum(props(Function = "alloc_words"))]
83     AllocWords,
84     /// Throws a BadMethodCall exception.
85     ///   BadMethodCall() -> noreturn
86     #[strum(props(Function = "hack_bad_method_call"))]
87     BadMethodCall,
88     /// Throws a BadProperty exception.
89     ///   BadProperty() -> noreturn
90     #[strum(props(Function = "hack_bad_property"))]
91     BadProperty,
92     /// Turns a raw boolean into a Mixed.
93     ///   Bool(n: bool) -> *Mixed
94     #[strum(props(Function = "hack_bool"))]
95     Bool,
96     /// Returns the Class identifier for the given class.
97     #[strum(props(Function = "hack_get_class"))]
98     GetClass,
99     /// Returns the Class identifier for the given class's static class.
100     #[strum(props(Function = "hack_get_static_class"))]
101     GetStaticClass,
102     /// Hhbc handlers.  See hphp/doc/bytecode.specification for docs.
103     Hhbc(Hhbc),
104     /// Turns a raw int into a Mixed.
105     ///   Int(n: int) -> *Mixed
106     #[strum(props(Function = "hack_int"))]
107     Int,
108     /// Returns true if the given Mixed is truthy.
109     ///   IsTrue(p: *Mixed) -> bool
110     #[strum(props(Function = "hack_is_true"))]
111     IsTrue,
112     /// Returns a Mixed containing a `null`.
113     ///   Null() -> *Mixed
114     #[strum(props(Function = "hack_null"))]
115     Null,
116     /// Returns true if the given raw pointer is null.
117     ///   RawPtrIsNull(*void) -> bool
118     #[strum(props(Function = "raw_ptr_is_null"))]
119     RawPtrIsNull,
120     /// Turns a raw string into a Mixed.
121     ///   String(s: *string) -> *Mixed
122     #[strum(props(Function = "hack_string"))]
123     String,
124     /// Used to check param count on function entry.
125     ///   VerifyParamCount(params, min, max)
126     #[strum(props(Function = "verify_param_count"))]
127     VerifyParamCount,
130 impl fmt::Display for Builtin {
131     fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
132         static DUMMY: OnceCell<ir::StringInterner> = OnceCell::new();
133         let strings = DUMMY.get_or_init(Default::default);
135         let name = match self {
136             Builtin::Hhbc(hhbc) => hhbc.get_str("Function").unwrap(),
137             _ => self.get_str("Function").unwrap(),
138         };
139         let method = ir::MethodName::new(ffi::Str::new(name.as_bytes()));
140         // Use a dummy string table - this is fine because builtins will never
141         // be based on the UnitBytesId.
142         w.write_str(&method.mangle(&BUILTINS_CLASS, strings))
143     }
146 pub(crate) fn call_builtin(
147     w: &mut textual::FuncWriter<'_>,
148     target: Builtin,
149     params: impl textual::VarArgs,
150 ) -> Result<Sid> {
151     w.call(&target.to_string(), params)
154 pub(crate) fn expr_builtin(target: Builtin, params: impl textual::VarArgs) -> textual::Expr {
155     textual::Expr::call(target.to_string(), params)