Skip to content
Browse files

Updated to the latest bits, fixed the cmake scripts so that hhvm comp…

…iles

Summary: Added plumbing to the cmake scripts to enable hhvm builds.
To build the VM, export USE_HHVM=1, and follow the wiki instructions
to do a clean build.
  • Loading branch information...
1 parent e20a731 commit dcd7a28fd42bcc3762bcde7be070242de73cbf65 @joelpob joelpob committed with Blank Ubuntu 64 bit
Showing with 9,783 additions and 6,380 deletions.
  1. +23 −11 .gitignore
  2. +4 −0 CMakeLists.txt
  3. +33 −5 Makefile
  4. +25 −1 bin/CMakeLists.base.txt
  5. +8 −1 bin/run.mk
  6. +1,779 −1,222 doc/bytecode.specification
  7. +4 −8 doc/command.admin_server
  8. +3 −3 doc/debug.profile
  9. +2 −0 doc/extension.new_functions
  10. +24 −0 doc/extension.type_hints
  11. +60 −0 doc/extension.yield
  12. +9 −20 doc/ffi.c++
  13. +30 −15 doc/index.php
  14. +4 −8 doc/options.compiled
  15. +80 −0 doc/repo
  16. +3 −27 doc/runtime.memory_model
  17. +26 −41 doc/server.documents
  18. +3 −3 doc/server.rpc_server
  19. +12 −116 doc/threading
  20. +43 −1 src/CMakeLists.txt
  21. +1,981 −1,738 src/Makefile
  22. +310 −283 src/compiler/Makefile
  23. +102 −30 src/compiler/analysis/alias_manager.cpp
  24. +1 −0 src/compiler/analysis/alias_manager.h
  25. +270 −402 src/compiler/analysis/analysis_result.cpp
  26. +16 −16 src/compiler/analysis/analysis_result.h
  27. +0 −1 src/compiler/analysis/ast_walker.cpp
  28. +19 −16 src/compiler/analysis/block_scope.cpp
  29. +16 −2 src/compiler/analysis/block_scope.h
  30. +488 −189 src/compiler/analysis/class_scope.cpp
  31. +66 −23 src/compiler/analysis/class_scope.h
  32. +5 −4 src/compiler/analysis/code_error.cpp
  33. +2 −1 src/compiler/analysis/code_error.h
  34. +14 −4 src/compiler/analysis/constant_table.cpp
  35. +1 −0 src/compiler/analysis/constant_table.h
  36. +13 −14 src/compiler/analysis/control_flow.cpp
  37. +5 −1 src/compiler/analysis/core_code_error.inc
  38. +8 −9 src/compiler/analysis/data_flow.cpp
  39. +0 −1 src/compiler/analysis/dictionary.cpp
  40. +2,460 −1,271 src/compiler/analysis/emitter.cpp
  41. +223 −132 src/compiler/analysis/emitter.h
  42. +0 −1 src/compiler/analysis/expr_dict.cpp
  43. +225 −30 src/compiler/analysis/file_scope.cpp
  44. +36 −13 src/compiler/analysis/file_scope.h
  45. +9 −43 src/compiler/analysis/function_container.cpp
  46. +1 −1 src/compiler/analysis/function_container.h
  47. +145 −64 src/compiler/analysis/function_scope.cpp
  48. +17 −1 src/compiler/analysis/function_scope.h
  49. +0 −1 src/compiler/analysis/live_dict.cpp
  50. +0 −1 src/compiler/analysis/ref_dict.cpp
  51. +13 −3 src/compiler/analysis/symbol_table.cpp
  52. +2 −0 src/compiler/analysis/symbol_table.h
  53. +50 −30 src/compiler/analysis/type.cpp
  54. +13 −2 src/compiler/analysis/type.h
  55. +61 −26 src/compiler/analysis/variable_table.cpp
  56. +5 −1 src/compiler/analysis/variable_table.h
  57. +0 −4 src/compiler/builtin_symbols.cpp
  58. +1 −1 src/compiler/builtin_symbols.h
  59. +9 −3 src/compiler/code_generator.cpp
  60. +26 −0 src/compiler/code_generator.h
  61. +18 −5 src/compiler/construct.cpp
  62. +1 −1 src/compiler/construct.h
  63. +0 −2 src/compiler/expression/array_element_expression.cpp
  64. +0 −22 src/compiler/expression/array_pair_expression.cpp
  65. +0 −2 src/compiler/expression/array_pair_expression.h
  66. +11 −5 src/compiler/expression/assignment_expression.cpp
  67. +17 −4 src/compiler/expression/binary_op_expression.cpp
  68. +6 −6 src/compiler/expression/class_constant_expression.cpp
  69. +34 −8 src/compiler/expression/closure_expression.cpp
  70. +3 −1 src/compiler/expression/closure_expression.h
  71. +0 −2 src/compiler/expression/constant_expression.cpp
  72. +55 −33 src/compiler/expression/dynamic_function_call.cpp
  73. +0 −2 src/compiler/expression/dynamic_variable.cpp
  74. +0 −2 src/compiler/expression/encaps_list_expression.cpp
  75. +33 −12 src/compiler/expression/expression.cpp
  76. +13 −7 src/compiler/expression/expression.h
  77. +6 −6 src/compiler/expression/expression_list.cpp
  78. +25 −7 src/compiler/expression/function_call.cpp
  79. +1 −1 src/compiler/expression/function_call.h
  80. +71 −71 src/compiler/expression/include_expression.cpp
  81. +19 −6 src/compiler/expression/include_expression.h
  82. +1 −2 src/compiler/expression/list_assignment.cpp
  83. +0 −2 src/compiler/expression/modifier_expression.cpp
  84. +17 −11 src/compiler/expression/new_object_expression.cpp
  85. +22 −20 src/compiler/expression/object_method_expression.cpp
  86. +131 −39 src/compiler/expression/object_property_expression.cpp
  87. +2 −0 src/compiler/expression/object_property_expression.h
  88. +84 −12 src/compiler/expression/parameter_expression.cpp
  89. +6 −1 src/compiler/expression/parameter_expression.h
  90. +0 −1 src/compiler/expression/qop_expression.cpp
  91. +3 −6 src/compiler/expression/scalar_expression.cpp
  92. +176 −124 src/compiler/expression/simple_function_call.cpp
  93. +10 −4 src/compiler/expression/simple_function_call.h
  94. +15 −7 src/compiler/expression/simple_variable.cpp
  95. +26 −29 src/compiler/expression/static_class_name.cpp
  96. +6 −2 src/compiler/expression/static_member_expression.cpp
  97. +48 −20 src/compiler/expression/unary_op_expression.cpp
  98. +4 −1 src/compiler/expression/unary_op_expression.h
  99. +73 −0 src/compiler/expression/user_attribute.cpp
  100. +21 −17 src/{runtime/base/memory/unsafe_pointer.cpp → compiler/expression/user_attribute.h}
  101. +0 −12 src/compiler/hook.mk
  102. +23 −5 src/compiler/option.cpp
  103. +7 −0 src/compiler/option.h
  104. +7 −16 src/compiler/package.cpp
