[phc-internals] [phc commit] r1641 - in branches/dataflow: . libphc src/codegen src/optimize test/framework test/subjects/code...

codesite-noreply at google.com codesite-noreply at google.com
Fri Sep 12 18:11:50 IST 2008


Author: paul.biggar
Date: Fri Sep 12 10:10:39 2008
New Revision: 1641

Added:
    branches/dataflow/test/subjects/codegen/assign_const_by_ref.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/assign_const_by_ref.php
    branches/dataflow/test/subjects/codegen/include_fail.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/include_fail.php
    branches/dataflow/test/subjects/codegen/non_string_var_vars.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/non_string_var_vars.php
    branches/dataflow/test/subjects/codegen/push_onto_scalar.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/push_onto_scalar.php
    branches/dataflow/test/subjects/codegen/push_onto_scalar_by_ref.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/push_onto_scalar_by_ref.php
     
branches/dataflow/test/subjects/codegen/push_reference_through_array_by_copy.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/push_reference_through_array_by_copy.php
    branches/dataflow/test/subjects/codegen/push_uninitialized.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/push_uninitialized.php
    branches/dataflow/test/subjects/codegen/solo_cast.php
       - copied unchanged from r1639,  
/trunk/test/subjects/codegen/solo_cast.php
    branches/dataflow/test/subjects/phc/prune_sym_table.php
       - copied unchanged from r1639,  
/trunk/test/subjects/phc/prune_sym_table.php
Modified:
    branches/dataflow/   (props changed)
    branches/dataflow/configure
    branches/dataflow/configure.ac
    branches/dataflow/libphc/support_routines.c
    branches/dataflow/src/codegen/Generate_C.cpp
    branches/dataflow/src/optimize/Prune_symbol_table.cpp
    branches/dataflow/test/framework/annotated_test.php
    branches/dataflow/test/subjects/phc/disable.php
    branches/dataflow/test/subjects/phc/dump_tokens.php
    branches/dataflow/test/subjects/phc/foreach_dump.php
    branches/dataflow/test/subjects/phc/list_passes.php
    branches/dataflow/test/subjects/phc/param_is_ref.php

Log:
Merge from trunk (to get the new regex annotations). Log:

Merged revisions 1617,1622-1624,1628,1630-1632,1639 via svnmerge from
https://phc.googlecode.com/svn/trunk

........
   r1617 | paul.biggar | 2008-09-08 11:16:07 +0100 (Mon, 08 Sep 2008) | 2  
lines

   Limit boost config to versnio 1.34.0, when the BOOST_FOREACH macro was  
introduced, and the dominator algorithm with added to BGL.
........
   r1622 | paul.biggar | 2008-09-08 22:35:52 +0100 (Mon, 08 Sep 2008) | 2  
lines

   Make pushing a little bit more correct with respect to scalars, but its  
still a little bit broken. We havent really got the semantics documented,  
so I think that needs to be done in general before we can fix these bugs.  
Adds a wider test case then we had previously.
........
   r1623 | paul.biggar | 2008-09-09 12:16:38 +0100 (Tue, 09 Sep 2008) | 2  
lines

   Add comments explaining the semantics of the assignment. These aren't  
based on the code they generate, rather, I'll begin checking that the code  
we generate does the right thing in respect to the comments.
........
   r1624 | paul.biggar | 2008-09-09 12:20:20 +0100 (Tue, 09 Sep 2008) | 2  
lines

   Add a test for which we leak memory in includes.
........
   r1628 | paul.biggar | 2008-09-09 18:54:47 +0100 (Tue, 09 Sep 2008) | 2  
lines

   I foolishly didnt test before my commit this morning. I left an open  
comment, so it wouldnt even compile. Fixed.
........
   r1630 | paul.biggar | 2008-09-10 11:20:34 +0100 (Wed, 10 Sep 2008) | 2  
lines

   Remove unused functions, and simplify assign_literal.
........
   r1631 | paul.biggar | 2008-09-10 14:27:30 +0100 (Wed, 10 Sep 2008) | 2  
lines

   Move the function initialization into a support function. The  
zend_fcall_info fields are shared, both for different call sites, and for  
param_is_ref. It only needs to be initialized once, but we have to check  
whether it is initialized each time, since the function might only be  
created at run-time.
........
   r1632 | paul.biggar | 2008-09-10 14:49:05 +0100 (Wed, 10 Sep 2008) | 2  
lines

   Pruning the symbol table stopped working, leading to a 5x slowdown. This  
fixes it, and adds a test.
........
   r1639 | paul.biggar | 2008-09-12 17:14:23 +0100 (Fri, 12 Sep 2008) | 2  
lines

   For testing options using regexes, require /s around the regex. This  
means we can now add !/.../ style patterns, which say the pattern is not  
found in the output. This is useful for testing optimizations, which  
generally remove code, or allow it to be removed.
........


Modified: branches/dataflow/configure
==============================================================================
--- branches/dataflow/configure	(original)
+++ branches/dataflow/configure	Fri Sep 12 10:10:39 2008
@@ -20219,7 +20219,7 @@


  if test "x$want_boost" = "xyes"; then
-	boost_lib_version_req=1.20.0
+	boost_lib_version_req=1.34.0
  	boost_lib_version_req_shorten=`expr  
$boost_lib_version_req : '\([0-9]*\.[0-9]*\)'`
  	boost_lib_version_req_major=`expr $boost_lib_version_req : '\([0-9]*\)'`
  	boost_lib_version_req_minor=`expr  
$boost_lib_version_req : '[0-9]*\.\([0-9]*\)'`

