Skip to content

Commit

Permalink
Temporarily re-add static locals
Browse files Browse the repository at this point in the history
Summary: This is meant for 4.2, not 4.1

Reviewed By: alexeyt

Differential Revision: D14525623

fbshipit-source-id: 02c576127292e04c982f40a158306ad2d6139697
  • Loading branch information
fredemmott authored and hhvm-bot committed Mar 21, 2019
1 parent 4a68c42 commit a9fd8fd
Show file tree
Hide file tree
Showing 269 changed files with 4,195 additions and 189 deletions.
27 changes: 27 additions & 0 deletions hphp/doc/bytecode.specification
Expand Up @@ -3670,6 +3670,33 @@ FuncNumArgs [] -> [C:Int]

Push the number of arguments the current function was called with.

StaticLocCheck <local variable id> <litstr id> [] -> [C:Bool]

Static variable. This instruction first checks if the static variable named
%2 has been marked as initialized. If the static variable has been marked as
initialized, this instruction binds the static variable to the local variable
%1 and pushes true. Otherwise, this instruction pushes false.

StaticLocDef <local variable id> <litstr id> [C] -> []

Initialize static variable. This instruction binds the static variable to
the local variable, assigns $1 to the local variable, and marks the static
variable as initialized.

Precondition: Except in memoized functions, the static local named %2 has
not been initialized

StaticLocInit <local variable id> <litstr id> [C] -> []

Static variable with initializer. This instruction first checks if the static
variable named %2 has been marked as initialized. If the static variable has
been marked as initialized, this instruction binds the static variable to the
local variable %1. Otherwise, this instruction binds the static variable to
the local variable, assigns $1 to the local variable, and marks the static
variable as initialized.

The cell in $1 must not be a reference counted type.

Catch [] -> [C:Obj]

Catch. Retrieves the current exception object and pushes it onto the stack.
Expand Down
20 changes: 20 additions & 0 deletions hphp/doc/ir.specification
Expand Up @@ -1523,6 +1523,16 @@ To string conversions:

Load the length of the string in S0.

| LdClosureStaticLoc<func,staticLocalName>, D(PtrToPropGen), S(Obj), NF

Get pointer to static local named 'staticLocName' for function 'func' whose
closure object is S0. func must either be a Closure, or generatorFromClosure

| LdStaticLoc<func,staticLocalName>, D(BoxedInitCell), NA, PRc

Load the address of the static local variable named 'staticLocalName' for
function 'func' in RDS. The variable must be initialized

| FuncSupportsAsyncEagerReturn, D(Bool), S(Func), NF

Tests for Func::m_attrs & AttrSupportsAsyncEagerReturn.
Expand Down Expand Up @@ -2296,6 +2306,16 @@ To string conversions:
Raises a runtime error unless whether each generic in S0 is reified or erased
matches exactly to the expectations of the func.

| CheckStaticLoc<func,staticLocalName>, ND, NA, B

Check whether the static local variable named 'staticLocalName' for
function 'func' is initialized in RDS, and branch if not.

| InitStaticLoc<func,staticLocalName>, ND, S(Cell), NF

Initialize the static local variable named 'staticLocalName' for
function 'func' with S0.

| InitClsCns<className,constName>, DCns, NA, PRc