Sorry, we could not display the entire diff because too many files (1,417) changed.
View
34 .gitignore
@@ -1,8 +1,9 @@
*.[oad]
+*.hhbc
/bin*-g
/bin*-O
/bin/*.so
-/bin/tainted_build
+/bin/hphp_options
/bin/systemlib.php
.mkdir
hphp.log
@@ -15,6 +16,7 @@ hphp.log
/src/test/test_fast.inc
/src/test/test_mysql_info.inc
/src/test/test_suite.inc
+/src/test/real_mysql_info.inc
/src/test/*.tmp
/src/test/vm/*.out
/src/test/vm/*.diff
@@ -23,9 +25,9 @@ hphp.log
/src/test/vm/perf/*.diff
/src/test/vm/perf/*.perf
/src/runtime/ext_hhvm/xconstants.php
-/src/runtime/ext_hhvm/ext_hhvm.cpp
+/src/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
/src/runtime/ext_hhvm/ext_noinline.cpp
-/src/runtime/ext_hhvm/ext_noinline.h
+*.ext_hhvm.cpp
/src/hphp/hphp
@@ -33,6 +35,7 @@ hphp.log
/src/runtime/tmp/run
/src/runtime/tmp/run.sh
/src/runtime/tmp/libtest.so
+/src/runtime/vm/repo_schema.h
/src/hphpi/gen
/src/hphpi/hphpi
@@ -45,6 +48,10 @@ hphp.log
/src/ffi/java/classes
/src/ffi/java/hphp_ffi_java.h
+# Ignore all makefiles generated for fbcode's third-party repo
+/bin/*.mk
+!/bin/run.mk
+
/facebook/autoload_files
/facebook/hotcold.hdf
/facebook/benchmark/shootout/output_bench
@@ -69,14 +76,6 @@ hphp.log
/facebook/extensions/gen
/facebook/extensions/hphpi
-/facebook/extensions/*/*.so
-/facebook/extensions/remake_ext_hhvm
-/facebook/extensions/string/test_string
-/facebook/extensions/photodna/test_photodna
-/facebook/extensions/utils/test_utils
-/facebook/extensions/fbobj/test_fbobj
-/facebook/extensions/fbobj_cache/test_fbobj_cache
-/facebook/extensions/fbobj/test_fbobj
/local/*.mk
CMakeFiles
@@ -84,3 +83,16 @@ CMakeCache.txt
cmake_install.cmake
/output_gd/
+
+/src/TAGS
+
+# arcanist working-copy settings
+.arc/
+
+# fbcode output directory
+/bin/_fbcode_bin/
+
+# eclipse files
+.project
+.cproject
+.settings
View
4 CMakeLists.txt
@@ -27,3 +27,7 @@ IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
message(STATUS "32-bit support is experimental, things may be broken")
message(STATUS "------------")
ENDIF()
+
+IF ("$ENV{USE_HHVM}" STREQUAL "1")
+ message("USE_HHVM is set")
+ENDIF()
View
38 Makefile
@@ -8,7 +8,7 @@ default_target: all
#=============================================================================
# Special targets provided by cmake.
-# Disable implicit rules so canoncical targets will work.
+# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
@@ -36,10 +36,10 @@ CMAKE_COMMAND = /usr/bin/cmake
RM = /usr/bin/cmake -E remove -f
# The top-level source directory on which CMake was run.
-CMAKE_SOURCE_DIR = /home/macvicar/dev/vm/hiphop-php
+CMAKE_SOURCE_DIR = /home/joelp/dev/hiphop-php
# The top-level build directory on which CMake was run.
-CMAKE_BINARY_DIR = /home/macvicar/dev/vm/hiphop-php
+CMAKE_BINARY_DIR = /home/joelp/dev/hiphop-php
#=============================================================================
# Targets provided globally by CMake.
@@ -107,9 +107,9 @@ rebuild_cache/fast: rebuild_cache
# The main all target
all: cmake_check_build_system
- $(CMAKE_COMMAND) -E cmake_progress_start /home/macvicar/dev/vm/hiphop-php/CMakeFiles /home/macvicar/dev/vm/hiphop-php/CMakeFiles/progress.marks
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/joelp/dev/hiphop-php/CMakeFiles /home/joelp/dev/hiphop-php/CMakeFiles/progress.marks
$(MAKE) -f CMakeFiles/Makefile2 all
- $(CMAKE_COMMAND) -E cmake_progress_start /home/macvicar/dev/vm/hiphop-php/CMakeFiles 0
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/joelp/dev/hiphop-php/CMakeFiles 0
.PHONY : all
# The main clean target
@@ -150,6 +150,19 @@ hphp_runtime_static/fast:
.PHONY : hphp_runtime_static/fast
#=============================================================================
+# Target rules for targets named xhp
+
+# Build rule for target.
+xhp: cmake_check_build_system
+ $(MAKE) -f CMakeFiles/Makefile2 xhp
+.PHONY : xhp
+
+# fast build rule for target.
+xhp/fast:
+ $(MAKE) -f src/third_party/xhp/xhp/CMakeFiles/xhp.dir/build.make src/third_party/xhp/xhp/CMakeFiles/xhp.dir/build
+.PHONY : xhp/fast
+
+#=============================================================================
# Target rules for targets named afdt
# Build rule for target.
@@ -215,6 +228,19 @@ hphp_analysis/fast:
.PHONY : hphp_analysis/fast
#=============================================================================
+# Target rules for targets named ext_hhvm_static
+
+# Build rule for target.
+ext_hhvm_static: cmake_check_build_system
+ $(MAKE) -f CMakeFiles/Makefile2 ext_hhvm_static
+.PHONY : ext_hhvm_static
+
+# fast build rule for target.
+ext_hhvm_static/fast:
+ $(MAKE) -f src/runtime/ext_hhvm/CMakeFiles/ext_hhvm_static.dir/build.make src/runtime/ext_hhvm/CMakeFiles/ext_hhvm_static.dir/build
+.PHONY : ext_hhvm_static/fast
+
+#=============================================================================
# Target rules for targets named hphp
# Build rule for target.
@@ -253,11 +279,13 @@ help:
@echo "... list_install_components"
@echo "... rebuild_cache"
@echo "... hphp_runtime_static"
+ @echo "... xhp"
@echo "... afdt"
@echo "... mbfl"
@echo "... sqlite3"
@echo "... timelib"
@echo "... hphp_analysis"
+ @echo "... ext_hhvm_static"
@echo "... hphp"
@echo "... test"
.PHONY : help
View
26 bin/CMakeLists.base.txt
@@ -22,6 +22,10 @@ IF("$ENV{HPHP_HOME}" STREQUAL "")
message(FATAL_ERROR "You should set the HPHP_HOME environmental")
ENDIF()
+IF("$ENV{USE_HHVM}" STREQUAL "1")
+ SET(USE_HHVM TRUE)
+ENDIF()
+
file(TO_CMAKE_PATH "$ENV{HPHP_HOME}" HPHP_HOME)
IF(NOT IS_DIRECTORY ${HPHP_HOME})
@@ -44,6 +48,10 @@ if ("${PROGRAM_NAME}" STREQUAL "")
set(PROGRAM_NAME program)
endif()
+if (USE_HHVM)
+ ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/src/hhvm\\\"")
+endif(USE_HHVM)
+
auto_sources(SOURCES "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}")
add_executable(${PROGRAM_NAME} ${SOURCES})
@@ -78,6 +86,22 @@ SET_PROPERTY(TARGET afdt PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libafdt.a"
add_library(mbfl STATIC IMPORTED)
SET_PROPERTY(TARGET mbfl PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libmbfl.a")
-target_link_libraries(${PROGRAM_NAME} libhphp_runtime)
+if (USE_HHVM)
+
+ add_library(libext_hhvm STATIC IMPORTED)
+SET_PROPERTY(TARGET libext_hhvm PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libext_hhvm.a")
+
+ add_library(libanalysis STATIC IMPORTED)
+SET_PROPERTY(TARGET libanalysis PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libhphp_analysis.a")
+
+ SET_TARGET_PROPERTIES(${PROGRAM_NAME} PROPERTIES LINK_FLAGS -Wl,-u,hphp_compiler_parse,-u,hphp_build_native_func_unit,-u,hphp_build_native_class_unit,${HPHP_HOME}/bin/libhphp_analysis.a)
+
+ target_link_libraries(${PROGRAM_NAME} libhphp_runtime libext_hhvm libanalysis)
+else()
+
+ target_link_libraries(${PROGRAM_NAME} libhphp_runtime)
+
+endif(USE_HHVM)
+
hphp_link(${PROGRAM_NAME})
View
9 bin/run.mk
@@ -24,11 +24,18 @@ endif
EXTRA_LIB :=
ifdef HPHP_EMITTER
-EXTRA_LIB := -Wl,-u,hphp_compiler_parse,$(HPHP_LIB)/libhphp_analysis.a
+EXTRA_LIB := -Wl,-u,hphp_compiler_parse,-u,hphp_build_native_func_unit,-u,hphp_build_native_class_unit,$(HPHP_LIB)/libhphp_analysis.a
+LIBS += $(HPHP_LIB)/libhphp_analysis.a
endif
ifdef HPHPI_THUNK
CPPFLAGS += -DTHUNK_FILENAME='"/.hphpi-thunk"'
endif
+ifdef HPHPI_BINARY
+CPPFLAGS += -DHPHPI_BINARY=1
+endif
+ifdef HHVM_BINARY
+CPPFLAGS += -DHHVM_BINARY=1
+endif
CPPFLAGS += -I. $(SEP_EXTENSION_INCLUDE_PATHS)
LIBS = $(EXTRA_LIB) $(SEP_EXTENSION_LIBS) $(HPHP_LIB)/libhphp_runtime.a $(ALL_LIBS) $(HHVM_EXT_LIB)
View
3,001 doc/bytecode.specification
1,779 additions, 1,222 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
12 doc/command.admin_server
@@ -75,12 +75,8 @@ If program was compiled with USE_JEMALLOC, these commands will become available,
/free-mem: ask jemalloc to release memory to system
/jemalloc-stats: get internal jemalloc stats
-/jemalloc-stats-print:
- get comprehensive jemalloc stats in human-readable form
-/jemalloc-prof-activate:
- activate heap profiling
-/jemalloc-prof-deactivate:
- deactivate heap profiling
-/jemalloc-prof-dump:
- dump heap profile
+/jemalloc-stats-print: get comprehensive jemalloc stats in human-readable form
+/jemalloc-prof-activate: activate heap profiling
+/jemalloc-prof-deactivate: deactivate heap profiling
+/jemalloc-prof-dump: dump heap profile
file optional, filesystem path
View
6 doc/debug.profile
@@ -11,7 +11,7 @@ There are two stages in profiling, collecting the profile and
processing it into a readable format. Collection is different on the
command line and server.
-<h3>Profiling from the command line</h3>
+= Profiling from the command line
For building stand alone programs you need to link with libprofiler and
libunwind:
@@ -29,7 +29,7 @@ times per second. The frequency can be changed: higher frequencies
will impact performance but lower frequencies will require a longer
run to collect a significant number of samples.
-<h3>Profiling from the server</h3>
+= Profiling from the server
Run
@@ -43,7 +43,7 @@ A file /hphp/pprof/[host]/hphp.prof should be created. The exact path is
configurable with the runtime option Debug.ProfilerOutputDir
(defaults to /tmp on production).
-<h3>Processing the profile</h3>
+= Processing the profile
Use the tool pprof to process the profile. For example:
View
2 doc/extension.new_functions
@@ -81,6 +81,8 @@ testing and some alternative PHP implementation.
- fb_get_code_coverage
- fb_utf8ize
- fb_const_fetch
+- fb_enable_code_coverage
+- fb_disable_code_coverage
- fb_get_taint
- fb_set_taint
View
24 doc/extension.type_hints
@@ -0,0 +1,24 @@
+
+<h2>Richer type hints</h2>
+
+This feature requires the [[index.php?file=options.compiler | compiler option]]
+EnableHipHopSyntax=true, or interpreter option Eval.EnableHipHopSyntax=true.
+
+HipHop extends the support of type hints to primitive types, like bool, int, and
+double. It also supports string for type hints.
+
+For example, the following code would only allow passing an integer to the
+function foo():
+
+ function foo(int $a) {
+ return $a + 1;
+ }
+
+The main purposes for type hinting are (1) more efficient execution, (2) more
+explicit contract for functions.
+
+As in vanilla PHP, HipHop allows type-hinted parameters to have null as the
+default value, even if the type hint is a primitive type.
+
+ function foo(int $a = null) { ... }
+ foo(null); // then passing null is allowed
View
60 doc/extension.yield
@@ -0,0 +1,60 @@
+
+<h2>yield and generator</h2>
+
+This feature requires the [[index.php?file=options.compiler | compiler option]]
+EnableHipHopSyntax=true, or interpreter option Eval.EnableHipHopSyntax=true.
+
+HipHop extends PHP to include Python and C#-style generators. If you're
+unfamiliar with the concept, see
+[[http://docs.python.org/tutorial/classes.html#generators | the Python docs]].
+As in Python, the <i>yield</i> keyword marks the enclosing function as a
+generator:
+
+ function foo() {
+ $a = 123;
+ yield $a;
+ $a = 456;
+ yield $a;
+ }
+
+ foreach (foo() as $a) {
+ print "$a,";
+ }
+
+The above program outputs "123,456,". To abort a generator sequence, use "yield
+break".
+
+ function bar() {
+ $a = 123;
+ // this will stop the "foreach" immediately without any value returned
+ if ($abort) yield break;
+ yield $a;
+ $a = 456;
+ yield $a;
+ }
+
+Generators must observe the following restrictions:
+
+- Generators are <b>not recursive</b>. In the above example, foo() cannot call
+ foo() while iterating.
+- Generators are <b>called once</b>: foo() cannot be called again after it's
+ done iterating.
+- Do not call the rewind() method of the objects (of class Iterator) returned by
+ iterator functions.
+
+Also, yield in HipHop also supports passing a value from outside of the
+generator.
+
+ function foo() {
+ $a = yield 5;
+ yield $a + 1;
+ }
+
+From outside the generator, instead of resuming the generator with
+Continuation::next(), one can call Continuation::send() to pass a value, which
+will be assigned to $a, back into the generator.
+
+Note that the yield expression in the above example is not really an expression;
+it can only appear on its own on the RHS of an assignment statement. This is to
+avoid the complicated evaluation order problem in bizarre expressions like
+"($a = yield 5) * (yield $a + 3) - ($a = yield 4)".
View
29 doc/ffi.c++
@@ -27,8 +27,9 @@ Both functions have to be called on per-thread basis.
If memory leak is detected, it may mean the PHP library has objects or arrays
forming cycles when referring to each other. This is problematic to reference
-counting based memory deallocation, but it can be solved by using
-MemoryManager that can sweep dangling memory periodically.
+counting based memory deallocation, but it can be solved by enabling the
+MemoryManager feature which sweeps memory when the current session is torn
+down.
To enable MemorManager, this has to be set at program startup time, and it
cannot be turned off afterwards:
@@ -40,27 +41,15 @@ cannot be turned off afterwards:
(same as above)
-(2) Taking a checkpoint
+(2) Recycle the session periodically
-The memory manager is powerful enough to take a snapshot of the memory at any
-time by doing
-
- hphp_session_init(); // required, same as above
- // optionally update more global states
- MemoryManager::TheMemoryManager()->checkpoint();
-
-We only recommend to take checkpoint just once on per-thread basis, because
-we have not tested what will happen when multiple checkpoint() is called.
-
-(3) Rollback periodically
-
-Call this once per end of "session":
-
- hphp_session_exit();
+It is a good idea to recycle the session periodically. The current session can
+be torn down by calling hphp_session_exit(), and subsequently a fresh session
+can be started by calling hphp_session_init().
Please make sure there is no stack variables that are still alive when calling
-rollback(). Otherwise, rollback() will release the memory to the pool, causing
-that stack variable's destructor to work on collected memory.
+hphp_session_exit(). Otherwise, hphp_session_exit() will release the memory
+while there are still stack variables pointing to that memory.
3. Thread Local Memory Management
View
45 doc/index.php
@@ -27,6 +27,8 @@
),
'New Features' => array(
'New functions' => 'extension.new_functions',
+ 'yield and generator' => 'extension.yield',
+ 'Richer type hints' => 'extension.type_hints',
'Parallel execution' => 'threading',
'Server documents' => 'server.documents',
'RPC server' => 'server.rpc_server',
@@ -61,30 +63,34 @@
///////////////////////////////////////////////////////////////////////////////
// main
-$css = 'style'; // default
-if (isset($_GET['css'])) $css = $_GET['css'];
-echo "<link type='text/css' rel='stylesheet' href='$css.css' />";
+echo "<link type='text/css' rel='stylesheet' href='style.css' />";
$file = 'coding_guideline';
if (isset($_GET['file'])) $file = $_GET['file'];
-$doc = file_get_contents(realpath(dirname(__FILE__))."/$file");
+$title = find_topics($topics, $file);
+echo '<title>'.htmlspecialchars($title ? $title : 'Invalid topic').'</title>';
echo '<table cellpadding=0 cellspacing=0 border=0>';
echo '<tr><td valign=top width=200>';
-echo format_index($file);
+format_index($topics, $file);
echo '</td><td valign=top bgcolor=white width=640>';
-if (preg_match('/^debugger\./', $file)) {
- echo format_debugger_doc($doc);
+if (!$title) {
+ echo 'Topic does not exist.';
} else {
- echo format_document($doc);
+ $doc = file_get_contents(realpath(dirname(__FILE__))."/$file");
+ if (preg_match('/^debugger\./', $file)) {
+ echo format_debugger_doc($doc);
+ } else {
+ echo format_document($doc);
+ }
}
echo '</td></tr></table>';
///////////////////////////////////////////////////////////////////////////////
// helpers
-function format_index($file) {
- global $topics;
+function find_topics(&$topics, $file) {
+ $title = '';
$found_files = array();
exec('find . -type f', $found_files);
@@ -93,12 +99,20 @@ function format_index($file) {
foreach ($found_files as $f) {
$f = substr($f, 2); // skipping "./"
if (!preg_match('/(~|Makefile|index\.php|style\.css|www\.pid)/', $f)) {
+ if ($f == $file) {
+ $title = $f;
+ }
$files[$f] = $f;
}
}
+ $allowed = isset($files[$file]);
+
foreach ($topics as $topic => $group) {
foreach ($group as $name => $f) {
+ if ($f == $file) {
+ $title = "$topic: $name";
+ }
unset($files[$f]);
}
}
@@ -106,6 +120,10 @@ function format_index($file) {
$topics['New Topics'] = $files;
}
+ return $title;
+}
+
+function format_index($topics, $file) {
echo '<table cellpadding=1 cellspacing=3 border=1 bgcolor=white>';
echo '<tr><td colspan=2 class="hphp">HipHopDoc</td></tr>';
echo '<tr><td colspan=2>&nbsp;</td></tr>';
@@ -114,8 +132,6 @@ function format_index($file) {
echo "<nobr>$topic</nobr></a></td></tr>";
foreach ($group as $name => $f) {
- unset($files[$f]);
-
echo '<tr><td width=5></td><td><nobr>';
$class = $f == $file ? 'current_file' : 'file';
echo "<span class='$class'><a href='index.php?file=".
@@ -127,6 +143,8 @@ function format_index($file) {
}
function format_document($doc) {
+ $doc = preg_replace('/<(?!\/?(b|h2|i)[ >])/',
+ '&lt;', $doc); // unsupported tags
$doc = preg_replace('/\n= (.*?)\n/',
"<h3>\\1</h3>\n", $doc); // h3 headers
$doc = preg_replace('/\n([0-9]+\. )(.*?)\n/',
@@ -147,8 +165,6 @@ function format_document($doc) {
$doc); // item: details
$doc = preg_replace('/\n\n/', '<p>', $doc); // paragraphs
- $doc = preg_replace('/<T>/', '&lt;T&gt;', $doc); // C++ templates
- $doc = preg_replace('/<\?/', '&lt;?', $doc); // PHP start tags
$doc = preg_replace('/\[\[[ \n]*(.*?)[ \n]*\|[ \n]*(.*?)[ \n]*\]\]/s',
'<a href="\\1">\\2</a>',$doc); // links
@@ -159,7 +175,6 @@ function format_document($doc) {
}
function format_debugger_doc($doc) {
- $doc = preg_replace('/</', '&lt;', $doc);
$doc = preg_replace('/ *(?:\xe2\x94\x80|\-){5,}(.*) '.
'(?:\xe2\x94\x80|\-){5,}/',
'<h2>$1</h2>', $doc);
View
12 doc/options.compiled
@@ -156,8 +156,8 @@ flood error logs.
# maximum memory size for image processing
ImageMemoryMaxBytes = UploadMaxFileSize * 2
- # Recommend to turn this on to avoid memory leaks and to enable warmup
- # document features.
+ # Recommended to turn this on to avoid memory leaks and to enable the
+ # RequestInitDocument and RequestInitFunction features.
EnableMemoryManager = false
# Only for debugging memory problems. When turned on, server will report
@@ -166,9 +166,8 @@ flood error logs.
# Recommend to turn this on for faster array operations.
UseZendArray = true
- # Faster data structure for arrays of size < 8. Requires UseZendArray=true.
- # Recommend to turn this on.
- UseSmallArray = true
+ # Faster data structure for arrays of size < 8. Deprecated and ignored.
+ UseSmallArray = false
# If ServerName is not specified for a virtual host, use prefix + this
# suffix to compose one. If "Pattern" was specified, matched pattern,
@@ -183,7 +182,6 @@ flood error logs.
TakeoverFilename = filename # for port takeover between server instances
DefaultDocument = index.php
StartupDocument = filename
- WarmupDocument = filename
RequestInitFunction = function_name
RequestInitDocument = filename
ThreadDocuments {
@@ -466,7 +464,6 @@ These are experimental LFU settings.
MaxRequest = 500
MaxDuration = 120 # in seconds
TimeoutSeconds = 30 # default to RequestTimeoutSeconds
- WarmupDocument = filename
RequestInitFunction = on_init
RequestInitDocument = filename
Password = authentication
@@ -495,7 +492,6 @@ patterns for pages to server over this port.
Port = 0
MaxRequest = 500
MaxDuration = 120
- WarmupDocument =
RequestInitFunction =
RequestInitDocument =
}
View
80 doc/repo
@@ -0,0 +1,80 @@
+hhvm stores serialized HipHop Bytecode and metadata in on-disk repositories, or
+"repos" for short. Repos are implemented using SQLite (http://www.sqlite.org/),
+which means that repo introspection is possible using the sqlite3 command line
+program, as well as via SQLite API bindings for any number of programming
+languages. For example, here is how to determine the schema within a repo named
+hhvm.hhbc:
+
+ $ sqlite3 hhvm.hhbc '.schema'
+
+This dumps the SQLite database schema, but the repo schema is a slightly
+different concept, in that one repo can support multiple repo schemas
+simultaneously. To make this possible, every SQLite table name is suffixed with
+the repo schema version number. For example, repo schema version 0 contains a
+table called "magic0":
+
+ $ sqlite3 hhvm.hhbc '.dump magic0'
+ PRAGMA foreign_keys=OFF;
+ BEGIN TRANSACTION;
+ CREATE TABLE magic0(product TEXT);
+ INSERT INTO "magic0"
+ VALUES('facebook.com HipHop Virtual Machine bytecode repository');
+ COMMIT;
+
+This table is used as a sanity check to assure that the repo is initialized to
+support the schema.
+
+hhvm utilizes SQLite transactions to ensure that the repo is always in a
+consistent state. For example, the repo schema is either fully in place or fully
+absent. The same is true for compilation units; if an entry exists in the Unit0
+table, then all the associated data exists in the other tables.
+
+ $ sqlite3 hhvm.hhbc '.dump Unit0'
+ PRAGMA foreign_keys=OFF;
+ BEGIN TRANSACTION;
+ CREATE TABLE Unit0(unitSn INTEGER PRIMARY KEY, md5 BLOB, bc BLOB, lines BLOB,
+ UNIQUE (md5));
+ COMMIT;
+
+Rather than use the bulky md5 blob as a unique identifier throughout the repo,
+unitSn is used. Incidentally, here is how to find out how many compilation units
+are stored:
+
+ $ sqlite3 hhvm.hhbc 'SELECT COUNT(*) FROM Unit0;'
+ 19452
+
+hhvm uses one or two repos, depending on configuration. The 'central' repo must
+always be writable, but the 'local' repo can be read-only, or even completely
+missing. Before opening either the central or local repo, the first occurrence
+of '%{schema}' in the path will be replaced by the current schema id. There are
+several runtime configuration options (and related environment variables) that
+can be used to control repo behavior:
+
+* Repo.Local.Mode: rw, r-(*), or -- (overrides HHVM_REPO_LOCAL_MODE)
+ rw: Use the local repo for reading and writing (if file permissions allow).
+ r-: Use the local repo for reading (if it exists and is readable).
+ --: Completely ignore the local repo, even if it exists.
+* Repo.Local.Path (overrides HHVM_REPO_LOCAL_PATH)
+ Repo.Local.Path or HHVM_REPO_LOCAL_PATH can be used to specify where the local
+ repo is. If unspecified, then the local repo is 'path/to/cli.php.hhbc' in cli
+ mode or '<cwd>/hhvm.hhbc' in srv mode.
+* Repo.Central.Path (overrides HHVM_REPO_CENTRAL_PATH)
+ There is always a central read-write repo. Non-eval units prefer to be written
+ in the local repo, but are written in the central repo if the local repo isn't
+ writable.
+* Repo.Eval.Mode: local, central, or readonly(*)
+ local: Write eval units to the local repo if it is writable; otherwise write
+ to the central repo.
+ central: Write eval units to the central repo.
+ readonly: Do not write eval units to a repo, but still search for them in
+ repos.
+* Repo.Commit: true(*) or false
+ If true, commit newly emitted units to the repo.
+* Repo.DebugInfo: true(*) or false
+ If true, store full source locations; otherwise store only line
+ numbers.
+* Repo.Authoritative: false(*) or true
+ If true, use Repo as authoritative source for unit bytecode, do
+ not consult filesystem to check for existence of file or parse it.
+ Otherwise, fall back to parsing file from filesystem if unit
+ is not found in Repo.
View
30 doc/runtime.memory_model
@@ -71,12 +71,10 @@ virtual functions that will be called by execution engine at startup and
shutdown time of an HTTP request.
-<h2>Memory Allocators</h2>
+<h2>SmartAllocator</h2>
-Two speciailized memory allocators are implemented in HipHop, in addition to
-the general purpose tcmalloc we used for replacing glic's malloc/free.
-
-1. SmartAllocator<T>
+When Server.EnableMemoryManager is set to true, HipHop will use speciailized
+memory allocators called SmartAllocators.
A SmartAllocator simply allocates one slab of multiple objects with the same
size a time. Then it will use replacement new (macro-ed as NEW in HipHop code
@@ -92,25 +90,3 @@ operations on the free list, with some rare malloc/free calls for slabs.
The tradeoff is, each object will take an extra 64-bit pointer storage in
free list.
-2. LinearAllocator
-
-HipHop supports memory state check points, so that on subsequent requests,
-certain user PHP code doesn't have to be executed again, if its sole purpose
-is to initialize global states to certain values.
-
-To support this feature, we also implemented a so-called "linear allocator"
-to allocate variable-sized objects during backup time of doing a checkpoint.
-
-For example, a String class wraps StringData that's in fixed size. So
-StringData may use SmartAllocator for its allocation/deallocation. But
-StringData may internally keep a char pointer that has a variable size. This
-string pointer will be allocated through general purpose malloc/free initially,
-but it will be copied into linear allocator, if it is allocated before a
-check point is taken. When we restore a checkpoint, we then don't have to
-make a new copy of the string any more, as all we have to do is to copy over
-the string pointer that's always valid, as long as we hold the linear allocator
-memory for the entire life.
-
-By doing so, we can memcpy entire linear allocator's memory each time we
-restore a checkpoint, thus making it cheaper than many smaller malloc/free
-calls.
View
67 doc/server.documents
@@ -20,26 +20,22 @@ This flow is implemented in hphp/src/cpp/base/server/http_server.cpp:
| Worker Thread | | Service Threads |
|____________________________| |_________________|
| | | |
- | +----------------+ | | ThreadDocuments |
- | | WarmupDocument | | | |
- | +-------+--------+ | +=================+
- | | |
- | +-----> (chekpoint) | ...
- | | | |
- | | V |
- | | +----------------+ |
- | | | RequestInit | |
- | | +----------------+ |
- | | | backup |
- | | +----------+ |
- | | V | |
- | | +----------------+ R |
- | | | URL Handling | P |
- | | +----------------+ C |
- | | | | |
- | | +-restore--+ |
- | | | |
- | +-(rollback)-+ |
+ | +-----------+ | | ThreadDocuments |
+ | | | | | |
+ | | V | +=================+
+ | | +----------------+ |
+ | | | RequestInit | |
+ | | +----------------+ |
+ | | | |
+ | | +----<-----+ |
+ | | V | |
+ | | +----------------+ R |
+ | | | URL Handling | P |
+ | | +----------------+ C |
+ | | | | |
+ | | +---->-----+ |
+ | | | |
+ | +--(sweep)--+ |
| |
+============================+
@@ -72,32 +68,21 @@ infinite loop, and doesn't have any requirements of hphp_service_thread_started
being called. It can be useful to recover memory after different execution of
the document.
-3. WarmupDocument
+3. RequestInitDocument and RequestInitFunction
-A warmup document is executed during a worker thread's startup time, and it's
-only executed just once for the entire life of a worker thread. Right after
-this warmup document is run, a worker thread takes a checkpoint of its memory
-state. Then the worker thread will start its request handling loop. At end of
-each request handling, it will rollback its memory state to the checkpoint.
+When a worker thread resets, the RequestInitDocument and/or RequestInitFunction
+are executed in order to initialize certain states or request specific coding.
+If both RequestInitDocument and RequestInitFunction are specified, the
+RequestInitDocument is executed before the RequestInitFunction.
-A warmup document can prepare global variables and other persistent data that
-are request neutral. This way we can avoid running the same initialization
-sequence for every single request.
-
-4. RequestInit Function/Document
-
-This function or document is executed after every checkpoint, so to initialize
-certain states or request specific coding. Both can be specified, and
-RequestInitDocument is executed ahead of RequestInitFunction.
-
-5. RPCRequestHandler
+4. RPCRequestHandler
RPCRequestHandler will call ExecutionContext::backupSession() right after
RequestInit function/document, and it will call ExecutionContext::
restoreSession() right after it finishes one request processing and it goes
back to a state right after RequestInit is executed.
-RPCRequestHandler will also reset itself from time to time, either after
-processing certain number of requests or after certain amount of time. When
-this happens, it will go back to checkpoint and re-execute RequestInit
-function/document.
+RPCRequestHandler will reset a worker thread from time to time, either after
+the worker thread has processed a certain number of requests or after certain
+amount of time. When this happens, it will perform a sweep and re-execute
+RequestInit function/document.
View
6 doc/server.rpc_server
@@ -73,9 +73,9 @@ assumption that the request is stateless.
There are two cases. First, the purpose of the RPC call is still to invoke a
function, but the definition of the function is in a file that is not in the
-normal initialization path, defined by the WarmupDocument or the
-RequestInitDocument. In order to invoke the function reliably, you can add
-"include=..." or "include_once=..." to the request:
+normal initialization path, defined by the RequestInitDocument. In order to
+invoke the function reliably, you can add "include=..." or "include_once=..."
+to the request:
http://[server]:[port]/function_name?include_once=file_name.php&...
View
128 doc/threading
@@ -1,14 +1,14 @@
<h2> Multi-Tasking and Multi-Threading Support</h2>
-To perform parallel execution in PHP without forking a new process, we can
-choose one of these 3 new facilities:
+To perform parallel execution in PHP without forking a new process, you may
+take advantage of one of these new facilities:
1. Pagelet Server
-This is already implemented. A pagelet server is similar to a CURL call to
-localhost. Look for "Pagelet Server" in compiled program's options for how to
-set it up. The new pagelet server functions work like this,
+The pagelet server is similar to a CURL call to localhost. Look for "Pagelet
+Server" in compiled program's options for how to set it up. The new pagelet
+server functions work like this:
// This starts a pagelet server thread to process the URL just as if
// it's a new web request with specified headers and post data.
@@ -27,9 +27,9 @@ set it up. The new pagelet server functions work like this,
2. Xbox Tasks
-This is already implemented. An xbox system is designed for cross-box messaging
-that's described in "server.xbox_server" documentation. But when it runs
-locally, it provides parallel execution in a separate thread.
+The xbox task system is designed to provide cross-box messaging as described in
+"server.xbox_server" documentation. The xbox task system may also be used to
+execute a task on the local machine in a separate thread. Here is an example:
// We start an xbox task by sending to localhost a message.
$task = <b>xbox_task_start</b>($message);
@@ -42,118 +42,14 @@ locally, it provides parallel execution in a separate thread.
$ret = null;
$code = <b>xbox_task_result</b>($task, $timeout_ms, $ret);
-On message processing side, one has to implement a PHP function like this,
+On the message processing side, one has to implement a PHP function like this:
function <b>xbox_process_message</b>($msg) {
...
return $ret;
}
-Please note that an xbox thread starts its execution with its own global
-states without sharing anything with main thread, other than $msg and $ret that
-are passed between these threads at enter and exit points. To share states,
-please read on for call_user_func_async() series.
+Note that an xbox thread starts its execution with its own global state without
+sharing anything with main thread, other than $msg and $ret that are passed
+between these threads at enter and exit points.
-3. call_user_func_async() and call_user_func_array_async()
-
-<b>Note: This functionality is deprecated. Please use one of the alternative
-forms of concurrency delineated above.</b>
-
-"Fork" program into 2 or more threads at any time point of the execution from
-the same set of global states, then "join" when thread finishes its execution.
-
- // This is non-blocking, and global states will be duplicated here.
- $handle = <b>call_user_func_async</b>($func, $param1, $param2, ...);
- // Main thread can now do extra work while the other thread is running.
- do_main_thread_jobs();
- $ret = <b>end_user_func_async</b>($handle, $default_strategy,
- $additional_strategies);
-
-Please note that global states will be duplicated when call_user_func_async()
-is called, so that each thread (the main thread and the new thread) will have
-its own copy of the states. From then on, they never share anything (other than
-APC). When end_user_func_async() is called, the global state of the new
-thread will be "merged" back into main thread's depending on how strategies are
-specified.
-
-$default_strategy can be,
-
-(1) GLOBAL_STATE_IGNORE (default)
-
-In this case, new thread's modifications of global states will be thrown away.
-
-(2) GLOBAL_STATE_OVERWRITE
-
-In this case, new thread's modifications of global states will entirely
-replace main thread's. Do so ONLY when you are sure main thread's global states
-can be lost during this overwrite. Otherwise, please use GLOBAL_STATE_IGNORE
-and use function output parameters to pass back global states that need to
-be copied back to main thread.
-
-(3) GLOBAL_STATE_SKIP
-
-In this case, new thread's modifications of global states will be merged into
-main thread's, and when there is a conflict, new thread's state will not be
-merged at all. "Conflict" is currently only defined as an array having the same
-first level key with different values. Then the new value under the key will
-be skipped. For example, if main thread has array('a' => 1, 'b' => 2) and
-new thread has array('a' => 3, 'b' => 4), after merge it would become
-array('a' => 1, 'b' => 4). Note that this is NOT recursive and it only applies
-to first level keys.
-
-$additional_strategies can be used to specify finer granularity rules:
-
- array({global symbol type} => array({name} => {strategy}, ...), ...);
-
-where {global symbol type} can be any one of these,
-
-- GLOBAL_SYMBOL_GLOBAL_VARIABLE
-- GLOBAL_SYMBOL_STATIC_VARIABLE
-- GLOBAL_SYMBOL_CLASS_STATIC
-- GLOBAL_SYMBOL_DYNAMIC_CONSTANT
-- GLOBAL_SYMBOL_FILE_INCLUDE
-- GLOBAL_SYMBOL_REDECLARED_FUNCTION
-- GLOBAL_SYMBOL_REDECLARED_CLASS
-
-For example,
-
- end_user_func_async($handle, GLOBAL_STATE_IGNORE,
- array(GLOBAL_SYMBOL_GLOBAL_VARIABLE =>
- array('CACHE' => GLOBAL_STATE_SKIP)));
-
-This will ignore all modifications from a new thread, except $GLOBALS['CACHE'],
-which will merge any values under $GLOBALS['CACHE'][$key] that are not present
-in main thread.
-
-NOTE: if the asynchronously invoked function has pass-by-ref parameters, at the
-time of end_user_func_async() call, their values will overwrite those in the
-main thread. This also applies to $this, which is essentially a special
-pass-by-ref parameter.
-
-For example,
-
- class A {
- var $a = 1;
- function f(&$a, $b) { $this->a = 2; $a = 2; $b = 2; }
- }
- $obj = new A;
- $a = 1;
- $b = 1;
- $h = call_user_func_async(array($obj, 'f'), $a, $b);
- end_user_func_async($h);
-
-After the end_user_func_async() call, $obj->a and $a will be 2, but $b will
-remain 1.
-
-Check status of the async job(s):
-
- mixed check_user_func_async(mixed $handles, int $timeout = -1);
-
-This function takes one or multiple handles and check whether the job(s) have
-finished. If taking a single handle, it will return TRUE or FALSE to indicate
-whether the job has finished. If taking an array, it will return an array of
-finished jobs.
-
-The parameter timeout is in milliseconds. If -1 is specified, it is
-non-blocking. If 0 is specified, it blocks until some of the specified jobs
-are done.
View
44 src/CMakeLists.txt
@@ -18,7 +18,24 @@
include(HPHPSetup)
# find all the source files
-set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system/gen system/lib util)
+if ("$ENV{USE_HHVM}" STREQUAL "1")
+ SET(USE_HHVM TRUE)
+ SET(ENV{HHVM} 1)
+else()
+ SET(USE_HHVM FALSE)
+endif()
+
+
+if (USE_HHVM)
+ ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/src/hhvm/hhvm\\\"")
+endif(USE_HHVM)
+
+if (USE_HHVM)
+ set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/ext_hhvm runtime/vm system/gen system/lib util)
+else()
+ set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system/gen system/lib util)
+endif(USE_HHVM)
+
foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
auto_sources(files "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
@@ -29,6 +46,25 @@ foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
endforeach(dir ${RECURSIVE_SOURCE_SUBDIRS})
+# remove ext_hhvm
+foreach (file ${CXX_SOURCES})
+ if (${file} MATCHES "ext_hhvm")
+ message("Removing hhvm file ${file}")
+ list(REMOVE_ITEM CXX_SOURCES ${file})
+ endif()
+endforeach(file ${CXX_SOURCES})
+
+# remove ext/sep for hhvm
+if (USE_HHVM)
+ foreach (file ${CXX_SOURCES})
+ if (${file} MATCHES "ext/sep")
+ message("Removing ${file}")
+ list(REMOVE_ITEM CXX_SOURCES ${file})
+ endif()
+ endforeach(file ${CXX_SOURCES})
+endif(USE_HHVM)
+
+
if (EXISTS "${hphp_SOURCE_DIR}/HPHP_EXCLUDE_FILES.txt")
FILE(READ ${hphp_SOURCE_DIR}/HPHP_EXCLUDE_FILES.txt HPHP_EXCLUDE_FILES)
STRING(REGEX REPLACE "[\n\r]" ";" HPHP_EXCLUDE_FILES "${HPHP_EXCLUDE_FILES}")
@@ -112,10 +148,16 @@ SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES PREFIX "lib")
#SET_TARGET_PROPERTIES(hphp_runtime PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+SET(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+
hphp_link(hphp_runtime_static)
add_subdirectory(compiler)
+if (USE_HHVM)
+ add_subdirectory(runtime/ext_hhvm)
+endif(USE_HHVM)
+
add_subdirectory(hphp)
add_subdirectory(test)
View
3,719 src/Makefile
1,981 additions, 1,738 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
593 src/compiler/Makefile
310 additions, 283 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
132 src/compiler/analysis/alias_manager.cpp
@@ -28,6 +28,7 @@
#include <compiler/expression/simple_function_call.h>
#include <compiler/expression/array_element_expression.h>
#include <compiler/expression/object_property_expression.h>
+#include <compiler/expression/object_method_expression.h>
#include <compiler/expression/parameter_expression.h>
#include <compiler/expression/expression_list.h>
#include <compiler/expression/expression.h>
@@ -49,6 +50,7 @@
#include <compiler/statement/do_statement.h>
#include <compiler/statement/exp_statement.h>
#include <compiler/statement/echo_statement.h>
+#include <compiler/statement/try_statement.h>
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/control_flow.h>
#include <compiler/analysis/variable_table.h>
@@ -72,7 +74,7 @@ using std::string;
AliasManager::AliasManager(int opt) :
m_bucketList(0), m_nextID(1), m_changes(0), m_replaced(0),
- m_wildRefs(false), m_nrvoFix(0), m_inlineAsExpr(true),
+ m_wildRefs(false), m_nrvoFix(0), m_inCall(0), m_inlineAsExpr(true),
m_noAdd(false), m_preOpt(opt<0), m_postOpt(opt>0),
m_cleared(false), m_inPseudoMain(false), m_genAttrs(false),
m_hasDeadStore(false), m_hasChainRoot(false),
@@ -106,7 +108,7 @@ bool AliasManager::parseOptimizations(const std::string &optimizations,
} else if (opt == "string") {
Option::StringLoopOpts = val;
} else if (opt == "inline") {
- Option::AutoInline = val ? 1 : 0;
+ Option::AutoInline = val ? 1 : -1;
} else if (opt == "cflow") {
Option::ControlFlow = val;
} else if (opt == "coalesce") {
@@ -115,7 +117,7 @@ bool AliasManager::parseOptimizations(const std::string &optimizations,
val = opt == "all";
Option::EliminateDeadCode = val;
Option::LocalCopyProp = val;
- Option::AutoInline = val ? 1 : 0;
+ Option::AutoInline = val ? 1 : -1;
Option::ControlFlow = val;
Option::CopyProp = val;
} else {
@@ -519,7 +521,7 @@ int AliasManager::testAccesses(ExpressionPtr e1, ExpressionPtr e2,
}
case Expression::KindOfIncludeExpression: {
IncludeExpressionPtr inc(spc(IncludeExpression, e2));
- if (!inc->getPrivateScope()) {
+ if (!inc->isPrivateScope()) {
return InterfAccess;
}
goto def;
@@ -1548,7 +1550,13 @@ ExpressionPtr AliasManager::canonicalizeNode(
}
cur = next;
}
- if (ae->isUnused() && m_accessList.isLast(ae)) {
+ if ((!m_inCall || (!hhvm && !ae->getValue()->hasEffect())) &&
+ ae->isUnused() && m_accessList.isLast(ae) &&
+ !(hhvm && Option::OutputHHBC &&
+ e->hasAnyContext(Expression::AccessContext |
+ Expression::ObjectContext |
+ Expression::ExistContext |
+ Expression::UnsetContext))) {
rep = ae->clone();
ae->setContext(Expression::DeadStore);
ae->setNthKid(1, ae->makeConstant(m_arp, "null"));
@@ -1782,6 +1790,8 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
bool delayVars = true;
bool pushStack = false;
+ bool inCall = false;
+ bool setInCall = true;
switch (e->getKindOf()) {
case Expression::KindOfQOpExpression:
@@ -1812,13 +1822,29 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
delayVars = false;
break;
- case Expression::KindOfObjectMethodExpression:
- case Expression::KindOfDynamicFunctionCall:
case Expression::KindOfSimpleFunctionCall:
- delayVars = false;
+ if (!hhvm || !Option::OutputHHBC) {
+ SimpleFunctionCallPtr f(spc(SimpleFunctionCall, e));
+ if (!f->getClass()) {
+ if (f->getClassName().empty()) {
+ if (f->getFuncScope() &&
+ !f->getFuncScope()->isVolatile()) {
+ setInCall = false;
+ }
+ } else if (ClassScopePtr cls = f->resolveClass()) {
+ if (!cls->isVolatile()) {
+ setInCall = false;
+ }
+ }
+ }
+ }
// fall through
-
case Expression::KindOfNewObjectExpression:
+ case Expression::KindOfDynamicFunctionCall:
+ inCall = setInCall;
+ case Expression::KindOfObjectMethodExpression:
+ delayVars = false;
+ // fall through
pushStack = m_accessList.size() > 0;
break;
@@ -1835,6 +1861,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
int n = e->getKidCount();
if (n < 2) delayVars = false;
+ m_inCall += inCall;
for (int j = delayVars ? 0 : 1; j < 2; j++) {
for (int i = 0; i < n; i++) {
if (ExpressionPtr kid = e->getNthExpr(i)) {
@@ -1863,6 +1890,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
if (pushStack) m_exprBeginStack.push_back(aBack);
ExpressionPtr ret(canonicalizeNode(e));
if (pushStack) m_exprBeginStack.pop_back();
+ m_inCall -= inCall;
return ret;
}
@@ -1897,7 +1925,6 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
case Statement::KindOfExpStatement:
case Statement::KindOfStatementList:
case Statement::KindOfBlockStatement:
- case Statement::KindOfTryStatement:
// No special action, just execute
// and fall through
break;
@@ -1972,6 +1999,18 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
ret = Branch;
break;
+ case Statement::KindOfTryStatement: {
+ TryStatementPtr trs(spc(TryStatement, s));
+ beginScope();
+ canonicalizeKid(s, trs->getBody(), 0);
+ endScope();
+ clear();
+ canonicalizeKid(s, trs->getCatches(), 1);
+ ret = Converge;
+ start = nkid;
+ break;
+ }
+
case Statement::KindOfCatchStatement:
clear();
ret = Converge;
@@ -2251,7 +2290,7 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
case Expression::KindOfIncludeExpression:
{
IncludeExpressionPtr inc(spc(IncludeExpression, e));
- if (!inc->getPrivateScope()) {
+ if (!inc->isPrivateScope()) {
m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
}
}
@@ -2415,14 +2454,8 @@ void AliasManager::gatherInfo(AnalysisResultConstPtr ar, MethodStatementPtr m) {
if (cp == m->getStmts()) cost = c;
}
- if (func->containsThis() && !m->getClassScope()) {
- func->setContainsThis(false);
- func->setContainsBareThis(false);
- }
-
if (m_inlineAsExpr) {
- if (!Option::AutoInline ||
- cost > Option::AutoInline ||
+ if (cost > Option::AutoInline ||
func->isVariableArgument() ||
m_variables->getAttribute(VariableTable::ContainsDynamicVariable) ||
m_variables->getAttribute(VariableTable::ContainsExtract) ||
@@ -3234,6 +3267,18 @@ class TypeAssertionRemover {
};
+static bool isNewResult(ExpressionPtr e) {
+ if (!e) return false;
+ if (e->is(Expression::KindOfNewObjectExpression)) return true;
+ if (e->is(Expression::KindOfAssignmentExpression)) {
+ return isNewResult(spc(AssignmentExpression, e)->getValue());
+ }
+ if (e->is(Expression::KindOfExpressionList)) {
+ return isNewResult(spc(ExpressionList, e)->listValue());
+ }
+ return false;
+}
+
class ConstructTagger : public ControlFlowGraphWalker {
public:
ConstructTagger(ControlFlowGraph *g,
@@ -3252,28 +3297,55 @@ class ConstructTagger : public ControlFlowGraphWalker {
m_block->setBit(DataFlow::Available, id);
e->setAnticipated();
}
- } else if (e->is(Expression::KindOfSimpleVariable)) {
- SimpleVariablePtr sv = spc(SimpleVariable, e);
- if (!sv->couldBeAliased()) {
+ } else {
+ bool set = true, cand = true;
+ SimpleVariablePtr sv;
+ if (e->is(Expression::KindOfSimpleVariable) &&
+ (e->isThis() || !e->hasContext(Expression::ObjectContext))) {
+ sv = spc(SimpleVariable, e);
+ cand = e->isThis() && e->hasContext(Expression::ObjectContext);
+ } else {
+ if (e->is(Expression::KindOfObjectMethodExpression)) {
+ ObjectMethodExpressionPtr om(spc(ObjectMethodExpression, e));
+ if (om->getObject()->is(Expression::KindOfSimpleVariable)) {
+ sv = spc(SimpleVariable, om->getObject());
+ }
+ } else if (e->is(Expression::KindOfObjectPropertyExpression)) {
+ ObjectPropertyExpressionPtr op(spc(ObjectPropertyExpression, e));
+ if (op->getObject()->is(Expression::KindOfSimpleVariable)) {
+ sv = spc(SimpleVariable, op->getObject());
+ set = false;
+ }
+ } else if (e->is(Expression::KindOfAssignmentExpression)) {
+ AssignmentExpressionPtr ae(spc(AssignmentExpression, e));
+ if (ae->getVariable()->is(Expression::KindOfSimpleVariable) &&
+ isNewResult(ae->getValue())) {
+ sv = spc(SimpleVariable, ae->getVariable());
+ }
+ }
+ if (sv && (sv->isThis() || sv->couldBeAliased())) sv.reset();
+ }
+ if (sv) {
id = m_gidMap["v:" + sv->getName()];
if (id) {
- if (e->hasContext(Expression::ObjectContext)) {
- e->setCanonID(id);
- e->clearAnticipated();
+ if (cand) {
+ sv->setCanonID(id);
+ sv->clearAnticipated();
if (m_block->getBit(DataFlow::Available, id)) {
- markAvailable(e);
+ markAvailable(sv);
} else {
if (!m_block->getBit(DataFlow::Altered, id)) {
- e->setAnticipated();
+ sv->setAnticipated();
}
- if (!e->hasContext(Expression::ExistContext)) {
+ if (set && !sv->hasAnyContext(Expression::ExistContext|
+ Expression::UnsetContext)) {
m_block->setBit(DataFlow::Available, id, true);
}
}
- } else if (e->hasAllContext(Expression::Declaration) ||
- e->hasAllContext(Expression::UnsetContext|
+ } else if (sv->hasAllContext(Expression::Declaration) ||
+ sv->hasAllContext(Expression::UnsetContext|
Expression::LValue) ||
- e->hasAnyContext(Expression::AssignmentLHS|
+ sv->hasAnyContext(Expression::AssignmentLHS|
Expression::OprLValue)) {
m_block->setBit(DataFlow::Available, id, false);
m_block->setBit(DataFlow::Altered, id, true);
View
1 src/compiler/analysis/alias_manager.h
@@ -251,6 +251,7 @@ class AliasManager {
std::string m_returnVar;
int m_nrvoFix;
+ int m_inCall;
bool m_inlineAsExpr;
bool m_noAdd;
bool m_preOpt;
View
672 src/compiler/analysis/analysis_result.cpp
@@ -29,6 +29,8 @@
#include <compiler/statement/if_branch_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/loop_statement.h>
+#include <compiler/statement/class_variable.h>
+#include <compiler/statement/use_trait_statement.h>
#include <compiler/analysis/symbol_table.h>
#include <compiler/package.h>
#include <compiler/parser/parser.h>
@@ -42,7 +44,6 @@
#include <compiler/expression/expression_list.h>
#include <compiler/expression/array_pair_expression.h>
#include <runtime/base/rtti_info.h>
-#include <runtime/base/array/small_array.h>
#include <runtime/ext/ext_json.h>
#include <runtime/base/zend/zend_printf.h>
#include <util/atomic.h>
@@ -54,8 +55,12 @@
#include <util/timer.h>
using namespace HPHP;
-using namespace std;
-using namespace boost;
+using std::map;
+using std::set;
+using std::ostringstream;
+using std::ofstream;
+using std::ifstream;
+using std::pair;
///////////////////////////////////////////////////////////////////////////////
// initialization
@@ -258,24 +263,13 @@ ClassScopePtr AnalysisResult::findExactClass(ConstructPtr cs,
const std::string &name) const {
ClassScopePtr cls = findClass(name);
if (!cls || !cls->isRedeclaring()) return cls;
- std::string lowerName = Util::toLower(name);
if (ClassScopePtr currentCls = cs->getClassScope()) {
- if (lowerName == currentCls->getName()) {
+ if (cls->getName() == currentCls->getName()) {
return currentCls;
}
}
if (FileScopePtr currentFile = cs->getFileScope()) {
- StatementList &stmts = *currentFile->getStmt();
- for (int i = stmts.getCount(); i--; ) {
- StatementPtr s = stmts[i];
- if (s && s->is(Statement::KindOfClassStatement)) {
- ClassScopeRawPtr scope =
- static_pointer_cast<ClassStatement>(s)->getClassScope();
- if (lowerName == scope->getName()) {
- return scope;
- }
- }
- }
+ return currentFile->resolveClass(cls);
}
return ClassScopePtr();
}
@@ -340,7 +334,7 @@ void AnalysisResult::countReturnTypes(std::map<std::string, int> &counts) {
// static analysis functions
bool AnalysisResult::declareFunction(FunctionScopePtr funcScope) const {
- ASSERT(m_phase <= AnalyzeInclude);
+ ASSERT(m_phase < AnalyzeAll);
string fname = funcScope->getName();
// System functions override
@@ -355,7 +349,7 @@ bool AnalysisResult::declareFunction(FunctionScopePtr funcScope) const {
}
bool AnalysisResult::declareClass(ClassScopePtr classScope) const {
- ASSERT(m_phase <= AnalyzeInclude);
+ ASSERT(m_phase < AnalyzeAll);
string cname = classScope->getName();
// System classes override
@@ -434,8 +428,12 @@ bool AnalysisResult::addClassDependency(FileScopePtr usingFile,
StringToClassScopePtrVecMap::const_iterator iter =
m_classDecs.find(className);
- if (iter == m_classDecs.end() || iter->second.size() != 1) return false;
+ if (iter == m_classDecs.end() || !iter->second.size()) return false;
ClassScopePtr classScope = iter->second[0];
+ if (iter->second.size() != 1) {
+ classScope = usingFile->resolveClass(classScope);
+ if (!classScope) return false;
+ }
FileScopePtr fileScope = classScope->getContainingFile();
link(usingFile, fileScope);
return true;
@@ -448,14 +446,17 @@ bool AnalysisResult::addFunctionDependency(FileScopePtr usingFile,
return true;
StringToFunctionScopePtrMap::const_iterator iter =
m_functionDecs.find(functionName);
- if (iter == m_functionDecs.end() || iter->second->isRedeclaring()) {
- return false;
- }
+ if (iter == m_functionDecs.end()) return false;
FunctionScopePtr functionScope = iter->second;
+ if (functionScope->isRedeclaring()) {
+ functionScope = usingFile->resolveFunction(functionScope);
+ if (!functionScope) return false;
+ }
FileScopePtr fileScope = functionScope->getContainingFile();
link(usingFile, fileScope);
return true;
}
+
bool AnalysisResult::addIncludeDependency(FileScopePtr usingFile,
const std::string &includeFilename) {
ASSERT(!includeFilename.empty());
@@ -524,6 +525,9 @@ void AnalysisResult::checkClassDerivations() {
BOOST_FOREACH(cls, iter->second) {
hphp_string_iset seen;
cls->checkDerivation(ar, seen);
+ if (Option::WholeProgram || !Option::OutputHHBC) {
+ cls->importUsedTraits(ar);
+ }
}
}
}
@@ -594,7 +598,6 @@ void AnalysisResult::analyzeProgram(bool system /* = false */) {
// Analyze Includes
Logger::Verbose("Analyzing Includes");
- setPhase(AnalysisResult::AnalyzeInclude);
sort(m_fileScopes.begin(), m_fileScopes.end(), by_filename); // fixed order
unsigned int i = 0;
for (i = 0; i < m_fileScopes.size(); i++) {
@@ -613,8 +616,6 @@ void AnalysisResult::analyzeProgram(bool system /* = false */) {
}
}
- // I think we need one more round of checking, as new includes may bring in
- // more classes.
checkClassDerivations();
// Analyze All
@@ -650,7 +651,8 @@ void AnalysisResult::analyzeProgram(bool system /* = false */) {
cls->collectMethods(ar, methods);
bool needAbstractMethodImpl =
(!cls->isAbstract() && !cls->isInterface() &&
- !cls->derivesFromRedeclaring());
+ !cls->derivesFromRedeclaring() &&
+ !cls->getAttribute(ClassScope::UsesUnknownTrait));
for (StringToFunctionScopePtrMap::const_iterator iterMethod =
methods.begin(); iterMethod != methods.end(); ++iterMethod) {
FunctionScopePtr func = iterMethod->second;
@@ -681,6 +683,13 @@ void AnalysisResult::analyzeProgram(bool system /* = false */) {
}
}
+void AnalysisResult::analyzeIncludes() {
+ AnalysisResultPtr ar = shared_from_this();
+ for (unsigned i = 0; i < m_fileScopes.size(); i++) {
+ m_fileScopes[i]->analyzeIncludes(ar);
+ }
+}
+
static void addClassRootMethods(AnalysisResultPtr ar, ClassScopePtr cls,
hphp_string_set &methods) {
const StringToFunctionScopePtrMap &funcs = cls->getFunctions();
@@ -743,16 +752,18 @@ void AnalysisResult::analyzePerfectVirtuals() {
continue;
}
- bool perfect = true;
- for (unsigned int i = 1; i < funcs.size(); i++) {
- if (!funcs[0]->matchParams(funcs[i])) {
- perfect = false;
- break;
+ if (!funcs[0]->isPrivate()) {
+ bool perfect = true;
+ for (unsigned int i = 1; i < funcs.size(); i++) {
+ if (funcs[i]->isPrivate() || !funcs[0]->matchParams(funcs[i])) {
+ perfect = false;
+ break;
+ }
}
- }
- if (perfect) {
- for (unsigned int i = 0; i < funcs.size(); i++) {
- funcs[i]->setPerfectVirtual();
+ if (perfect) {
+ for (unsigned int i = 0; i < funcs.size(); i++) {
+ funcs[i]->setPerfectVirtual();
+ }
}
}
}
@@ -1756,7 +1767,7 @@ void AnalysisResult::outputCPPNamedScalarArrays(const std::string &file) {
cg_printf("%s = %s[%d];\n", name.c_str(), prefix, id);
if (m_namedScalarVarArrays.find(strings[i]) !=
m_namedScalarVarArrays.end()) {
- cg_printf("%s = %s;\n",
+ cg_printf("new (&%s) VarNR(%s);\n",
getScalarVarArrayName(hash, i).c_str(), name.c_str());
}
}
@@ -1891,6 +1902,11 @@ void AnalysisResult::outputCPPNamedScalarVarDoubles(const std::string &file) {
cg.namespaceEnd();
}
+void AnalysisResult::addInteger(int64 n) {
+ Lock lock(m_allIntegersMutex);
+ m_allIntegers.insert(n);
+}
+
int AnalysisResult::checkScalarVarInteger(int64 val, int &index) {
Lock lock(m_namedScalarVarIntegersMutex);
@@ -1935,16 +1951,18 @@ string AnalysisResult::getScalarVarDoubleName(int hash, int index) {
}
string AnalysisResult::prepareFile(const char *root, const string &fileName,
- bool chop) {
+ bool chop, bool stripPath /* = true */) {
string fullPath = root;
if (!fullPath.empty() && fullPath[fullPath.size() - 1] != '/') {
fullPath += "/";
}
string file = fileName;
- size_t npos = file.rfind('/');
- if (npos != string::npos) {
- file = file.substr(npos + 1);
+ if (stripPath) {
+ size_t npos = file.rfind('/');
+ if (npos != string::npos) {
+ file = file.substr(npos + 1);
+ }
}
if (chop && file.size() > 4 && file.substr(file.length() - 4) == ".php") {
@@ -2132,7 +2150,7 @@ void AnalysisResult::repartitionCPP(const string &filename, int64 targetSize,
snprintf(foutName, sizeof(foutName), "%s-%d.cpp", base.c_str(), seq);
ofstream fout(foutName);
while (getline(fin, line)) {
- fout << line << endl;
+ fout << line << "\n";
origLine++;
newLine++;
@@ -2142,22 +2160,20 @@ void AnalysisResult::repartitionCPP(const string &filename, int64 targetSize,
}
current += line.length() + 1;
- if (inPreface) preface.push_back(line);
-
if (line.find(CodeGenerator::HASH_INCLUDE) == 0) {
includes.push_back(line);
} else if (line == "/* preface starts */") {
inPreface = true;
- preface.clear();
- preface.push_back(line);
} else if (line == "/* preface finishes */") {
inPreface = false;
+ } else if (inPreface) {
+ preface.push_back(line);
} else if (line == CodeGenerator::SPLITTER_MARKER) {
// a possible cut point
if (current > targetSize) {
if (insideHPHP) {
// namespace HPHP
- fout << "}" << endl;
+ fout << "}" << "\n";
}
fout.close();
@@ -2167,17 +2183,19 @@ void AnalysisResult::repartitionCPP(const string &filename, int64 targetSize,
newLine = 0;
current = 0;
for (unsigned int j = 0; j < includes.size(); j++) {
- fout << includes[j] << endl;
+ fout << includes[j] << "\n";
newLine++;
}
if (insideHPHP) {
- fout << "namespace HPHP {" << endl;
+ fout << "namespace HPHP {\n";
newLine++;
}
+ fout << "/* preface starts */\n";
for (unsigned int j = 0; j < preface.size(); j++) {
- fout << preface[j] << endl;
+ fout << preface[j] << "\n";
newLine++;
}
+ fout << "/* preface finishes */\n";
}
}
}
@@ -2410,7 +2428,6 @@ DECLARE_JOB(Main, outputCPPMain());
DECLARE_JOB(ScalarArrays, outputCPPScalarArrays(false));
DECLARE_JOB(GlobalVarMeth,outputCPPGlobalVariablesMethods());
DECLARE_JOB(GlobalState, outputCPPGlobalState());
-DECLARE_JOB(FiberGlobal, outputCPPFiberGlobalState());
class RepartitionJob : public OutputJob {
public:
@@ -2551,7 +2568,6 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
SCHEDULE_JOB(ScalarArrays);
SCHEDULE_JOB(GlobalVarMeth);
SCHEDULE_JOB(GlobalState);
- SCHEDULE_JOB(FiberGlobal);
}
dispatcher.run();
@@ -2562,7 +2578,7 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
// 3rd round code generation
renameStaticNames(m_namedStringLiterals, "literal_strings_remap.h",
- Option::StaticStringPrefix);
+ Option::StaticStringProxyPrefix);
renameStaticNames(m_namedScalarArrays, "scalar_arrays_remap.h",
Option::StaticArrayPrefix);
if (Option::UseScalarVariant && !Option::SystemGen) {
@@ -2651,7 +2667,6 @@ void AnalysisResult::outputCPPClassMapFile() {
cg_printf("\n");
cg.printImplStarter();
- cg_printf("using namespace std;\n");
cg.namespaceBegin();
outputCPPClassMap(cg);
cg.namespaceEnd();
@@ -2845,7 +2860,7 @@ void AnalysisResult::outputCPPUtilImpl(CodeGenerator::Output output) {
cg_printInclude(string(Option::SystemFilePrefix) + "cpputil.h");
}
cg_printInclude("<runtime/base/array/zend_array.h>");
- cg_printInclude("<runtime/base/array/small_array.h>");
+ cg_printInclude("<runtime/base/array/vector_array.h>");
cg_printInclude("<runtime/base/taint/taint_observer.h>");
cg_printInclude("<runtime/base/taint/taint_data.h>");
cg.printImplStarter();
@@ -2893,6 +2908,7 @@ void AnalysisResult::outputArrayCreateDecl(CodeGenerator &cg) {
void AnalysisResult::outputArrayCreateImpl(CodeGenerator &cg) {
ASSERT(cg.getCurrentIndentation() == 0);
const char text1[] =
+ "HOT_FUNC\n"
"ArrayData *array_createvs(int64 n, ...) {\n"
" va_list ap;\n"
" va_start(ap, n);\n"
@@ -2910,9 +2926,18 @@ void AnalysisResult::outputArrayCreateImpl(CodeGenerator &cg) {
" return NEW(ZendArray)(n, 0, p);\n"
"}\n";
const char text2[] =
+ "HOT_FUNC\n"
"ArrayData *array_createvi(int64 n, ...) {\n"
" va_list ap;\n"
" va_start(ap, n);\n"
+ " if (enable_vector_array && RuntimeOption::UseVectorArray) {\n"
+ " const Variant *p[%d], **pp = p;\n"
+ " for (int64 k = 0; k < n; k++) {\n"
+ " *pp++ = va_arg(ap, const Variant *);\n"
+ " }\n"
+ " va_end(ap);\n"
+ " return NEW(VectorArray)(n, p);\n"
+ " }\n"
" ZendArray::Bucket *p[%d], **pp = p;\n"
" SmartAllocator<HPHP::ZendArray::Bucket, SmartAllocatorImpl::Bucket,\n"
" SmartAllocatorImpl::NoCallbacks> *a =\n"
@@ -2933,6 +2958,7 @@ void AnalysisResult::outputArrayCreateImpl(CodeGenerator &cg) {
}
if (m_arrayIntegerKeyMaxSize > 0) {
cg_printf(text2,
+ m_arrayIntegerKeyMaxSize,
m_arrayIntegerKeyMaxSize + 1,
m_arrayIntegerKeyMaxSize,
m_arrayIntegerKeyMaxSize + 1);
@@ -2973,7 +2999,6 @@ void AnalysisResult::outputCPPDynamicTablesHeader
cg.printImplStarter();
if (!noNamespace) {
cg_printf("\n");
- cg_printf("using namespace std;\n");
cg.namespaceBegin();
}
}
@@ -3030,12 +3055,16 @@ void AnalysisResult::outputCPPDefaultInvokeFile(CodeGenerator &cg,
const char *file) {
FileScopePtr fs = findFileScope(file);
cg_printf("if (s.empty()) return ");
- if (fs->canUseDummyPseudoMain(shared_from_this())) {
- cg_printf("dummy_pm(once, variables, get_globals());\n");
+ if (hhvm) {
+ cg_printf("vm_default_invoke_file(once);\n");
} else {
- cg_printf("%s%s(once, variables, get_globals());\n",
- Option::PseudoMainPrefix,
- Option::MangleFilename(file, true).c_str());
+ if (fs->canUseDummyPseudoMain(shared_from_this())) {
+ cg_printf("dummy_pm(once, variables, get_globals());\n");
+ } else {
+ cg_printf("%s%s(once, variables, get_globals());\n",
+ Option::PseudoMainPrefix,
+ Option::MangleFilename(file, true).c_str());
+ }
}
}
@@ -3099,6 +3128,7 @@ void AnalysisResult::outputCPPHashTableInvokeFile(
cg_printf(text1, tableSize, entries.size());
BOOST_FOREACH(FileScopePtr f, m_fileScopes) {
if (!f->getPseudoMain()) continue;
+// if (f->isPrivateInclude()) continue;
cg_printf(" (const char *)\"%s\", (const char *)&",
f->getName().c_str());
if (f->canUseDummyPseudoMain(shared_from_this())) {
@@ -3141,7 +3171,8 @@ void AnalysisResult::outputCPPDynamicClassTables(
for (ClassScopePtrVec::const_iterator iter2 = iter->second.begin();
iter2 != iter->second.end(); ++iter2) {
cls = *iter2;
- if (cls->isUserClass() && !cls->isInterface()) {
+ if (cls->isUserClass() &&
+ (!cls->isInterface() || cls->checkHasPropTable())) {
classes.push_back(cls->getOriginalName().c_str());
classScopes[cls->getName()].push_back(cls);
if (!cls->isRedeclaring()) {
@@ -3183,7 +3214,7 @@ void AnalysisResult::outputCPPHashTableGetConstant(
CodeGenerator &cg,
bool system,
const map<string, TypePtr> &constMap,
- const hphp_const_char_map<bool> &dyns) {
+ const hphp_string_map<bool> &dyns) {
ASSERT(constMap.size() > 0);
ASSERT(cg.getCurrentIndentation() == 0);
const char text1[] =
@@ -3272,7 +3303,7 @@ void AnalysisResult::outputCPPHashTableGetConstant(
string escaped = CodeGenerator::EscapeLabel(name);
string varName = string(Option::ConstantPrefix) +
CodeGenerator::FormatLabel(name);
- hphp_const_char_map<bool>::const_iterator it = dyns.find(name);
+ hphp_string_map<bool>::const_iterator it = dyns.find(iter->first);
bool dyn = it != dyns.end() && it->second;
if (dyn) {
const char *globals =
@@ -3337,14 +3368,14 @@ void AnalysisResult::outputCPPDynamicConstantTable(
outputCPPDynamicTablesHeader(cg, true, false);
map<string, TypePtr> constMap;
- hphp_const_char_map<bool> dyns;
+ hphp_string_map<bool> dyns;
ConstantTablePtr ct = getConstants();
vector<string> syms;
ct->getSymbols(syms);
BOOST_FOREACH(string sym, syms) {
if (system || ct->isSepExtension(sym)) {
constMap[sym] = ct->getSymbol(sym)->getFinalType();
- dyns[sym.c_str()] = ct->isDynamic(sym);
+ dyns[sym] = ct->isDynamic(sym);
}
}
BOOST_FOREACH(FileScopePtr fs, m_fileScopes) {
@@ -3359,7 +3390,7 @@ void AnalysisResult::outputCPPDynamicConstantTable(
continue;
}
constMap[sym] = ct->getSymbol(sym)->getFinalType();
- dyns[sym.c_str()] = ct->isDynamic(sym);
+ dyns[sym] = ct->isDynamic(sym);
}
ct->outputCPP(cg, ar);
}
@@ -3442,9 +3473,10 @@ void AnalysisResult::outputCPPDynamicConstantTable(
void AnalysisResult::outputCPPDynamicTables(CodeGenerator::Output output) {
AnalysisResultPtr ar = shared_from_this();
bool system = output == CodeGenerator::SystemCPP;
+ bool useSwitch = false;
{
string tablePath = m_outputPath + "/" + Option::SystemFilePrefix +
- (!system ? "dynamic_table_func.cpp" : "dynamic_table_func.no.cpp");
+ (!useSwitch ? "dynamic_table_func.cpp" : "dynamic_table_func.no.cpp");
Util::mkdir(tablePath);
ofstream fTable(tablePath.c_str());
CodeGenerator cg(&fTable, output);
@@ -3455,7 +3487,7 @@ void AnalysisResult::outputCPPDynamicTables(CodeGenerator::Output output) {
if (system) {
bool needGlobals;
outputCPPJumpTableSupport(cg, ar, 0, needGlobals);
- outputCPPCodeInfoTable(cg, ar, true, m_functions);
+ outputCPPCodeInfoTable(cg, ar, useSwitch, m_functions);
} else {
// For functions declared in separable extensions, generate CallInfo and
// add to declaration list to be included it the table.
@@ -3470,7 +3502,7 @@ void AnalysisResult::outputCPPDynamicTables(CodeGenerator::Output output) {
funcDec = func;
}
}
- outputCPPCodeInfoTable(cg, ar, false, m_functionDecs);
+ outputCPPCodeInfoTable(cg, ar, useSwitch, m_functionDecs);
}
cg.namespaceEnd();
fTable.close();
@@ -3491,6 +3523,7 @@ void AnalysisResult::outputCPPDynamicTables(CodeGenerator::Output output) {