Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Latest bits from trunk:

Fix casting resources to strings in the translator
Add request_alloc(); use it for non-ObjectData instead of ALLOCOBJSZ
Take two at reverting short array notation
Make more requires "mergeable"
Fix TestCodeRun-Exit
Change VectorArray to allocate values contiguously
Force file removal in merge-me-to-rc and merge-rc-to-release.
Run all C++ tests on each hphp diff sent out
Fix uncompilable code gen
Move HPHP::VM::Verifier::Arena to HPHP::Arena
Add a TinyVector<> class that can replace some uses of vector; use it some
ServiceRouter: bump version in hphp after single host fix
HPHP: get building with gcc-4.7.1
HPHP extension for textGetHyperlinks
Export translation counters through the hardware counters interface
Fix Makefile
HphpArray methods don't need to be virtual, clean up inline decls.
Remove a few things we don't follow from coding_guideline
Fix bugs with attributes for closures and methods imported from traits
Remove some new using directives that crept in after earlier removal
Add a check for lowercase extension function names in gen_ext_hhvm.php
[tc-print] More detailed summary of events
[tc-print] Changes to tc-prod-collect
Allow COMPILER_ID to be overridden on the command line
Remove boolean args from HphpArray::addVal[WithRef]
Fix NameValueTable load factor check.
Reduce StringBuffer memory usage
Fix compilation errors
Update login for megabench test user
make zend array bucket smaller
Clean up HphpArray code
Fix parser to allow xhp classes as attribute type hints
Enable the use of static analysis types in RepoAuthoritative mode
Fix compilation errors in HphpArray without USE_JEMALLOC
Remove extra element alignment and casting in HphpArray
Revert "HPHP extension for textGetHyperlinks"
bump fbcode revision to include D507348
HPHP extension for textGetHyperlinks
Remove KindOfIndirect support from HphpArray, add new VarEnv implementation
Teach the hhas assembler about string and int vector immediates
Allow ':' to be followed by T_XHP_LABEL
[tc-print] Add top translations summary
Fix string buffer overflows and other issues
Make type-profiling name-driven, and fix bugs.
  • Loading branch information...
commit 39415630e84538fb553cd325a85ce837bcf6cb70 1 parent ec56d1d
@joelpob joelpob authored
Showing with 7,585 additions and 25,271 deletions.
  1. +8 −0 .gitignore
  2. +4 −18 Makefile
  3. +27 −14 doc/bytecode.specification
  4. +2 −16 doc/coding_guideline
  5. +1,561 −3,397 src/Makefile
  6. +285 −285 src/compiler/Makefile
  7. +24 −21 src/compiler/analysis/alias_manager.cpp
  8. +17 −16 src/compiler/analysis/analysis_result.cpp
  9. +9 −44 src/compiler/analysis/class_scope.cpp
  10. +4 −1 src/compiler/analysis/control_flow.h
  11. +499 −170 src/compiler/analysis/emitter.cpp
  12. +40 −16 src/compiler/analysis/emitter.h
  13. +0 −4 src/compiler/analysis/function_container.cpp
  14. +8 −5 src/compiler/analysis/function_scope.cpp
  15. +4 −0 src/compiler/analysis/function_scope.h
  16. +12 −12 src/compiler/analysis/type.cpp
  17. +2 −34 src/compiler/analysis/variable_table.cpp
  18. +5 −0 src/compiler/construct.cpp
  19. +17 −12 src/compiler/construct.h
  20. +5 −2 src/compiler/expression/dynamic_function_call.cpp
  21. +51 −4 src/compiler/expression/expression.cpp
  22. +2 −1  src/compiler/expression/expression.h
  23. +2 −2 src/compiler/expression/expression_list.cpp
  24. +12 −10 src/compiler/expression/object_method_expression.cpp
  25. +6 −5 src/compiler/expression/object_property_expression.cpp
  26. +1 −1  src/compiler/expression/parameter_expression.cpp
  27. +1 −1  src/compiler/expression/simple_function_call.cpp
  28. +1 −1  src/compiler/expression/unary_op_expression.cpp
  29. +2 −3 src/compiler/expression/user_attribute.cpp
  30. +2,668 −2,672 src/compiler/parser/hphp.tab.cpp
  31. +21 −4 src/compiler/statement/class_constant.cpp
  32. +42 −0 src/compiler/statement/statement_list.cpp
  33. +1 −0  src/compiler/statement/statement_list.h
  34. +2 −2 src/dirs.mk
  35. +18 −18 src/hphp/Makefile
  36. +6 −5 src/hphp/main.cpp
  37. +65 −80 src/idl/continuation.idl.php
  38. +19 −0 src/idl/misc.idl.php
  39. +37 −0 src/idl/sqlite3.idl.php
  40. +4 −14 src/runtime/base/array/array_data.cpp
  41. +29 −13 src/runtime/base/array/array_data.h
  42. +2 −6 src/runtime/base/array/array_init.cpp
  43. +3 −3 src/runtime/base/array/array_iterator.cpp
  44. +9 −9 src/runtime/base/array/array_iterator.h
  45. +409 −1,070 src/runtime/base/array/hphp_array.cpp
  46. +190 −229 src/runtime/base/array/hphp_array.h
  47. +73 −62 src/runtime/base/array/vector_array.cpp
  48. +3 −11 src/runtime/base/array/vector_array.h
  49. +66 −90 src/runtime/base/array/zend_array.cpp
  50. +56 −20 src/runtime/base/array/zend_array.h
  51. +24 −35 src/runtime/base/builtin_functions.cpp
  52. +19 −14 src/runtime/base/class_info.cpp
  53. +5 −5 src/runtime/base/class_info.h
  54. +1 −0  src/runtime/base/compiler_id.h
  55. +1 −0  src/runtime/base/complex_types.h
  56. +10 −0 src/runtime/base/execution_context.cpp
  57. +5 −4 src/runtime/base/execution_context.h
  58. +1 −51 src/runtime/base/frame_injection.cpp
  59. +4 −9 src/runtime/base/frame_injection.h
  60. +1 −24 src/runtime/base/global_array_wrapper.cpp
  61. +1 −8 src/runtime/base/global_array_wrapper.h
  62. +3 −23 src/runtime/base/hphp_system.cpp
  63. +0 −3  src/runtime/base/hphp_system.h
  64. +2 −2 src/runtime/base/hphp_value.h
  65. +1 −1  src/runtime/base/intercept.cpp
  66. +0 −6 src/runtime/base/macros.h
  67. +2 −2 src/runtime/base/md5.h
  68. +1 −0  src/runtime/base/memory/smart_allocator.core.inc
  69. +2 −0  src/runtime/base/memory/smart_allocator.cpp
  70. +37 −6 src/runtime/base/memory/smart_allocator.h
  71. +157 −164 src/runtime/base/object_data.cpp
  72. +40 −36 src/runtime/base/object_data.h
  73. +31 −43 src/runtime/base/program_functions.cpp
  74. +10 −13 src/runtime/{eval/ast/statement.cpp → base/ref_data.cpp}
  75. +71 −0 src/runtime/base/ref_data.h
  76. +14 −4 src/runtime/base/resource_data.cpp
  77. +11 −1 src/runtime/base/resource_data.h
  78. +2 −2 src/runtime/base/rtti_info.cpp
  79. +29 −15 src/runtime/base/runtime_option.cpp
  80. +11 −0 src/runtime/base/runtime_option.h
  81. +1 −0  src/runtime/base/server/admin_request_handler.cpp
  82. +1 −1  src/runtime/base/server/http_protocol.cpp
  83. +1 −1  src/runtime/base/server/http_request_handler.cpp
  84. +1 −0  src/runtime/base/server/server_stats.cpp
  85. +0 −4 src/runtime/base/shared/shared_map.h
  86. +239 −133 src/runtime/base/string_data.cpp
  87. +158 −45 src/runtime/base/string_data.h
  88. +3 −0  src/runtime/base/string_util.cpp
  89. +1 −4 src/runtime/base/thread_init_fini.cpp
  90. +6 −6 src/runtime/base/tv_helpers.cpp
  91. +54 −37 src/runtime/base/tv_helpers.h
  92. +17 −17 src/runtime/base/tv_macros.h
  93. +1 −1  src/runtime/base/type_array.cpp
  94. +0 −1  src/runtime/base/type_array.h
  95. +1 −1  src/runtime/base/type_conversions.h
  96. +29 −55 src/runtime/base/type_string.cpp
  97. +17 −0 src/runtime/base/type_string.h
  98. +106 −105 src/runtime/base/type_variant.cpp
  99. +70 −60 src/runtime/base/type_variant.h
  100. +5 −2 src/runtime/base/types.h
  101. +10 −2 src/runtime/base/util/string_buffer.cpp
  102. +4 −2 src/runtime/base/util/string_buffer.h
  103. +1 −1  src/runtime/base/variable_serializer.cpp
  104. +5 −0 src/runtime/base/zend/zend_string.cpp
  105. +0 −117 src/runtime/eval/analysis/block.cpp
  106. +0 −63 src/runtime/eval/analysis/block.h
  107. +0 −461 src/runtime/eval/ast/array_element_expression.cpp
  108. +0 −69 src/runtime/eval/ast/array_element_expression.h
  109. +0 −174 src/runtime/eval/ast/array_expression.cpp
  110. +0 −101 src/runtime/eval/ast/array_expression.h
  111. +0 −381 src/runtime/eval/ast/assignment_op_expression.cpp
  112. +0 −157 src/runtime/eval/ast/assignment_op_expression.h
  113. +0 −56 src/runtime/eval/ast/assignment_ref_expression.cpp
  114. +0 −46 src/runtime/eval/ast/assignment_ref_expression.h
  115. +0 −600 src/runtime/eval/ast/binary_op_expression.cpp
  116. +0 −99 src/runtime/eval/ast/binary_op_expression.h
  117. +0 −63 src/runtime/eval/ast/break_statement.cpp
  118. +0 −44 src/runtime/eval/ast/break_statement.h
  119. +0 −61 src/runtime/eval/ast/class_constant_expression.cpp
  120. +0 −46 src/runtime/eval/ast/class_constant_expression.h
  121. +0 −2,244 src/runtime/eval/ast/class_statement.cpp
  122. +0 −237 src/runtime/eval/ast/class_statement.h
  123. +0 −88 src/runtime/eval/ast/closure_expression.cpp
  124. +0 −47 src/runtime/eval/ast/closure_expression.h
  125. +0 −85 src/runtime/eval/ast/constant_expression.cpp
  126. +0 −45 src/runtime/eval/ast/constant_expression.h
  127. +0 −99 src/runtime/eval/ast/construct.cpp
  128. +0 −110 src/runtime/eval/ast/construct.h
  129. +0 −60 src/runtime/eval/ast/do_while_statement.cpp
  130. +0 −44 src/runtime/eval/ast/do_while_statement.h
  131. +0 −54 src/runtime/eval/ast/echo_statement.cpp
  132. +0 −43 src/runtime/eval/ast/echo_statement.h
  133. +0 −63 src/runtime/eval/ast/encaps_list_expression.cpp
  134. +0 −44 src/runtime/eval/ast/encaps_list_expression.h
  135. +0 −52 src/runtime/eval/ast/expr_statement.cpp
  136. +0 −43 src/runtime/eval/ast/expr_statement.h
  137. +0 −65 src/runtime/eval/ast/expression.cpp
  138. +0 −174 src/runtime/eval/ast/expression.h
  139. +0 −112 src/runtime/eval/ast/for_statement.cpp
  140. +0 −50 src/runtime/eval/ast/for_statement.h
  141. +0 −108 src/runtime/eval/ast/foreach_statement.cpp
  142. +0 −48 src/runtime/eval/ast/foreach_statement.h
  143. +0 −72 src/runtime/eval/ast/function_call_expression.cpp
  144. +0 −53 src/runtime/eval/ast/function_call_expression.h
  145. +0 −936 src/runtime/eval/ast/function_statement.cpp
  146. +0 −245 src/runtime/eval/ast/function_statement.h
  147. +0 −101 src/runtime/eval/ast/global_statement.cpp
  148. +0 −56 src/runtime/eval/ast/global_statement.h
  149. +0 −46 src/runtime/eval/ast/goto_statement.cpp
  150. +0 −42 src/runtime/eval/ast/goto_statement.h
  151. +0 −112 src/runtime/eval/ast/if_statement.cpp
  152. +0 −60 src/runtime/eval/ast/if_statement.h
  153. +0 −204 src/runtime/eval/ast/inc_op_expression.cpp
  154. +0 −91 src/runtime/eval/ast/inc_op_expression.h
  155. +0 −88 src/runtime/eval/ast/include_expression.cpp
  156. +0 −48 src/runtime/eval/ast/include_expression.h
  157. +0 −56 src/runtime/eval/ast/instanceof_expression.cpp
  158. +0 −44 src/runtime/eval/ast/instanceof_expression.h
  159. +0 −53 src/runtime/eval/ast/isset_expression.cpp
  160. +0 −42 src/runtime/eval/ast/isset_expression.h
  161. +0 −41 src/runtime/eval/ast/label_statement.cpp
  162. +0 −41 src/runtime/eval/ast/label_statement.h
  163. +0 −165 src/runtime/eval/ast/list_assignment_expression.cpp
  164. +0 −76 src/runtime/eval/ast/list_assignment_expression.h
  165. +0 −107 src/runtime/eval/ast/lval_expression.cpp
  166. +0 −53 src/runtime/eval/ast/lval_expression.h
  167. +0 −367 src/runtime/eval/ast/method_statement.cpp
  168. +0 −85 src/runtime/eval/ast/method_statement.h
  169. +0 −153 src/runtime/eval/ast/name.cpp
  170. +0 −111 src/runtime/eval/ast/name.h
  171. +0 −98 src/runtime/eval/ast/new_object_expression.cpp
  172. +0 −44 src/runtime/eval/ast/new_object_expression.h
  173. +0 −116 src/runtime/eval/ast/object_method_expression.cpp
  174. +0 −44 src/runtime/eval/ast/object_method_expression.h
  175. +0 −666 src/runtime/eval/ast/object_property_expression.cpp
  176. +0 −114 src/runtime/eval/ast/object_property_expression.h
  177. +0 −58 src/runtime/eval/ast/qop_expression.cpp
  178. +0 −45 src/runtime/eval/ast/qop_expression.h
  179. +0 −67 src/runtime/eval/ast/ref_param_expression.cpp
  180. +0 −48 src/runtime/eval/ast/ref_param_expression.h
  181. +0 −60 src/runtime/eval/ast/return_statement.cpp
  182. +0 −43 src/runtime/eval/ast/return_statement.h
  183. +0 −207 src/runtime/eval/ast/scalar_expression.cpp
  184. +0 −69 src/runtime/eval/ast/scalar_expression.h
  185. +0 −132 src/runtime/eval/ast/scalar_value_expression.cpp
  186. +0 −65 src/runtime/eval/ast/scalar_value_expression.h
  187. +0 −228 src/runtime/eval/ast/simple_function_call_expression.cpp
  188. +0 −90 src/runtime/eval/ast/simple_function_call_expression.h
  189. +0 −108 src/runtime/eval/ast/statement.h
  190. +0 −66 src/runtime/eval/ast/statement_list_statement.cpp
  191. +0 −48 src/runtime/eval/ast/statement_list_statement.h
  192. +0 −88 src/runtime/eval/ast/static_member_expression.cpp
  193. +0 −47 src/runtime/eval/ast/static_member_expression.h
  194. +0 −139 src/runtime/eval/ast/static_method_expression.cpp
  195. +0 −45 src/runtime/eval/ast/static_method_expression.h
  196. +0 −91 src/runtime/eval/ast/static_statement.cpp
  197. +0 −61 src/runtime/eval/ast/static_statement.h
  198. +0 −96 src/runtime/eval/ast/strong_foreach_statement.cpp
  199. +0 −49 src/runtime/eval/ast/strong_foreach_statement.h
  200. +0 −133 src/runtime/eval/ast/switch_statement.cpp
  201. +0 −63 src/runtime/eval/ast/switch_statement.h
  202. +0 −49 src/runtime/eval/ast/temp_expression.cpp
  203. +0 −59 src/runtime/eval/ast/temp_expression.h
  204. +0 −199 src/runtime/eval/ast/temp_expression_list.cpp
  205. +0 −130 src/runtime/eval/ast/temp_expression_list.h
  206. +0 −63 src/runtime/eval/ast/this_expression.cpp
  207. +0 −43 src/runtime/eval/ast/this_expression.h
  208. +0 −48 src/runtime/eval/ast/throw_statement.cpp
  209. +0 −43 src/runtime/eval/ast/throw_statement.h
  210. +0 −47 src/runtime/eval/ast/trait_alias_statement.cpp
  211. +0 −56 src/runtime/eval/ast/trait_alias_statement.h
  212. +0 −48 src/runtime/eval/ast/trait_prec_statement.cpp
  213. +0 −51 src/runtime/eval/ast/trait_prec_statement.h
  214. +0 −116 src/runtime/eval/ast/try_statement.cpp
  215. +0 −65 src/runtime/eval/ast/try_statement.h
  216. +0 −168 src/runtime/eval/ast/unary_op_expression.cpp
  217. +0 −50 src/runtime/eval/ast/unary_op_expression.h
  218. +0 −67 src/runtime/eval/ast/unset_statement.cpp
  219. +0 −44 src/runtime/eval/ast/unset_statement.h
  220. +0 −43 src/runtime/eval/ast/use_trait_statement.cpp
  221. +0 −49 src/runtime/eval/ast/use_trait_statement.h
  222. +0 −51 src/runtime/eval/ast/user_attribute.cpp
  223. +0 −46 src/runtime/eval/ast/user_attribute.h
  224. +0 −210 src/runtime/eval/ast/variable_expression.cpp
  225. +0 −105 src/runtime/eval/ast/variable_expression.h
  226. +0 −68 src/runtime/eval/ast/while_statement.cpp
  227. +0 −44 src/runtime/eval/ast/while_statement.h
  228. +0 −55 src/runtime/eval/base/ast_ptr.h
  229. +0 −42 src/runtime/eval/base/function.h
  230. +0 −2  src/runtime/eval/debugger/cmd/cmd_global.cpp
  231. +0 −2  src/runtime/eval/debugger/cmd/cmd_info.cpp
  232. +1 −7 src/runtime/eval/debugger/cmd/cmd_variable.cpp
  233. +1 −1  src/runtime/eval/debugger/debugger.cpp
  234. +1 −25 src/runtime/eval/debugger/debugger_proxy.cpp
  235. +21 −221 src/runtime/eval/eval.cpp
  236. +0 −38 src/runtime/eval/eval.h
  237. +0 −292 src/runtime/eval/ext/ext.cpp
  238. +0 −43 src/runtime/eval/ext/ext.h