Initialize the RDS entry for a constant for a class, invoking autoload if it
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/annotated_ast/aast.ml
Expand Up @@ -72,6 +72,7 @@ and stmt_ =
| Return of expr option
| GotoLabel of pstring
| Goto of pstring
| Static_var of expr list
| Global_var of expr list
| Awaitall of (lid option * expr) list
| If of expr * block * block
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/annotated_ast/aast_mapper.ml
Expand Up @@ -239,6 +239,7 @@ struct
| S.Return oe -> T.Return (Option.map oe (map_expr menv))
| S.GotoLabel label -> T.GotoLabel label
| S.Goto label -> T.Goto label
| S.Static_var el -> T.Static_var (map_exprl menv el)
| S.Global_var el -> T.Global_var (map_exprl menv el)
| S.Awaitall el ->
let el = List.map el (fun (lid, expr) -> (lid, map_expr menv expr)) in
Expand Down
6 changes: 6 additions & 0 deletions hphp/hack/src/facts/flatten_smart_constructors.ml
Expand Up @@ -267,6 +267,12 @@ module WithOp(Op : Op_S) = struct
let make_continue_statement arg0 arg1 arg2 state =
if Op.is_zero arg0 && Op.is_zero arg1 && Op.is_zero arg2 then state, Op.zero
else state, Op.flatten [arg0; arg1; arg2]
let make_function_static_statement arg0 arg1 arg2 state =
if Op.is_zero arg0 && Op.is_zero arg1 && Op.is_zero arg2 then state, Op.zero
else state, Op.flatten [arg0; arg1; arg2]
let make_static_declarator arg0 arg1 state =
if Op.is_zero arg0 && Op.is_zero arg1 then state, Op.zero
else state, Op.flatten [arg0; arg1]
let make_echo_statement arg0 arg1 arg2 state =
if Op.is_zero arg0 && Op.is_zero arg1 && Op.is_zero arg2 then state, Op.zero
else state, Op.flatten [arg0; arg1; arg2]
Expand Down
6 changes: 6 additions & 0 deletions hphp/hack/src/hackfmt/hack_format.ml
Expand Up @@ -157,6 +157,7 @@ let rec t (env: Env.t) (node: Syntax.t) : Doc.t =
| Syntax.PipeVariableExpression _
| Syntax.PropertyDeclarator _
| Syntax.ConstantDeclarator _
| Syntax.StaticDeclarator _
| Syntax.ScopeResolutionExpression _
| Syntax.EmbeddedMemberSelectionExpression _
| Syntax.EmbeddedSubscriptExpression _
Expand Down Expand Up @@ -1236,6 +1237,11 @@ let rec t (env: Env.t) (node: Syntax.t) : Doc.t =
continue_level = level;
continue_semicolon = semi; } ->
transform_keyword_expression_statement env kw level semi
| Syntax.FunctionStaticStatement {
static_static_keyword = static_kw;
static_declarations = declarators;
static_semicolon = semi; } ->
transform_keyword_expr_list_statement env static_kw declarators semi
| Syntax.EchoStatement {
echo_keyword = kw;
echo_expressions = expr_list;
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hh_single_compile.ml
Expand Up @@ -429,6 +429,7 @@ let make_popt () =
~enable_await_as_an_expression:(enable_await_as_an_expression co)
~disable_nontoplevel_declarations:(phpism_disable_nontoplevel_declarations co)
~disable_static_closures:(phpism_disable_static_closures co)
~disable_static_local_variables:(phpism_disable_static_local_variables co)
~enable_hh_syntax_for_hhvm:(enable_hiphop_syntax co)
~enable_stronger_await_binding:(enable_stronger_await_binding co)
~disable_lval_as_an_expression:(disable_lval_as_an_expression co)
Expand Down
23 changes: 23 additions & 0 deletions hphp/hack/src/hhbc/closure_convert.ml
Expand Up @@ -88,6 +88,9 @@ type state = {
inout_wrappers : fun_ list;
(* The current namespace environment *)
namespace: Namespace_env.env;
(* Static variables in closures have special properties with mangled names
* defined for them *)
static_vars : ULS.t;
(* Set of closure names that used to have explicit 'use' language construct
in original anonymous function *)
explicit_use_set: SSet.t;
Expand Down Expand Up @@ -140,6 +143,7 @@ let initial_state popt =
named_hoisted_functions = SMap.empty;
inout_wrappers = [];
namespace = Namespace_env.empty popt;
static_vars = ULS.empty;
explicit_use_set = SSet.empty;
closure_namespaces = SMap.empty;
closure_enclosing_classes = SMap.empty;
Expand Down Expand Up @@ -368,8 +372,12 @@ let enter_lambda st =
captured_vars = ULS.empty;
captured_this = false;
captured_generics = ULS.empty;
static_vars = ULS.empty;
}

let add_static_var st var =
{ st with static_vars = ULS.add st.static_vars var }

let set_namespace st ns =
{ st with namespace = ns }

Expand Down Expand Up @@ -433,6 +441,9 @@ let make_closure ~class_num
let cvl =
List.map lambda_vars
(fun name -> (p, (p, Hhbc_string_utils.Locals.strip_dollar name), None)) in
let cvl = cvl @ (List.map (ULS.items st.static_vars)
(fun name -> (p, (p,
"86static_" ^ (Hhbc_string_utils.Locals.strip_dollar name)), None))) in
let cd = {
c_mode = fd.f_mode;
c_user_attributes = [];
Expand Down Expand Up @@ -878,6 +889,7 @@ and convert_lambda env st p fd use_vars_opt =
let captured_vars = st.captured_vars in
let captured_this = st.captured_this in
let captured_generics = st.captured_generics in
let static_vars = st.static_vars in
let old_function_state = st.current_function_state in
let st = enter_lambda st in
let old_env = env in
Expand Down Expand Up @@ -970,6 +982,7 @@ and convert_lambda env st p fd use_vars_opt =
let st = { st with captured_vars;
captured_this;
captured_generics;
static_vars;
explicit_use_set;
closure_enclosing_classes;
closure_namespaces = SMap.add
Expand Down Expand Up @@ -1014,6 +1027,16 @@ and convert_stmt env st (p, stmt_ as stmt) : _ * stmt =
| Return opt_e ->
let st, opt_e = convert_opt_expr env st opt_e in
st, (p, Return opt_e)
| Static_var el ->
let visit_static_var st e =
begin match snd e with
| Lvar (_, name)
| Binop (Eq None, (_, Lvar (_, name)), _) -> add_static_var st name
| _ -> failwith "Static var - impossible"
end in
let st = List.fold_left el ~init:st ~f:visit_static_var in
let st, el = convert_exprs env st el in
st, (p, Static_var el)
| Awaitall el ->
let st, el = List.map_env st el (convert_snd_expr env) in
st, (p, Awaitall el)
Expand Down
22 changes: 20 additions & 2 deletions hphp/hack/src/hhbc/emit_body.ml
Expand Up @@ -134,7 +134,7 @@ and emit_defs env defs =

let make_body body_instrs decl_vars
is_memoize_wrapper is_memoize_wrapper_lsb
params return_type_info doc_comment
params return_type_info static_inits doc_comment
env =
let body_instrs = rewrite_user_labels body_instrs in
let body_instrs = rewrite_class_refs body_instrs in
Expand All @@ -154,6 +154,7 @@ let make_body body_instrs decl_vars
is_memoize_wrapper_lsb
params
return_type_info
static_inits
doc_comment
env

Expand Down Expand Up @@ -332,6 +333,10 @@ let emit_body
then remove_this vars @ ["$this"]
else vars in

let starts_with s prefix =
String.length s >= String.length prefix &&
String.sub s 0 (String.length prefix) = prefix in

let has_this = Ast_scope.Scope.has_this scope in
let is_toplevel = Ast_scope.Scope.is_toplevel scope in
(* see comment in decl_vars.ml, method on_efun of declvar_visitor
Expand Down Expand Up @@ -360,7 +365,9 @@ let emit_body
|> List.concat_map ~f:(fun item ->
match item with
| Ast.ClassVars { Ast.cv_names = cvl; _ } ->
List.map cvl ~f:(fun (_, (_, id), _) -> ("$" ^ id))
List.filter_map cvl ~f:(fun (_, (_, id), _) ->
if not (starts_with id "86static_")
then Some ("$" ^ id) else None)
| _ -> []) in
"$0Closure" ::
captured_vars @
Expand Down Expand Up @@ -418,6 +425,15 @@ let emit_body
let generator_instr =
if is_generator then gather [instr_createcont; instr_popc] else empty
in
let svar_map = Static_var.make_static_map body in
let emit_expr env e =
gather [
Emit_expression.emit_expr env ~need_ref:false e;
Emit_pos.emit_pos (fst e)
] in
let stmt_instrs =
rewrite_static_instrseq svar_map emit_expr env stmt_instrs
in
let first_instruction_is_label =
match Instruction_sequence.first stmt_instrs with
| Some (ILabel _) -> true
Expand Down Expand Up @@ -447,6 +463,7 @@ let emit_body
begin_label;
header_content;
] in
let svar_instrs = SMap.ordered_keys svar_map in
let body_instrs = gather [
header;
stmt_instrs;
Expand All @@ -464,6 +481,7 @@ let emit_body
false (*is_memoize_wrapper_lsb*)
params
(Some return_type_info)
svar_instrs
doc_comment
(Some env),
is_generator,
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_body.mli
Expand Up @@ -14,6 +14,7 @@ val make_body:
bool ->
Hhas_param.t list ->
Hhas_type_info.t option ->
string list ->
string option ->
Emit_env.t option ->
Hhas_body.t
Expand Down
2 changes: 2 additions & 0 deletions hphp/hack/src/hhbc/emit_class.ml
Expand Up @@ -59,6 +59,7 @@ let make_86method
let method_is_memoize_wrapper_lsb = false in
let method_no_injection = true in
let method_inout_wrapper = false in
let method_static_inits = [] in
let method_doc_comment = None in
let method_is_interceptable = false in
let method_is_memoize_impl = false in
Expand All @@ -70,6 +71,7 @@ let make_86method
method_is_memoize_wrapper_lsb
params
method_return_type
method_static_inits
method_doc_comment
method_env in
Hhas_method.make
Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_inout_function.ml
Expand Up @@ -107,6 +107,7 @@ let make_wrapper_body env doc decl_vars return_type params instrs =
false (* is_memoize_wrapper_lsb *)
params
(Some return_type)
[] (* static_inits: this is intentionally empty *)
doc
(Some env)

Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_memoize_function.ml
Expand Up @@ -120,6 +120,7 @@ let make_wrapper_body env return_type params instrs =
false (* is_memoize_wrapper_lsb *)
params
(Some return_type)
[] (* static_inits: this is intentionally empty *)
None (* doc *)
(Some env)

Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_memoize_method.ml
Expand Up @@ -288,6 +288,7 @@ let make_wrapper env return_type params instrs with_lsb =
with_lsb (* is_memoize_wrapper_lsb *)
params
(Some return_type)
[] (* static_inits *)
None (* doc *)
(Some env)

Expand Down
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_native_opcode.ml
Expand Up @@ -78,5 +78,6 @@ let emit_body scope namespace class_attrs name params ret =
false
params
(Some return_type_info)
[]
None
None
1 change: 1 addition & 0 deletions hphp/hack/src/hhbc/emit_program.ml
Expand Up @@ -49,6 +49,7 @@ let emit_fatal_program ~ignore_message op pos message =
false (*is_memoize_wrapper_lsb*)
[] (* params *)
None (* return_type_info *)
[] (* static_inits static_inits *)
None (* doc *)
None (* env *)
in
Expand Down
15 changes: 15 additions & 0 deletions hphp/hack/src/hhbc/emit_statement.ml
Expand Up @@ -286,6 +286,8 @@ let rec emit_stmt env (pos, st_) =
emit_foreach env pos collection await_pos iterator (pos, A.Block block)
| A.Def_inline def ->
emit_def_inline def
| A.Static_var es ->
emit_static_var pos es
| A.Global_var es ->
emit_global_vars pos es
| A.Awaitall el ->
Expand Down Expand Up @@ -359,6 +361,19 @@ and emit_global_vars p es =
end in
Emit_pos.emit_pos_then p @@ gather (List.rev instrs)

and emit_static_var pos es =
let emit_static_var_single e =
match snd e with
| A.Lvar (_, name)
| A.Binop (A.Eq _, (_, A.Lvar (_, name)), _) ->
gather [
Emit_pos.emit_pos pos;
instr_static_loc_init name
]
| _ -> failwith "Static var - impossible"
in
gather @@ List.map es ~f:emit_static_var_single

and emit_awaitall env pos el =
match el with
| [] -> empty
Expand Down
4 changes: 4 additions & 0 deletions hphp/hack/src/hhbc/hhas_body.ml
Expand Up @@ -17,6 +17,7 @@ type t = {
body_is_memoize_wrapper_lsb: bool;
body_params : Hhas_param.t list;
body_return_type : Hhas_type_info.t option;
body_static_inits : string list;
body_doc_comment : string option;
body_env : Emit_env.t option;
}
Expand All @@ -30,6 +31,7 @@ let make
is_memoize_wrapper_lsb
params
return_type
static_inits
doc_comment
env =
{
Expand All @@ -41,6 +43,7 @@ let make
body_is_memoize_wrapper_lsb = is_memoize_wrapper_lsb;
body_params = params;
body_return_type = return_type;
body_static_inits = static_inits;
body_doc_comment = doc_comment;
body_env = env;
}
Expand All @@ -54,5 +57,6 @@ let return_type body = body.body_return_type
let is_memoize_wrapper body = body.body_is_memoize_wrapper
let is_memoize_wrapper_lsb body = body.body_is_memoize_wrapper_lsb
let with_instrs body instrs = { body with body_instrs = instrs }
let static_inits body = body.body_static_inits
let doc_comment body = body.body_doc_comment
let env body = body.body_env

0 comments on commit a9fd8fd

Please sign in to comment.