Modified: branches/dataflow/configure.ac
==============================================================================
--- branches/dataflow/configure.ac	(original)
+++ branches/dataflow/configure.ac	Fri Sep 12 10:10:39 2008
@@ -43,7 +43,7 @@
  AC_PATH_PROG([valgrind], [valgrind])
  AC_PATH_PROG([dot], [dot])
  AC_PATH_PROG([graphviz_gc], [gc])
-AX_BOOST_BASE()
+AX_BOOST_BASE([1.34.0])

  AC_ARG_WITH([maketea],
     AS_HELP_STRING([--with-maketea], [path to maketea (if installed)]),

Modified: branches/dataflow/libphc/support_routines.c
==============================================================================
--- branches/dataflow/libphc/support_routines.c	(original)
+++ branches/dataflow/libphc/support_routines.c	Fri Sep 12 10:10:39 2008
@@ -691,22 +691,20 @@
  {
    if (Z_TYPE_P (*p_var) == IS_STRING)
      {
-		 if (Z_STRLEN_PP (p_var) > 0)
-		 {
-			 php_error_docref (NULL TSRMLS_CC, E_ERROR,
-					 "[] operator not supported for strings");
-		 }
-		 else
-		 {
-			 zval_ptr_dtor (p_var);
-			 ALLOC_INIT_ZVAL (*p_var);
-			 array_init (*p_var);
-		 }
-	 }
-
-  // TODO looking at the interpreter source, it looks like this might only  
be
-  // the case for false?
-  if (Z_TYPE_P (*p_var) == IS_BOOL)
+      if (Z_STRLEN_PP (p_var) > 0)
+	{
+	  php_error_docref (NULL TSRMLS_CC, E_ERROR,
+			    "[] operator not supported for strings");
+	}
+      else
+	{
+	  zval_ptr_dtor (p_var);
+	  ALLOC_INIT_ZVAL (*p_var);
+	  array_init (*p_var);
+	}
+    }
+
+  if (Z_TYPE_P (*p_var) == IS_BOOL && Z_BVAL_PP (p_var))
      {
        php_error_docref (NULL TSRMLS_CC, E_WARNING,
  			"Cannot use a scalar value as an array");
@@ -769,80 +767,6 @@
    return arg;
  }

-static zval **
-fetch_array_arg_by_ref (zval ** p_var, zval * ind, int *is_arg_new  
TSRMLS_DC)
-{
-  // if its not an array, make it an array
-  assert (Z_TYPE_PP (p_var) != IS_STRING);	// TODO unimplemented
-  HashTable *ht = extract_ht (p_var TSRMLS_CC);
-
-  // find the var
-  // TODO this is the model for wht is to come. We need to add to the
-  // symbol table (similar to get_st_entry) and pass that. We need to
-  // do this in quite a lot of places apart from this, but we need a
-  // more efficient implementation here first.
-  zval **p_arg = get_ht_entry (p_var, ind TSRMLS_CC);
-
-  // We are passing by reference.
-  sep_copy_on_write_ex (p_arg);
-
-  // We don't need to restore ->is_ref afterwards,
-  // because the called function will reduce the
-  // refcount of arg on return, and will reset is_ref to
-  // 0 when refcount drops to 1.  If the refcount does
-  // not drop to 1 when the function returns, but we did
-  // set is_ref to 1 here, that means that is_ref must
-  // already have been 1 to start with (since if it had
-  // not, that means that the variable would have been
-  // in a copy-on-write set, and would have been
-  // separated above).
-  (*p_arg)->is_ref = 1;
-
-  return p_arg;
-}
-
-/* Dont pass-by-ref */
-static zval *
-fetch_array_arg (zval * var, zval * ind, int *is_arg_new TSRMLS_DC)
-{
-  if (var == EG (uninitialized_zval_ptr))
-    return EG (uninitialized_zval_ptr);
-
-  if (Z_TYPE_P (var) != IS_ARRAY)
-    {
-      if (Z_TYPE_P (var) == IS_STRING)
-	{
-	  *is_arg_new = 1;
-	  return read_string_index (var, ind TSRMLS_CC);
-	}
-      return EG (uninitialized_zval_ptr);
-    }
-
-  // if its not an array, make it an array
-  HashTable *ht = Z_ARRVAL_P (var);
-
-  // find the var
-  zval **p_arg;
-  if (ht_find (ht, ind, &p_arg) != SUCCESS)
-    return EG (uninitialized_zval_ptr);
-
-  zval *arg = *p_arg;
-  if (arg->is_ref)
-    {
-      // We dont separate since we don't own one of ARG's references.
-      zvp_clone (&arg, is_arg_new);
-
-      // It seems we get incorrect refcounts without this.
-      // TODO This decreases the refcount to zero, which seems wrong,
-      // but gives the right answer. We should look at how zend does
-      // this.
-
-      arg->refcount--;
-    }
-
-  return arg;
-}
-
  static void
  cast_var (zval ** p_zvp, int type)
  {
@@ -965,4 +889,22 @@
    assert (EG (uninitialized_zval).value.lval == 0);
    assert (EG (uninitialized_zval).type == IS_NULL);
    assert (EG (uninitialized_zval).is_ref == 0);
+}
+
+static void
+initialize_function_call (zend_fcall_info* fci, zend_fcall_info_cache*  
fcic, char* function_name, char* filename, int line_number TSRMLS_DC)
+{
+  if (!fcic->initialized)	// check for missing function
+    {
+      zval fn;
+      INIT_PZVAL (&fn);
+      ZVAL_STRING (&fn, function_name, 0);
+      int result = zend_fcall_info_init (&fn, fci, fcic TSRMLS_CC);
+      if (result != SUCCESS)
+	{
+	  phc_setup_error (1, filename, line_number, NULL TSRMLS_CC);
+	  php_error_docref (NULL TSRMLS_CC, E_ERROR,
+			    "Call to undefined function %s()", function_name);
+	}
+    }
  }

Modified: branches/dataflow/src/codegen/Generate_C.cpp
==============================================================================
--- branches/dataflow/src/codegen/Generate_C.cpp	(original)
+++ branches/dataflow/src/codegen/Generate_C.cpp	Fri Sep 12 10:10:39 2008
@@ -17,6 +17,7 @@

  // TODO Variable_variables cannot be used to access superglobals. See  
warning
  // in http://php.net/manual/en/language.variables.superglobals.php
+// TODO: that is not true - add a test case.

  // TODO:
  //		magic methods are:
@@ -729,6 +730,7 @@

  	void generate_code(Generate_C* gen)
  	{
+		// TODO we done always need the sym-table entry.
  		code
  		<<	get_st_entry (LOCAL, "p_lhs", lhs->value)
  		;
@@ -770,6 +772,21 @@
  	return ss.str();
  }

+/* $x[$i] = $y; (1)
+ *		or
+ * $x[$i] =& $y; (2)
+ *
+ * Semantics:
+ *	(1) If $x[$i] is a reference, copy the value of $y into the zval at  
$x[$i].
+ *	       If $y doesn't exist, we can copy from uninitialized_zval.
+ *	    If $x[$i] is not a reference, overwrite the HT entry with $y,  
removing the old entry.
+ *	       If $y doesn't exist, put in uninitialized_zval.
+ *			 If $x[$i] doesnt exist, put uninitiliazed_val in, then replace it
+ *			 with $y (saved a second hashing operation).
+ *
+ *	(2) Remove the current HT entry, replacing it with a reference to $y.
+ *	    If $y doesnt exist, initialize it. If $x[$i] doesn't exist, it  
doesnt matter.
+ */
  class Pattern_assign_array : public Pattern
  {
  public:
@@ -801,31 +818,20 @@
  	Wildcard<VARIABLE_NAME>* rhs;
  };

-string push_rhs (bool is_ref, VARIABLE_NAME* rhs)
-{
-	stringstream ss;
-	if (!is_ref)
-	{
-		ss
-		<< declare ("p_rhs")
-
-		<< read_var (LOCAL, "p_rhs", rhs)
-
-		<< "if (*p_lhs != *p_rhs)\n"
-		<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
-
-		<< cleanup ("p_rhs");
-	}
-	else
-	{
-		ss
-		<< get_st_entry (LOCAL, "p_rhs", rhs)
-		<< "copy_into_ref (p_lhs, p_rhs);\n"
-		;
-	}
-	return ss.str();
-}
-
+/*
+ * $x[] = $y; (1)
+ *		or
+ * $x[] =& $y; (2)
+ *
+ * Semantics:
+ * (1) Copy $y in to $x (even if $y is a reference, we copy)
+ * (2) Place a reference to $y into $x.
+ * In both cases $x may not be initialized, or may not be an array.
+ * If $x is uninitiliazed, it becomes an array, and the value is pushed.
+ * If $x is false, or "" (but not 0), it is initialized (no warning).
+ * If $x is a different scalar, a warning is printed, but that $x is not  
initialized (nothing pushed).
+ * If $x is a string (but not ""), a fatal error is thrown.
+ */
  class Pattern_push_array : public Pattern
  {
  public:
@@ -852,9 +858,30 @@
  	
  		// TODO this can return NULL if there is an error.
  		<<	"if (p_lhs != NULL)\n"
-		<<	"{\n"
-		<<		push_rhs (agn->is_ref, rhs->value)
-		<<	"}\n"
+		<<	"{\n";
+
+		if (!agn->is_ref)
+		{
+			code
+			<< declare ("p_rhs")
+
+			<< read_var (LOCAL, "p_rhs", rhs->value)
+
+			<< "if (*p_lhs != *p_rhs)\n"
+			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
+
+			<< cleanup ("p_rhs");
+		}
+		else
+		{
+			// TODO this is wrong
+			code	
+			<< get_st_entry (LOCAL, "p_rhs", rhs->value)
+			<< "copy_into_ref (p_lhs, p_rhs);\n"
+			;
+		}
+
+		code << "}\n"
  		;
  	}

@@ -865,6 +892,182 @@
  };

  /*
+ * $x = $y; (1)
+ *		or
+ *	$x =& $y; (2)
+ *
+ *	Semantics (same as $x[$i] = $y, except with sym-table insted of  
hash-table):
+ *	(1) If $x is a reference, copy the value of $y into the zval at $x.
+ *	       If $y doesn't exist, copy from uninitialized_zval.
+ *	    If $x is not a reference, overwrite the ST entry with $y, removing  
the old entry.
+ *	       If $y doesn't exist, put in uninitialized_zval.
+ *			 If $x doesnt exist, put uninitiliazed_val in, then replace it
+ *			 with $y (saved a second hashing operation).
+ *	(2) Remove the current ST entry, replacing it with a reference to $y.
+ *	    If $y doesnt exist, initialize it. If $x doesn't exist, it doesnt  
matter.
+ */
+class Pattern_assign_var_to_var : public Pattern_assign_var
+{
+public:
+	Expr* rhs_pattern()
+	{
+		rhs = new Wildcard<VARIABLE_NAME>;
+		return rhs;
+	}
+
+	void generate_rhs ()
+	{
+		// TODO combine with assign_var_var_to_var
+		// and assign_array_index_to_var
+		if (!agn->is_ref)
+		{
+			code
+			<< declare ("p_rhs")
+
+			<< read_var (LOCAL, "p_rhs", rhs->value)
+
+			<< "if (*p_lhs != *p_rhs)\n"
+			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
+
+			<< cleanup ("p_rhs");
+		}
+		else
+		{
+			code
+			<< get_st_entry (LOCAL, "p_rhs", rhs->value)
+			<< "copy_into_ref (p_lhs, p_rhs);\n"
+			;
+		}
+	}
+
+protected:
+	Wildcard<VARIABLE_NAME>* rhs;
+};
+
+/* $x = $$y;
+ *		or
+ *	$x =& $$y;
+ *
+ * Semantics:
+ *		The same as $x = $z; except $z is named at run-time by $y.
+ *		Additionally, there is a conversion to strings needed:
+ *			TODO
+ */
+class Pattern_assign_var_var_to_var  : public Pattern_assign_var
+{
+public:
+	Expr* rhs_pattern()
+	{
+		rhs = new Wildcard<Variable_variable>;
+		return rhs;
+	}
+
+	void generate_rhs ()
+	{
+		if (!agn->is_ref)
+		{
+			code
+			<< declare ("p_rhs")
+
+			<< read_var_var (LOCAL, "p_rhs", rhs->value)
+
+			<< "if (*p_lhs != *p_rhs)\n"
+			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
+
+			<< cleanup ("p_rhs")
+			;
+		}
+		else
+		{
+			code
+			<< index_lhs (LOCAL, "p_rhs", rhs->value)
+			<< "copy_into_ref (p_lhs, p_rhs);\n"
+			;
+		}
+	}
+
+protected:
+	Wildcard<Variable_variable>* rhs;
+};
+
+
+class Pattern_assign_array_index_to_var : public Pattern_assign_var
+{
+public:
+	Expr* rhs_pattern()
+	{
+		rhs = new Wildcard<Array_access>;
+		return rhs;
+	}
+
+	void generate_rhs ()
+	{
+		if (!agn->is_ref)
+		{
+			code
+			<< declare ("p_rhs")
+
+			<< read_array_index (LOCAL, "p_rhs", rhs->value)
+			
+			<< "if (*p_lhs != *p_rhs)\n"
+			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
+
+			<< cleanup ("p_rhs");
+		}
+		else
+		{
+			code
+			<< get_array_entry (LOCAL, "p_rhs", rhs->value->variable_name,  
rhs->value->index)
+			<< "copy_into_ref (p_lhs, p_rhs);\n"
+			;
+		}
+	}
+
+protected:
+	Wildcard<Array_access>* rhs;
+};
+
+
+class Pattern_cast : public Pattern_assign_var_to_var
+{
+// Casts without a lhs have a LHS added, hence this is an assign_var, not a
+// eval_expr_or_assign_var.
+public:
+	Expr* rhs_pattern()
+	{
+		rhs = new Wildcard<VARIABLE_NAME>;
+		cast = new Wildcard<CAST>;
+		return new Cast (cast, rhs);
+	}
+
+	void generate_rhs ()
+	{
+		assert (agn->is_ref == false);
+		assert (lhs);
+		Pattern_assign_var_to_var::generate_rhs ();
+
+		if (*cast->value->value == "string")
+			code << "cast_var (p_lhs, IS_STRING);\n";
+		else if (*cast->value->value == "int")
+			code << "cast_var (p_lhs, IS_LONG);\n";
+		else if (*cast->value->value == "array")
+			code << "cast_var (p_lhs, IS_ARRAY);\n";
+		else if (*cast->value->value == "null")
+			code << "cast_var (p_lhs, IS_NULL);\n";
+		else if (*cast->value->value == "bool" || *cast->value->value  
== "boolean")
+			code << "cast_var (p_lhs, IS_BOOL);\n";
+		else if (*cast->value->value == "real")
+			code << "cast_var (p_lhs, IS_DOUBLE);\n";
+		else
+			assert (0 && "unimplemented"); // TODO: unimplemented
+	}
+
+public:
+	Wildcard<CAST>* cast;
+};
+
+
+/*
   * Assign_zval is a specialization of Assignment for assignments to a  
simple
   * zval which takes care of creating a new zval for the LHS if necessary.
   *
@@ -921,6 +1124,7 @@
  	// record if we've seen this variable before
  	void generate_rhs ()
  	{
+		assert (!agn->is_ref);
  		// TODO If this isnt static, there is a new hash each time,
  		// because there is a new object each time it is called. Why is
  		// there a new object each time?
@@ -951,17 +1155,8 @@
  			}
  			code
  			<< "if (" << var << " != *p_lhs)\n"
-			<< "{\n"
-			<<		"assert (!" << var << "->is_ref);\n"
-			<<		"if ((*p_lhs)->is_ref)\n"
-			<<			"overwrite_lhs (*p_lhs, " << var << ");\n"
-			<<		"else\n"
-			<<		"{\n"
-			<<			var << "->refcount++;\n"
-			<<			"zval_ptr_dtor (p_lhs);\n"
-			<<			"*p_lhs = " << var << ";\n"
-			<<		"}\n"
-			<<	"}\n";
+			<<		"write_var (p_lhs, &" << var << ", NULL);\n"
+			;
  		}
  		else
  		{
@@ -1064,157 +1259,6 @@
  };


-class Pattern_assign_var_to_var : public Pattern_assign_var
-{
-public:
-	Expr* rhs_pattern()
-	{
-		rhs = new Wildcard<VARIABLE_NAME>;
-		return rhs;
-	}
-
-	void generate_rhs ()
-	{
-		// TODO combine with assign_var_var_to_var
-		// and assign_array_index_to_var
-		if (!agn->is_ref)
-		{
-			code
-			<< declare ("p_rhs")
-
-			<< read_var (LOCAL, "p_rhs", rhs->value)
-
-			<< "if (*p_lhs != *p_rhs)\n"
-			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
-
-			<< cleanup ("p_rhs");
-		}
-		else
-		{
-			code
-			<< get_st_entry (LOCAL, "p_rhs", rhs->value)
-			<< "copy_into_ref (p_lhs, p_rhs);\n"
-			;
-		}
-	}
-
-protected:
-	Wildcard<VARIABLE_NAME>* rhs;
-};
-
-class Pattern_assign_var_var_to_var  : public Pattern_assign_var
-{
-public:
-	Expr* rhs_pattern()
-	{
-		rhs = new Wildcard<Variable_variable>;
-		return rhs;
-	}
-
-	void generate_rhs ()
-	{
-		if (!agn->is_ref)
-		{
-			code
-			<< declare ("p_rhs")
-
-			<< read_var_var (LOCAL, "p_rhs", rhs->value)
-
-			<< "if (*p_lhs != *p_rhs)\n"
-			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
-
-			<< cleanup ("p_rhs")
-			;
-		}
-		else
-		{
-			code
-			<< index_lhs (LOCAL, "p_rhs", rhs->value)
-			<< "copy_into_ref (p_lhs, p_rhs);\n"
-			;
-		}
-	}
-
-protected:
-	Wildcard<Variable_variable>* rhs;
-};
-
-
-class Pattern_assign_array_index_to_var : public Pattern_assign_var
-{
-public:
-	Expr* rhs_pattern()
-	{
-		rhs = new Wildcard<Array_access>;
-		return rhs;
-	}
-
-	void generate_rhs ()
-	{
-		if (!agn->is_ref)
-		{
-			code
-			<< declare ("p_rhs")
-
-			<< read_array_index (LOCAL, "p_rhs", rhs->value)
-			
-			<< "if (*p_lhs != *p_rhs)\n"
-			<<		"write_var (p_lhs, p_rhs, &is_p_rhs_new TSRMLS_CC);\n"
-
-			<< cleanup ("p_rhs");
-		}
-		else
-		{
-			code
-			<< get_array_entry (LOCAL, "p_rhs", rhs->value->variable_name,  
rhs->value->index)
-			<< "copy_into_ref (p_lhs, p_rhs);\n"
-			;
-		}
-	}
-
-protected:
-	Wildcard<Array_access>* rhs;
-};
-
-
-class Pattern_cast : public Pattern_assign_var_to_var
-{
-// Casts without a lhs have a LHS added, hence this is an assign_var, not a
-// eval_expr_or_assign_var.
-public:
-	Expr* rhs_pattern()
-	{
-		rhs = new Wildcard<VARIABLE_NAME>;
-		cast = new Wildcard<CAST>;
-		return new Cast (cast, rhs);
-	}
-
-	void generate_rhs ()
-	{
-		assert (agn->is_ref == false);
-		assert (lhs);
-		Pattern_assign_var_to_var::generate_rhs ();
-
-		if (*cast->value->value == "string")
-			code << "cast_var (p_lhs, IS_STRING);\n";
-		else if (*cast->value->value == "int")
-			code << "cast_var (p_lhs, IS_LONG);\n";
-		else if (*cast->value->value == "array")
-			code << "cast_var (p_lhs, IS_ARRAY);\n";
-		else if (*cast->value->value == "null")
-			code << "cast_var (p_lhs, IS_NULL);\n";
-		else if (*cast->value->value == "bool" || *cast->value->value  
== "boolean")
-			code << "cast_var (p_lhs, IS_BOOL);\n";
-		else if (*cast->value->value == "real")
-			code << "cast_var (p_lhs, IS_DOUBLE);\n";
-		else
-			assert (0 && "unimplemented"); // TODO: unimplemented
-	}
-
-public:
-	Wildcard<CAST>* cast;
-};
-
  class Pattern_global : public Pattern
  {
  public:
@@ -1388,6 +1432,39 @@
  	Wildcard<Actual_parameter>* arg;
  };

+void
+init_function_record (string name, Node* node)
+{
+	static set<string> record;
+
+	string fci_name = suffix (name, "fci");
+	string fcic_name = suffix (name, "fcic");
+
+	// initialize and declare the first time only
+	if (record.find (name) == record.end ())
+	{
+		record.insert (name);
+
+		prologue
+		<< "static zend_fcall_info " << fci_name << ";\n"
+		<< "static zend_fcall_info_cache " << fcic_name << " =  
{0,NULL,NULL,NULL};\n"
+		;
+	}
+
+	// Its not necessarily a good idea to initialize at the start, since we
+	// still have to check if its initialized at call-time (it may have been
+	// created in the meantime.
+	code
+	<< "initialize_function_call ("
+	<<			"&" << fci_name << ", "
+	<<			"&" << fcic_name << ", "
+	<<			"\"" << name << "\", "
+	<<			"\"" << *node->get_filename () << "\", "
+	<<			node->get_line_number ()
+	<<			" TSRMLS_CC);\n"
+	;
+}
+
  class Pattern_assign_param_is_ref : public Pattern_assign_var
  {
  public:
@@ -1400,39 +1477,17 @@
  	void generate_rhs ()
  	{
  		assert (!agn->is_ref);
-		String* name = dyc<METHOD_NAME> (rhs->value->method_name)->value;
-		int index = rhs->value->param_index->value;

-		// TODO only do this once per function
+		string name = *dyc<METHOD_NAME> (rhs->value->method_name)->value;
+		int index = rhs->value->param_index->value;

-		code
-		// lookup the function and cache it for next time
-		<< "// Call the function\n"
-		<< "static zend_fcall_info fci;\n"
-		<< "static zend_fcall_info_cache fcic = {0,NULL,NULL,NULL};\n"
-		<< "if (!fcic.initialized)\n"
-		<< "{\n"
-		<<		"zval function_name;\n"
-		<<		"INIT_PZVAL(&function_name);\n"
-		<<		"ZVAL_STRING(&function_name, "
-		<<			"\"" << *name << "\", "
-		<<			"0);\n"
+		init_function_record (name, rhs->value);

-		<<		"int result = zend_fcall_info_init (&function_name, &fci, &fcic  
TSRMLS_CC);\n"
-		<< 	"if (result == FAILURE) // check for missing function\n"
-		<< 	"{\n"
-		<<			"phc_setup_error (1, \""
-		<< 			*rhs->get_filename () << "\", "
-		<< 			rhs->get_line_number () << ", "
-		<<				"NULL TSRMLS_CC);\n"
-					// die
-		<<			"php_error_docref (NULL TSRMLS_CC, E_ERROR, "
-		<<				"\"Call to undefined function %s()\", \""
-		<< 			*name << "\");\n"
-		<< 	"}\n"
-		<< "}\n"
+		string fci_name = suffix (name, "fci");
+		string fcic_name = suffix (name, "fcic");

-		<< "zend_function* signature = fcic.function_handler;\n"
+		code
+		<< "zend_function* signature = " << fcic_name << ".function_handler;\n"
  		<< "zend_arg_info* arg_info = signature->common.arg_info;\n"
  		<< "int count = 0;\n"
  		<< "while (arg_info && count < " << index << ")\n"
@@ -1484,47 +1539,19 @@
  		// code << "debug_hash(EG(active_symbol_table));\n";

  		// Variable function or ordinary function?
-		METHOD_NAME* name;
-		name = dynamic_cast<METHOD_NAME*>(rhs->value->method_name);
-
+		METHOD_NAME* name = dynamic_cast<METHOD_NAME*>(rhs->value->method_name);
  		if (name == NULL) phc_unsupported (rhs->value);

-		code
-		<< declare ("p_rhs")
-		;
+		string fci_name = suffix (*name->value, "fci");
+		string fcic_name = suffix (*name->value, "fcic");
+		init_function_record (*name->value, rhs->value);

-		int num_args = rhs->value->actual_parameters->size();
  		code
-		// lookup the function and cache it for next time
-		<< "// Call the function\n"
-		<< "static zend_fcall_info fci;\n"
-		<< "static zend_fcall_info_cache fcic = {0,NULL,NULL,NULL};\n"
-		<< "if (!fcic.initialized)\n"
-		<< "{\n"
-		<<		"zval function_name;\n"
-		<<		"INIT_PZVAL(&function_name);\n"
-		<<		"ZVAL_STRING(&function_name, "
-		<<			"\"" << *name->value << "\", "
-		<<			"0);\n"
-
-		<<		"int result = zend_fcall_info_init (&function_name, &fci, &fcic  
TSRMLS_CC);\n"
-		<< 	"if (result == FAILURE) // check for missing function\n"
-		<< 	"{\n"
-		<<			"phc_setup_error (1, \""
-		<< 			*rhs->get_filename () << "\", "
-		<< 			rhs->get_line_number () << ", "
-		<<				"NULL TSRMLS_CC);\n"
-					// die
-		<<			"php_error_docref (NULL TSRMLS_CC, E_ERROR, "
-		<<				"\"Call to undefined function %s()\", \""
-		<< 			*name->value << "\");\n"
-		<< 	"}\n"
-		<< "}\n"
-		<< "zend_function* signature = fcic.function_handler;\n"
+		<< "zend_function* signature = " << fcic_name << ".function_handler;\n"
  		;

-
  		// Figure out which parameters need to be passed by reference
+		int num_args = rhs->value->actual_parameters->size();
  		if (num_args)
  		{
  			code
@@ -1608,23 +1635,25 @@
  		<< "			NULL TSRMLS_CC);\n"

  		// save existing paramters, in case of recursion
-		<< "int param_count_save = fci.param_count;\n"
-		<< "zval*** params_save = fci.params;\n"
-		<< "zval** retval_save = fci.retval_ptr_ptr;\n"
+		<< "int param_count_save = " << fci_name << ".param_count;\n"
+		<< "zval*** params_save = " << fci_name << ".params;\n"
+		<< "zval** retval_save = " << fci_name << ".retval_ptr_ptr;\n"
+
+		<< declare ("p_rhs")

  		// set up params
-		<< "fci.params = args_ind;\n"
-		<< "fci.param_count = " << num_args << ";\n"
-		<< "fci.retval_ptr_ptr = p_rhs;\n"
+		<< fci_name << ".params = args_ind;\n"
+		<< fci_name << ".param_count = " << num_args << ";\n"
+		<< fci_name << ".retval_ptr_ptr = p_rhs;\n"

  		// call the function
-		<< "int success = zend_call_function (&fci, &fcic TSRMLS_CC);\n"
+		<< "int success = zend_call_function (&" << fci_name << ", &" <<  
fcic_name << " TSRMLS_CC);\n"
  		<< "assert(success == SUCCESS);\n"

  		// restore params
-		<< "fci.params = params_save;\n"
-		<< "fci.param_count = param_count_save;\n"
-		<< "fci.retval_ptr_ptr = retval_save;\n"
+		<< fci_name << ".params = params_save;\n"
+		<< fci_name << ".param_count = param_count_save;\n"
+		<< fci_name << ".retval_ptr_ptr = retval_save;\n"

  		// unset the errors
  		<< "phc_setup_error (0, NULL, 0, NULL TSRMLS_CC);\n"
@@ -2065,6 +2094,8 @@
  			aliased_name = class_alias->value->class_name->value;
  			alias_name = class_alias->value->alias->value;
  		}
+		else
+			assert (0);

  		alias_name = alias_name->clone ();
  		alias_name->toLower();
@@ -2508,9 +2539,6 @@
  		"   php_embed_init (argc, argv PTSRMLS_CC);\n"
  		"   zend_first_try\n"
  		"   {\n"
-		"      // initialize all the constants\n"
-		<< initializations.str () <<
-		"\n"
  		"      // load the compiled extension\n"
  		"      zend_startup_module (&" << *extension_name << "_module_entry);\n"
  		"\n"
@@ -2522,6 +2550,9 @@
  		"      // Use standard errors, on stdout\n"
  		"      zend_alter_ini_entry (\"report_zend_debug\",  
sizeof(\"report_zend_debug\"), \"0\", sizeof(\"0\") - 1, PHP_INI_ALL,  
PHP_INI_STAGE_RUNTIME);\n"
  		"      zend_alter_ini_entry (\"display_startup_errors\",  
sizeof(\"display_startup_errors\"), \"1\", sizeof(\"1\") - 1, PHP_INI_ALL,  
PHP_INI_STAGE_RUNTIME);\n"
+		"\n"
+		"      // initialize all the constants\n"
+		<< initializations.str () << // TODO put this in __MAIN__, or else  
extensions cant use it.
  		"\n"
  		"      // call __MAIN__\n"
  		"      int success = call_user_function( \n"

Modified: branches/dataflow/src/optimize/Prune_symbol_table.cpp
==============================================================================
--- branches/dataflow/src/optimize/Prune_symbol_table.cpp	(original)
+++ branches/dataflow/src/optimize/Prune_symbol_table.cpp	Fri Sep 12  
10:10:39 2008
@@ -42,11 +42,6 @@
  	vars = new map<string, bool>;
  }

-// TODO we cant compile nested functions anyway, but this needs to be
-// updated when we do.
-
-
-
  class Analysis : public Visitor
  {
  public:
@@ -61,7 +56,8 @@
  	bool record_globals;

  	Analysis (map<string, bool>* vars)
-	: prune (false)
+	: prune (true)
+	, var_reflection_present (false)
  	, vars(vars)
  	{
  	}
@@ -89,6 +85,7 @@
  		{
  			// Since eval, include etc are builtin, and cant be called as
  			// variable variables, its actually safe to prune here.
+			// TODO not so sure
  		}
  	}


Modified: branches/dataflow/test/framework/annotated_test.php
==============================================================================
--- branches/dataflow/test/framework/annotated_test.php	(original)
+++ branches/dataflow/test/framework/annotated_test.php	Fri Sep 12 10:10:39  
2008
@@ -22,7 +22,7 @@

  	function add_value ($options, $value)
  	{
-		phc_assert (preg_match ("!{$this->value_regex}!", $value), "Value  
($value )provided does not match regex ({$this->value_regex})");
+		phc_assert (preg_match ("~{$this->value_regex}~", $value), "Value  
($value )provided does not match regex ({$this->value_regex})");
  		$this->options[] = array_merge ($this->get_default_options(), $options);
  		$this->values[] = $value;
  	}
@@ -103,7 +103,8 @@
  	{
  		parent::__construct ();
  		$this->name = "phc-stdout";
-		$this->value_regex = ".+";
+		// either
+		$this->value_regex = "(!?/.*/)|([^/])|([^/].*[^/])";
  	}

  	function get_default_options ()