Sorry, we could not display the entire diff because too many files (426) changed.
View
8 .gitignore
@@ -4,6 +4,7 @@
/bin*-O
/bin/*.so
/bin/hphp_options
+/bin/systemlib.php
.mkdir
hphp.log
@@ -23,6 +24,10 @@ hphp.log
/src/test/vm/perf/*.out
/src/test/vm/perf/*.diff
/src/test/vm/perf/*.perf
+/src/runtime/ext_hhvm/xconstants.php
+/src/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
+/src/runtime/ext_hhvm/ext_noinline.cpp
+*.ext_hhvm.cpp
/src/hphp/hphp
@@ -30,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
@@ -48,6 +54,8 @@ hphp.log
/bin/*.mk
!/bin/run.mk
+/facebook/arcanist/.phutil_module_cache
+
/facebook/autoload_files
/facebook/hotcold.hdf
/facebook/benchmark/shootout/output_bench
View
22 Makefile
@@ -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/joelp/dev2/hiphop-php
+CMAKE_SOURCE_DIR = /home/joelp/dev/hiphop-php
# The top-level build directory on which CMake was run.
-CMAKE_BINARY_DIR = /home/joelp/dev2/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/joelp/dev2/hiphop-php/CMakeFiles /home/joelp/dev2/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/joelp/dev2/hiphop-php/CMakeFiles 0
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/joelp/dev/hiphop-php/CMakeFiles 0
.PHONY : all
# The main clean target
@@ -228,19 +228,6 @@ 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.
@@ -285,7 +272,6 @@ help:
@echo "... sqlite3"
@echo "... timelib"
@echo "... hphp_analysis"
- @echo "... ext_hhvm_static"
@echo "... hphp"
@echo "... test"
.PHONY : help
View
41 doc/bytecode.specification
@@ -720,16 +720,19 @@ descriptors:
EC - consume a cell from the evaluation stack as an element
EL:<id> - consume a local given by an immediate id as an element
+ ET:<id> - consume a litstr given by an immediate id as an element
+ EI:<int>- consume a immediate integer as an element
PC - consume a cell from the evaluation stack as a property
- PL:<id> - consume a local given by an immediate id as an element
+ PL:<id> - consume a local given by an immediate id as a property
+ PT:<id> - consume a litstr given by an immediate id as a property
W - synthesize a new element (no corresponding local variable or
evaluation stack slot)
For example, the following correspondence exists (ignoring setup bytecode):
Source code: $a[3][$b][]['hi'] = 42;
- Bytecode: SetM <L:0 EC EL:1 W EC>
- Stack: [3 'hi' 42] -> [42]
+ Bytecode: SetM <L:0 EI:3 EL:1 W ET:hi>
+ Stack: [] -> [42]
Instructions that have an immediate argument vector have different stack
transition descriptions depending on the kind of location descriptor and member
@@ -923,14 +926,6 @@ Mod [C C] -> [C:Bool|Int]
Modulus (%). Pushes ((int)$2 % (int)$1) onto the stack. This instruction
never throws a fatal error.
-And [C C] -> [C:Bool]
-
- Logical and (and,&&). Pushes ((bool)$2 && (bool)$1) onto the stack.
-
-Or [C C] -> [C:Bool]
-
- Logical or (or,||). Pushes ((bool)$2 || (bool)$1) onto the stack.
-
Xor [C C] -> [C:Bool]
Logical xor (xor). Pushes ((bool)$2 xor (bool)$1) onto the stack.
@@ -1101,10 +1096,23 @@ JmpNZ <relative offset> [C] -> []
Jump if not zero. Conditionally transfers control to the location specified
by %1 if (bool)$1 != (bool)0.
-Switch <offset vector> [C:Int] -> []
+Switch <offset vector> <base> <bounded> [C] -> []
+
+ Switch over integer case values. If bounded == 0, the implementation will
+ assume that $1 is an integer in the range [0, length(vector)) and
+ unconditionally transfer control to the location specified by
+ vector[$1]. Undefined behavior will result if $1 is not an integer inside
+ this range. If bounded != 0, the following rules take over:
- $1 must be an integer in the range [0, vector length). Control will be
- unconditionally transferred to the location specified by vector[$1].
+ For a bounded Switch, the last two elements of the offset vector are special:
+ they represent the first non-zero case and the default case,
+ respectively. base + length(vector) - 2 must not be greater than 2^63-1. If
+ $1 === true, control will be transferred to the location specified by
+ vector[length(vector) - 2]. If $1 is equal (as defined by Eq) to any integer
+ $n in the range [base, base + length(vector) - 2), control will be
+ transferred to the location specified by vector[$n - base]. Otherwise,
+ control will be transferred to the location specified by
+ vector[length(vector) - 1].
RetC [C] -> []
RetV [V] -> []
@@ -2949,6 +2957,11 @@ member code to process all but the last member. Finally, perform a final
operation depending on member code to process the last member. See the
instruction-specific tables for details.
+The member codes that represent immediate literal data (ET, EI, PT) are
+implemented using the corresponding EC or PC intermediate operation: they
+behave exactly as though that literal data had been pushed on the stack as a
+cell, then consumed by an ElemC* or PropC* operation.
+
CGetM <loc-desc : M-vector> [C..C] -> [C]
Get member as cell.
View
18 doc/coding_guideline
@@ -21,15 +21,6 @@ Follow existing code when in doubt.
};
}}
-- Switch-cases indentations:
-
- switch (...) {
- case: {
- }
- default: {
- }
- }
-
- Function parameter indentations:
void foo(int param1,
@@ -55,14 +46,13 @@ Follow existing code when in doubt.
if (...)
one-liner;
-- When possible, fit one function into one screen-ful. Or, no long functions.
+- When possible, fit one function into one screen-full. Or, no long functions.
(5) Naming
- Class instance members start with "<b>m_</b>", unless trivial class/struct.
- Class static members start with "<b>s_</b>".
- Class instance methods use <b>camelCase</b>.
-- Class static methods start with <b>CapitalLetters</b>.
- Global functions use <b>small_underscore_small</b>() style.
- Enums start with <b>UpperCase</b>.
@@ -72,7 +62,6 @@ Follow existing code when in doubt.
- Try to keep one class one file, unless trivial classes or sub-classes.
- Try to keep class name consistent with file name so people can find them.
- Avoid function bodies in header files, unless absolutely necessary.
-- No point to have a virtual function body in header, as it's never inlined.
(7) Implementation Files
@@ -99,10 +88,7 @@ Since it doesn't depend on any other libraries, includes can use double-quotes:
(2) Core Runtime Library
runtime/base and runtime/eval depend on util/. Since there may be file name conflicts,
-ALWAYS use full include paths starting after src/. No double-quote include is
-allowed:
-
- #include &lt;runtime/base/exceptions.h&gt;
+ALWAYS use full include paths starting after src/.
(3) Extension Library
View
4,958 src/Makefile
1,561 additions, 3,397 deletions not shown
View
570 src/compiler/Makefile
285 additions, 285 deletions not shown
View
45 src/compiler/analysis/alias_manager.cpp
@@ -2261,9 +2261,10 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
if (!id) id = m_gidMap.size();
e->setCanonID(id);
}
- } else if ((context & Expression::ObjectContext) &&
- m_graph &&
- !sym->isReferenced()) {
+ } else if (m_graph &&
+ !sv->couldBeAliased() &&
+ sv->getActualType() &&
+ !Type::IsMappedToVariant(sv->getActualType())) {
m_objMap[sym->getName()] = sv;
}
if ((context & Expression::UnsetContext) &&
@@ -2480,6 +2481,7 @@ static void markAvailable(ExpressionRawPtr e) {
if (e->is(Expression::KindOfSimpleVariable)) {
SimpleVariableRawPtr sv(spc(SimpleVariable,e));
sv->setGuarded();
+ sv->setNonNull();
} else {
StaticClassName *scn = dynamic_cast<StaticClassName*>(e.get());
assert(scn);
@@ -3301,9 +3303,15 @@ class ConstructTagger : public ControlFlowGraphWalker {
bool set = true, cand = true;
SimpleVariablePtr sv;
if (e->is(Expression::KindOfSimpleVariable) &&
- (e->isThis() || !e->hasContext(Expression::ObjectContext))) {
+ (e->isThis() ||
+ !e->hasContext(Expression::ObjectContext) ||
+ e->getAssertedType())) {
sv = spc(SimpleVariable, e);
- cand = e->isThis() && e->hasContext(Expression::ObjectContext);
+ cand = (e->isThis() && e->hasContext(Expression::ObjectContext));
+ if (e->getAssertedType()) {
+ markAvailable(sv);
+ cand = true;
+ }
} else {
if (e->is(Expression::KindOfObjectMethodExpression)) {
ObjectMethodExpressionPtr om(spc(ObjectMethodExpression, e));
@@ -3323,12 +3331,19 @@ class ConstructTagger : public ControlFlowGraphWalker {
sv = spc(SimpleVariable, ae->getVariable());
}
}
- if (sv && (sv->isThis() || sv->couldBeAliased())) sv.reset();
+ if (sv && sv->isThis()) sv.reset();
}
- if (sv) {
+ if (sv && (!cand || !sv->couldBeAliased())) {
id = m_gidMap["v:" + sv->getName()];
if (id) {
- if (cand) {
+ if (sv->hasAllContext(Expression::Declaration) ||
+ sv->hasAllContext(Expression::UnsetContext|
+ Expression::LValue) ||
+ sv->hasAnyContext(Expression::AssignmentLHS|
+ Expression::OprLValue)) {
+ m_block->setBit(DataFlow::Available, id, false);
+ m_block->setBit(DataFlow::Altered, id, true);
+ } else if (cand) {
sv->setCanonID(id);
sv->clearAnticipated();
if (m_block->getBit(DataFlow::Available, id)) {
@@ -3338,17 +3353,10 @@ class ConstructTagger : public ControlFlowGraphWalker {
sv->setAnticipated();
}
if (set && !sv->hasAnyContext(Expression::ExistContext|
- Expression::UnsetContext)) {
+ Expression::UnsetContext)) {
m_block->setBit(DataFlow::Available, id, true);
}
}
- } else if (sv->hasAllContext(Expression::Declaration) ||
- sv->hasAllContext(Expression::UnsetContext|
- Expression::LValue) ||
- sv->hasAnyContext(Expression::AssignmentLHS|
- Expression::OprLValue)) {
- m_block->setBit(DataFlow::Available, id, false);
- m_block->setBit(DataFlow::Altered, id, true);
}
}
}
@@ -3605,11 +3613,6 @@ void AliasManager::finalSetup(AnalysisResultConstPtr ar, MethodStatementPtr m) {
m_objMap.begin(), end = m_objMap.end(); it != end; ++it) {
SimpleVariablePtr sv = it->second;
const Symbol *sym = sv->getSymbol();
- if (sym->isReferenced() ||
- !sym->getFinalType() ||
- !sym->getFinalType()->is(Type::KindOfObject)) {
- continue;
- }
int &id = m_gidMap["v:"+sym->getName()];
ASSERT(!id);
id = m_gidMap.size();
View
33 src/compiler/analysis/analysis_result.cpp
@@ -1328,6 +1328,7 @@ int DepthFirstVisitor<Pre, OptVisitor>::visitScope(BlockScopeRawPtr scope) {
if (MethodStatementPtr m =
dynamic_pointer_cast<MethodStatement>(stmt)) {
WriteLock lock(m->getFunctionScope()->getInlineMutex());
+ bool keepUseKindCaller = false;
do {
scope->clearUpdated();
if (Option::LocalCopyProp || Option::EliminateDeadCode) {
@@ -1339,10 +1340,20 @@ int DepthFirstVisitor<Pre, OptVisitor>::visitScope(BlockScopeRawPtr scope) {
StatementPtr rep = this->visitStmtRecur(stmt);
assert(!rep);
}
+ if (hhvm && Option::OutputHHBC) {
+ if (m->getFunctionScope()->inPseudoMain() &&
+ !m->getFunctionScope()->isMergeable()) {
+ if (m->getStmts()->markMergeable(this->m_data.m_ar)) {
+ all_updates |= BlockScope::UseKindCaller;
+ keepUseKindCaller = true;
+ }
+ }
+ }
updates = scope->getUpdated();
all_updates |= updates;
} while (updates);
if (all_updates & BlockScope::UseKindCaller &&
+ !keepUseKindCaller &&
!m->getFunctionScope()->getInlineAsExpr()) {
all_updates &= ~BlockScope::UseKindCaller;
}
@@ -2307,6 +2318,8 @@ class OutputJob {
: m_ar(ar), m_root(root), m_output(output), m_compileDir(compileDir) {
}
+ virtual ~OutputJob() {}
+
void output() {
outputImpl();
}
@@ -2952,15 +2965,11 @@ void AnalysisResult::outputArrayCreateImpl(CodeGenerator &cg) {
"}\n";
if (m_arrayLitstrKeyMaxSize > 0) {
cg_printf(text1,
- m_arrayLitstrKeyMaxSize + 1,
- m_arrayLitstrKeyMaxSize,
m_arrayLitstrKeyMaxSize + 1);
}
if (m_arrayIntegerKeyMaxSize > 0) {
cg_printf(text2,
m_arrayIntegerKeyMaxSize,
- m_arrayIntegerKeyMaxSize + 1,
- m_arrayIntegerKeyMaxSize,
m_arrayIntegerKeyMaxSize + 1);
}
}
@@ -3085,7 +3094,7 @@ void AnalysisResult::outputCPPHashTableInvokeFile(
" hashNodeFile *next;\n"
"};\n"
"static hashNodeFile *fileMapTable[%d];\n"
- "static hashNodeFile fileBuckets[%d];\n"
+ "static hashNodeFile fileBuckets[%zd];\n"
"\n"
"static class FileTableInitializer {\n"
" public: FileTableInitializer() {\n"
@@ -3240,7 +3249,7 @@ void AnalysisResult::outputCPPHashTableGetConstant(
" hashNodeCon *next;\n"
"};\n"
"static hashNodeCon *conMapTable[%d];\n"
- "static hashNodeCon conBuckets[%d];\n"
+ "static hashNodeCon conBuckets[%zd];\n"
"\n"
"void init_%sconstant_table() {\n%s"
" const char *conMapData[] = {\n";
@@ -3428,14 +3437,6 @@ void AnalysisResult::outputCPPDynamicConstantTable(
system ? "builtin_" : "");
cg.printDeclareGlobals();
- if (!system && Option::EnableEval == Option::FullEval) {
- // See if there's an eval'd version
- cg_indentBegin("{\n");
- cg_printf("Variant r;\n");
- cg_printf("if (eval_constant_hook(r, name)) return r;\n");
- cg_indentEnd("}\n");
- }
-
if (useHashTable) {
if (system) cg_printf("const char* s = name.data();\n");
cg_printf("const hashNodeCon *p = findCon(name.data(), name->hash());\n");
@@ -4419,7 +4420,7 @@ void AnalysisResult::outputCPPClassMap(CodeGenerator &cg) {
ASSERT(!func->isUserFunction());
func->outputCPPClassMap(cg, ar);
}
-
+
cg_printf("NULL,\n"); // methods
cg_printf("NULL,\n"); // properties
@@ -4470,7 +4471,7 @@ void AnalysisResult::outputCPPClassMap(CodeGenerator &cg) {
ConstantTablePtr constants = m_fileScopes[i]->getConstants();
constants->outputCPPClassMap(cg, ar, (i == (int)m_fileScopes.size() - 1));
}
-
+
cg_printf("NULL,\n"); // attributes
// system classes
View
53 src/compiler/analysis/class_scope.cpp
@@ -1194,7 +1194,7 @@ void ClassScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) {
// constants
m_constants->outputCPPClassMap(cg, ar);
-
+
// user attributes
UserAttributeMap::const_iterator it = m_userAttributes.begin();
for (; it != m_userAttributes.end(); ++it) {
@@ -1585,14 +1585,6 @@ void ClassScope::outputCPPClassVarInitImpl
cg_indentBegin("Variant get_class_var_init(CStrRef s, "
"const char *var) {\n");
- if (Option::EnableEval == Option::FullEval) {
- // See if there's an eval'd version
- cg_indentBegin("{\n");
- cg_printf("Variant r;\n");
- cg_printf("if (eval_get_class_var_init_hook(r, s, var)) "
- "return r;\n");
- cg_indentEnd("}\n");
- }
cg_printf("const ObjectStaticCallbacks *cwo = "
"get_%sobject_static_callbacks(s);\n"
"return LIKELY(cwo != 0) ? "
@@ -1644,16 +1636,6 @@ void ClassScope::outputCPPGetCallInfoStaticMethodImpl(
cg_indentBegin(
"bool get_call_info_static_method(MethodCallPackage &mcp) {\n");
- if (Option::EnableEval == Option::FullEval) {
- cg_printf("bool foundClass = false;\n");
- cg_printf("if (eval_get_call_info_static_method_hook(mcp, foundClass)) "
- "return true;\n");
- cg_indentBegin("else if (foundClass) {\n");
- cg_printf("mcp.fail();\n");
- cg_printf("return false;\n");
- cg_indentEnd("}\n");
- }
-
cg_printf("StringData *s ATTRIBUTE_UNUSED (mcp.rootCls);\n");
cg_printf("const ObjectStaticCallbacks *cwo = "
@@ -1674,14 +1656,6 @@ void ClassScope::outputCPPGetStaticPropertyImpl
cg_indentBegin("Variant get_static_property(CStrRef s, "
"const char *prop) {\n");
- if (Option::EnableEval == Option::FullEval) {
- // See if there's an eval'd version
- cg_indentBegin("{\n");
- cg_printf("Variant r;\n");
- cg_printf("if (eval_get_static_property_hook(r, s, prop)) "
- "return r;\n");
- cg_indentEnd("}\n");
- }
cg.printf("const ObjectStaticCallbacks * cwo = "
"get%s_object_static_callbacks(s);\n",
@@ -1692,14 +1666,6 @@ void ClassScope::outputCPPGetStaticPropertyImpl
cg_indentBegin("Variant *get_static_property_lv(CStrRef s, "
"const char *prop) {\n");
- if (Option::EnableEval == Option::FullEval) {
- // See if there's an eval'd version
- cg_indentBegin("{\n");
- cg_printf("Variant *r;\n");
- cg_printf("if (eval_get_static_property_lv_hook(r, s, prop)) "
- "return r;\n");
- cg_indentEnd("}\n");
- }
cg.printf("const ObjectStaticCallbacks * cwo = "
"get%s_object_static_callbacks(s);\n",
@@ -2077,7 +2043,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
ExpressionPtr val = getSymInit(sym);
string name, cls, id;
int flags = 0;
- int type = 0;
+ DataType type = KindOfUnknown;
if (!val) {
if (sym->isConstant()) {
name = sym->getName();
@@ -2102,7 +2068,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
}
int *p;
int name_ix = -1, cls_ix = -1;
- if ((flags & ConstNeedsSysCon) && type != KindOfVariant) {
+ if ((flags & ConstNeedsSysCon) && type != KindOfUnknown) {
string n = cls + "$$" + name;
p = &siIndex[n];
if (!*p) {
@@ -2187,8 +2153,8 @@ void ClassScope::outputCPPGetClassPropTableImpl(
Option::ClassPropTablePrefix, svarIndex[id] - 1);
}
}
- } else if ((flags & ConstNeedsSysCon) && type != KindOfVariant) {
- cg_printf("0x%08x%07x7", name_ix, type);
+ } else if ((flags & ConstNeedsSysCon) && type != KindOfUnknown) {
+ cg_printf("0x%08x%07x7", name_ix, int(type));
} else if (flags & ConstMagicIO) {
cg_printf("(int64)&BuiltinFiles::Get%s, 0x1%07x6",
name.c_str(), index++);
@@ -2272,12 +2238,12 @@ void ClassScope::outputCPPGetClassPropTableImpl(
string prop(sym->getName());
int flags = 0;
- int dtype = sym->getFinalType()->getDataType();
+ DataType ptype = sym->getFinalType()->getDataType();
if (sym->isStatic()) {
flags |= ClassPropTableEntry::Static;
if (v[k].privIndex < 0) {
bool needsInit = true;
- switch (dtype) {
+ switch (ptype) {
case KindOfBoolean:
if (cflags & ConstFalse) needsInit = false;
goto check_plain;
@@ -2288,10 +2254,9 @@ void ClassScope::outputCPPGetClassPropTableImpl(
if (cflags & ConstDZero) needsInit = false;
goto check_plain;
case KindOfString:
- case KindOfStaticString:
case KindOfArray:
if (cflags & ConstNull) needsInit = false;
- case KindOfVariant:
+ case KindOfUnknown:
check_plain:
if (cflags & ConstPlain && !system) {
flags |= ClassPropTableEntry::FastInit;
@@ -2335,7 +2300,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
sym->getName().size()),
next - cur, off,
int(s ? 0 : prop.size() - sym->getName().size()),
- flags, dtype);
+ flags, int(ptype));
if (s) {
if (s == 2 && !sym->isDynamic()) {
cg_printf("0,");
View
5 src/compiler/analysis/control_flow.h
@@ -17,8 +17,8 @@
#ifndef __CONTROL_FLOW_H__
#define __CONTROL_FLOW_H__
-#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
+#include <boost/graph/adjacency_iterator.hpp>
#include <compiler/hphp.h>
@@ -311,6 +311,9 @@ inline void put(vertex_color_t c,
///////////////////////////////////////////////////////////////////////////////
}
+// This needs to come after the definitions of 'out_degree', 'out_edges', etc.
+#include <boost/graph/adjacency_list.hpp>
+
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
View
669 src/compiler/analysis/emitter.cpp
@@ -25,6 +25,7 @@
#include <runtime/vm/as.h>
#include <runtime/base/runtime_option.h>
#include <runtime/base/zend/zend_string.h>
+#include <runtime/base/type_conversions.h>
#include <runtime/eval/runtime/file_repository.h>
#include <compiler/builtin_symbols.h>
@@ -64,6 +65,7 @@
#include <compiler/statement/class_variable.h>
#include <compiler/statement/do_statement.h>
#include <compiler/statement/echo_statement.h>
+#include <compiler/statement/exp_statement.h>
#include <compiler/statement/for_statement.h>
#include <compiler/statement/foreach_statement.h>
#include <compiler/statement/function_statement.h>
@@ -111,6 +113,8 @@ namespace StackSym {
static const char R = 0x04; // Return value symbolic flavor
static const char F = 0x05; // Function argument symbolic flavor
static const char L = 0x06; // Local symbolic flavor
+ static const char T = 0x07; // String literal symbolic flavor
+ static const char I = 0x08; // int literal symbolic flavor
static const char N = 0x10; // Name marker
static const char G = 0x20; // Global name marker
@@ -145,6 +149,8 @@ namespace StackSym {
case StackSym::R: res = "R"; break;
case StackSym::F: res = "F"; break;
case StackSym::L: res = "L"; break;
+ case StackSym::T: res = "T"; break;
+ case StackSym::I: res = "I"; break;
default: break;
}
char marker = StackSym::GetMarker(sym);
@@ -195,10 +201,6 @@ class FuncFinisher {
TRACE(1, "Finishing func: %s %p\n", m_fe->name()->data(), m_fe);
m_ev->finishFunc(m_e, m_fe);
}
-
- void setIsMergeOnlyCandidate() {
- m_fe->setIsMergeOnlyCandidate();
- }
};
// RAII guard for temporarily overriding an Emitter's location
@@ -235,12 +237,12 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
}
// Count each of the members; MEC and MPC account for one value on
- // the stack, while MW/MEL/MPL don't account for any values on the
- // stack.
+ // the stack, while MW/MEL/MPL/MET/MPT/MEI don't account for any
+ // values on the stack.
while (vec - &immVec[0] < int(immVec.size())) {
MemberCode code = MemberCode(*vec++);
if (memberCodeHasImm(code)) {
- decodeVariableSizeImm(&vec);
+ decodeMemberCodeImm(&vec, code);
} else if (code != MW) {
++count;
}
@@ -273,7 +275,7 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
DEC_##t1 a1, DEC_##t2 a2, DEC_##t3 a3
#define NA
#define DEC_MA std::vector<uchar>
-#define DEC_ILA std::vector<Label*>&
+#define DEC_BLA std::vector<Label*>&
#define DEC_IVA int32
#define DEC_HA int32
#define DEC_IA int32
@@ -286,14 +288,14 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
#define POP_NOV
#define POP_ONE(t) \
- POP_##t
+ POP_##t(0)
#define POP_TWO(t1, t2) \
- POP_##t1; \
- POP_##t2
+ POP_##t1(0); \
+ POP_##t2(1)
#define POP_THREE(t1, t2, t3) \
- POP_##t1; \
- POP_##t2; \
- POP_##t3
+ POP_##t1(0); \
+ POP_##t2(1); \
+ POP_##t3(2)
#define POP_LMANY() \
getEmitterVisitor().popEvalStackLMany()
#define POP_C_LMANY() \
@@ -305,37 +307,37 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
#define POP_FMANY \
getEmitterVisitor().popEvalStackFMany(a1) \
-#define POP_CV getEmitterVisitor().popEvalStack(StackSym::C)
-#define POP_VV getEmitterVisitor().popEvalStack(StackSym::V)
-#define POP_AV getEmitterVisitor().popEvalStack(StackSym::A)
-#define POP_RV getEmitterVisitor().popEvalStack(StackSym::R)
-#define POP_FV getEmitterVisitor().popEvalStack(StackSym::F)
+#define POP_CV(i) getEmitterVisitor().popEvalStack(StackSym::C, i, curPos)
+#define POP_VV(i) getEmitterVisitor().popEvalStack(StackSym::V, i, curPos)
+#define POP_AV(i) getEmitterVisitor().popEvalStack(StackSym::A, i, curPos)
+#define POP_RV(i) getEmitterVisitor().popEvalStack(StackSym::R, i, curPos)
+#define POP_FV(i) getEmitterVisitor().popEvalStack(StackSym::F, i, curPos)
// Pop of virtual "locs" on the stack that turn into immediates.
#define POP_HA_ONE(t) \
- POP_HA_##t
+ POP_HA_##t(0)
#define POP_HA_TWO(t1, t2) \
- POP_HA_##t1 \
- POP_HA_##t2
+ POP_HA_##t1(0) \
+ POP_HA_##t2(1)
#define POP_HA_THREE(t1, t2, t3) \
- POP_HA_##t1 \
- POP_HA_##t2 \
- POP_HA_##t3
+ POP_HA_##t1(0) \
+ POP_HA_##t2(1) \
+ POP_HA_##t3(2)
#define POP_HA_NA
-#define POP_HA_MA
-#define POP_HA_ILA
-#define POP_HA_IVA
-#define POP_HA_IA
-#define POP_HA_I64A
-#define POP_HA_DA
-#define POP_HA_SA
-#define POP_HA_AA
-#define POP_HA_BA
-#define POP_HA_OA
-
-#define POP_HA_HA \
- getEmitterVisitor().popSymbolicLocal(opcode)
+#define POP_HA_MA(i)
+#define POP_HA_BLA(i)
+#define POP_HA_IVA(i)
+#define POP_HA_IA(i)
+#define POP_HA_I64A(i)
+#define POP_HA_DA(i)
+#define POP_HA_SA(i)
+#define POP_HA_AA(i)
+#define POP_HA_BA(i)
+#define POP_HA_OA(i)
+
+#define POP_HA_HA(i) \
+ getEmitterVisitor().popSymbolicLocal(opcode, i, curPos)
#define PUSH_NOV
#define PUSH_ONE(t) \
@@ -386,15 +388,15 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
#define IMPL2_MA IMPL_MA(a2)
#define IMPL3_MA IMPL_MA(a3)
-#define IMPL_ILA(var) do { \
+#define IMPL_BLA(var) do { \
getUnitEmitter().emitInt32(var.size()); \
for (unsigned int i = 0; i < var.size(); ++i) { \
IMPL_BA(*var[i]); \
} \
} while (0)
-#define IMPL1_ILA IMPL_ILA(a1)
-#define IMPL2_ILA IMPL_ILA(a2)
-#define IMPL3_ILA IMPL_ILA(a3)
+#define IMPL1_BLA IMPL_BLA(a1)
+#define IMPL2_BLA IMPL_BLA(a2)
+#define IMPL3_BLA IMPL_BLA(a3)
#define IMPL_IVA(var) do { \
getUnitEmitter().emitIVA(var); \
@@ -516,10 +518,10 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
#undef IMPL1_MA
#undef IMPL2_MA
#undef IMPL3_MA
-#undef IMPL_ILA
-#undef IMPL1_ILA
-#undef IMPL2_ILA
-#undef IMPL3_ILA
+#undef IMPL_BLA
+#undef IMPL1_BLA
+#undef IMPL2_BLA
+#undef IMPL3_BLA
#undef IMPL_IVA
#undef IMPL1_IVA
#undef IMPL2_IVA
@@ -566,9 +568,11 @@ static void checkJmpTargetEvalStack(const SymbolicStack& source,
}
for (unsigned int i = 0; i < source.size(); ++i) {
+ char flavor = StackSym::GetSymFlavor(source.get(i));
bool matches = source.get(i) == dest.get(i) &&
- (StackSym::GetSymFlavor(source.get(i)) != StackSym::L ||
- source.getLoc(i) == dest.getLoc(i));
+ (flavor != StackSym::L || source.getLoc(i) == dest.getLoc(i)) &&
+ (flavor != StackSym::T || source.getName(i) == dest.getName(i)) &&
+ (flavor != StackSym::I || source.getInt(i) == dest.getInt(i));
if (!matches) {
Logger::Warning("Emitter detected a point in the bytecode where the "
"symbolic flavor of a slot on the stack is not the same "
@@ -593,8 +597,11 @@ std::string SymbolicStack::pretty() const {
out << "*";
}
out << StackSym::ToString(m_symStack[i].sym);
- if (StackSym::GetSymFlavor(m_symStack[i].sym) == StackSym::L) {
- out << ":" << m_symStack[i].loc;
+ char flavor = StackSym::GetSymFlavor(m_symStack[i].sym);
+ if (flavor == StackSym::L || flavor == StackSym::I) {
+ out << ":" << m_symStack[i].intval;
+ } else if (flavor == StackSym::T) {
+ out << ":" << m_symStack[i].metaData.name->data();
}
out << ' ';
}
@@ -602,7 +609,8 @@ std::string SymbolicStack::pretty() const {
}
void SymbolicStack::push(char sym) {
- if (sym != StackSym::W && sym != StackSym::K && sym != StackSym::L) {
+ if (sym != StackSym::W && sym != StackSym::K && sym != StackSym::L &&
+ sym != StackSym::T && sym != StackSym::I) {
m_actualStack.push_back(m_symStack.size());
*m_actualStackHighWaterPtr = MAX(*m_actualStackHighWaterPtr,
(int)m_actualStack.size());
@@ -614,8 +622,9 @@ void SymbolicStack::pop() {
// TODO(drew): ASSERT eval stack unknown is false?
ASSERT(!m_symStack.empty());
char sym = m_symStack.back().sym;
+ char flavor = StackSym::GetSymFlavor(sym);
if (StackSym::GetMarker(sym) != StackSym::W &&
- StackSym::GetSymFlavor(sym) != StackSym::L) {
+ flavor != StackSym::L && flavor != StackSym::T && flavor != StackSym::I) {
ASSERT(!m_actualStack.empty());
m_actualStack.pop_back();
}
@@ -634,34 +643,105 @@ char SymbolicStack::get(int index) const {
const StringData* SymbolicStack::getName(int index) const {
ASSERT(index >= 0 && index < (int)m_symStack.size());
- return m_symStack[index].name;
+ if (m_symStack[index].metaType == META_CLASS ||
+ m_symStack[index].metaType == META_CLASS_NON_NULL ||
+ m_symStack[index].metaType == META_LITSTR) {
+ return m_symStack[index].metaData.name;
+ }
+ return NULL;
}
bool SymbolicStack::isCls(int index) const {
ASSERT(index >= 0 && index < (int)m_symStack.size());
- return m_symStack[index].cls;
+ return m_symStack[index].metaType == META_CLASS ||
+ m_symStack[index].metaType == META_CLASS_NON_NULL;
}
void SymbolicStack::setString(const StringData* s) {
ASSERT(m_symStack.size());
- m_symStack.back().name = s;
- m_symStack.back().cls = false;
+ SymEntry& se = m_symStack.back();
+ if (se.metaType == META_LITSTR) {
+ ASSERT(se.metaData.name == s);
+ } else {
+ ASSERT(se.metaType == META_NONE);
+ }
+ se.metaData.name = s;
+ se.metaType = META_LITSTR;
+}
+
+void SymbolicStack::setKnownCls(const StringData* s, bool nonNull) {
+ ASSERT(m_symStack.size());
+ SymEntry& se = m_symStack.back();
+ if (se.metaType == META_CLASS_NON_NULL) {
+ ASSERT(se.metaData.name == s);
+ nonNull = true;
+ } else if (se.metaType == META_DATA_TYPE) {
+ ASSERT(se.metaData.dt == KindOfObject);
+ nonNull = true;
+ } else if (se.metaType == META_CLASS) {
+ ASSERT(se.metaData.name == s);
+ } else {
+ ASSERT(se.metaType == META_NONE);
+ }
+ se.metaData.name = s;
+ se.metaType = nonNull ? META_CLASS_NON_NULL : META_CLASS;
}
-void SymbolicStack::setCls(const StringData* s) {
+void SymbolicStack::setNotRef() {
ASSERT(m_symStack.size());
- m_symStack.back().name = s;
- m_symStack.back().cls = true;
+ SymEntry& se = m_symStack.back();
+ se.notRef = true;
}
-void SymbolicStack::setClsBaseType(ClassBaseType type) {
- ASSERT(!m_symStack.empty());
- m_symStack.back().clsBaseType = type;
+bool SymbolicStack::getNotRef() const {
+ ASSERT(m_symStack.size());
+ const SymEntry& se = m_symStack.back();
+ return se.notRef;
+}
+
+void SymbolicStack::setInt(int64 v) {
+ ASSERT(m_symStack.size());
+ m_symStack.back().intval = v;
+}
+
+void SymbolicStack::setKnownType(DataType dt) {
+ ASSERT(m_symStack.size());
+ SymEntry& se = m_symStack.back();
+ if (se.metaType == META_CLASS_NON_NULL ||
+ se.metaType == META_CLASS) {
+ ASSERT(dt == KindOfObject);
+ se.metaType = META_CLASS_NON_NULL;
+ } else {
+ ASSERT(se.metaType == META_NONE);
+ se.metaType = META_DATA_TYPE;
+ se.metaData.dt = dt;
+ }
+}
+
+DataType SymbolicStack::getKnownType(int index, bool noRef) const {
+ if (index < 0) index += m_symStack.size();
+ ASSERT((unsigned)index < m_symStack.size());
+ const SymEntry& se = m_symStack[index];
+ if (!noRef || se.notRef) {
+ if (se.metaType == META_CLASS_NON_NULL) {
+ return KindOfObject;
+ } else if (se.metaType == META_DATA_TYPE) {
+ return se.metaData.dt;
+ }
+ }
+ return KindOfUnknown;
+}
+
+void SymbolicStack::cleanTopMeta() {
+ SymEntry& se = m_symStack.back();
+ se.clsBaseType = CLS_INVALID;
+ se.metaType = META_NONE;
+ se.notRef = false;
}
-void SymbolicStack::setLocal(int localId) {
+void SymbolicStack::setClsBaseType(ClassBaseType type) {
ASSERT(!m_symStack.empty());
- m_symStack.back().loc = localId;
+ m_symStack.back().clsBaseType = type;
}
void SymbolicStack::setUnnamedLocal(int index,
@@ -670,7 +750,7 @@ void SymbolicStack::setUnnamedLocal(int index,
ASSERT(size_t(index) < m_symStack.size());
ASSERT(m_symStack[index].sym == StackSym::K);
ASSERT(m_symStack[index].clsBaseType == CLS_UNNAMED_LOCAL);
- m_symStack[index].loc = localId;
+ m_symStack[index].intval = localId;
m_symStack[index].unnamedLocalStart = startOff;
}
@@ -756,8 +836,14 @@ int SymbolicStack::getLoc(int index) const {
ASSERT(StackSym::GetSymFlavor(m_symStack[index].sym) == StackSym::L ||
m_symStack[index].clsBaseType == CLS_NAMED_LOCAL ||
m_symStack[index].clsBaseType == CLS_UNNAMED_LOCAL);
- ASSERT(m_symStack[index].loc != -1);
- return m_symStack[index].loc;
+ ASSERT(m_symStack[index].intval != -1);
+ return m_symStack[index].intval;
+}
+
+int64 SymbolicStack::getInt(int index) const {
+ ASSERT(m_symStack.size() > size_t(index));
+ ASSERT(StackSym::GetSymFlavor(m_symStack[index].sym) == StackSym::I);
+ return m_symStack[index].intval;
}
Offset SymbolicStack::getUnnamedLocStart(int index) const {
@@ -770,7 +856,7 @@ Offset SymbolicStack::getUnnamedLocStart(int index) const {
// Insert an element in the actual stack at the specified depth of the
// actual stack.
void SymbolicStack::insertAt(int depth, char sym) {
- ASSERT(size_t(depth) <= sizeActual() && depth > 0);
+ ASSERT(depth <= sizeActual() && depth > 0);
int virtIdx = m_actualStack[sizeActual() - depth];
m_symStack.insert(m_symStack.begin() + virtIdx, SymEntry(sym));
@@ -872,6 +958,14 @@ struct FPIRegionRecorder {
//=============================================================================
// EmitterVisitor.
+void EmitterVisitor::addMetaInfo(int pos, Unit::MetaInfo::Kind kind,
+ bool mVector, int arg, Id data) {
+ ASSERT(arg >= 0);
+ if (arg > 127) return;
+ if (mVector) arg |= Unit::MetaInfo::VectorArg;
+ m_metaMap[pos].push_back(Unit::MetaInfo(kind, arg, data));
+}
+
static StringData* continuationClassName(const StringData* fname) {
std::ostringstream str;
str << "continuation$" << fname->data();
@@ -917,7 +1011,7 @@ void EmitterVisitor::unexpectedStackSym(char sym, const char* where) const {
m_ue.bcPos());
}
-void EmitterVisitor::popEvalStack(char expected) {
+void EmitterVisitor::popEvalStack(char expected, int arg, int pos) {
// Pop a value off of the evaluation stack, and verify that it
// matches the specified symbolic flavor
if (m_evalStack.size() == 0) {
@@ -928,6 +1022,14 @@ void EmitterVisitor::popEvalStack(char expected) {
m_ue.bcPos());
return;
}
+
+ if (arg >= 0 && pos >= 0 && expected == StackSym::C) {
+ DataType dt = m_evalStack.getKnownType();
+ if (dt != KindOfUnknown) {
+ addMetaInfo(pos, Unit::MetaInfo::DataType, false, arg, dt);
+ }
+ }
+
char sym = m_evalStack.top();
char actual = StackSym::GetSymFlavor(sym);
m_evalStack.pop();
@@ -944,7 +1046,7 @@ void EmitterVisitor::popEvalStack(char expected) {
}
}
-void EmitterVisitor::popSymbolicLocal(Opcode op) {
+void EmitterVisitor::popSymbolicLocal(Opcode op, int arg, int pos) {
// Special case for instructions that consume the loc below the
// top.
int belowTop = -1;
@@ -964,6 +1066,12 @@ void EmitterVisitor::popSymbolicLocal(Opcode op) {
}
m_evalStack.consumeBelowTop(belowTop - 1);
} else {
+ if (arg >= 0 && pos >= 0) {
+ DataType dt = m_evalStack.getKnownType();
+ if (dt != KindOfUnknown) {
+ addMetaInfo(pos, Unit::MetaInfo::DataType, false, arg, dt);
+ }
+ }
popEvalStack(StackSym::L);
}
}
@@ -974,13 +1082,14 @@ void EmitterVisitor::popEvalStackLMany() {
char symFlavor = StackSym::GetSymFlavor(sym);
char marker = StackSym::GetMarker(sym);
if (marker == StackSym::E || marker == StackSym::P) {
- if (symFlavor != StackSym::C && symFlavor != StackSym::L) {
+ if (symFlavor != StackSym::C && symFlavor != StackSym::L &&
+ symFlavor != StackSym::T && symFlavor != StackSym::I) {
InvariantViolation(
"Emitter emitted an instruction that tries to consume "
"a value from the stack when the top of the stack "
"does not match the symbolic flavor that the instruction "
- "expects (expected symbolic flavor \"C\" or \"L\", actual "
- "symbolic flavor \"%s\" at offset %d)",
+ "expects (expected symbolic flavor \"C\", \"L\", \"T\", or \"I\", "
+ "actual symbolic flavor \"%s\" at offset %d)",
StackSym::ToString(symFlavor).c_str(),
m_ue.bcPos());
}
@@ -1292,6 +1401,8 @@ void EmitterVisitor::visit(FileScopePtr file) {
// 0 through k-1, while any unnamed local variable will have an id >= k.
assignLocalVariableIds(func);
+ AnalysisResultPtr ar(file->getContainingProgram());
+ ASSERT(ar);
MethodStatementPtr m(dynamic_pointer_cast<MethodStatement>(func->getStmt()));
if (!m) return;
StatementListPtr stmts(m->getStmts());
@@ -1330,7 +1441,10 @@ void EmitterVisitor::visit(FileScopePtr file) {
e.InitThisLoc(thisId);
}
FuncFinisher ff(this, e, m_curFunc);
- bool mergeOnlyCandidate = true;
+ TypedValue mainReturn;
+ mainReturn.m_type = KindOfInvalid;
+ bool notMergeOnly = false;
+ PreClass::Hoistable allHoistable = PreClass::AlwaysHoistable;
for (i = 0; i < nk; i++) {
StatementPtr s = (*stmts)[i];
switch (s->getKindOf()) {
@@ -1342,17 +1456,66 @@ void EmitterVisitor::visit(FileScopePtr file) {
// Handle classes directly here, since only top-level classes are
// hoistable.
ClassScopePtr cNode = s->getClassScope();
- if (!emitClass(e, cNode, true)) {
- mergeOnlyCandidate = false;
+ PreClass::Hoistable h = emitClass(e, cNode, true);
+ if (h < allHoistable) allHoistable = h;
+ break;
+ }
+ case Statement::KindOfReturnStatement: {
+ ReturnStatementPtr r(static_pointer_cast<ReturnStatement>(s));
+ Variant v(Variant::nullInit);
+ if (r->getRetExp() &&
+ (!r->getRetExp()->getScalarValue(v) ||
+ v.isArray())) {
+ TV_WRITE_UNINIT(&mainReturn);
+ goto fail;
+ }
+ if (mainReturn.m_type == KindOfInvalid ||
+ v.same(tvAsVariant(&mainReturn))) {
+ mainReturn = *v.getTypedAccessor();
+ } else {
+ TV_WRITE_UNINIT(&mainReturn);
}
break;
}
- default:
- mergeOnlyCandidate = false;
+ case Statement::KindOfExpStatement: {
+ ExpressionPtr e =
+ static_pointer_cast<ExpStatement>(s)->getExpression();
+ switch (e->getKindOf()) {
+ case Expression::KindOfIncludeExpression: {
+ IncludeExpressionPtr inc =
+ static_pointer_cast<IncludeExpression>(e);
+ if (FileScopeRawPtr f = inc->getIncludedFile(ar)) {
+ if (StatementListPtr sl = f->getStmt()) {
+ FunctionScopeRawPtr ps = sl->getFunctionScope();
+ ASSERT(ps && ps->inPseudoMain());
+ if (false && ps->isMergeable()) {
+ /*
+ * TODO: implement the code to deal with this
+ * case in Unit::merge, and then enable it
+ */
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } // fall through
+ default: fail:
+ notMergeOnly = true;
visit(s);
}
}
- if (mergeOnlyCandidate) ff.setIsMergeOnlyCandidate();
+ if (mainReturn.m_type == KindOfInvalid) {
+ TV_WRITE_UNINIT(&mainReturn);
+ tvAsVariant(&mainReturn) = 1;
+ }
+ // Use _count as a flag for VMExecutionContext::evalUnit
+ // since its otherwise unused
+ mainReturn._count = !notMergeOnly;
+ m_ue.setMainReturn(&mainReturn);
// If the exitHnd label was used, we need to emit some extra code
// to handle stray breaks
Label exit;
@@ -1429,7 +1592,11 @@ void EmitterVisitor::fixReturnType(Emitter& e, FunctionCallPtr fn) {
FunctionScope::GetFunctionInfo(fn->getName());
if (!fi || !fi->getMaybeRefReturn()) ref = false;
}
- if (ref >= 0) {
+ if (ref >= 0 &&
+ (!ref || !fn->hasAnyContext(Expression::AccessContext |
+ Expression::ObjectContext))) {
+ /* we dont support V in M-vectors, so leave it as an R in that
+ case */
ASSERT(m_evalStack.get(m_evalStack.size() - 1) == StackSym::R);
Offset cur = m_ue.bcPos();
if (ref) {
@@ -1437,8 +1604,7 @@ void EmitterVisitor::fixReturnType(Emitter& e, FunctionCallPtr fn) {
} else {
e.UnboxR();
}
- m_metaMap[cur].push_back(
- Unit::MetaInfo(Unit::MetaInfo::NopOut, -1, 0));
+ addMetaInfo(cur, Unit::MetaInfo::NopOut, false, 0, 0);
}
}
@@ -1450,6 +1616,28 @@ void EmitterVisitor::visitKids(ConstructPtr c) {
}
bool EmitterVisitor::visit(ConstructPtr node) {
+ bool ret = visitImpl(node);
+ if (!Option::WholeProgram || !ret || !node->isNonNull()) return ret;
+ ExpressionPtr e = boost::dynamic_pointer_cast<Expression>(node);
+ if (!e || e->isScalar()) return ret;
+ TypePtr act = e->getActualType();
+ if (!act) return ret;
+ DataType dt = act->getDataType();
+ if (dt == KindOfUnknown) return ret;
+ char sym = m_evalStack.top();
+ if (StackSym::GetMarker(sym)) return ret;
+ switch (StackSym::GetSymFlavor(sym)) {
+ case StackSym::C:
+ m_evalStack.setNotRef();
+ case StackSym::L:
+ m_evalStack.setKnownType(dt);
+ break;
+ }
+
+ return ret;
+}
+
+bool EmitterVisitor::visitImpl(ConstructPtr node) {
if (!node) return false;
Emitter e(node, m_ue, *this);
@@ -1792,48 +1980,50 @@ bool EmitterVisitor::visit(ConstructPtr node) {
emitContinuationSwitch(e, sw);
return false;
}
- if (!simpleSubject) {
- // Evaluate the subject once and stash it in a local
- tempLocal = m_curFunc->allocUnnamedLocal();
- emitVirtualLocal(tempLocal);
- visit(subject);
- emitConvertToCell(e);
- emitSet(e);
- emitPop(e);
- start = m_ue.bcPos();
- }
+ bool didIntSwitch = emitIntegerSwitch(e, sw, caseLabels, done);
+ if (!didIntSwitch) {
+ if (!simpleSubject) {
+ // Evaluate the subject once and stash it in a local
+ tempLocal = m_curFunc->allocUnnamedLocal();
+ emitVirtualLocal(tempLocal);
+ visit(subject);
+ emitConvertToCell(e);
+ emitSet(e);
+ emitPop(e);
+ start = m_ue.bcPos();
+ }
- int defI = -1;
- uint i = 0;
- for (i = 0; i < ncase; i++) {
- CaseStatementPtr c(static_pointer_cast<CaseStatement>((*cases)[i]));
- if (c->getCondition()) {
- if (simpleSubject) {
- // Evaluate the subject every time.
- visit(subject);
- emitConvertToCellOrLoc(e);
- visit(c->getCondition());
- emitConvertToCell(e);
- emitConvertSecondToCell(e);
+ int defI = -1;
+ for (uint i = 0; i < ncase; i++) {
+ CaseStatementPtr c(static_pointer_cast<CaseStatement>((*cases)[i]));
+ if (c->getCondition()) {
+ if (simpleSubject) {
+ // Evaluate the subject every time.
+ visit(subject);
+ emitConvertToCellOrLoc(e);
+ visit(c->getCondition());
+ emitConvertToCell(e);
+ emitConvertSecondToCell(e);
+ } else {
+ emitVirtualLocal(tempLocal);
+ emitCGet(e);
+ visit(c->getCondition());
+ emitConvertToCell(e);
+ }
+ e.Eq();
+ e.JmpNZ(caseLabels[i]);
} else {
- emitVirtualLocal(tempLocal);
- emitCGet(e);
- visit(c->getCondition());
- emitConvertToCell(e);
+ // Default clause. The last one wins.
+ defI = i;
}
- e.Eq();
- e.JmpNZ(caseLabels[i]);
+ }
+ if (defI != -1) {
+ e.Jmp(caseLabels[defI]);
} else {
- // Default clause. The last one wins.
- defI = i;
+ e.Jmp(done);
}
}
- if (defI != -1) {
- e.Jmp(caseLabels[defI]);
- } else {
- e.Jmp(done);
- }
- for (i = 0; i < ncase; i++) {
+ for (uint i = 0; i < ncase; i++) {
caseLabels[i].set(e);
CaseStatementPtr c(static_pointer_cast<CaseStatement>((*cases)[i]));
CONTROL_BODY(done, done, brkHand, cntHand);
@@ -1844,7 +2034,7 @@ bool EmitterVisitor::visit(ConstructPtr node) {
emitBreakHandler(e, done, done, brkHand, cntHand);
}
done.set(e);
- if (!simpleSubject) {
+ if (!didIntSwitch && !simpleSubject) {
// Null out temp local, to invoke any needed refcounting
ASSERT(tempLocal >= 0);
ASSERT(start != InvalidAbsoluteOffset);
@@ -2420,7 +2610,20 @@ bool EmitterVisitor::visit(ConstructPtr node) {
emitConvertToCellIfVar(e);
}
- if (visit(ae->getOffset())) {
+ ExpressionPtr offset = ae->getOffset();
+ Variant v;
+ if (!ae->isSuperGlobal() && offset &&
+ offset->getScalarValue(v) && (v.isInteger() || v.isString())) {
+ if (v.isString()) {
+ m_evalStack.push(StackSym::T);
+ m_evalStack.setString(
+ StringData::GetStaticString(v.toCStrRef().get()));
+ } else {
+ m_evalStack.push(StackSym::I);
+ m_evalStack.setInt(v.asInt64Val());
+ }
+ markElem(e);
+ } else if (visit(offset)) {
emitConvertToCellOrLoc(e);
if (ae->isSuperGlobal()) {
markGlobalName(e);
@@ -2765,9 +2968,8 @@ bool EmitterVisitor::visit(ConstructPtr node) {
}
if (clsName) {
Id id = m_ue.mergeLitstr(clsName);
- m_metaMap[fpiStart].push_back(
- Unit::MetaInfo(Unit::MetaInfo::Class,
- om->getName().empty() ? 1 : 0, id));
+ addMetaInfo(fpiStart, Unit::MetaInfo::Class, false,
+ om->getName().empty() ? 1 : 0, id);
}
{
FPIRegionRecorder fpi(this, m_ue, m_evalStack, fpiStart);
@@ -2789,8 +2991,10 @@ bool EmitterVisitor::visit(ConstructPtr node) {
static_pointer_cast<ObjectPropertyExpression>(node));
visit(op->getObject());
StringData* clsName = getClassName(op->getObject());
- if (clsName) m_evalStack.setCls(clsName);
- emitNameString(e, op->getProperty());
+ if (clsName && !StackSym::GetMarker(m_evalStack.top())) {
+ m_evalStack.setKnownCls(clsName, false);
+ }
+ emitNameString(e, op->getProperty(), true);
if (!op->hasAnyContext(Expression::AccessContext|
Expression::ObjectContext)) {
m_tempLoc = op->getLocation();
@@ -2819,6 +3023,7 @@ bool EmitterVisitor::visit(ConstructPtr node) {
visit(q->getNo());
emitConvertToCell(e);
done.set(e);
+ m_evalStack.cleanTopMeta();
} else {
// <expr> ?: <expr>
Label done;
@@ -2830,6 +3035,7 @@ bool EmitterVisitor::visit(ConstructPtr node) {
visit(q->getNo());
emitConvertToCell(e);
done.set(e);
+ m_evalStack.cleanTopMeta();
}
return true;
}
@@ -2895,6 +3101,9 @@ bool EmitterVisitor::visit(ConstructPtr node) {
}
Id i = m_curFunc->lookupVarId(nLiteral);
emitVirtualLocal(i);
+ if (!sv->couldBeAliased()) {
+ m_evalStack.setNotRef();
+ }
if (sv->getAlwaysStash() &&
!sv->hasAnyContext(Expression::ExistContext |
Expression::RefValue |
@@ -3075,9 +3284,9 @@ bool EmitterVisitor::visit(ConstructPtr node) {
StringData::GetStaticString("closure");
const Location* sLoc = ce->getLocation().get();
PreClassEmitter* pce = m_ue.newPreClassEmitter(className,
- /* hoistable = */ false);
+ PreClass::NotHoistable);
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), AttrNone,
- parentName, false, NULL);
+ parentName, NULL);
e.DefCls(pce->id());
// We're still at the closure definition site. Emit code to instantiate
@@ -3168,11 +3377,15 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
char sym = m_evalStack.get(iFirst);
char symFlavor = StackSym::GetSymFlavor(sym);
char marker = StackSym::GetMarker(sym);
- const StringData* name = m_evalStack.getName(iFirst);
- if (name && m_evalStack.isCls(iFirst)) {
- Id id = m_ue.mergeLitstr(name);
- m_metaMap[m_ue.bcPos()].push_back(
- Unit::MetaInfo(Unit::MetaInfo::Class, 0, id));
+ if (m_evalStack.isCls(iFirst)) {
+ const StringData* cls = m_evalStack.getName(iFirst);
+ ASSERT(cls);
+ Id id = m_ue.mergeLitstr(cls);
+ addMetaInfo(m_ue.bcPos(), Unit::MetaInfo::Class, true, 0, id);
+ }
+ DataType dt = m_evalStack.getKnownType(iFirst);
+ if (dt != KindOfUnknown) {
+ addMetaInfo(m_ue.bcPos(), Unit::MetaInfo::DataType, true, 0, dt);
}
switch (marker) {
case StackSym::N: {
@@ -3229,11 +3442,16 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
char sym = m_evalStack.get(i);
char symFlavor = StackSym::GetSymFlavor(sym);
char marker = StackSym::GetMarker(sym);
- const StringData* name = m_evalStack.getName(i);
- if (name && !m_evalStack.isCls(i)) {
- Id id = m_ue.mergeLitstr(name);
- m_metaMap[m_ue.bcPos()].push_back(
- Unit::MetaInfo(Unit::MetaInfo::String, metaI, id));
+ Id strid = -1;
+ if (const StringData* name = m_evalStack.getName(i)) {
+ strid = m_ue.mergeLitstr(name);
+ // If this string is an m-vector litstr it will be stored in the
+ // m-vector later on in this function. Don't duplicate it in the
+ // metadata table.
+ if (symFlavor != StackSym::T) {
+ addMetaInfo(m_ue.bcPos(), Unit::MetaInfo::String,
+ true, metaI, strid);
+ }
}
switch (marker) {
case StackSym::M: {
@@ -3243,6 +3461,10 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
case StackSym::E: {
if (symFlavor == StackSym::L) {
vectorImm.push_back(MEL);
+ } else if (symFlavor == StackSym::T) {
+ vectorImm.push_back(MET);
+ } else if (symFlavor == StackSym::I) {
+ vectorImm.push_back(MEI);
} else {
vectorImm.push_back(MEC);
}
@@ -3258,6 +3480,8 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
case StackSym::P: {
if (symFlavor == StackSym::L) {
vectorImm.push_back(MPL);
+ } else if (symFlavor == StackSym::T) {
+ vectorImm.push_back(MPT);
} else {
vectorImm.push_back(MPC);
}
@@ -3270,6 +3494,11 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
if (symFlavor == StackSym::L) {
encodeIvaToVector(vectorImm, m_evalStack.getLoc(i));
+ } else if (symFlavor == StackSym::T) {
+ ASSERT(strid != -1);
+ encodeToVector<int32>(vectorImm, strid);
+ } else if (symFlavor == StackSym::I) {
+ encodeToVector<int64>(vectorImm, m_evalStack.getInt(i));
}
++i;
@@ -3475,7 +3704,8 @@ void EmitterVisitor::emitFuncCallArg(Emitter& e,
int paramId) {
visit(exp);
if (checkIfStackEmpty("FPass*")) return;
- if (Option::WholeProgram && !exp->hasAnyContext(Expression::InvokeArgument)) {
+ if (Option::WholeProgram && !exp->hasAnyContext(Expression::InvokeArgument |
+ Expression::RefParameter)) {
if (exp->hasContext(Expression::RefValue)) {
emitVGet(e);
} else {
@@ -4010,11 +4240,88 @@ void EmitterVisitor::emitContinuationSwitch(Emitter& e,
targets[caseIdx] = getContinuationGotoLabel(c->getStatement());
}
visit(sw->getExp());
- e.Switch(targets);
+ e.Switch(targets, 0, 0);
case0.set(e);
}
}
+bool EmitterVisitor::emitIntegerSwitch(Emitter& e,
+ SwitchStatementPtr sw,
+ std::vector<Label>& caseLabels,
+ Label& done) {
+ StatementListPtr cases(sw->getCases());
+ const int ncase = cases->getCount();
+ int defI = -1;
+ int nonZeroI = -1;
+ // Map from case value to index in caseLabels
+ std::map<int64, int> caseMap;
+
+ // Bail if there are one or more non-integer cases
+ for (int i = 0; i < ncase; ++i) {
+ CaseStatementPtr c(static_pointer_cast<CaseStatement>((*cases)[i]));
+ ExpressionPtr condition = c->getCondition();
+ if (condition) {
+ Variant cval;
+ if (!(condition->getScalarValue(cval) && cval.getType() == KindOfInt64)) {
+ return false;
+ }
+ int64 n = cval.asInt64Val();
+ if (!mapContains(caseMap, n)) {
+ // If 'case n:' appears multiple times, only the first will
+ // ever match
+ caseMap[n] = i;
+ }
+ if (nonZeroI == -1 && n != 0) {
+ // true is equal to any non-zero integer, so to preserve php's
+ // switch semantics we have to remember the first non-zero
+ // case to appear in the source text
+ nonZeroI = i;
+ }
+ } else {
+ // Last 'default:' wins
+ defI = i;
+ }
+ }
+
+ if (caseMap.empty()) {
+ // If there are no non-default cases, evaluate the subject for
+ // side effects and fall through. If there's a default case it
+ // will be emitted immediately after this.
+ visit(sw->getExp());
+ emitPop(e);
+ return true;
+ }
+
+ int64 base = caseMap.begin()->first;
+ int64 nTargets = caseMap.rbegin()->first - base + 1;
+ // Fail if the cases are too sparse
+ if ((float)caseMap.size() / nTargets < 0.5) {
+ return false;
+ }
+
+ // It's on. Map case values to Labels, filling in the blanks as
+ // appropriate.
+ Label* defLabel = defI == -1 ? &done : &caseLabels[defI];
+ std::vector<Label*> labels(nTargets + 2);
+ for (int i = 0; i < nTargets; ++i) {
+ int caseIdx;
+ if (mapGet(caseMap, base + i, &caseIdx)) {
+ labels[i] = &caseLabels[caseIdx];
+ } else {
+ labels[i] = defLabel;
+ }
+ }
+
+ // Fill in offsets for the first non-zero case and default
+ labels[labels.size() - 2] = nonZeroI == -1 ? defLabel : &caseLabels[nonZeroI];
+ labels[labels.size() - 1] = defLabel;
+
+ visit(sw->getExp());
+ emitConvertToCell(e);
+ e.Switch(labels, base, 1);
+ return true;
+}
+
void EmitterVisitor::markElem(Emitter& e) {
if (m_evalStack.empty()) {
InvariantViolation("Emitter encountered an empty evaluation stack inside"
@@ -4023,7 +4330,8 @@ void EmitterVisitor::markElem(Emitter& e) {
return;
}
char sym = m_evalStack.top();
- if (sym == StackSym::C || sym == StackSym::L) {
+ if (sym == StackSym::C || sym == StackSym::L || sym == StackSym::T ||
+ sym == StackSym::I) {
m_evalStack.set(m_evalStack.size()-1, (sym | StackSym::E));
} else {
InvariantViolation(
@@ -4048,7 +4356,7 @@ void EmitterVisitor::markProp(Emitter& e) {
return;
}
char sym = m_evalStack.top();
- if (sym == StackSym::C || sym == StackSym::L) {
+ if (sym == StackSym::C || sym == StackSym::L || sym == StackSym::T) {
m_evalStack.set(m_evalStack.size()-1, (sym | StackSym::P));
} else {
InvariantViolation(
@@ -4134,11 +4442,16 @@ void EmitterVisitor::markGlobalName(Emitter& e) {
}
}
-void EmitterVisitor::emitNameString(Emitter& e, ExpressionPtr n) {
+void EmitterVisitor::emitNameString(Emitter& e, ExpressionPtr n,
+ bool allowLiteral) {
Variant v;
if (n->getScalarValue(v) && v.isString()) {
StringData* nLiteral = StringData::GetStaticString(v.toCStrRef().get());
- e.String(nLiteral);
+ if (allowLiteral) {
+ m_evalStack.push(StackSym::T);
+ } else {
+ e.String(nLiteral);
+ }
m_evalStack.setString(nLiteral);
} else {
visit(n);
@@ -4291,9 +4604,10 @@ void EmitterVisitor::emitPostponedMeths() {
/*
In WholeProgram mode, we inline the traits into their
classes. If a trait method name matches the class name
- its NOT a constructor.
- Putting AttrTrait on a method, tells it not to treat
- it as a constructor, even if it looks like one.
+ it is NOT a constructor.
+ We mark the method with AttrTrait so that we can avoid
+ treating it as a constructor even though it looks like
+ one.
*/
attrs = (Attr)(attrs | AttrTrait);
}
@@ -4303,6 +4617,13 @@ void EmitterVisitor::emitPostponedMeths() {
}
}
+ // For closures, the MethodStatement didn't have real attributes; enforce
+ // that the __invoke method is public here
+ if (fe->isClosureBody()) {
+ ASSERT(!(attrs & (AttrProtected | AttrPrivate)));
+ attrs = (Attr)(attrs | AttrPublic);
+ }
+
Label topOfBody(e);
const Location* sLoc = p.m_meth->getLocation().get();
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), attrs, p.m_top, methDoc);
@@ -4324,9 +4645,6 @@ void EmitterVisitor::emitPostponedMeths() {
e.VerifyParamType(i);
}
if (fe->isClosureBody()) {
- // The MethodStatement didn't have real attributes; enforce that the
- // __invoke method is public here
- fe->setAttrs(AttrPublic);
ASSERT(p.m_closureUseVars != NULL);
// Emit code to unpack the instance variables (which store the
// use-variables) into locals. Some of the use-variables may have the
@@ -4409,8 +4727,9 @@ void EmitterVisitor::newContinuationClass(const StringData* name) {
StringData* className = continuationClassName(name);
static const StringData* parentName =
StringData::GetStaticString("GenericContinuation");
- PreClassEmitter* pce = m_ue.newPreClassEmitter(className, true);
- pce->init(0, 0, m_ue.bcPos(), AttrNone, parentName, true, NULL);
+ PreClassEmitter* pce = m_ue.newPreClassEmitter(className,
+ PreClass::AlwaysHoistable);
+ pce->init(0, 0, m_ue.bcPos(), AttrNone, parentName, NULL);
}
void EmitterVisitor::emitPostponedCtors() {
@@ -4682,7 +5001,7 @@ void EmitterVisitor::emitVirtualLocal(int localId) {
prepareEvalStack();
m_evalStack.push(StackSym::L);
- m_evalStack.setLocal(localId);
+ m_evalStack.setInt(localId);
}
template<class Expr>
@@ -4702,7 +5021,7 @@ void EmitterVisitor::emitVirtualClassBase(Emitter& e, Expr* node) {
StringData* name = StringData::GetStaticString(sv->getName());
Id locId = m_curFunc->lookupVarId(name);
m_evalStack.setClsBaseType(SymbolicStack::CLS_NAMED_LOCAL);
- m_evalStack.setLocal(locId);
+ m_evalStack.setInt(locId);
} else {
/*
* More complex expressions get stashed into an unnamed local so
@@ -4891,8 +5210,8 @@ void EmitterVisitor::emitClassUseTrait(PreClassEmitter* pce,
}
}
-bool EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
- bool hoistable) {
+PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
+ bool toplevel) {
InterfaceStatementPtr is(
static_pointer_cast<InterfaceStatement>(cNode->getStmt()));
StringData* className = StringData::GetStaticString(cNode->getOriginalName());
@@ -4920,20 +5239,24 @@ bool EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
const std::vector<std::string>& bases(cNode->getBases());
int firstInterface = cNode->getOriginalParent().empty() ? 0 : 1;
int nInterfaces = bases.size();
- /*
- XXX
- When processing SystemLib.php, we dont evaluate pseudoMain,
- so all the classes have to be hoistable. But several have interfaces
- so we have to allow classes with interfaces to be hoistable.
- Better long term fix is to fully execute SystemLib.php - but that
- may have perf implications.
- */
- if (nInterfaces > firstInterface && SystemLib::s_inited) hoistable = false;
- if (cNode->getUsedTraitNames().size()) hoistable = false;
+ PreClass::Hoistable hoistable = PreClass::NotHoistable;
+ if (toplevel) {
+ if (nInterfaces > firstInterface || cNode->getUsedTraitNames().size()) {
+ hoistable = PreClass::Mergeable;
+ } else if (firstInterface &&
+ !m_hoistables.count(cNode->getOriginalParent())) {
+ hoistable = PreClass::MaybeHoistable;
+ } else {
+ hoistable = PreClass::AlwaysHoistable;
+ m_hoistables.insert(cNode->getOriginalName());
+ }
+ }
PreClassEmitter* pce = m_ue.newPreClassEmitter(className, hoistable);
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), attr, parentName,
- hoistable, classDoc);
- e.DefCls(pce->id());
+ classDoc);
+ if (hoistable != PreClass::AlwaysHoistable) {
+ e.DefCls(pce->id());
+ }
for (int i = firstInterface; i < nInterfaces; ++i) {
pce->addInterface(StringData::GetStaticString(bases[i]));
}
@@ -5628,6 +5951,7 @@ static Unit* emitHHBCNativeFuncUnit(const HhbcExtFuncInfo* builtinFuncs,
ue->emitInt64(1);
ue->emitOp(OpRetC);
Offset past = ue->bcPos();
+ mfe->setMaxStackCells(1);
mfe->finish(past, false);
ue->recordFunction(mfe);
@@ -5742,6 +6066,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
ue->emitInt64(1);
ue->emitOp(OpRetC);
Offset past = ue->bcPos();
+ mfe->setMaxStackCells(1);
</