From 579c855d4dd881686698ff7c24a297fb10aa8c16 Mon Sep 17 00:00:00 2001 From: Paul Biggar Date: Tue, 18 Nov 2008 19:12:05 +0000 Subject: [PATCH] Add function signatures for PHP functions. I've only used them in one place so far: adding aliases for actual function parameters only if the call is by reference. Though I can see a number of places this has reduced the number of aliases, the performance results remain the same. This introduces an optimization Oracle, which sits between PHP and the optimizers. It interfaces with PHP to get function signatures, but can also be given functions signatures by the optimizers. An MIR::Signature now has an extra field: pass_rest_by_ref, indicating that parameters that do not have a formal parameter are passed by reference. Even though we cant create functions with the property (or I dont think we can), internal functions can use this, and so we need to model it. We don't need to fix_solo_phi_args since we drop phi args. We can model dataflow properties through phis just as well as if they were put into real statements, but the real statements wouldnt be dropped at the end of the function. --- Makefile.am | 2 ++ Makefile.in | 36 ++++++++++++-------- src/codegen/Generate_C.cpp | 4 +-- src/codegen/Lift_functions_and_classes.cpp | 1 + src/embed/embed.h | 3 ++ src/embed/optimize.cpp | 38 ++++++++++++++++++++++ src/generated/MIR.cpp | 35 +++++++++++++++----- src/generated/MIR.h | 9 +++-- src/generated/MIR_factory.cpp | 5 +-- src/generated/MIR_fold.h | 7 ++-- src/generated/MIR_visitor.cpp | 3 +- src/generated_src/mir.tea | 15 +++++++-- src/hir_to_mir/HIR_to_MIR.h | 5 +-- src/lib/List.h | 15 +++++++++ src/optimize/Address_taken.cpp | 14 +++++++- src/optimize/CFG.cpp | 4 +++ src/optimize/Oracle.cpp | 33 +++++++++++++++++++ src/optimize/Oracle.h | 25 ++++++++++++++ src/optimize/SCCP.cpp | 2 +- src/pass_manager/Pass_manager.cpp | 8 ++--- src/process_mir/MIR_to_AST.h | 4 +-- src/process_mir/Main_uppering.h | 1 + 22 files changed, 225 insertions(+), 44 deletions(-) create mode 100644 src/optimize/Oracle.cpp create mode 100644 src/optimize/Oracle.h diff --git a/Makefile.am b/Makefile.am index c5dc16c8a..c8d8f19ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -174,6 +174,8 @@ libphc_la_SOURCES= \ src/optimize/Lattice.h \ src/optimize/Live_variable_analysis.cpp \ src/optimize/Live_variable_analysis.h \ + src/optimize/Oracle.cpp \ + src/optimize/Oracle.h \ src/optimize/SCCP.cpp \ src/optimize/SCCP.h \ - src/optimize/Prune_symbol_table.cpp \ diff --git a/Makefile.in b/Makefile.in index b1ed2b0c4..8b972cdc8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,19 +102,19 @@ am_libphc_la_OBJECTS = getopt1.lo getopt.lo AST_annotate.lo \ Integer.lo Object.lo String.lo Address_taken.lo Basic_block.lo \ CFG.lo CFG_visitor.lo Dead_code_elimination.lo Def_use.lo \ Edge.lo Flow_visitor.lo If_simplification.lo Lattice.lo \ - Live_variable_analysis.lo SCCP.lo Prune_symbol_table.lo Set.lo \ - Dominance.lo HSSA.lo Phi.lo SSA.lo SSA_ops.lo \ - Virtual_variable.lo Visit_once.lo Parse_buffer.lo parse.lo \ - PHP_context.lo XML_parser.lo Optimization_pass.lo \ - Pass_manager.lo Plugin_pass.lo AST_unparser.lo \ - Constant_folding.lo DOT_unparser.lo Invalid_check.lo \ - Note_top_level_declarations.lo Process_includes.lo \ - Remove_concat_null.lo Remove_parser_temporaries.lo \ - Strip_unparser_attributes.lo Token_conversion.lo \ - HIR_unparser.lo debug.lo fresh.lo General.lo IR.lo \ - PHP_unparser.lo XML_unparser.lo Alias_uppering.lo \ - Foreach_uppering.lo Goto_uppering.lo MIR_unparser.lo \ - Param_is_ref_uppering.lo + Live_variable_analysis.lo Oracle.lo SCCP.lo \ + Prune_symbol_table.lo Set.lo Dominance.lo HSSA.lo Phi.lo \ + SSA.lo SSA_ops.lo Virtual_variable.lo Visit_once.lo \ + Parse_buffer.lo parse.lo PHP_context.lo XML_parser.lo \ + Optimization_pass.lo Pass_manager.lo Plugin_pass.lo \ + AST_unparser.lo Constant_folding.lo DOT_unparser.lo \ + Invalid_check.lo Note_top_level_declarations.lo \ + Process_includes.lo Remove_concat_null.lo \ + Remove_parser_temporaries.lo Strip_unparser_attributes.lo \ + Token_conversion.lo HIR_unparser.lo debug.lo fresh.lo \ + General.lo IR.lo PHP_unparser.lo XML_unparser.lo \ + Alias_uppering.lo Foreach_uppering.lo Goto_uppering.lo \ + MIR_unparser.lo Param_is_ref_uppering.lo libphc_la_OBJECTS = $(am_libphc_la_OBJECTS) plugins_tests_canonical_unparser_la_LIBADD = am_plugins_tests_canonical_unparser_la_OBJECTS = \ @@ -712,6 +712,8 @@ libphc_la_SOURCES = \ src/optimize/Lattice.h \ src/optimize/Live_variable_analysis.cpp \ src/optimize/Live_variable_analysis.h \ + src/optimize/Oracle.cpp \ + src/optimize/Oracle.h \ src/optimize/SCCP.cpp \ src/optimize/SCCP.h \ - src/optimize/Prune_symbol_table.cpp \ @@ -1314,6 +1316,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Note_top_level_declarations.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Object.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Optimization_pass.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Oracle.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PHP_context.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PHP_unparser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Param_is_ref_uppering.Plo@am__quote@ @@ -1829,6 +1832,13 @@ Live_variable_analysis.lo: src/optimize/Live_variable_analysis.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Live_variable_analysis.lo `test -f 'src/optimize/Live_variable_analysis.cpp' || echo '$(srcdir)/'`src/optimize/Live_variable_analysis.cpp +Oracle.lo: src/optimize/Oracle.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Oracle.lo -MD -MP -MF $(DEPDIR)/Oracle.Tpo -c -o Oracle.lo `test -f 'src/optimize/Oracle.cpp' || echo '$(srcdir)/'`src/optimize/Oracle.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Oracle.Tpo $(DEPDIR)/Oracle.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/optimize/Oracle.cpp' object='Oracle.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Oracle.lo `test -f 'src/optimize/Oracle.cpp' || echo '$(srcdir)/'`src/optimize/Oracle.cpp + SCCP.lo: src/optimize/SCCP.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SCCP.lo -MD -MP -MF $(DEPDIR)/SCCP.Tpo -c -o SCCP.lo `test -f 'src/optimize/SCCP.cpp' || echo '$(srcdir)/'`src/optimize/SCCP.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/SCCP.Tpo $(DEPDIR)/SCCP.Plo diff --git a/src/codegen/Generate_C.cpp b/src/codegen/Generate_C.cpp index bab7e2234..1332744bf 100644 --- a/src/codegen/Generate_C.cpp +++ b/src/codegen/Generate_C.cpp @@ -439,7 +439,7 @@ class Pattern_method_definition : public Pattern gen->methods->push_back(signature); method_entry(); - gen->return_by_reference = signature->is_ref; + gen->return_by_reference = signature->return_by_ref; gen->visit_statement_list(pattern->value->statements); method_exit(); } @@ -2665,7 +2665,7 @@ void Generate_C::post_php_script(PHP_script* in) // TODO: pass by reference only works for PHP>5.1.0. Do we care? code << "ZEND_BEGIN_ARG_INFO_EX(" << *name << "_arg_info, 0, " - << (s->is_ref ? "1" : "0") + << (s->return_by_ref ? "1" : "0") << ", 0)\n" ; diff --git a/src/codegen/Lift_functions_and_classes.cpp b/src/codegen/Lift_functions_and_classes.cpp index d364f50dc..93a01c464 100644 --- a/src/codegen/Lift_functions_and_classes.cpp +++ b/src/codegen/Lift_functions_and_classes.cpp @@ -30,6 +30,7 @@ void Lift_functions_and_classes::children_php_script(PHP_script* in) new Signature( new Method_mod(), false, + false, new METHOD_NAME(new String("__MAIN__")), new Formal_parameter_list), main)); diff --git a/src/embed/embed.h b/src/embed/embed.h index 0b000ee1c..afcb24565 100644 --- a/src/embed/embed.h +++ b/src/embed/embed.h @@ -62,8 +62,11 @@ class PHP static MIR::Literal* fold_string_index (MIR::Literal* array, MIR::Literal* index); // Functions + // TODO: move to the oracle. We want to keep this to embedding PHP. static bool is_pure_function (MIR::METHOD_NAME* in); + static MIR::Signature* get_signature (MIR::METHOD_NAME*); static MIR::Literal* call_function (MIR::METHOD_NAME* in, MIR::Literal_list* params); + }; #endif // PHC_EMBED_H diff --git a/src/embed/optimize.cpp b/src/embed/optimize.cpp index 4486da2b8..c0ee151c6 100644 --- a/src/embed/optimize.cpp +++ b/src/embed/optimize.cpp @@ -24,6 +24,8 @@ extern void ***tsrm_ls; using namespace MIR; + + bool PHP::is_pure_function (METHOD_NAME* in) { @@ -231,6 +233,42 @@ PHP::cast_to (CAST* cast, Literal* lit) return NULL; } +Signature* +PHP::get_signature (METHOD_NAME* method_name) +{ + zval fn; + INIT_PZVAL (&fn); + ZVAL_STRING (&fn, const_cast (method_name->value->c_str ()), 0); + + zend_fcall_info fci; + zend_fcall_info_cache fcic; + int result = zend_fcall_info_init (&fn, &fci, &fcic TSRMLS_CC); + + zend_function* func = fcic.function_handler; + if (result != SUCCESS) + return NULL; + + Signature* sig = new Signature (method_name->value->c_str ()); + + sig->pass_rest_by_ref = func->common.pass_rest_by_reference; + sig->return_by_ref = func->common.return_reference; + + for (unsigned int i = 0; i < func->common.num_args; i++) + { + stringstream ss; + ss << "unknown" << i; + + Formal_parameter* param = + new Formal_parameter ( + NULL, // TODO + ARG_MUST_BE_SENT_BY_REF (func, i+1), + new VARIABLE_NAME (s (ss.str ()))); + + sig->formal_parameters->push_back (param); + } + return sig; +} + Literal* PHP::call_function (METHOD_NAME* name, Literal_list* params) diff --git a/src/generated/MIR.cpp b/src/generated/MIR.cpp index c3cf2bd7d..8394f4aad 100644 --- a/src/generated/MIR.cpp +++ b/src/generated/MIR.cpp @@ -290,10 +290,11 @@ Member::Member() { } -Signature::Signature(Method_mod* method_mod, bool is_ref, METHOD_NAME* method_name, Formal_parameter_list* formal_parameters) +Signature::Signature(Method_mod* method_mod, bool pass_rest_by_ref, bool return_by_ref, METHOD_NAME* method_name, Formal_parameter_list* formal_parameters) { this->method_mod = method_mod; - this->is_ref = is_ref; + this->pass_rest_by_ref = pass_rest_by_ref; + this->return_by_ref = return_by_ref; this->method_name = method_name; this->formal_parameters = formal_parameters; } @@ -301,7 +302,8 @@ Signature::Signature(Method_mod* method_mod, bool is_ref, METHOD_NAME* method_na Signature::Signature() { this->method_mod = 0; - this->is_ref = 0; + this->pass_rest_by_ref = 0; + this->return_by_ref = 0; this->method_name = 0; this->formal_parameters = 0; } @@ -339,7 +341,8 @@ bool Signature::match(Node* in) else if(!this->method_mod->match(that->method_mod)) return false; - that->is_ref = this->is_ref; + that->pass_rest_by_ref = this->pass_rest_by_ref; + that->return_by_ref = this->return_by_ref; if(this->method_name == NULL) { if(that->method_name != NULL && !that->method_name->match(this->method_name)) @@ -384,7 +387,10 @@ bool Signature::equals(Node* in) else if(!this->method_mod->equals(that->method_mod)) return false; - if(this->is_ref != that->is_ref) + if(this->pass_rest_by_ref != that->pass_rest_by_ref) + return false; + + if(this->return_by_ref != that->return_by_ref) return false; if(this->method_name == NULL || that->method_name == NULL) @@ -426,7 +432,8 @@ bool Signature::equals(Node* in) Signature* Signature::clone() { Method_mod* method_mod = this->method_mod ? this->method_mod->clone() : NULL; - bool is_ref = this->is_ref; + bool pass_rest_by_ref = this->pass_rest_by_ref; + bool return_by_ref = this->return_by_ref; METHOD_NAME* method_name = this->method_name ? this->method_name->clone() : NULL; Formal_parameter_list* formal_parameters = NULL; if(this->formal_parameters != NULL) @@ -436,7 +443,7 @@ Signature* Signature::clone() for(i = this->formal_parameters->begin(); i != this->formal_parameters->end(); i++) formal_parameters->push_back(*i ? (*i)->clone() : NULL); } - Signature* clone = new Signature(method_mod, is_ref, method_name, formal_parameters); + Signature* clone = new Signature(method_mod, pass_rest_by_ref, return_by_ref, method_name, formal_parameters); clone->Node::clone_mixin_from(this); return clone; } @@ -527,12 +534,24 @@ Signature::Signature(const char* name) { { this->method_mod = Method_mod::new_PUBLIC(); - this->is_ref = false; + this->pass_rest_by_ref = false; + this->return_by_ref = false; this->method_name = new METHOD_NAME(name); this->formal_parameters = new Formal_parameter_list; } } +// Returns if the parameter at index PARAM_INDEX is passed by reference. +bool Signature::is_param_passed_by_ref(int param_index) +{ + { + if (this->formal_parameters->size () > (unsigned int)(param_index)) + return formal_parameters->at (param_index)->is_ref; + else + return this->pass_rest_by_ref; + } +} + Method_mod::Method_mod(bool is_public, bool is_protected, bool is_private, bool is_static, bool is_abstract, bool is_final) { this->is_public = is_public; diff --git a/src/generated/MIR.h b/src/generated/MIR.h index bbb63726e..c85b58751 100644 --- a/src/generated/MIR.h +++ b/src/generated/MIR.h @@ -339,16 +339,17 @@ class Member : virtual public Node virtual void assert_valid() = 0; }; -// Signature ::= Method_mod is_ref:"&" METHOD_NAME Formal_parameter* ; +// Signature ::= Method_mod pass_rest_by_ref:"rest_by_ref" return_by_ref:"&" METHOD_NAME Formal_parameter* ; class Signature : virtual public Node { public: - Signature(Method_mod* method_mod, bool is_ref, METHOD_NAME* method_name, Formal_parameter_list* formal_parameters); + Signature(Method_mod* method_mod, bool pass_rest_by_ref, bool return_by_ref, METHOD_NAME* method_name, Formal_parameter_list* formal_parameters); protected: Signature(); public: Method_mod* method_mod; - bool is_ref; + bool pass_rest_by_ref; + bool return_by_ref; METHOD_NAME* method_name; Formal_parameter_list* formal_parameters; public: @@ -371,6 +372,8 @@ class Signature : virtual public Node virtual void assert_valid(); public: Signature(const char* name); + // Returns if the parameter at index PARAM_INDEX is passed by reference. + bool is_param_passed_by_ref(int param_index); }; // Method_mod ::= "public"? "protected"? "private"? "static"? "abstract"? "final"? ; diff --git a/src/generated/MIR_factory.cpp b/src/generated/MIR_factory.cpp index a09630849..effaceb99 100644 --- a/src/generated/MIR_factory.cpp +++ b/src/generated/MIR_factory.cpp @@ -57,11 +57,12 @@ Object* Node_factory::create(char const* type_id, List* args) if(!strcmp(type_id, "Signature")) { Method_mod* method_mod = dynamic_cast(*i++); - bool is_ref = dynamic_cast(*i++)->value(); + bool pass_rest_by_ref = dynamic_cast(*i++)->value(); + bool return_by_ref = dynamic_cast(*i++)->value(); METHOD_NAME* method_name = dynamic_cast(*i++); Formal_parameter_list* formal_parameters = dynamic_cast(*i++); assert(i == args->end()); - return new Signature(method_mod, is_ref, method_name, formal_parameters); + return new Signature(method_mod, pass_rest_by_ref, return_by_ref, method_name, formal_parameters); } if(!strcmp(type_id, "Method_mod")) { diff --git a/src/generated/MIR_fold.h b/src/generated/MIR_fold.h index 5b6831182..dd4e39c75 100644 --- a/src/generated/MIR_fold.h +++ b/src/generated/MIR_fold.h @@ -214,7 +214,8 @@ class Fold { _Method_mod method_mod = 0; if(in->method_mod != NULL) method_mod = fold_method_mod(in->method_mod); - bool is_ref = in->is_ref; + bool pass_rest_by_ref = in->pass_rest_by_ref; + bool return_by_ref = in->return_by_ref; _METHOD_NAME method_name = 0; if(in->method_name != NULL) method_name = fold_method_name(in->method_name); _List<_Formal_parameter>* formal_parameters = 0; @@ -226,7 +227,7 @@ class Fold if(*i != NULL) formal_parameters->push_back(fold_formal_parameter(*i)); else formal_parameters->push_back(0); } - return fold_impl_signature(in, method_mod, is_ref, method_name, formal_parameters); + return fold_impl_signature(in, method_mod, pass_rest_by_ref, return_by_ref, method_name, formal_parameters); } virtual _Method_mod fold_method_mod(Method_mod* in) @@ -764,7 +765,7 @@ class Fold virtual _Class_mod fold_impl_class_mod(Class_mod* orig, bool is_abstract, bool is_final) { assert(0); }; virtual _Interface_def fold_impl_interface_def(Interface_def* orig, _INTERFACE_NAME interface_name, _List<_INTERFACE_NAME>* extends, _List<_Member>* members) { assert(0); }; virtual _Method fold_impl_method(Method* orig, _Signature signature, _List<_Statement>* statements) { assert(0); }; - virtual _Signature fold_impl_signature(Signature* orig, _Method_mod method_mod, bool is_ref, _METHOD_NAME method_name, _List<_Formal_parameter>* formal_parameters) { assert(0); }; + virtual _Signature fold_impl_signature(Signature* orig, _Method_mod method_mod, bool pass_rest_by_ref, bool return_by_ref, _METHOD_NAME method_name, _List<_Formal_parameter>* formal_parameters) { assert(0); }; virtual _Method_mod fold_impl_method_mod(Method_mod* orig, bool is_public, bool is_protected, bool is_private, bool is_static, bool is_abstract, bool is_final) { assert(0); }; virtual _Formal_parameter fold_impl_formal_parameter(Formal_parameter* orig, _Type type, bool is_ref, _Name_with_default var) { assert(0); }; virtual _Type fold_impl_type(Type* orig, _CLASS_NAME class_name) { assert(0); }; diff --git a/src/generated/MIR_visitor.cpp b/src/generated/MIR_visitor.cpp index 926aea814..41fbfd296 100644 --- a/src/generated/MIR_visitor.cpp +++ b/src/generated/MIR_visitor.cpp @@ -756,7 +756,8 @@ void Visitor::children_method(Method* in) void Visitor::children_signature(Signature* in) { visit_method_mod(in->method_mod); - visit_marker("is_ref", in->is_ref); + visit_marker("pass_rest_by_ref", in->pass_rest_by_ref); + visit_marker("return_by_ref", in->return_by_ref); visit_method_name(in->method_name); visit_formal_parameter_list(in->formal_parameters); } diff --git a/src/generated_src/mir.tea b/src/generated_src/mir.tea index d226a9e6e..2899e1bdd 100644 --- a/src/generated_src/mir.tea +++ b/src/generated_src/mir.tea @@ -59,7 +59,8 @@ Interface_def ::= INTERFACE_NAME extends:INTERFACE_NAME* Member* ; Member ::= Method | Attribute ; Method ::= Signature Statement*? ; -Signature ::= Method_mod is_ref:"&"? METHOD_NAME Formal_parameter* ; +-- Pass_rest_by_ref is so that we can treat fully model ZEND_INTERNAL_FUNCTIONs as Signatures +Signature ::= Method_mod pass_rest_by_ref:"rest_by_ref"? return_by_ref:"&"? METHOD_NAME Formal_parameter* ; Method_mod ::= "public"? "protected"? "private"? "static"? "abstract"? "final"? ; Formal_parameter ::= Type is_ref:"&"? var:Name_with_default ; Type ::= CLASS_NAME? ; @@ -271,10 +272,20 @@ public: Signature(const char* name) { this->method_mod = Method_mod::new_PUBLIC(); - this->is_ref = false; + this->pass_rest_by_ref = false; + this->return_by_ref = false; this->method_name = new METHOD_NAME(name); this->formal_parameters = new Formal_parameter_list; } + + // Returns if the parameter at index PARAM_INDEX is passed by reference. + bool is_param_passed_by_ref (int param_index) + { + if (this->formal_parameters->size () > (unsigned int)(param_index)) + return formal_parameters->at (param_index)->is_ref; + else + return this->pass_rest_by_ref; + } }; class Method_mod diff --git a/src/hir_to_mir/HIR_to_MIR.h b/src/hir_to_mir/HIR_to_MIR.h index 150b124e9..76c21d984 100644 --- a/src/hir_to_mir/HIR_to_MIR.h +++ b/src/hir_to_mir/HIR_to_MIR.h @@ -164,10 +164,11 @@ class HIR_to_MIR : virtual public GC_obj, public HIR::Fold return result; } - MIR::Signature* fold_impl_signature(HIR::Signature* orig, MIR::Method_mod* method_mod, bool is_ref, MIR::METHOD_NAME* method_name, MIR::Formal_parameter_list* formal_parameters) + MIR::Signature* fold_impl_signature(HIR::Signature* orig, MIR::Method_mod* method_mod, bool return_by_ref, MIR::METHOD_NAME* method_name, MIR::Formal_parameter_list* formal_parameters) { MIR::Signature* result; - result = new MIR::Signature(method_mod, is_ref, method_name, formal_parameters); + // The HIR doesnt have a pass_rest_by_ref field + result = new MIR::Signature(method_mod, false, return_by_ref, method_name, formal_parameters); copy_attrs (result, orig); return result; } diff --git a/src/lib/List.h b/src/lib/List.h index d97c264e6..a26264a8b 100644 --- a/src/lib/List.h +++ b/src/lib/List.h @@ -120,6 +120,21 @@ class List : public std::list<_Tp, _Alloc>, virtual public Object return result; } + + _Tp at (int index) + { + int i = 0; + assert (this->size () > (unsigned int)(i)); + foreach (_Tp elem, *this) + { + if (i == index) + return elem; + + i++; + } + + assert (0); + } }; template diff --git a/src/optimize/Address_taken.cpp b/src/optimize/Address_taken.cpp index 86352b39b..534912412 100644 --- a/src/optimize/Address_taken.cpp +++ b/src/optimize/Address_taken.cpp @@ -6,7 +6,9 @@ */ #include "process_ir/General.h" + #include "Address_taken.h" +#include "Oracle.h" #include "ssa/Virtual_variable.h" using namespace MIR; @@ -290,8 +292,18 @@ Address_taken::visit_isset (Statement_block* bb, MIR::Isset* in) void Address_taken::visit_method_invocation (Statement_block* bb, MIR::Method_invocation* in) { + Signature* sig = NULL; + if (in->target == NULL && isa (in->method_name)) + sig = Oracle::get_signature (dyc (in->method_name)); + + int i = 0; foreach (Actual_parameter* ap, *in->actual_parameters) - aliased (bb,ap->rvalue); + { + if (!sig || sig->is_param_passed_by_ref (i)) + aliased (bb, ap->rvalue); + + i++; + } } void Address_taken::visit_new (Statement_block* bb, MIR::New* in) diff --git a/src/optimize/CFG.cpp b/src/optimize/CFG.cpp index ddcd569fd..baa12344c 100644 --- a/src/optimize/CFG.cpp +++ b/src/optimize/CFG.cpp @@ -1091,6 +1091,10 @@ CFG::remove_unreachable_blocks () void CFG::fix_solo_phi_args () { + // This is no longer important, since we drop phi nodes at the end of the + // function. + return; + foreach (Basic_block* bb, *get_all_bbs ()) { // TODO: The theory is that each Phi node executes simultaneously. If diff --git a/src/optimize/Oracle.cpp b/src/optimize/Oracle.cpp new file mode 100644 index 000000000..410661437 --- /dev/null +++ b/src/optimize/Oracle.cpp @@ -0,0 +1,33 @@ +#include "Oracle.h" +#include "embed/embed.h" + +using namespace MIR; + + +Map Oracle::sigs; + +Signature* +Oracle::get_signature (METHOD_NAME* method_name) +{ + // Cached + if (Oracle::sigs.has (*method_name->value)) + return Oracle::sigs[*method_name->value]; + + // Lookup the embed SAPI + Signature* sig = PHP::get_signature (method_name); + + // Cache it + if (sig) + add_signature (method_name, sig); + + return sig; +} + +void +Oracle::add_signature (METHOD_NAME* method_name, Signature* sig) +{ + if (Oracle::sigs.has (*method_name->value)) + assert (0); + + sigs[*method_name->value] = sig; +} diff --git a/src/optimize/Oracle.h b/src/optimize/Oracle.h new file mode 100644 index 000000000..d12f1ef17 --- /dev/null +++ b/src/optimize/Oracle.h @@ -0,0 +1,25 @@ +#ifndef PHC_ORACLE +#define PHC_ORACLE + +#include "MIR.h" + +// The optimization oracle. This is a layer between the PHP:: embed functions +// and the optimizer, in order to allow the optimizer update the information. +// +// TODO: though currently a singleton, we may want to make this instantiable +// (and clonable presumably) to handle context-sensitivity, or speculative +// optimizations. +class Oracle +{ +private: + Oracle (); +public: + static Map sigs; + + // Returns NULL if none is available + static MIR::Signature* get_signature (MIR::METHOD_NAME* method_name); + + static void add_signature (MIR::METHOD_NAME* method_name, MIR::Signature* sig); +}; + +#endif // PHC_ORACLE diff --git a/src/optimize/SCCP.cpp b/src/optimize/SCCP.cpp index be33d77b9..573214a3c 100644 --- a/src/optimize/SCCP.cpp +++ b/src/optimize/SCCP.cpp @@ -819,7 +819,7 @@ class SCCP_updater : public Visit_once void visit_return (Statement_block* bb, MIR::Return* in) { // Dont propagate to return-by-ref - if (bb->cfg->get_entry_bb ()->method->signature->is_ref) + if (bb->cfg->get_entry_bb ()->method->signature->return_by_ref) return; // TODO change Return to take an Rvalue diff --git a/src/pass_manager/Pass_manager.cpp b/src/pass_manager/Pass_manager.cpp index c848d5e9d..ea727f72a 100644 --- a/src/pass_manager/Pass_manager.cpp +++ b/src/pass_manager/Pass_manager.cpp @@ -630,13 +630,13 @@ void Pass_manager::run_optimization_passes (MIR::PHP_script* in) cfg_dump (cfg, cfg_pass, s("Iterating"), iter); foreach (Pass* pass, *optimization_queue) { - if (args_info->verbose_flag) - cout << "Running pass: " << *pass->name << endl; - Optimization_pass* opt = dynamic_cast (pass); - if (opt == NULL) + if (opt == NULL || !pass->is_enabled (pm)) continue; + if (args_info->verbose_flag) + cout << "Running pass: " << *pass->name << endl; + // Convert to SSA form maybe_enable_debug (build_pass); HSSA* hssa = new HSSA (cfg); diff --git a/src/process_mir/MIR_to_AST.h b/src/process_mir/MIR_to_AST.h index 3ebc31cd4..5e5713ada 100644 --- a/src/process_mir/MIR_to_AST.h +++ b/src/process_mir/MIR_to_AST.h @@ -232,10 +232,10 @@ class MIR_to_AST : virtual public GC_obj, public MIR::Fold return result; } - AST::Signature* fold_impl_signature(MIR::Signature* orig, AST::Method_mod* method_mod, bool is_ref, AST::METHOD_NAME* method_name, AST::Formal_parameter_list* formal_parameters) + AST::Signature* fold_impl_signature(MIR::Signature* orig, AST::Method_mod* method_mod, bool pass_rest_by_ref, bool return_by_ref, AST::METHOD_NAME* method_name, AST::Formal_parameter_list* formal_parameters) { AST::Signature* result; - result = new AST::Signature(method_mod, is_ref, method_name, formal_parameters); + result = new AST::Signature(method_mod, return_by_ref, method_name, formal_parameters); result->attrs = orig->attrs; return result; } diff --git a/src/process_mir/Main_uppering.h b/src/process_mir/Main_uppering.h index 3a57b22b3..cb9f0cec2 100644 --- a/src/process_mir/Main_uppering.h +++ b/src/process_mir/Main_uppering.h @@ -24,6 +24,7 @@ class Main_uppering : public MIR::Visitor, virtual public GC_obj new MIR::Signature ( new MIR::Wildcard, false, + false, new MIR::METHOD_NAME (s ("__MAIN__")), NULL), NULL)))