@@ -122,9 +123,24 @@
  		{
  			$options = array_shift ($this->options);

+			$negate = false;
  			// Process the options
  			if (!$options["regex"])
  				$value = preg_quote ($value);
+			else
+			{
+				if ($value[0] == "!")
+				{
+					$negate = true;
+					$value = substr ($value, 1); // remove !
+				}
+
+				phc_assert ($value[0] == "/", "regexes must start with \"/\" or  
\"!/\"");
+				phc_assert ($value[strlen($value)-1] == "/", "regexes must end with  
\"/\"");
+
+				// remove '/' at front and back (back first, front changes the indices)
+				$value = substr ($value, 1, strlen ($value) - 2);
+			}

  			if ($options["stderr"])
  			{
@@ -146,20 +162,30 @@
  					."in a later release\n!ms";
  			}
  			else
-				$pattern = "!$value!ms";
+				$pattern = "/$value/ms";
+
+			$my_pattern = "/hir\s+\(disabled/ms";

  			$result = preg_match ($pattern, $out);

  			// Potential errors
  			$suffix = "\"$value\" using pattern \"$pattern\"";
-			if ($result === 0)
-				return "{$options['prefix']} not found, expected: $suffix";
+			if ($negate)
+			{
+				if ($negate && $result === 1)
+					return "{$options['prefix']} found, not expected: $suffix";
+			}
+			else
+			{
+				if ($result === 0)
+					return "{$options['prefix']} not found, expected: $suffix";

-			if ($result === FALSE)
-				return "Test annotation error with: $suffix";
+				if ($result === FALSE)
+					return "Test annotation error with: $suffix";

-			if ($result !== 1)
-				return "Unexpected error with: $suffix";
+				if ($result !== 1)
+					return "Unexpected error with: $suffix";
+			}
  		}
  	}
  }

Modified: branches/dataflow/test/subjects/phc/disable.php
==============================================================================
--- branches/dataflow/test/subjects/phc/disable.php	(original)
+++ branches/dataflow/test/subjects/phc/disable.php	Fri Sep 12 10:10:39 2008
@@ -2,6 +2,6 @@

  	// check that disabling passes works
  	// { phc-option: --disable=hir --list-passes }
-	// { phc-regex-output: hir\s+\(disabled }
+	// { phc-regex-output: /hir\s+\(disabled/ }

  ?>

Modified: branches/dataflow/test/subjects/phc/dump_tokens.php
==============================================================================
--- branches/dataflow/test/subjects/phc/dump_tokens.php	(original)
+++ branches/dataflow/test/subjects/phc/dump_tokens.php	Fri Sep 12 10:10:39  
2008
@@ -2,5 +2,5 @@

  	// Check --dump=tokens has some output
  	// { phc-option: --dump=tokens }
-	// { phc-regex-output: .+ }
+	// { phc-regex-output: /.+/ }
  ?>

Modified: branches/dataflow/test/subjects/phc/foreach_dump.php
==============================================================================
--- branches/dataflow/test/subjects/phc/foreach_dump.php	(original)
+++ branches/dataflow/test/subjects/phc/foreach_dump.php	Fri Sep 12  
10:10:39 2008
@@ -3,8 +3,8 @@
  	// Check foreach loop are unparsed in the MIR

  	// { phc-option: --dump=mir }
-	// { phc-regex-output: foreach_reset\(\$\w+, ht_iterator\d+\); }
-	// { phc-regex-output: \$THK10 = foreach_has_key\(\$\w+, ht_iterator\d+\)  
}
+	// { phc-regex-output: /foreach_reset\(\$\w+, ht_iterator\d+\);/ }
+	// { phc-regex-output: /\$THK10 = foreach_has_key\(\$\w+,  
ht_iterator\d+\)/ }

  	foreach ($x as $y)
  	{

Modified: branches/dataflow/test/subjects/phc/list_passes.php
==============================================================================
--- branches/dataflow/test/subjects/phc/list_passes.php	(original)
+++ branches/dataflow/test/subjects/phc/list_passes.php	Fri Sep 12 10:10:39  
2008
@@ -3,5 +3,5 @@
  	// Check --list-passes is in the correct format

  	// { phc-option: --list-passes }
-	// { phc-regex-output: Passes:\n([a-zA-Z-_0-9]+\s+\((enabled| 
disabled)\s+- (AST|HIR|MIR|LIR)\)\s+.+?)+ }
+	// { phc-regex-output: /Passes:\n([a-zA-Z-_0-9]+\s+\((enabled| 
disabled)\s+- (AST|HIR|MIR|LIR)\)\s+.+?)+/ }
  ?>

Modified: branches/dataflow/test/subjects/phc/param_is_ref.php
==============================================================================
--- branches/dataflow/test/subjects/phc/param_is_ref.php	(original)
+++ branches/dataflow/test/subjects/phc/param_is_ref.php	Fri Sep 12  
10:10:39 2008
@@ -3,7 +3,7 @@
  	// Test unparsing param_is_ref

  	// { phc-option: --dump=mir }
-	// { phc-regex-output:  param_is_ref \(NULL, "var_dump", 0\) }
+	// { phc-regex-output:  /param_is_ref \(NULL, "var_dump", 0\)/ }

  	var_dump ($t->$$x[$i][$j]);



More information about the phc-internals mailing list