Comparar commits
120 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b74a0da062 | |||
| e663cfb0fd | |||
| b3b41e08bb | |||
| 3e24e506f4 | |||
| ef1d4c9c1e | |||
| cee31f4412 | |||
| 65d2487ab7 | |||
| 67013476b5 | |||
| 2b3ae234fb | |||
| 6fed85fbb4 | |||
| bd2e014e8f | |||
| c8cc07a61c | |||
| 26c4d57cfa | |||
| f58323820c | |||
| 2f9f1a705b | |||
| 387a3555e2 | |||
| 8a119496e1 | |||
| 5662a67f12 | |||
| ac63ae02c6 | |||
| f3a6aaee37 | |||
| bbdf9729fb | |||
| 09e01875a0 | |||
| 26a6669575 | |||
| 162b46fb99 | |||
| f5188b8fe9 | |||
| 0f9c93f9f9 | |||
| 5ed74f1e03 | |||
| d9943ae3c5 | |||
| f109b02c7d | |||
| ac0ec5696a | |||
| 64b6d99ef2 | |||
| e300bc8cce | |||
| bc6703d03f | |||
| aee58ac19e | |||
| c375ba70b0 | |||
| 1643cb1d17 | |||
| 51f0a5bd3b | |||
| 8572bdeb7f | |||
| cf7133b406 | |||
| a44b190095 | |||
| e69e05711a | |||
| 3cf77e2df9 | |||
| 7fd841e6c1 | |||
| f3ddbe63f1 | |||
| 1e4b0ed05b | |||
| 2406e11d44 | |||
| 1e54607680 | |||
| 28116234fb | |||
| 337f15cc8d | |||
| a18dd73d06 | |||
| 067e38c23d | |||
| 2db86bd721 | |||
| 527a155239 | |||
| 1bc06a26cf | |||
| 76681bfc14 | |||
| 740868989c | |||
| 26c2654528 | |||
| bab632f35a | |||
| 51ffd22f03 | |||
| 03c8d47acb | |||
| a4903eb14e | |||
| 9efb3c8e25 | |||
| c21f2c3966 | |||
| 3a5087077f | |||
| dc8cc4656b | |||
| 00b2101db0 | |||
| 3248a83461 | |||
| 14c9e841c8 | |||
| 839bb3103e | |||
| dec99505a6 | |||
| f3cf268bb1 | |||
| 5455370de0 | |||
| 116bb2c662 | |||
| cc5cc6d5cb | |||
| cc863bf301 | |||
| e09dbb6f89 | |||
| 5acac417e2 | |||
| b17ec4702a | |||
| f6efec4d7c | |||
| 75948e48f7 | |||
| 3286e1d7c0 | |||
| d6be84e026 | |||
| 0763e566f4 | |||
| 8c57d016d5 | |||
| 44dc3b58f4 | |||
| b24236e602 | |||
| dbab820ff4 | |||
| 441fb578ec | |||
| 755d38157f | |||
| 4196354f4f | |||
| f7dd399bd6 | |||
| 0b586489c9 | |||
| 31222e2c84 | |||
| d87811fd9b | |||
| 6492f650f5 | |||
| d09fd3e421 | |||
| 5baef2646d | |||
| 22541f491c | |||
| a4b2eea173 | |||
| e3d0c97679 | |||
| 795400d899 | |||
| 5483751a25 | |||
| 4797536f9d | |||
| c67d35c50a | |||
| 453c9938c9 | |||
| 3e19c90b93 | |||
| bed8c0e6fe | |||
| 1b83a11ee8 | |||
| 94081c2cbc | |||
| c7959bbe6a | |||
| 94aed72d26 | |||
| 6ac06a50eb | |||
| 5e7c9d3457 | |||
| 1eeb100510 | |||
| 6a4ec5ae0e | |||
| 52697c84a0 | |||
| c4956fac10 | |||
| ddd8720bf4 | |||
| 84d9aa7236 | |||
| 363d1bb20f |
+38
-78
@@ -8,102 +8,62 @@
|
|||||||
.mkdir
|
.mkdir
|
||||||
hphp.log
|
hphp.log
|
||||||
|
|
||||||
/src/test/test
|
/hphp/test/test
|
||||||
/src/test/test_fast.inc
|
/hphp/test/test_fast.inc
|
||||||
/src/test/test_mysql_info.inc
|
/hphp/test/test_mysql_info.inc
|
||||||
/src/test/test_suite.inc
|
/hphp/test/test_suite.inc
|
||||||
/src/test/real_mysql_info.inc
|
/hphp/test/real_mysql_info.inc
|
||||||
/src/test/*.tmp
|
/hphp/test/*.tmp
|
||||||
/src/test/vm/*.out
|
/hphp/test/vm/*.out
|
||||||
/src/test/vm/*.diff
|
/hphp/test/vm/*.diff
|
||||||
/src/test/vm/*.log
|
/hphp/test/vm/*.log
|
||||||
/src/test/vm/*.reduce_out
|
/hphp/test/vm/*.reduce_out
|
||||||
/src/test/vm/*.reduce_diff
|
/hphp/test/vm/*.reduce_diff
|
||||||
/src/test/vm/*.reduce_exp
|
/hphp/test/vm/*.reduce_exp
|
||||||
/src/test/vm/*.perf
|
/hphp/test/vm/*.perf
|
||||||
/src/test/vm/perf/*.out
|
/hphp/test/vm/perf/*.out
|
||||||
/src/test/vm/perf/*.diff
|
/hphp/test/vm/perf/*.diff
|
||||||
/src/test/vm/perf/*.perf
|
/hphp/test/vm/perf/*.perf
|
||||||
/src/runtime/ext_hhvm/xconstants.php
|
/hphp/runtime/ext_hhvm/ext_noinline.cpp
|
||||||
/src/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
|
/hphp/compiler/analysis/code_error.inc
|
||||||
/src/runtime/ext_hhvm/ext_noinline.cpp
|
|
||||||
/src/compiler/analysis/code_error.inc
|
|
||||||
|
|
||||||
/src/runtime/tmp/Test*
|
/hphp/runtime/tmp/Test*
|
||||||
/src/runtime/tmp/run
|
/hphp/runtime/tmp/run
|
||||||
/src/runtime/tmp/run.sh
|
/hphp/runtime/tmp/run.sh
|
||||||
/src/runtime/tmp/libtest.so
|
/hphp/runtime/tmp/libtest.so
|
||||||
/src/runtime/vm/repo_schema.h
|
/hphp/runtime/vm/repo_schema.h
|
||||||
/src/runtime/base/compiler_id.h
|
/hphp/runtime/base/compiler_id.h
|
||||||
|
|
||||||
/src/hphpi/gen
|
/hphp/hphpi/gen
|
||||||
/src/hphpi/hphpi
|
/hphp/hphpi/hphpi
|
||||||
|
|
||||||
/src/hhvm/gen
|
/hphp/hhvm/gen
|
||||||
/src/hhvm/hhvm
|
/hphp/hhvm/hhvm
|
||||||
/src/hhvm/hphp
|
|
||||||
|
|
||||||
/src/tools/shmw/shmw
|
/hphp/tools/shmw/shmw
|
||||||
|
|
||||||
/src/ffi/java/classes
|
/hphp/ffi/java/classes
|
||||||
/src/ffi/java/hphp_ffi_java.h
|
/hphp/ffi/java/hphp_ffi_java.h
|
||||||
|
|
||||||
# Ignore all makefiles generated for fbcode's third-party repo
|
# Ignore all makefiles generated for fbcode's third-party repo
|
||||||
/bin/*.mk
|
/bin/*.mk
|
||||||
!/bin/run.mk
|
!/bin/run.mk
|
||||||
|
|
||||||
/facebook/arcanist/.phutil_module_cache
|
|
||||||
|
|
||||||
/facebook/autoload_files
|
|
||||||
/facebook/hotcold.hdf
|
|
||||||
/facebook/benchmark/shootout/output_bench
|
|
||||||
/facebook/benchmark/shootout/output_bintree_new
|
|
||||||
/facebook/libcore_files
|
|
||||||
/facebook/output_*
|
|
||||||
/facebook/push/install
|
|
||||||
/facebook/stub_funcs.hdf
|
|
||||||
/facebook/volatile.hdf
|
|
||||||
/facebook/www.pid
|
|
||||||
|
|
||||||
/facebook/push/apc
|
|
||||||
/facebook/push/apclog
|
|
||||||
/facebook/push/autoload_files
|
|
||||||
/facebook/push/hotcold.hdf
|
|
||||||
/facebook/push/output_www
|
|
||||||
/facebook/push/system.tgz
|
|
||||||
/facebook/push/volatile.hdf
|
|
||||||
/facebook/push/stub_funcs.hdf
|
|
||||||
/facebook/push/output
|
|
||||||
/facebook/push/shared
|
|
||||||
|
|
||||||
/facebook/extensions/gen
|
|
||||||
/facebook/extensions/hphpi
|
|
||||||
/local/*.mk
|
|
||||||
|
|
||||||
CMakeFiles
|
CMakeFiles
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
|
|
||||||
/output_gd/
|
/output_gd/
|
||||||
|
|
||||||
/src/TAGS
|
/hphp/TAGS
|
||||||
|
|
||||||
# arcanist working-copy settings
|
|
||||||
.arc/
|
|
||||||
|
|
||||||
# fbcode output directory
|
|
||||||
/bin/_fbcode_bin/
|
|
||||||
|
|
||||||
# Generated makefiles
|
# Generated makefiles
|
||||||
/src/third_party/lz4/Makefile
|
/hphp/runtime/ext_hhvm/Makefile
|
||||||
/src/third_party/double-conversion/Makefile
|
/hphp/test/Makefile
|
||||||
/src/third_party/folly/Makefile
|
/hphp/hphp/Makefile
|
||||||
/src/runtime/ext_hhvm/Makefile
|
/hphp/hhvm/Makefile
|
||||||
/src/test/Makefile
|
/hphp/compiler/Makefile
|
||||||
/src/hphp/Makefile
|
/hphp/Makefile
|
||||||
/src/hhvm/Makefile
|
|
||||||
/src/compiler/Makefile
|
|
||||||
/src/Makefile
|
|
||||||
/Makefile
|
/Makefile
|
||||||
|
|
||||||
# eclipse files
|
# eclipse files
|
||||||
|
|||||||
+12
-12
@@ -134,15 +134,15 @@ find_package(EXPAT REQUIRED)
|
|||||||
include_directories(${EXPAT_INCLUDE_DIRS})
|
include_directories(${EXPAT_INCLUDE_DIRS})
|
||||||
|
|
||||||
# SQLite3 + timelib are bundled in HPHP sources
|
# SQLite3 + timelib are bundled in HPHP sources
|
||||||
include_directories("${HPHP_HOME}/src/third_party/libsqlite3")
|
include_directories("${HPHP_HOME}/hphp/third_party/libsqlite3")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/timelib")
|
include_directories("${HPHP_HOME}/hphp/third_party/timelib")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/libafdt/src")
|
include_directories("${HPHP_HOME}/hphp/third_party/libafdt/src")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/libmbfl")
|
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/libmbfl/mbfl")
|
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl/mbfl")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/libmbfl/filter")
|
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl/filter")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/lz4")
|
include_directories("${HPHP_HOME}/hphp/third_party/lz4")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/double-conversion/src")
|
include_directories("${HPHP_HOME}/hphp/third_party/double-conversion/src")
|
||||||
include_directories("${HPHP_HOME}/src/third_party/folly")
|
include_directories("${HPHP_HOME}/hphp/third_party/folly")
|
||||||
|
|
||||||
FIND_LIBRARY(XHP_LIB xhp)
|
FIND_LIBRARY(XHP_LIB xhp)
|
||||||
FIND_PATH(XHP_INCLUDE_DIR xhp_preprocess.hpp)
|
FIND_PATH(XHP_INCLUDE_DIR xhp_preprocess.hpp)
|
||||||
@@ -151,7 +151,7 @@ if (XHP_LIB AND XHP_INCLUDE_DIR)
|
|||||||
include_directories(${XHP_INCLUDE_DIR})
|
include_directories(${XHP_INCLUDE_DIR})
|
||||||
set(SKIP_BUNDLED_XHP ON)
|
set(SKIP_BUNDLED_XHP ON)
|
||||||
else()
|
else()
|
||||||
include_directories("${HPHP_HOME}/src/third_party/xhp/xhp")
|
include_directories("${HPHP_HOME}/hphp/third_party/xhp/xhp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ICU
|
# ICU
|
||||||
@@ -351,8 +351,8 @@ endif()
|
|||||||
# message(FATAL_ERROR "Flex is too old, found ${FLEX_VERSION} and we need 2.5.33")
|
# message(FATAL_ERROR "Flex is too old, found ${FLEX_VERSION} and we need 2.5.33")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
include_directories(${HPHP_HOME}/src)
|
include_directories(${HPHP_HOME}/hphp)
|
||||||
include_directories(${HPHP_HOME}/src/system/gen)
|
include_directories(${HPHP_HOME}/hphp/system/gen)
|
||||||
|
|
||||||
macro(hphp_link target)
|
macro(hphp_link target)
|
||||||
if (GOOGLE_HEAP_PROFILER_ENABLED OR GOOGLE_CPU_PROFILER_ENABLED)
|
if (GOOGLE_HEAP_PROFILER_ENABLED OR GOOGLE_CPU_PROFILER_ENABLED)
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ endif()
|
|||||||
|
|
||||||
IF($ENV{CXX} MATCHES "icpc")
|
IF($ENV{CXX} MATCHES "icpc")
|
||||||
set(CMAKE_C_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -w")
|
set(CMAKE_C_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -w")
|
||||||
set(CMAKE_CXX_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -fno-omit-frame-pointer -ftemplate-depth-60 -Wall -Woverloaded-virtual -Wno-deprecated -w1 -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names")
|
set(CMAKE_CXX_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -fno-omit-frame-pointer -ftemplate-depth-120 -Wall -Woverloaded-virtual -Wno-deprecated -w1 -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names")
|
||||||
else()
|
else()
|
||||||
set(CMAKE_C_FLAGS "-w")
|
set(CMAKE_C_FLAGS "-w")
|
||||||
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-60 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
|
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-120 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||||
@@ -126,6 +126,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
|
|||||||
SET (CMAKE_CXX_FLAGS_RELEASE "-O3")
|
SET (CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
include_directories(${HPHP_HOME}/src)
|
include_directories(${HPHP_HOME}/hphp)
|
||||||
include_directories(${HPHP_HOME}/src/lib/system/gen)
|
include_directories(${HPHP_HOME}/hphp/lib/system/gen)
|
||||||
include_directories(${HPHP_HOME})
|
include_directories(${HPHP_HOME})
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
|
|||||||
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/HPHPFunctions.cmake")
|
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/HPHPFunctions.cmake")
|
||||||
include(CheckFunctionExists)
|
include(CheckFunctionExists)
|
||||||
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hphp)
|
||||||
|
|
||||||
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
|
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
|
||||||
|
|||||||
+3
-5
@@ -179,16 +179,14 @@ class Exception {
|
|||||||
// Remove top stack frames up to and including Exception::__init__,
|
// Remove top stack frames up to and including Exception::__init__,
|
||||||
// set the 'file' and 'line' properties appropriately
|
// set the 'file' and 'line' properties appropriately
|
||||||
while (!empty($this->trace)) {
|
while (!empty($this->trace)) {
|
||||||
$top = $this->trace[0];
|
$top = array_shift($this->trace);
|
||||||
if (isset($top['class']) && isset($top['function']) &&
|
if (isset($top['class']) && isset($top['function']) &&
|
||||||
strcasecmp($top['class'], 'exception') === 0 &&
|
strcasecmp($top['class'], 'exception') === 0 &&
|
||||||
strcasecmp($top['function'], '__init__') === 0) {
|
strcasecmp($top['function'], '__init__') === 0) {
|
||||||
$frame = array_shift($this->trace);
|
if (isset($top['file'])) $this->file = $top['file'];
|
||||||
if (isset($frame['file'])) $this->file = $frame['file'];
|
if (isset($top['line'])) $this->line = $top['line'];
|
||||||
if (isset($frame['line'])) $this->line = $frame['line'];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
array_shift($this->trace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
#
|
||||||
|
# +----------------------------------------------------------------------+
|
||||||
|
# | HipHop for PHP |
|
||||||
|
# +----------------------------------------------------------------------+
|
||||||
|
# | Copyright (c) 2010 Facebook, Inc. (http://www.facebook.com) |
|
||||||
|
# | Copyright (c) 1997-2010 The PHP Group |
|
||||||
|
# +----------------------------------------------------------------------+
|
||||||
|
# | This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
# | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
# | available through the world-wide-web at the following url: |
|
||||||
|
# | http://www.php.net/license/3_01.txt |
|
||||||
|
# | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
# | obtain it through the world-wide-web, please send a note to |
|
||||||
|
# | license@php.net so we can mail you a copy immediately. |
|
||||||
|
# +----------------------------------------------------------------------+
|
||||||
|
#
|
||||||
|
|
||||||
|
include(HPHPSetup)
|
||||||
|
|
||||||
|
if ("$ENV{USE_HHVM}" STREQUAL "1")
|
||||||
|
# HHVM Build
|
||||||
|
SET(USE_HHVM TRUE)
|
||||||
|
SET(ENV{HHVM} 1)
|
||||||
|
ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/hphp/hhvm/hhvm\\\"")
|
||||||
|
|
||||||
|
if ("$ENV{USE_HPHPC}" STREQUAL "1")
|
||||||
|
message(FATAL_ERROR "Both USE_HHVM and USE_HPHPC are set, you may only select one")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# HPHPc Build
|
||||||
|
SET(USE_HHVM FALSE)
|
||||||
|
ADD_DEFINITIONS("-DHHVM_PATH=\"\"")
|
||||||
|
|
||||||
|
if (NOT "$ENV{USE_HPHPC}" STREQUAL "1")
|
||||||
|
message(FATAL_ERROR "You must select which version of HipHop to build by setting either USE_HHVM=1 or USE_HPHPC=1 in your environment")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system/gen system/lib util)
|
||||||
|
foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
|
||||||
|
|
||||||
|
auto_sources(files "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
|
||||||
|
list(APPEND CXX_SOURCES ${files})
|
||||||
|
|
||||||
|
auto_sources(files "*.c" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
|
||||||
|
list(APPEND C_SOURCES ${files})
|
||||||
|
|
||||||
|
endforeach(dir ${RECURSIVE_SOURCE_SUBDIRS})
|
||||||
|
|
||||||
|
# Disable hardware counters off of Linux
|
||||||
|
if(NOT LINUX)
|
||||||
|
add_definitions(-DNO_HARDWARE_COUNTERS)
|
||||||
|
list(REMOVE_ITEM CXX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtime/base/hardware_counter.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# remove ext_hhvm, util/tests, and runtime/vm/translator/test
|
||||||
|
foreach (file ${CXX_SOURCES})
|
||||||
|
if (${file} MATCHES "ext_hhvm")
|
||||||
|
list(REMOVE_ITEM CXX_SOURCES ${file})
|
||||||
|
endif()
|
||||||
|
if (${file} MATCHES "util/test")
|
||||||
|
list(REMOVE_ITEM CXX_SOURCES ${file})
|
||||||
|
endif()
|
||||||
|
if (${file} MATCHES "runtime/vm/translator/test")
|
||||||
|
list(REMOVE_ITEM CXX_SOURCES ${file})
|
||||||
|
endif()
|
||||||
|
if (${file} MATCHES "runtime/vm/translator/hopt/test")
|
||||||
|
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")
|
||||||
|
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}")
|
||||||
|
else ()
|
||||||
|
SET(HPHP_EXCLUDE_FILES)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
foreach (t ${HPHP_EXCLUDE_FILES})
|
||||||
|
string(SUBSTRING ${t} 0 1 T_FIRST_CHAR)
|
||||||
|
if (${T_FIRST_CHAR} STREQUAL "D")
|
||||||
|
|
||||||
|
string(REGEX REPLACE "^[D]" "" SKIP_DIR "${t}")
|
||||||
|
file(TO_CMAKE_PATH "${hphp_SOURCE_DIR}/${SKIP_DIR}" SKIP_DIR)
|
||||||
|
string(LENGTH "${SKIP_DIR}" SKIP_DIR_LENGTH)
|
||||||
|
|
||||||
|
message(STATUS "Let's remove ${SKIP_DIR}")
|
||||||
|
|
||||||
|
foreach (file ${CXX_SOURCES})
|
||||||
|
string(LENGTH "${file}" FILE_LENGTH)
|
||||||
|
if (${FILE_LENGTH} GREATER ${SKIP_DIR_LENGTH})
|
||||||
|
string(SUBSTRING ${file} 0 ${SKIP_DIR_LENGTH} FILE_PATH)
|
||||||
|
if (${FILE_PATH} STREQUAL ${SKIP_DIR})
|
||||||
|
list(REMOVE_ITEM CXX_SOURCES ${file})
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
endforeach(file ${CXX_SOURCES})
|
||||||
|
|
||||||
|
elseif (${T_FIRST_CHAR} STREQUAL "#")
|
||||||
|
|
||||||
|
# doing nothing since this is a comment
|
||||||
|
|
||||||
|
else ()
|
||||||
|
list(FIND CXX_SOURCES "${hphp_SOURCE_DIR}/${t}" FOUND_T)
|
||||||
|
if (FOUND_T GREATER -1)
|
||||||
|
LIST(REMOVE_AT CXX_SOURCES ${FOUND_T})
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
endforeach(t ${HPHP_EXCLUDE_FILES})
|
||||||
|
|
||||||
|
#FLEX_TARGET(HphpScanner ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.x ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/lex.eval_.cpp COMPILE_FLAGS " -w -i -Peval_")
|
||||||
|
#BISON_TARGET(HphpParser ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.y ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.tab.cpp COMPILE_FLAGS " -v -d -p eval_")
|
||||||
|
#ADD_FLEX_BISON_DEPENDENCY(HphpScanner HphpParser)
|
||||||
|
|
||||||
|
# required to remove warning when a file is there twice
|
||||||
|
#list(REMOVE_ITEM CXX_SOURCES ${FLEX_HphpScanner_OUTPUTS} ${BISON_HphpParser_OUTPUTS})
|
||||||
|
#list(APPEND CXX_SOURCES ${FLEX_HphpScanner_OUTPUTS} ${BISON_HphpParser_OUTPUTS})
|
||||||
|
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
|
||||||
|
|
||||||
|
#add_library(sqlite3 STATIC "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libsqlite3/sqlite3.c")
|
||||||
|
|
||||||
|
#auto_sources(TIMELIB_SOURCES "*.c" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/third_party/timelib")
|
||||||
|
#add_library(timelib STATIC ${TIMELIB_SOURCES})
|
||||||
|
|
||||||
|
if (NOT SKIP_BUNDLED_XHP)
|
||||||
|
add_subdirectory(third_party/xhp/xhp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(third_party/libafdt)
|
||||||
|
add_subdirectory(third_party/libmbfl)
|
||||||
|
add_subdirectory(third_party/libsqlite3)
|
||||||
|
add_subdirectory(third_party/timelib)
|
||||||
|
add_subdirectory(third_party/lz4)
|
||||||
|
add_subdirectory(third_party/double-conversion)
|
||||||
|
add_subdirectory(third_party/folly)
|
||||||
|
|
||||||
|
foreach (CXX_FILE ${CXX_SOURCES})
|
||||||
|
if(${CXX_FILE} MATCHES ".no.cpp$")
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(
|
||||||
|
${CXX_FILE}
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_FLAGS -O0
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT runtime/base/compiler_id.h
|
||||||
|
COMMAND hphp/tools/generate_compiler_id.sh
|
||||||
|
DEPENDS ${CXX_SOURCES} ${C_SOURCES}
|
||||||
|
WORKING_DIRECTORY ${HPHP_HOME}
|
||||||
|
COMMENT "Generating Compiler ID"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT runtime/vm/repo_schema.h
|
||||||
|
COMMAND hphp/tools/generate_repo_schema.sh
|
||||||
|
DEPENDS ${CXX_SOURCES} ${C_SOURCES}
|
||||||
|
WORKING_DIRECTORY ${HPHP_HOME}
|
||||||
|
COMMENT "Generating Repo Schema ID"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
ADD_LIBRARY(hphp_runtime_static STATIC runtime/vm/repo_schema.h runtime/base/compiler_id.h ${CXX_SOURCES} ${C_SOURCES})
|
||||||
|
#ADD_LIBRARY(hphp_runtime SHARED ${C_SOURCES} ${CXX_SOURCES})
|
||||||
|
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES OUTPUT_NAME "hphp_runtime")
|
||||||
|
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()
|
||||||
|
|
||||||
|
add_subdirectory(hhvm)
|
||||||
|
|
||||||
|
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif ()
|
||||||
+10
-10
@@ -1438,7 +1438,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
|
|||||||
Expression::UnsetContext)) {
|
Expression::UnsetContext)) {
|
||||||
ExpressionPtr rep;
|
ExpressionPtr rep;
|
||||||
int interf =
|
int interf =
|
||||||
findInterf(e, true, rep, NULL, doArrayCSE);
|
findInterf(e, true, rep, nullptr, doArrayCSE);
|
||||||
add(m_accessList, e);
|
add(m_accessList, e);
|
||||||
if (interf == SameAccess) {
|
if (interf == SameAccess) {
|
||||||
if (e->getKindOf() == rep->getKindOf()) {
|
if (e->getKindOf() == rep->getKindOf()) {
|
||||||
@@ -1498,7 +1498,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
|
|||||||
Expression::UnsetContext))) {
|
Expression::UnsetContext))) {
|
||||||
ExpressionPtr rep;
|
ExpressionPtr rep;
|
||||||
int interf =
|
int interf =
|
||||||
findInterf(e, true, rep, NULL, doArrayCSE);
|
findInterf(e, true, rep, nullptr, doArrayCSE);
|
||||||
if (!m_inPseudoMain && interf == DisjointAccess && !m_cleared &&
|
if (!m_inPseudoMain && interf == DisjointAccess && !m_cleared &&
|
||||||
e->is(Expression::KindOfSimpleVariable) &&
|
e->is(Expression::KindOfSimpleVariable) &&
|
||||||
!e->isThis()) {
|
!e->isThis()) {
|
||||||
@@ -3669,7 +3669,7 @@ void AliasManager::doFinal(MethodStatementPtr m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
|
void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
|
||||||
always_assert(m_graph != NULL);
|
always_assert(m_graph != nullptr);
|
||||||
|
|
||||||
// bail out for pseudomain context
|
// bail out for pseudomain context
|
||||||
if (m->getScope()->inPseudoMain()) return;
|
if (m->getScope()->inPseudoMain()) return;
|
||||||
@@ -3696,7 +3696,7 @@ void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AliasManager::copyProp(MethodStatementPtr m) {
|
int AliasManager::copyProp(MethodStatementPtr m) {
|
||||||
if (m_graph == NULL) createCFG(m);
|
if (m_graph == nullptr) createCFG(m);
|
||||||
|
|
||||||
performReferencedAndNeededAnalysis(m);
|
performReferencedAndNeededAnalysis(m);
|
||||||
|
|
||||||
@@ -3719,13 +3719,13 @@ int AliasManager::copyProp(MethodStatementPtr m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AliasManager::deleteCFG() {
|
void AliasManager::deleteCFG() {
|
||||||
assert(m_graph != NULL);
|
assert(m_graph != nullptr);
|
||||||
delete m_graph;
|
delete m_graph;
|
||||||
m_graph = NULL;
|
m_graph = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AliasManager::createCFG(MethodStatementPtr m) {
|
void AliasManager::createCFG(MethodStatementPtr m) {
|
||||||
assert(m_graph == NULL);
|
assert(m_graph == nullptr);
|
||||||
m_graph = ControlFlowGraph::buildControlFlow(m);
|
m_graph = ControlFlowGraph::buildControlFlow(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3735,7 +3735,7 @@ void AliasManager::insertTypeAssertions(AnalysisResultConstPtr ar,
|
|||||||
i.walk(m->getStmts());
|
i.walk(m->getStmts());
|
||||||
|
|
||||||
if (Option::ControlFlow && Option::DumpAst) {
|
if (Option::ControlFlow && Option::DumpAst) {
|
||||||
if (m_graph != NULL) deleteCFG();
|
if (m_graph != nullptr) deleteCFG();
|
||||||
createCFG(m);
|
createCFG(m);
|
||||||
printf("-------- BEGIN INSERTED -----------\n");
|
printf("-------- BEGIN INSERTED -----------\n");
|
||||||
m_graph->dump(m_arp);
|
m_graph->dump(m_arp);
|
||||||
@@ -3750,7 +3750,7 @@ void AliasManager::removeTypeAssertions(AnalysisResultConstPtr ar,
|
|||||||
r.walk(m->getStmts());
|
r.walk(m->getStmts());
|
||||||
|
|
||||||
if (Option::ControlFlow && Option::DumpAst) {
|
if (Option::ControlFlow && Option::DumpAst) {
|
||||||
if (m_graph != NULL) deleteCFG();
|
if (m_graph != nullptr) deleteCFG();
|
||||||
createCFG(m);
|
createCFG(m);
|
||||||
printf("-------- BEGIN REMOVED -----------\n");
|
printf("-------- BEGIN REMOVED -----------\n");
|
||||||
m_graph->dump(m_arp);
|
m_graph->dump(m_arp);
|
||||||
@@ -3778,7 +3778,7 @@ int AliasManager::optimize(AnalysisResultConstPtr ar, MethodStatementPtr m) {
|
|||||||
if (copyProp(m)) return 1;
|
if (copyProp(m)) return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_graph != NULL) deleteCFG();
|
if (m_graph != nullptr) deleteCFG();
|
||||||
|
|
||||||
m_hasChainRoot = false;
|
m_hasChainRoot = false;
|
||||||
|
|
||||||
+20
-20
@@ -74,7 +74,7 @@ IMPLEMENT_THREAD_LOCAL(BlockScopeRawPtrFlagsHashMap,
|
|||||||
AnalysisResult::AnalysisResult()
|
AnalysisResult::AnalysisResult()
|
||||||
: BlockScope("Root", "", StatementPtr(), BlockScope::ProgramScope),
|
: BlockScope("Root", "", StatementPtr(), BlockScope::ProgramScope),
|
||||||
m_arrayLitstrKeyMaxSize(0), m_arrayIntegerKeyMaxSize(0),
|
m_arrayLitstrKeyMaxSize(0), m_arrayIntegerKeyMaxSize(0),
|
||||||
m_package(NULL), m_parseOnDemand(false), m_phase(ParseAllFiles),
|
m_package(nullptr), m_parseOnDemand(false), m_phase(ParseAllFiles),
|
||||||
m_scalarArraysCounter(0), m_paramRTTICounter(0),
|
m_scalarArraysCounter(0), m_paramRTTICounter(0),
|
||||||
m_scalarArraySortedAvgLen(0), m_scalarArraySortedIndex(0),
|
m_scalarArraySortedAvgLen(0), m_scalarArraySortedIndex(0),
|
||||||
m_scalarArraySortedSumLen(0), m_scalarArrayCompressedTextSize(0),
|
m_scalarArraySortedSumLen(0), m_scalarArrayCompressedTextSize(0),
|
||||||
@@ -1611,7 +1611,7 @@ public:
|
|||||||
template<>
|
template<>
|
||||||
void AnalysisResult::preWaitCallback<Post>(
|
void AnalysisResult::preWaitCallback<Post>(
|
||||||
bool first, const BlockScopeRawPtrQueue &scopes, void *opaque) {
|
bool first, const BlockScopeRawPtrQueue &scopes, void *opaque) {
|
||||||
assert(!Option::ControlFlow || opaque != NULL);
|
assert(!Option::ControlFlow || opaque != nullptr);
|
||||||
if (first && Option::ControlFlow) {
|
if (first && Option::ControlFlow) {
|
||||||
JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *dispatcher
|
JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *dispatcher
|
||||||
= (JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *) opaque;
|
= (JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *) opaque;
|
||||||
@@ -1814,14 +1814,14 @@ void AnalysisResult::outputCPPNamedScalarVarIntegers(const std::string &file) {
|
|||||||
const vector<string> &strings = it->second;
|
const vector<string> &strings = it->second;
|
||||||
for (unsigned int i = 0; i < strings.size(); i++) {
|
for (unsigned int i = 0; i < strings.size(); i++) {
|
||||||
int64 val;
|
int64 val;
|
||||||
sscanf(strings[i].c_str(), "%llx", &val);
|
sscanf(strings[i].c_str(), "%" PRIx64, &val);
|
||||||
Variant v(val);
|
Variant v(val);
|
||||||
int64 *startp = (int64 *)&v;
|
int64 *startp = (int64 *)&v;
|
||||||
int64 *endp = (startp + multiple);
|
int64 *endp = (startp + multiple);
|
||||||
for (int64 *p = startp; p < endp; p++) {
|
for (int64 *p = startp; p < endp; p++) {
|
||||||
cg_printf("0x%016llxLL, ", *p);
|
cg_printf("0x%016" PRIx64 "L, ", *p);
|
||||||
}
|
}
|
||||||
cg_printf("// %lld\n", val);
|
cg_printf("// %" PRId64 "\n", val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cg_indentEnd("};\n");
|
cg_indentEnd("};\n");
|
||||||
@@ -1844,7 +1844,7 @@ void AnalysisResult::outputCPPNamedScalarVarIntegers(const std::string &file) {
|
|||||||
|
|
||||||
void AnalysisResult::outputCPPFiniteDouble(CodeGenerator &cg, double dval) {
|
void AnalysisResult::outputCPPFiniteDouble(CodeGenerator &cg, double dval) {
|
||||||
assert(finite(dval));
|
assert(finite(dval));
|
||||||
char *buf = NULL;
|
char *buf = nullptr;
|
||||||
if (dval == 0.0) dval = 0.0; // so to avoid "-0" output
|
if (dval == 0.0) dval = 0.0; // so to avoid "-0" output
|
||||||
// 17 to ensure lossless conversion
|
// 17 to ensure lossless conversion
|
||||||
vspprintf(&buf, 0, "%.*G", 17, dval);
|
vspprintf(&buf, 0, "%.*G", 17, dval);
|
||||||
@@ -1882,12 +1882,12 @@ void AnalysisResult::outputCPPNamedScalarVarDoubles(const std::string &file) {
|
|||||||
const vector<string> &strings = it->second;
|
const vector<string> &strings = it->second;
|
||||||
for (unsigned int i = 0; i < strings.size(); i++) {
|
for (unsigned int i = 0; i < strings.size(); i++) {
|
||||||
double val;
|
double val;
|
||||||
sscanf(strings[i].c_str(), "%llx", (int64*)(&val));
|
sscanf(strings[i].c_str(), "%" PRIx64, (int64*)(&val));
|
||||||
Variant v(val);
|
Variant v(val);
|
||||||
int64 *startp = (int64 *)&v;
|
int64 *startp = (int64 *)&v;
|
||||||
int64 *endp = (startp + multiple);
|
int64 *endp = (startp + multiple);
|
||||||
for (int64 *p = startp; p < endp; p++) {
|
for (int64 *p = startp; p < endp; p++) {
|
||||||
cg_printf("0x%016llxLL, ", *p);
|
cg_printf("0x%016" PRIx64 "L, ", *p);
|
||||||
}
|
}
|
||||||
cg_printf("// ");
|
cg_printf("// ");
|
||||||
outputCPPFiniteDouble(cg, val);
|
outputCPPFiniteDouble(cg, val);
|
||||||
@@ -2511,7 +2511,7 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
|
|||||||
{
|
{
|
||||||
vector<OutputJob*> jobs;
|
vector<OutputJob*> jobs;
|
||||||
JobQueueDispatcher<OutputJob*, OutputWorker>
|
JobQueueDispatcher<OutputJob*, OutputWorker>
|
||||||
dispatcher(threadCount, true, 0, false, NULL);
|
dispatcher(threadCount, true, 0, false, nullptr);
|
||||||
|
|
||||||
string root = getOutputPath() + "/";
|
string root = getOutputPath() + "/";
|
||||||
for (StringToFileScopePtrVecMap::const_iterator iter = clusters.begin();
|
for (StringToFileScopePtrVecMap::const_iterator iter = clusters.begin();
|
||||||
@@ -2544,7 +2544,7 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
|
|||||||
{
|
{
|
||||||
vector<OutputJob*> jobs;
|
vector<OutputJob*> jobs;
|
||||||
JobQueueDispatcher<OutputJob*, OutputWorker>
|
JobQueueDispatcher<OutputJob*, OutputWorker>
|
||||||
dispatcher(threadCount, true, 0, false, NULL);
|
dispatcher(threadCount, true, 0, false, nullptr);
|
||||||
|
|
||||||
if (clusterCount > 0) {
|
if (clusterCount > 0) {
|
||||||
OutputJob *job = new RepartitionJob(ar, filenames, additionalCPPs);
|
OutputJob *job = new RepartitionJob(ar, filenames, additionalCPPs);
|
||||||
@@ -2809,7 +2809,7 @@ void AnalysisResult::outputCPPNameMaps() {
|
|||||||
char **params = (char **)calloc(m_paramRTTICounter, sizeof(char*));
|
char **params = (char **)calloc(m_paramRTTICounter, sizeof(char*));
|
||||||
for (map<string, int>::const_iterator
|
for (map<string, int>::const_iterator
|
||||||
iter = m_paramRTTIs.begin(); iter != m_paramRTTIs.end(); ++iter) {
|
iter = m_paramRTTIs.begin(); iter != m_paramRTTIs.end(); ++iter) {
|
||||||
assert(params[iter->second] == NULL);
|
assert(params[iter->second] == nullptr);
|
||||||
params[iter->second] = (char *)iter->first.c_str();
|
params[iter->second] = (char *)iter->first.c_str();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < m_paramRTTICounter; i++) {
|
for (int i = 0; i < m_paramRTTICounter; i++) {
|
||||||
@@ -2828,7 +2828,7 @@ void AnalysisResult::outputCPPNameMaps() {
|
|||||||
void AnalysisResult::outputRTTIMetaData(const char *filename) {
|
void AnalysisResult::outputRTTIMetaData(const char *filename) {
|
||||||
assert(filename && *filename);
|
assert(filename && *filename);
|
||||||
FILE *f = fopen(filename, "w");
|
FILE *f = fopen(filename, "w");
|
||||||
if (f == NULL) {
|
if (f == nullptr) {
|
||||||
throw Exception("Unable to open %s: %s", filename,
|
throw Exception("Unable to open %s: %s", filename,
|
||||||
Util::safe_strerror(errno).c_str());
|
Util::safe_strerror(errno).c_str());
|
||||||
}
|
}
|
||||||
@@ -2886,10 +2886,10 @@ void AnalysisResult::outputCPPUtilImpl(CodeGenerator::Output output) {
|
|||||||
for (set<int64>::const_iterator it = m_allIntegers.begin();
|
for (set<int64>::const_iterator it = m_allIntegers.begin();
|
||||||
it != m_allIntegers.end(); it++) {
|
it != m_allIntegers.end(); it++) {
|
||||||
if (!String::HasConverted(*(it))) {
|
if (!String::HasConverted(*(it))) {
|
||||||
if (*(it) == LONG_MIN) {
|
if (*(it) == std::numeric_limits<int64_t>::min()) {
|
||||||
cg_printf("(int64)0x%llxLL,\n", (uint64)LONG_MIN);
|
cg_printf("(int64)0x8000000000000000LL,\n");
|
||||||
} else {
|
} else {
|
||||||
cg_printf("%lldLL,\n", *(it));
|
cg_printf("%" PRId64 "L,\n", *(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4587,7 +4587,7 @@ void AnalysisResult::preGenerateCPP(CodeGenerator::Output output,
|
|||||||
AnalysisResultPtr ar = shared_from_this();
|
AnalysisResultPtr ar = shared_from_this();
|
||||||
vector<PreGenerateCPPJob*> jobs;
|
vector<PreGenerateCPPJob*> jobs;
|
||||||
JobQueueDispatcher<OutputJob*, OutputWorker>
|
JobQueueDispatcher<OutputJob*, OutputWorker>
|
||||||
dispatcher(threadCount, true, 0, false, NULL);
|
dispatcher(threadCount, true, 0, false, nullptr);
|
||||||
|
|
||||||
m_pregenerating = true;
|
m_pregenerating = true;
|
||||||
BOOST_FOREACH(FileScopePtr fs, files) {
|
BOOST_FOREACH(FileScopePtr fs, files) {
|
||||||
@@ -5065,7 +5065,7 @@ void AnalysisResult::outputStringProxyData(CodeGenerator &cg,
|
|||||||
cg_printf("%s,\n", lStrings[i].c_str());
|
cg_printf("%s,\n", lStrings[i].c_str());
|
||||||
}
|
}
|
||||||
for (uint i = 0; i < bStrings.size(); i++) {
|
for (uint i = 0; i < bStrings.size(); i++) {
|
||||||
cg_printf("%s, (const char *)%lldLL,\n",
|
cg_printf("%s, (const char *)%" PRId64 "L,\n",
|
||||||
bStrings[i].first.c_str(), (int64)bStrings[i].second);
|
bStrings[i].first.c_str(), (int64)bStrings[i].second);
|
||||||
}
|
}
|
||||||
cg_indentEnd("};\n");
|
cg_indentEnd("};\n");
|
||||||
@@ -5306,7 +5306,7 @@ void AnalysisResult::outputCPPSepExtensionMake() {
|
|||||||
for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
|
for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
|
||||||
Option::SepExtensionOptions &options = Option::SepExtensions[i];
|
Option::SepExtensionOptions &options = Option::SepExtensions[i];
|
||||||
if (options.include_path.empty()) {
|
if (options.include_path.empty()) {
|
||||||
f << "\t-I $(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
|
f << "\t-I $(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
|
||||||
} else {
|
} else {
|
||||||
f << "\t-I " << options.include_path;
|
f << "\t-I " << options.include_path;
|
||||||
}
|
}
|
||||||
@@ -5318,14 +5318,14 @@ void AnalysisResult::outputCPPSepExtensionMake() {
|
|||||||
Option::SepExtensionOptions &options = Option::SepExtensions[i];
|
Option::SepExtensionOptions &options = Option::SepExtensions[i];
|
||||||
if (options.shared) {
|
if (options.shared) {
|
||||||
if (options.lib_path.empty()) {
|
if (options.lib_path.empty()) {
|
||||||
f << "\t-L $(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
|
f << "\t-L $(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
|
||||||
} else {
|
} else {
|
||||||
f << "\t-L " << options.lib_path;
|
f << "\t-L " << options.lib_path;
|
||||||
}
|
}
|
||||||
f << " -l" << options.name << " \\\n";
|
f << " -l" << options.name << " \\\n";
|
||||||
} else {
|
} else {
|
||||||
if (options.lib_path.empty()) {
|
if (options.lib_path.empty()) {
|
||||||
f << "\t$(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
|
f << "\t$(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
|
||||||
} else {
|
} else {
|
||||||
f << "\t" << options.lib_path;
|
f << "\t" << options.lib_path;
|
||||||
}
|
}
|
||||||
+1
-1
@@ -635,7 +635,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
void processScopesParallel(const char *id, void *opaque = NULL);
|
void processScopesParallel(const char *id, void *opaque = nullptr);
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
void preWaitCallback(bool first,
|
void preWaitCallback(bool first,
|
||||||
@@ -116,13 +116,13 @@ public:
|
|||||||
static bool SkipRecurse(ConstructRawPtr cp);
|
static bool SkipRecurse(ConstructRawPtr cp);
|
||||||
|
|
||||||
static bool SkipRecurse(StatementPtr s) {
|
static bool SkipRecurse(StatementPtr s) {
|
||||||
return SkipRecurse(s ? s.get() : NULL);
|
return SkipRecurse(s ? s.get() : nullptr);
|
||||||
}
|
}
|
||||||
static bool SkipRecurse(StatementConstPtr s) {
|
static bool SkipRecurse(StatementConstPtr s) {
|
||||||
return SkipRecurse(s ? s.get() : NULL);
|
return SkipRecurse(s ? s.get() : nullptr);
|
||||||
}
|
}
|
||||||
static bool SkipRecurse(StatementRawPtr s) {
|
static bool SkipRecurse(StatementRawPtr s) {
|
||||||
return SkipRecurse(s ? s.get() : NULL);
|
return SkipRecurse(s ? s.get() : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SkipRecurse(const Statement *stmt);
|
static bool SkipRecurse(const Statement *stmt);
|
||||||
@@ -1247,7 +1247,7 @@ TypePtr ClassScope::checkConst(BlockScopeRawPtr context,
|
|||||||
ConstructPtr construct,
|
ConstructPtr construct,
|
||||||
const std::vector<std::string> &bases,
|
const std::vector<std::string> &bases,
|
||||||
BlockScope *&defScope) {
|
BlockScope *&defScope) {
|
||||||
defScope = NULL;
|
defScope = nullptr;
|
||||||
return getConstants()->check(context, name, type, coerce,
|
return getConstants()->check(context, name, type, coerce,
|
||||||
ar, construct, m_bases, defScope);
|
ar, construct, m_bases, defScope);
|
||||||
}
|
}
|
||||||
@@ -2216,7 +2216,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
|
|||||||
Option::ConstantPrefix,
|
Option::ConstantPrefix,
|
||||||
CodeGenerator::FormatLabel(name).c_str());
|
CodeGenerator::FormatLabel(name).c_str());
|
||||||
}
|
}
|
||||||
cg_printf("0x%x1LL", name_ix);
|
cg_printf("int64_t(0x%xd)", name_ix);
|
||||||
} else if (flags & ConstRedeclared) {
|
} else if (flags & ConstRedeclared) {
|
||||||
cg_printf("offsetof(%s,%s%s)+0x%x00000003",
|
cg_printf("offsetof(%s,%s%s)+0x%x00000003",
|
||||||
system ? "SystemGlobals" : "GlobalVariables",
|
system ? "SystemGlobals" : "GlobalVariables",
|
||||||
@@ -2232,7 +2232,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
|
|||||||
CodeGenerator::FormatLabel(name).c_str(),
|
CodeGenerator::FormatLabel(name).c_str(),
|
||||||
cls_ix);
|
cls_ix);
|
||||||
} else {
|
} else {
|
||||||
cg_printf("0x%x%07x%dLL", name_ix, cls_ix,
|
cg_printf("0x%x%07x%dL", name_ix, cls_ix,
|
||||||
flags & ConstDerivesFromRedeclared ? 4 : 5);
|
flags & ConstDerivesFromRedeclared ? 4 : 5);
|
||||||
}
|
}
|
||||||
*p = ++index;
|
*p = ++index;
|
||||||
@@ -3219,9 +3219,9 @@ void ClassScope::outputCPPMethodInvokeTableSupport(CodeGenerator &cg,
|
|||||||
assert(iterFuncs != funcScopes.end());
|
assert(iterFuncs != funcScopes.end());
|
||||||
FunctionScopePtr func = iterFuncs->second;
|
FunctionScopePtr func = iterFuncs->second;
|
||||||
|
|
||||||
const char *extra = NULL;
|
const char *extra = nullptr;
|
||||||
string prefix;
|
string prefix;
|
||||||
const char *instance = NULL;
|
const char *instance = nullptr;
|
||||||
if (func->isStatic()) {
|
if (func->isStatic()) {
|
||||||
prefix += Option::ClassPrefix;
|
prefix += Option::ClassPrefix;
|
||||||
prefix += id;
|
prefix += id;
|
||||||
@@ -3459,7 +3459,7 @@ void ClassScope::outputMethodWrappers(CodeGenerator &cg,
|
|||||||
FunctionScopePtr func = m_functionsVec[i];
|
FunctionScopePtr func = m_functionsVec[i];
|
||||||
if (func->isPublic() && !func->isConstructor(self) &&
|
if (func->isPublic() && !func->isConstructor(self) &&
|
||||||
!func->isMagic() && !func->isAbstract()) {
|
!func->isMagic() && !func->isAbstract()) {
|
||||||
func->outputMethodWrapper(cg, ar, NULL);
|
func->outputMethodWrapper(cg, ar, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ void ClearErrors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Error(ErrorType error, ConstructPtr construct) {
|
void Error(ErrorType error, ConstructPtr construct) {
|
||||||
if (hhvm) return;
|
if (!Option::RecordErrors) return;
|
||||||
ErrorInfoPtr errorInfo(new ErrorInfo());
|
ErrorInfoPtr errorInfo(new ErrorInfo());
|
||||||
errorInfo->m_error = error;
|
errorInfo->m_error = error;
|
||||||
errorInfo->m_construct1 = construct;
|
errorInfo->m_construct1 = construct;
|
||||||
@@ -187,7 +187,7 @@ void Error(ErrorType error, ConstructPtr construct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
|
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
|
||||||
if (hhvm) return;
|
if (!Option::RecordErrors) return;
|
||||||
ErrorInfoPtr errorInfo(new ErrorInfo());
|
ErrorInfoPtr errorInfo(new ErrorInfo());
|
||||||
errorInfo->m_error = error;
|
errorInfo->m_error = error;
|
||||||
errorInfo->m_construct1 = construct1;
|
errorInfo->m_construct1 = construct1;
|
||||||
@@ -197,7 +197,7 @@ void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Error(ErrorType error, ConstructPtr construct, const std::string &data) {
|
void Error(ErrorType error, ConstructPtr construct, const std::string &data) {
|
||||||
if (hhvm) return;
|
if (!Option::RecordErrors) return;
|
||||||
ErrorInfoPtr errorInfo(new ErrorInfo());
|
ErrorInfoPtr errorInfo(new ErrorInfo());
|
||||||
errorInfo->m_error = error;
|
errorInfo->m_error = error;
|
||||||
errorInfo->m_construct1 = construct;
|
errorInfo->m_construct1 = construct;
|
||||||
+1
-1
@@ -165,7 +165,7 @@ TypePtr ConstantTable::check(BlockScopeRawPtr context,
|
|||||||
assert(!m_blockScope.is(BlockScope::FunctionScope));
|
assert(!m_blockScope.is(BlockScope::FunctionScope));
|
||||||
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
|
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
|
||||||
TypePtr actualType;
|
TypePtr actualType;
|
||||||
defScope = NULL;
|
defScope = nullptr;
|
||||||
if (name == "true" || name == "false") {
|
if (name == "true" || name == "false") {
|
||||||
actualType = Type::Boolean;
|
actualType = Type::Boolean;
|
||||||
} else {
|
} else {
|
||||||
@@ -128,7 +128,7 @@ private:
|
|||||||
|
|
||||||
ControlFlowInfo *get(ConstructRawPtr cp) {
|
ControlFlowInfo *get(ConstructRawPtr cp) {
|
||||||
ConstructCFIMap::iterator it = m_ccfiMap.find(cp);
|
ConstructCFIMap::iterator it = m_ccfiMap.find(cp);
|
||||||
return it == m_ccfiMap.end() ? NULL : &it->second;
|
return it == m_ccfiMap.end() ? nullptr : &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlowInfo &cfi(ConstructRawPtr cp) {
|
ControlFlowInfo &cfi(ConstructRawPtr cp) {
|
||||||
@@ -735,7 +735,7 @@ const StringData* SymbolicStack::getName(int index) const {
|
|||||||
if (m_symStack[index].metaType == META_LITSTR) {
|
if (m_symStack[index].metaType == META_LITSTR) {
|
||||||
return m_symStack[index].metaData.name;
|
return m_symStack[index].metaData.name;
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StringData* SymbolicStack::getClsName(int index) const {
|
const StringData* SymbolicStack::getClsName(int index) const {
|
||||||
@@ -1353,7 +1353,7 @@ void EmitterVisitor::prepareEvalStack() {
|
|||||||
if (m_evalStackIsUnknown) {
|
if (m_evalStackIsUnknown) {
|
||||||
if (!m_evalStack.empty()) {
|
if (!m_evalStack.empty()) {
|
||||||
InvariantViolation("Emitter expected to have an empty evaluation "
|
InvariantViolation("Emitter expected to have an empty evaluation "
|
||||||
"stack because the eval stack was unknown, but"
|
"stack because the eval stack was unknown, but "
|
||||||
"it was non-empty.");
|
"it was non-empty.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1400,19 +1400,24 @@ bool EmitterVisitor::isJumpTarget(Offset target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define CONTROL_BODY(brk, cnt, brkH, cntH) \
|
#define CONTROL_BODY(brk, cnt, brkH, cntH) \
|
||||||
ControlTargetPusher _cop(this, -1, brk, cnt, brkH, cntH)
|
ControlTargetPusher _cop(this, -1, false, brk, cnt, brkH, cntH)
|
||||||
#define FOREACH_BODY(itId, brk, cnt, brkH, cntH) \
|
#define FOREACH_BODY(itId, itRef, brk, cnt, brkH, cntH) \
|
||||||
ControlTargetPusher _cop(this, itId, brk, cnt, brkH, cntH)
|
ControlTargetPusher _cop(this, itId, itRef, brk, cnt, brkH, cntH)
|
||||||
|
|
||||||
class IterFreeThunklet : public Thunklet {
|
class IterFreeThunklet : public Thunklet {
|
||||||
public:
|
public:
|
||||||
IterFreeThunklet(Id iterId) : m_id(iterId) {}
|
IterFreeThunklet(Id iterId, bool itRef) : m_id(iterId), m_itRef(itRef) {}
|
||||||
virtual void emit(Emitter& e) {
|
virtual void emit(Emitter& e) {
|
||||||
e.IterFree(m_id);
|
if (m_itRef) {
|
||||||
|
e.MIterFree(m_id);
|
||||||
|
} else {
|
||||||
|
e.IterFree(m_id);
|
||||||
|
}
|
||||||
e.Unwind();
|
e.Unwind();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Id m_id;
|
Id m_id;
|
||||||
|
bool m_itRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1595,7 +1600,7 @@ void EmitterVisitor::visit(FileScopePtr file) {
|
|||||||
StringData::GetStaticString(meth->getOriginalName());
|
StringData::GetStaticString(meth->getOriginalName());
|
||||||
m_methLabels[methName] = new Label();
|
m_methLabels[methName] = new Label();
|
||||||
// Emit afterwards
|
// Emit afterwards
|
||||||
postponeMeth(meth, NULL, true);
|
postponeMeth(meth, nullptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -1788,7 +1793,7 @@ static StringData* getClassName(ExpressionPtr e) {
|
|||||||
if (cls && !cls->isTrait()) {
|
if (cls && !cls->isTrait()) {
|
||||||
return StringData::GetStaticString(cls->getOriginalName());
|
return StringData::GetStaticString(cls->getOriginalName());
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataType getPredictedDataType(ExpressionPtr expr) {
|
static DataType getPredictedDataType(ExpressionPtr expr) {
|
||||||
@@ -1890,7 +1895,7 @@ bool isTupleInit(ExpressionPtr init_expr, int* cap) {
|
|||||||
ExpressionPtr ex = (*el)[i];
|
ExpressionPtr ex = (*el)[i];
|
||||||
if (ex->getKindOf() != Expression::KindOfArrayPairExpression) return false;
|
if (ex->getKindOf() != Expression::KindOfArrayPairExpression) return false;
|
||||||
ArrayPairExpressionPtr ap = static_pointer_cast<ArrayPairExpression>(ex);
|
ArrayPairExpressionPtr ap = static_pointer_cast<ArrayPairExpression>(ex);
|
||||||
if (ap->getName() != NULL || ap->isRef()) return false;
|
if (ap->getName() != nullptr || ap->isRef()) return false;
|
||||||
}
|
}
|
||||||
*cap = n;
|
*cap = n;
|
||||||
return true;
|
return true;
|
||||||
@@ -1960,7 +1965,11 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
}
|
}
|
||||||
if (bs->is(Statement::KindOfBreakStatement)) {
|
if (bs->is(Statement::KindOfBreakStatement)) {
|
||||||
if (m_contTargets.front().m_itId != -1) {
|
if (m_contTargets.front().m_itId != -1) {
|
||||||
e.IterFree(m_contTargets.front().m_itId);
|
if (m_contTargets.front().m_itRef) {
|
||||||
|
e.MIterFree(m_contTargets.front().m_itId);
|
||||||
|
} else {
|
||||||
|
e.IterFree(m_contTargets.front().m_itId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e.Jmp(m_contTargets.front().m_brkTarg);
|
e.Jmp(m_contTargets.front().m_brkTarg);
|
||||||
} else {
|
} else {
|
||||||
@@ -2514,7 +2523,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
postponeMeth(m, NULL, true);
|
postponeMeth(m, nullptr, true);
|
||||||
} else {
|
} else {
|
||||||
FuncEmitter* fe = m_ue.newFuncEmitter(nName, false);
|
FuncEmitter* fe = m_ue.newFuncEmitter(nName, false);
|
||||||
e.DefFunc(fe->id());
|
e.DefFunc(fe->id());
|
||||||
@@ -2834,7 +2843,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
if (op == T_COLLECTION) {
|
if (op == T_COLLECTION) {
|
||||||
ScalarExpressionPtr cls =
|
ScalarExpressionPtr cls =
|
||||||
static_pointer_cast<ScalarExpression>(b->getExp1());
|
static_pointer_cast<ScalarExpression>(b->getExp1());
|
||||||
const std::string* clsName = NULL;
|
const std::string* clsName = nullptr;
|
||||||
cls->getString(clsName);
|
cls->getString(clsName);
|
||||||
int cType = 0;
|
int cType = 0;
|
||||||
if (!strcasecmp(clsName->c_str(), "vector")) {
|
if (!strcasecmp(clsName->c_str(), "vector")) {
|
||||||
@@ -2987,7 +2996,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
ExpressionListPtr args(el->getExpressions());
|
ExpressionListPtr args(el->getExpressions());
|
||||||
int n = args ? args->getCount() : 0;
|
int n = args ? args->getCount() : 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
FPIRegionRecorder* fpi = NULL;
|
FPIRegionRecorder* fpi = nullptr;
|
||||||
if (el->getType() == '`') {
|
if (el->getType() == '`') {
|
||||||
const static StringData* s_shell_exec =
|
const static StringData* s_shell_exec =
|
||||||
StringData::GetStaticString("shell_exec");
|
StringData::GetStaticString("shell_exec");
|
||||||
@@ -3398,20 +3407,29 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
ExpressionListPtr params(om->getParams());
|
ExpressionListPtr params(om->getParams());
|
||||||
int numParams = params ? params->getCount() : 0;
|
int numParams = params ? params->getCount() : 0;
|
||||||
|
|
||||||
Offset fpiStart;
|
Offset fpiStart = 0;
|
||||||
if (!om->getName().empty()) {
|
ExpressionPtr methName = om->getNameExp();
|
||||||
// $obj->name(...)
|
bool useDirectForm = false;
|
||||||
// ^^^^
|
if (methName->is(Expression::KindOfScalarExpression)) {
|
||||||
// Use getOriginalName, which hasn't been case-normalized, since
|
ScalarExpressionPtr sval(
|
||||||
// __call() is case-preserving.
|
static_pointer_cast<ScalarExpression>(methName));
|
||||||
StringData* nameLiteral =
|
const std::string& methStr = sval->getOriginalLiteralString();
|
||||||
StringData::GetStaticString(om->getOriginalName());
|
if (!methStr.empty()) {
|
||||||
fpiStart = m_ue.bcPos();
|
// $obj->name(...)
|
||||||
e.FPushObjMethodD(numParams, nameLiteral);
|
// ^^^^
|
||||||
} else {
|
// Use getOriginalLiteralString(), which hasn't been
|
||||||
|
// case-normalized, since __call() needs to preserve
|
||||||
|
// the case.
|
||||||
|
StringData* nameLiteral = StringData::GetStaticString(methStr);
|
||||||
|
fpiStart = m_ue.bcPos();
|
||||||
|
e.FPushObjMethodD(numParams, nameLiteral);
|
||||||
|
useDirectForm = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!useDirectForm) {
|
||||||
// $obj->{...}(...)
|
// $obj->{...}(...)
|
||||||
// ^^^^^
|
// ^^^^^
|
||||||
visit(om->getNameExp());
|
visit(methName);
|
||||||
emitConvertToCell(e);
|
emitConvertToCell(e);
|
||||||
fpiStart = m_ue.bcPos();
|
fpiStart = m_ue.bcPos();
|
||||||
e.FPushObjMethod(numParams);
|
e.FPushObjMethod(numParams);
|
||||||
@@ -3419,7 +3437,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
if (clsName) {
|
if (clsName) {
|
||||||
Id id = m_ue.mergeLitstr(clsName);
|
Id id = m_ue.mergeLitstr(clsName);
|
||||||
m_metaInfo.add(fpiStart, Unit::MetaInfo::Class, false,
|
m_metaInfo.add(fpiStart, Unit::MetaInfo::Class, false,
|
||||||
om->getName().empty() ? 1 : 0, id);
|
useDirectForm ? 0 : 1, id);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
FPIRegionRecorder fpi(this, m_ue, m_evalStack, fpiStart);
|
FPIRegionRecorder fpi(this, m_ue, m_evalStack, fpiStart);
|
||||||
@@ -3625,7 +3643,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
TypedValue tvVal;
|
TypedValue tvVal;
|
||||||
initScalar(tvVal, val);
|
initScalar(tvVal, val);
|
||||||
|
|
||||||
if (key != NULL) {
|
if (key != nullptr) {
|
||||||
// Key.
|
// Key.
|
||||||
assert(key->isScalar());
|
assert(key->isScalar());
|
||||||
TypedValue tvKey;
|
TypedValue tvKey;
|
||||||
@@ -3768,7 +3786,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
PreClassEmitter* pce = m_ue.newPreClassEmitter(
|
PreClassEmitter* pce = m_ue.newPreClassEmitter(
|
||||||
className, PreClass::AlwaysHoistable);
|
className, PreClass::AlwaysHoistable);
|
||||||
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(),
|
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(),
|
||||||
AttrUnique | AttrPersistent, parentName, NULL);
|
AttrUnique | AttrPersistent, parentName, nullptr);
|
||||||
|
|
||||||
// We're still at the closure definition site. Emit code to instantiate
|
// We're still at the closure definition site. Emit code to instantiate
|
||||||
// the new anonymous class, with the use variables as arguments.
|
// the new anonymous class, with the use variables as arguments.
|
||||||
@@ -3789,7 +3807,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
|||||||
TypedValue uninit;
|
TypedValue uninit;
|
||||||
tvWriteUninit(&uninit);
|
tvWriteUninit(&uninit);
|
||||||
for (int i = 0; i < useCount; ++i) {
|
for (int i = 0; i < useCount; ++i) {
|
||||||
pce->addProperty(useVars[i].first, AttrPrivate, NULL, &uninit);
|
pce->addProperty(useVars[i].first, AttrPrivate, nullptr, &uninit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The constructor. This is entirely generated; all it does is stash its
|
// The constructor. This is entirely generated; all it does is stash its
|
||||||
@@ -4135,13 +4153,7 @@ void EmitterVisitor::emitVGet(Emitter& e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PassByRefKind {
|
EmitterVisitor::PassByRefKind EmitterVisitor::getPassByRefKind(ExpressionPtr exp) {
|
||||||
static const ssize_t AllowCell = 0;
|
|
||||||
static const ssize_t WarnOnCell = 1;
|
|
||||||
static const ssize_t ErrorOnCell = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t getPassByRefKind(ExpressionPtr exp) {
|
|
||||||
// The PassByRefKind of a list assignment expression is determined
|
// The PassByRefKind of a list assignment expression is determined
|
||||||
// by the PassByRefKind of the RHS. This loop will repeatedly recurse
|
// by the PassByRefKind of the RHS. This loop will repeatedly recurse
|
||||||
// on the RHS until it encounters an expression other than a list
|
// on the RHS until it encounters an expression other than a list
|
||||||
@@ -4265,21 +4277,25 @@ void EmitterVisitor::emitFuncCallArg(Emitter& e,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
emitFPass(e, paramId, getPassByRefKind(exp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitterVisitor::emitFPass(Emitter& e, int paramId, PassByRefKind passByRefKind) {
|
||||||
|
if (checkIfStackEmpty("FPass*")) return;
|
||||||
|
LocationGuard locGuard(e, m_tempLoc);
|
||||||
|
m_tempLoc.reset();
|
||||||
|
|
||||||
emitClsIfSPropBase(e);
|
emitClsIfSPropBase(e);
|
||||||
int iLast = m_evalStack.size()-1;
|
int iLast = m_evalStack.size()-1;
|
||||||
int i = scanStackForLocation(iLast);
|
int i = scanStackForLocation(iLast);
|
||||||
int sz = iLast - i;
|
int sz = iLast - i;
|
||||||
assert(sz >= 0);
|
assert(sz >= 0);
|
||||||
char sym = m_evalStack.get(i);
|
char sym = m_evalStack.get(i);
|
||||||
// This ensures that the FPass instruction will be associated with
|
|
||||||
// exp's source location.
|
|
||||||
LocationGuard locGuard(e, m_tempLoc);
|
|
||||||
m_tempLoc.reset();
|
|
||||||
if (sz == 0 || (sz == 1 && StackSym::GetMarker(sym) == StackSym::S)) {
|
if (sz == 0 || (sz == 1 && StackSym::GetMarker(sym) == StackSym::S)) {
|
||||||
switch (sym) {
|
switch (sym) {
|
||||||
case StackSym::L: e.FPassL(paramId, m_evalStack.getLoc(i)); break;
|
case StackSym::L: e.FPassL(paramId, m_evalStack.getLoc(i)); break;
|
||||||
case StackSym::C:
|
case StackSym::C:
|
||||||
switch (getPassByRefKind(exp)) {
|
switch (passByRefKind) {
|
||||||
case PassByRefKind::AllowCell: e.FPassC(paramId); break;
|
case PassByRefKind::AllowCell: e.FPassC(paramId); break;
|
||||||
case PassByRefKind::WarnOnCell: e.FPassCW(paramId); break;
|
case PassByRefKind::WarnOnCell: e.FPassCW(paramId); break;
|
||||||
case PassByRefKind::ErrorOnCell: e.FPassCE(paramId); break;
|
case PassByRefKind::ErrorOnCell: e.FPassCE(paramId); break;
|
||||||
@@ -4575,7 +4591,13 @@ void EmitterVisitor::emitConvertToCell(Emitter& e) {
|
|||||||
|
|
||||||
void EmitterVisitor::emitFreePendingIters(Emitter& e) {
|
void EmitterVisitor::emitFreePendingIters(Emitter& e) {
|
||||||
for (unsigned i = 0; i < m_pendingIters.size(); ++i) {
|
for (unsigned i = 0; i < m_pendingIters.size(); ++i) {
|
||||||
e.IterFree(m_pendingIters[i]);
|
auto pendingIter = m_pendingIters[i];
|
||||||
|
if (pendingIter.second == KindOfMIter) {
|
||||||
|
e.MIterFree(pendingIter.first);
|
||||||
|
} else {
|
||||||
|
assert(pendingIter.second == KindOfIter);
|
||||||
|
e.IterFree(pendingIter.first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4739,7 +4761,7 @@ void EmitterVisitor::emitClsIfSPropBase(Emitter& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
|
Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
|
||||||
Label* label = NULL;
|
Label* label = nullptr;
|
||||||
StatementListPtr stmts(static_pointer_cast<StatementList>(s));
|
StatementListPtr stmts(static_pointer_cast<StatementList>(s));
|
||||||
for (int i = 0; i < stmts->getCount(); i++) {
|
for (int i = 0; i < stmts->getCount(); i++) {
|
||||||
StatementPtr s((*stmts)[i]);
|
StatementPtr s((*stmts)[i]);
|
||||||
@@ -4749,7 +4771,7 @@ Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
|
|||||||
visit(f);
|
visit(f);
|
||||||
} else if (s->is(Statement::KindOfGotoStatement)) {
|
} else if (s->is(Statement::KindOfGotoStatement)) {
|
||||||
GotoStatementPtr g(static_pointer_cast<GotoStatement>(s));
|
GotoStatementPtr g(static_pointer_cast<GotoStatement>(s));
|
||||||
always_assert(label == NULL);
|
always_assert(label == nullptr);
|
||||||
label = &m_gotoLabels[StringData::GetStaticString(g->label())];
|
label = &m_gotoLabels[StringData::GetStaticString(g->label())];
|
||||||
} else {
|
} else {
|
||||||
not_implemented();
|
not_implemented();
|
||||||
@@ -5292,7 +5314,7 @@ void EmitterVisitor::emitPostponedMeths() {
|
|||||||
e.VerifyParamType(i);
|
e.VerifyParamType(i);
|
||||||
}
|
}
|
||||||
if (fe->isClosureBody()) {
|
if (fe->isClosureBody()) {
|
||||||
assert(p.m_closureUseVars != NULL);
|
assert(p.m_closureUseVars != nullptr);
|
||||||
// Emit code to unpack the instance variables (which store the
|
// Emit code to unpack the instance variables (which store the
|
||||||
// use-variables) into locals. Some of the use-variables may have the
|
// use-variables) into locals. Some of the use-variables may have the
|
||||||
// same name, in which case the last one wins.
|
// same name, in which case the last one wins.
|
||||||
@@ -5583,7 +5605,7 @@ void EmitterVisitor::emitPostponedClosureCtors() {
|
|||||||
ClosureUseVarVec& useVars = ctor.m_useVars;
|
ClosureUseVarVec& useVars = ctor.m_useVars;
|
||||||
FuncEmitter* fe = ctor.m_fe;
|
FuncEmitter* fe = ctor.m_fe;
|
||||||
const Location* sLoc = ctor.m_expr->getLocation().get();
|
const Location* sLoc = ctor.m_expr->getLocation().get();
|
||||||
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), AttrPublic, false, NULL);
|
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), AttrPublic, false, nullptr);
|
||||||
|
|
||||||
unsigned n = useVars.size();
|
unsigned n = useVars.size();
|
||||||
Emitter e(ctor.m_expr, m_ue, *this);
|
Emitter e(ctor.m_expr, m_ue, *this);
|
||||||
@@ -5837,7 +5859,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
|||||||
ExpressionListPtr params(node->getParams());
|
ExpressionListPtr params(node->getParams());
|
||||||
int numParams = params ? params->getCount() : 0;
|
int numParams = params ? params->getCount() : 0;
|
||||||
bool isBuiltinCall = false;
|
bool isBuiltinCall = false;
|
||||||
StringData* nLiteral = NULL;
|
StringData* nLiteral = nullptr;
|
||||||
Offset fpiStart;
|
Offset fpiStart;
|
||||||
if (node->getClass() || !node->getClassName().empty()) {
|
if (node->getClass() || !node->getClassName().empty()) {
|
||||||
bool isSelfOrParent = node->isSelf() || node->isParent();
|
bool isSelfOrParent = node->isSelf() || node->isParent();
|
||||||
@@ -5884,7 +5906,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
|||||||
e.FPushFuncD(numParams, nLiteral);
|
e.FPushFuncD(numParams, nLiteral);
|
||||||
} else {
|
} else {
|
||||||
// Special handling for func_get_args and friends inside a generator.
|
// Special handling for func_get_args and friends inside a generator.
|
||||||
const StringData* specialMethodName = NULL;
|
const StringData* specialMethodName = nullptr;
|
||||||
static const StringData* contName =
|
static const StringData* contName =
|
||||||
StringData::GetStaticString(CONTINUATION_OBJECT_NAME);
|
StringData::GetStaticString(CONTINUATION_OBJECT_NAME);
|
||||||
Id contId = m_curFunc->lookupVarId(contName);
|
Id contId = m_curFunc->lookupVarId(contName);
|
||||||
@@ -5902,7 +5924,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
|||||||
specialMethodName = s_get_arg;
|
specialMethodName = s_get_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specialMethodName != NULL) {
|
if (specialMethodName != nullptr) {
|
||||||
emitVirtualLocal(contId);
|
emitVirtualLocal(contId);
|
||||||
emitCGet(e);
|
emitCGet(e);
|
||||||
fpiStart = m_ue.bcPos();
|
fpiStart = m_ue.bcPos();
|
||||||
@@ -6082,9 +6104,9 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
pce->addUserAttribute(uaName, tv);
|
pce->addUserAttribute(uaName, tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
NonScalarVec* nonScalarPinitVec = NULL;
|
NonScalarVec* nonScalarPinitVec = nullptr;
|
||||||
NonScalarVec* nonScalarSinitVec = NULL;
|
NonScalarVec* nonScalarSinitVec = nullptr;
|
||||||
NonScalarVec* nonScalarConstVec = NULL;
|
NonScalarVec* nonScalarConstVec = nullptr;
|
||||||
if (StatementListPtr stmts = is->getStmts()) {
|
if (StatementListPtr stmts = is->getStmts()) {
|
||||||
int i, n = stmts->getCount();
|
int i, n = stmts->getCount();
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@@ -6128,12 +6150,12 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
} else {
|
} else {
|
||||||
tvWriteUninit(&tvVal);
|
tvWriteUninit(&tvVal);
|
||||||
if (!(attrs & AttrStatic)) {
|
if (!(attrs & AttrStatic)) {
|
||||||
if (nonScalarPinitVec == NULL) {
|
if (nonScalarPinitVec == nullptr) {
|
||||||
nonScalarPinitVec = new NonScalarVec();
|
nonScalarPinitVec = new NonScalarVec();
|
||||||
}
|
}
|
||||||
nonScalarPinitVec->push_back(NonScalarPair(propName, vNode));
|
nonScalarPinitVec->push_back(NonScalarPair(propName, vNode));
|
||||||
} else {
|
} else {
|
||||||
if (nonScalarSinitVec == NULL) {
|
if (nonScalarSinitVec == nullptr) {
|
||||||
nonScalarSinitVec = new NonScalarVec();
|
nonScalarSinitVec = new NonScalarVec();
|
||||||
}
|
}
|
||||||
nonScalarSinitVec->push_back(NonScalarPair(propName, vNode));
|
nonScalarSinitVec->push_back(NonScalarPair(propName, vNode));
|
||||||
@@ -6166,7 +6188,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
initScalar(tvVal, vNode);
|
initScalar(tvVal, vNode);
|
||||||
} else {
|
} else {
|
||||||
tvWriteUninit(&tvVal);
|
tvWriteUninit(&tvVal);
|
||||||
if (nonScalarConstVec == NULL) {
|
if (nonScalarConstVec == nullptr) {
|
||||||
nonScalarConstVec = new NonScalarVec();
|
nonScalarConstVec = new NonScalarVec();
|
||||||
}
|
}
|
||||||
nonScalarConstVec->push_back(NonScalarPair(constName, vNode));
|
nonScalarConstVec->push_back(NonScalarPair(constName, vNode));
|
||||||
@@ -6198,7 +6220,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
postponeCtor(is, fe);
|
postponeCtor(is, fe);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonScalarPinitVec != NULL) {
|
if (nonScalarPinitVec != nullptr) {
|
||||||
// Non-scalar property initializers require 86pinit() for run-time
|
// Non-scalar property initializers require 86pinit() for run-time
|
||||||
// initialization support.
|
// initialization support.
|
||||||
static const StringData* methName = StringData::GetStaticString("86pinit");
|
static const StringData* methName = StringData::GetStaticString("86pinit");
|
||||||
@@ -6207,7 +6229,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
postponePinit(is, fe, nonScalarPinitVec);
|
postponePinit(is, fe, nonScalarPinitVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonScalarSinitVec != NULL) {
|
if (nonScalarSinitVec != nullptr) {
|
||||||
// Non-scalar property initializers require 86sinit() for run-time
|
// Non-scalar property initializers require 86sinit() for run-time
|
||||||
// initialization support.
|
// initialization support.
|
||||||
static const StringData* methName = StringData::GetStaticString("86sinit");
|
static const StringData* methName = StringData::GetStaticString("86sinit");
|
||||||
@@ -6216,7 +6238,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
postponeSinit(is, fe, nonScalarSinitVec);
|
postponeSinit(is, fe, nonScalarSinitVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonScalarConstVec != NULL) {
|
if (nonScalarConstVec != nullptr) {
|
||||||
// Non-scalar constant initializers require 86cinit() for run-time
|
// Non-scalar constant initializers require 86cinit() for run-time
|
||||||
// initialization support.
|
// initialization support.
|
||||||
static const StringData* methName = StringData::GetStaticString("86cinit");
|
static const StringData* methName = StringData::GetStaticString("86cinit");
|
||||||
@@ -6230,15 +6252,25 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
|||||||
return hoistable;
|
return hoistable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
|
void
|
||||||
Label& cntTarg, Label& brkHand, Label& cntHand, Id iter /* = -1 */) {
|
EmitterVisitor::emitBreakHandler(Emitter& e,
|
||||||
|
Label& brkTarg,
|
||||||
|
Label& cntTarg,
|
||||||
|
Label& brkHand,
|
||||||
|
Label& cntHand,
|
||||||
|
Id iter /* = -1 */,
|
||||||
|
IterKind itKind /* = KindOfIter */) {
|
||||||
// Handle dynamic break
|
// Handle dynamic break
|
||||||
if (brkHand.isUsed()) {
|
if (brkHand.isUsed()) {
|
||||||
brkHand.set(e);
|
brkHand.set(e);
|
||||||
// Whatever happens, we have left this loop
|
// Whatever happens, we have left this loop
|
||||||
if (iter != -1) {
|
if (iter != -1) {
|
||||||
e.IterFree(iter);
|
if (itKind == KindOfMIter) {
|
||||||
|
e.MIterFree(iter);
|
||||||
|
} else {
|
||||||
|
assert(itKind == KindOfIter);
|
||||||
|
e.IterFree(iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e.Int(1);
|
e.Int(1);
|
||||||
e.Sub();
|
e.Sub();
|
||||||
@@ -6266,7 +6298,12 @@ void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
|
|||||||
e.Jmp(cntTarg);
|
e.Jmp(cntTarg);
|
||||||
leaving.set(e);
|
leaving.set(e);
|
||||||
// Leaving this loop
|
// Leaving this loop
|
||||||
e.IterFree(iter);
|
if (itKind == KindOfMIter) {
|
||||||
|
e.MIterFree(iter);
|
||||||
|
} else {
|
||||||
|
assert(itKind == KindOfIter);
|
||||||
|
e.IterFree(iter);
|
||||||
|
}
|
||||||
e.Jmp(topContHandler());
|
e.Jmp(topContHandler());
|
||||||
} else {
|
} else {
|
||||||
e.JmpZ(topContHandler());
|
e.JmpZ(topContHandler());
|
||||||
@@ -6279,11 +6316,11 @@ void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
|
|||||||
class ForeachIterGuard {
|
class ForeachIterGuard {
|
||||||
EmitterVisitor& m_ev;
|
EmitterVisitor& m_ev;
|
||||||
public:
|
public:
|
||||||
ForeachIterGuard(EmitterVisitor& ev, Id iterId) : m_ev(ev) {
|
ForeachIterGuard(EmitterVisitor& ev, Id iterId, bool itRef) : m_ev(ev) {
|
||||||
m_ev.pushIterId(iterId);
|
m_ev.pushIterScope(iterId, itRef);
|
||||||
}
|
}
|
||||||
~ForeachIterGuard() {
|
~ForeachIterGuard() {
|
||||||
m_ev.popIterId();
|
m_ev.popIterScope();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6306,7 +6343,7 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
Label start;
|
Label start;
|
||||||
Offset bIterStart;
|
Offset bIterStart;
|
||||||
Id itId = m_curFunc->allocIterator();
|
Id itId = m_curFunc->allocIterator();
|
||||||
ForeachIterGuard fig(*this, itId);
|
ForeachIterGuard fig(*this, itId, strong);
|
||||||
bool simpleCase = (!key || key->is(Expression::KindOfSimpleVariable)) &&
|
bool simpleCase = (!key || key->is(Expression::KindOfSimpleVariable)) &&
|
||||||
val->is(Expression::KindOfSimpleVariable);
|
val->is(Expression::KindOfSimpleVariable);
|
||||||
|
|
||||||
@@ -6334,9 +6371,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
if (strong) {
|
if (strong) {
|
||||||
emitConvertToVar(e);
|
emitConvertToVar(e);
|
||||||
if (key) {
|
if (key) {
|
||||||
e.IterInitMK(itId, exit, valTempLocal, keyTempLocal);
|
e.MIterInitK(itId, exit, valTempLocal, keyTempLocal);
|
||||||
} else {
|
} else {
|
||||||
e.IterInitM(itId, exit, valTempLocal);
|
e.MIterInit(itId, exit, valTempLocal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emitConvertToCell(e);
|
emitConvertToCell(e);
|
||||||
@@ -6366,9 +6403,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
|
|
||||||
if (strong) {
|
if (strong) {
|
||||||
if (key) {
|
if (key) {
|
||||||
e.IterInitMK(itId, exit, valTempLocal, keyTempLocal);
|
e.MIterInitK(itId, exit, valTempLocal, keyTempLocal);
|
||||||
} else {
|
} else {
|
||||||
e.IterInitM(itId, exit, valTempLocal);
|
e.MIterInit(itId, exit, valTempLocal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (key) {
|
if (key) {
|
||||||
@@ -6413,7 +6450,7 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FOREACH_BODY(itId, exit, next, brkHand, cntHand);
|
FOREACH_BODY(itId, strong, exit, next, brkHand, cntHand);
|
||||||
if (body) visit(body);
|
if (body) visit(body);
|
||||||
}
|
}
|
||||||
bool needBreakHandler = (brkHand.isUsed() || cntHand.isUsed());
|
bool needBreakHandler = (brkHand.isUsed() || cntHand.isUsed());
|
||||||
@@ -6432,9 +6469,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
m_evalStack.cleanTopMeta();
|
m_evalStack.cleanTopMeta();
|
||||||
if (strong) {
|
if (strong) {
|
||||||
if (key) {
|
if (key) {
|
||||||
e.IterNextMK(itId, start, valTempLocal, keyTempLocal);
|
e.MIterNextK(itId, start, valTempLocal, keyTempLocal);
|
||||||
} else {
|
} else {
|
||||||
e.IterNextM(itId, start, valTempLocal);
|
e.MIterNext(itId, start, valTempLocal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (key) {
|
if (key) {
|
||||||
@@ -6443,10 +6480,12 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
|
|||||||
e.IterNext(itId, start, valTempLocal);
|
e.IterNext(itId, start, valTempLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newFaultRegion(bIterStart, m_ue.bcPos(), new IterFreeThunklet(itId), itId);
|
newFaultRegion(bIterStart, m_ue.bcPos(), new IterFreeThunklet(itId, strong),
|
||||||
|
itId);
|
||||||
if (needBreakHandler) {
|
if (needBreakHandler) {
|
||||||
e.Jmp(exit);
|
e.Jmp(exit);
|
||||||
emitBreakHandler(e, exit, next, brkHand, cntHand, itId);
|
IterKind itKind = strong ? KindOfMIter : KindOfIter;
|
||||||
|
emitBreakHandler(e, exit, next, brkHand, cntHand, itId, itKind);
|
||||||
}
|
}
|
||||||
if (!simpleCase) {
|
if (!simpleCase) {
|
||||||
m_curFunc->freeUnnamedLocal(valTempLocal);
|
m_curFunc->freeUnnamedLocal(valTempLocal);
|
||||||
@@ -6604,8 +6643,8 @@ void EmitterVisitor::finishFunc(Emitter& e, FuncEmitter* fe) {
|
|||||||
|
|
||||||
StringData* EmitterVisitor::newClosureName() {
|
StringData* EmitterVisitor::newClosureName() {
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
str << "closure$";
|
str << "Closure" << '$';
|
||||||
if (m_curFunc->pce() != NULL) {
|
if (m_curFunc->pce() != nullptr) {
|
||||||
str << m_curFunc->pce()->name()->data();
|
str << m_curFunc->pce()->name()->data();
|
||||||
}
|
}
|
||||||
str << '$';
|
str << '$';
|
||||||
@@ -6806,14 +6845,14 @@ static Unit* emitHHBCNativeFuncUnit(const HhbcExtFuncInfo* builtinFuncs,
|
|||||||
fe->finish(ue->bcPos(), false);
|
fe->finish(ue->bcPos(), false);
|
||||||
ue->recordFunction(fe);
|
ue->recordFunction(fe);
|
||||||
|
|
||||||
for (ssize_t i = 0LL; i < numBuiltinFuncs; ++i) {
|
for (ssize_t i = 0; i < numBuiltinFuncs; ++i) {
|
||||||
const HhbcExtFuncInfo* info = &builtinFuncs[i];
|
const HhbcExtFuncInfo* info = &builtinFuncs[i];
|
||||||
StringData* name = StringData::GetStaticString(info->m_name);
|
StringData* name = StringData::GetStaticString(info->m_name);
|
||||||
BuiltinFunction bif = (BuiltinFunction)info->m_builtinFunc;
|
BuiltinFunction bif = (BuiltinFunction)info->m_builtinFunc;
|
||||||
BuiltinFunction nif = (BuiltinFunction)info->m_nativeFunc;
|
BuiltinFunction nif = (BuiltinFunction)info->m_nativeFunc;
|
||||||
const ClassInfo::MethodInfo* mi = ClassInfo::FindFunction(name);
|
const ClassInfo::MethodInfo* mi = ClassInfo::FindFunction(name);
|
||||||
assert(mi &&
|
assert(mi &&
|
||||||
"MethodInfo not found; probably need to rebuild src/system");
|
"MethodInfo not found; probably need to rebuild hphp/system");
|
||||||
FuncEmitter* fe = ue->newFuncEmitter(name, /*top*/ true);
|
FuncEmitter* fe = ue->newFuncEmitter(name, /*top*/ true);
|
||||||
Offset base = ue->bcPos();
|
Offset base = ue->bcPos();
|
||||||
fe->setBuiltinFunc(mi, bif, nif, base);
|
fe->setBuiltinFunc(mi, bif, nif, base);
|
||||||
@@ -6929,7 +6968,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
|||||||
// Build up extClassHash, a hashtable that maps class names to structures
|
// Build up extClassHash, a hashtable that maps class names to structures
|
||||||
// containing C++ function pointers for the class's methods and constructors
|
// containing C++ function pointers for the class's methods and constructors
|
||||||
assert(Class::s_extClassHash.size() == 0);
|
assert(Class::s_extClassHash.size() == 0);
|
||||||
for (long long i = 0LL; i < numBuiltinClasses; ++i) {
|
for (long long i = 0; i < numBuiltinClasses; ++i) {
|
||||||
const HhbcExtClassInfo* info = builtinClasses + i;
|
const HhbcExtClassInfo* info = builtinClasses + i;
|
||||||
StringData *s = StringData::GetStaticString(info->m_name);
|
StringData *s = StringData::GetStaticString(info->m_name);
|
||||||
Class::s_extClassHash[s] = info;
|
Class::s_extClassHash[s] = info;
|
||||||
@@ -6978,13 +7017,13 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
|||||||
assert(pending.empty());
|
assert(pending.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0LL; i < classEntries.size(); ++i) {
|
for (unsigned int i = 0; i < classEntries.size(); ++i) {
|
||||||
Entry& e = classEntries[i];
|
Entry& e = classEntries[i];
|
||||||
StringData* parentName =
|
StringData* parentName =
|
||||||
StringData::GetStaticString(e.ci->getParentClass().get());
|
StringData::GetStaticString(e.ci->getParentClass().get());
|
||||||
PreClassEmitter* pce = ue->newPreClassEmitter(e.name,
|
PreClassEmitter* pce = ue->newPreClassEmitter(e.name,
|
||||||
PreClass::AlwaysHoistable);
|
PreClass::AlwaysHoistable);
|
||||||
pce->init(0, 0, ue->bcPos(), AttrUnique | AttrPersistent, parentName, NULL);
|
pce->init(0, 0, ue->bcPos(), AttrUnique | AttrPersistent, parentName, nullptr);
|
||||||
pce->setBuiltinClassInfo(e.ci, e.info->m_InstanceCtor, e.info->m_sizeof);
|
pce->setBuiltinClassInfo(e.ci, e.info->m_InstanceCtor, e.info->m_sizeof);
|
||||||
{
|
{
|
||||||
ClassInfo::InterfaceVec intfVec = e.ci->getInterfacesVec();
|
ClassInfo::InterfaceVec intfVec = e.ci->getInterfacesVec();
|
||||||
@@ -7013,7 +7052,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
|||||||
const ClassInfo::MethodInfo* mi =
|
const ClassInfo::MethodInfo* mi =
|
||||||
e.ci->getMethodInfo(std::string(methodInfo->m_name));
|
e.ci->getMethodInfo(std::string(methodInfo->m_name));
|
||||||
Offset base = ue->bcPos();
|
Offset base = ue->bcPos();
|
||||||
fe->setBuiltinFunc(mi, bcf, NULL, base);
|
fe->setBuiltinFunc(mi, bcf, nullptr, base);
|
||||||
ue->emitOp(OpNativeImpl);
|
ue->emitOp(OpNativeImpl);
|
||||||
}
|
}
|
||||||
Offset past = ue->bcPos();
|
Offset past = ue->bcPos();
|
||||||
@@ -7062,7 +7101,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
||||||
assert(ue != NULL);
|
assert(ue != nullptr);
|
||||||
|
|
||||||
if (Option::GenerateTextHHBC) {
|
if (Option::GenerateTextHHBC) {
|
||||||
std::unique_ptr<Unit> unit(ue->create());
|
std::unique_ptr<Unit> unit(ue->create());
|
||||||
@@ -7087,7 +7126,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
|
|||||||
class UEQ : public Synchronizable {
|
class UEQ : public Synchronizable {
|
||||||
public:
|
public:
|
||||||
void push(UnitEmitter* ue) {
|
void push(UnitEmitter* ue) {
|
||||||
assert(ue != NULL);
|
assert(ue != nullptr);
|
||||||
Lock lock(this);
|
Lock lock(this);
|
||||||
m_ues.push_back(ue);
|
m_ues.push_back(ue);
|
||||||
notify();
|
notify();
|
||||||
@@ -7097,12 +7136,12 @@ class UEQ : public Synchronizable {
|
|||||||
if (m_ues.empty()) {
|
if (m_ues.empty()) {
|
||||||
// Check for empty() after wait(), in case of spurious wakeup.
|
// Check for empty() after wait(), in case of spurious wakeup.
|
||||||
if (!wait(sec, nsec) || m_ues.empty()) {
|
if (!wait(sec, nsec) || m_ues.empty()) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(m_ues.size() > 0);
|
assert(m_ues.size() > 0);
|
||||||
UnitEmitter* ue = m_ues.front();
|
UnitEmitter* ue = m_ues.front();
|
||||||
assert(ue != NULL);
|
assert(ue != nullptr);
|
||||||
m_ues.pop_front();
|
m_ues.pop_front();
|
||||||
return ue;
|
return ue;
|
||||||
}
|
}
|
||||||
@@ -7264,7 +7303,7 @@ void emitAllHHBC(AnalysisResultPtr ar) {
|
|||||||
// Poll, but with a 100ms timeout so that this thread doesn't spin wildly
|
// Poll, but with a 100ms timeout so that this thread doesn't spin wildly
|
||||||
// if it gets ahead of the workers.
|
// if it gets ahead of the workers.
|
||||||
UnitEmitter* ue = s_ueq.tryPop(0, 100 * 1000 * 1000);
|
UnitEmitter* ue = s_ueq.tryPop(0, 100 * 1000 * 1000);
|
||||||
if ((didPop = (ue != NULL))) {
|
if ((didPop = (ue != nullptr))) {
|
||||||
ues.push_back(ue);
|
ues.push_back(ue);
|
||||||
}
|
}
|
||||||
if (ues.size() == kBatchSize
|
if (ues.size() == kBatchSize
|
||||||
@@ -7306,6 +7345,7 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
|
|||||||
for (auto& i : RuntimeOption::DynamicInvokeFunctions) {
|
for (auto& i : RuntimeOption::DynamicInvokeFunctions) {
|
||||||
Option::DynamicInvokeFunctions.insert(i);
|
Option::DynamicInvokeFunctions.insert(i);
|
||||||
}
|
}
|
||||||
|
Option::RecordErrors = false;
|
||||||
Option::OutputHHBC = true;
|
Option::OutputHHBC = true;
|
||||||
Option::ParseTimeOpts = false;
|
Option::ParseTimeOpts = false;
|
||||||
Option::WholeProgram = false;
|
Option::WholeProgram = false;
|
||||||
@@ -7315,7 +7355,7 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
|
|||||||
BuiltinSymbols::Load(ar, true);
|
BuiltinSymbols::Load(ar, true);
|
||||||
BuiltinSymbols::NoSuperGlobals = false;
|
BuiltinSymbols::NoSuperGlobals = false;
|
||||||
TypeConstraint tc;
|
TypeConstraint tc;
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -7350,15 +7390,13 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
|
|||||||
fsp->analyzeProgram(ar);
|
fsp->analyzeProgram(ar);
|
||||||
|
|
||||||
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
||||||
if (RuntimeOption::RepoCommit) {
|
Repo::get().commitUnit(ue, unitOrigin);
|
||||||
Repo::get().commitUnit(ue, unitOrigin);
|
|
||||||
}
|
|
||||||
Unit* unit = ue->create();
|
Unit* unit = ue->create();
|
||||||
delete ue;
|
delete ue;
|
||||||
return unit;
|
return unit;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
// extern "C" function should not be throwing exceptions...
|
// extern "C" function should not be throwing exceptions...
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,12 +379,20 @@ public:
|
|||||||
EXCEPTION_COMMON_IMPL(IncludeTimeFatalException);
|
EXCEPTION_COMMON_IMPL(IncludeTimeFatalException);
|
||||||
};
|
};
|
||||||
|
|
||||||
void pushIterId(Id id) { m_pendingIters.push_back(id); }
|
enum IterKind {
|
||||||
void popIterId() { m_pendingIters.pop_back(); }
|
KindOfIter = 0,
|
||||||
|
KindOfMIter = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
void pushIterScope(Id id, bool itRef = false) {
|
||||||
|
IterKind itKind = itRef ? KindOfMIter : KindOfIter;
|
||||||
|
m_pendingIters.push_back(std::pair<Id,IterKind>(id,itKind));
|
||||||
|
}
|
||||||
|
void popIterScope() { m_pendingIters.pop_back(); }
|
||||||
private:
|
private:
|
||||||
typedef std::pair<StringData*, bool> ClosureUseVar; // (name, byRef)
|
typedef std::pair<StringData*, bool> ClosureUseVar; // (name, byRef)
|
||||||
typedef std::vector<ClosureUseVar> ClosureUseVarVec;
|
typedef std::vector<ClosureUseVar> ClosureUseVarVec;
|
||||||
typedef std::vector<Id> IdVec;
|
typedef std::vector<std::pair<Id,IterKind> > PendingIterVec;
|
||||||
class PostponedMeth {
|
class PostponedMeth {
|
||||||
public:
|
public:
|
||||||
PostponedMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
|
PostponedMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
|
||||||
@@ -427,10 +435,12 @@ private:
|
|||||||
};
|
};
|
||||||
class ControlTargets {
|
class ControlTargets {
|
||||||
public:
|
public:
|
||||||
ControlTargets(Id itId, Label& brkTarg, Label& cntTarg, Label& brkHand,
|
ControlTargets(Id itId, bool itRef, Label& brkTarg, Label& cntTarg,
|
||||||
Label& cntHand) : m_itId(itId), m_brkTarg(brkTarg), m_cntTarg(cntTarg),
|
Label& brkHand, Label& cntHand) :
|
||||||
m_brkHand(brkHand), m_cntHand(cntHand) {}
|
m_itId(itId), m_itRef(itRef), m_brkTarg(brkTarg), m_cntTarg(cntTarg),
|
||||||
|
m_brkHand(brkHand), m_cntHand(cntHand) {}
|
||||||
Id m_itId;
|
Id m_itId;
|
||||||
|
bool m_itRef;
|
||||||
Label& m_brkTarg; // Jump here for "break;" (after doing IterFree)
|
Label& m_brkTarg; // Jump here for "break;" (after doing IterFree)
|
||||||
Label& m_cntTarg; // Jump here for "continue;"
|
Label& m_cntTarg; // Jump here for "continue;"
|
||||||
Label& m_brkHand; // Push N and jump here for "break N;"
|
Label& m_brkHand; // Push N and jump here for "break N;"
|
||||||
@@ -438,9 +448,9 @@ private:
|
|||||||
};
|
};
|
||||||
class ControlTargetPusher {
|
class ControlTargetPusher {
|
||||||
public:
|
public:
|
||||||
ControlTargetPusher(EmitterVisitor* e, Id itId, Label& brkTarg,
|
ControlTargetPusher(EmitterVisitor* e, Id itId, bool itRef, Label& brkTarg,
|
||||||
Label& cntTarg, Label& brkHand, Label& cntHand) : m_e(e) {
|
Label& cntTarg, Label& brkHand, Label& cntHand) : m_e(e) {
|
||||||
e->m_contTargets.push_front(ControlTargets(itId, brkTarg, cntTarg,
|
e->m_contTargets.push_front(ControlTargets(itId, itRef, brkTarg, cntTarg,
|
||||||
brkHand, cntHand));
|
brkHand, cntHand));
|
||||||
}
|
}
|
||||||
~ControlTargetPusher() {
|
~ControlTargetPusher() {
|
||||||
@@ -505,7 +515,7 @@ private:
|
|||||||
std::deque<PostponedNonScalars> m_postponedSinits;
|
std::deque<PostponedNonScalars> m_postponedSinits;
|
||||||
std::deque<PostponedNonScalars> m_postponedCinits;
|
std::deque<PostponedNonScalars> m_postponedCinits;
|
||||||
std::deque<PostponedClosureCtor> m_postponedClosureCtors;
|
std::deque<PostponedClosureCtor> m_postponedClosureCtors;
|
||||||
IdVec m_pendingIters;
|
PendingIterVec m_pendingIters;
|
||||||
typedef std::map<const StringData*, Label*, string_data_lt> LabelMap;
|
typedef std::map<const StringData*, Label*, string_data_lt> LabelMap;
|
||||||
LabelMap m_methLabels;
|
LabelMap m_methLabels;
|
||||||
SymbolicStack m_evalStack;
|
SymbolicStack m_evalStack;
|
||||||
@@ -535,6 +545,12 @@ public:
|
|||||||
void buildVectorImm(std::vector<uchar>& vectorImm,
|
void buildVectorImm(std::vector<uchar>& vectorImm,
|
||||||
int iFirst, int iLast, bool allowW,
|
int iFirst, int iLast, bool allowW,
|
||||||
Emitter& e);
|
Emitter& e);
|
||||||
|
enum class PassByRefKind {
|
||||||
|
AllowCell,
|
||||||
|
WarnOnCell,
|
||||||
|
ErrorOnCell,
|
||||||
|
};
|
||||||
|
PassByRefKind getPassByRefKind(ExpressionPtr exp);
|
||||||
void emitAGet(Emitter& e);
|
void emitAGet(Emitter& e);
|
||||||
void emitCGetL2(Emitter& e);
|
void emitCGetL2(Emitter& e);
|
||||||
void emitCGetL3(Emitter& e);
|
void emitCGetL3(Emitter& e);
|
||||||
@@ -561,6 +577,7 @@ public:
|
|||||||
void emitConvertToCellOrLoc(Emitter& e);
|
void emitConvertToCellOrLoc(Emitter& e);
|
||||||
void emitConvertSecondToCell(Emitter& e);
|
void emitConvertSecondToCell(Emitter& e);
|
||||||
void emitConvertToVar(Emitter& e);
|
void emitConvertToVar(Emitter& e);
|
||||||
|
void emitFPass(Emitter& e, int paramID, PassByRefKind passByRefKind);
|
||||||
void emitVirtualLocal(int localId, DataType dt = KindOfUnknown);
|
void emitVirtualLocal(int localId, DataType dt = KindOfUnknown);
|
||||||
template<class Expr> void emitVirtualClassBase(Emitter&, Expr* node);
|
template<class Expr> void emitVirtualClassBase(Emitter&, Expr* node);
|
||||||
void emitResolveClsBase(Emitter& e, int pos);
|
void emitResolveClsBase(Emitter& e, int pos);
|
||||||
@@ -587,7 +604,7 @@ public:
|
|||||||
void emitAssignment(Emitter& e, ExpressionPtr c, int op, bool bind);
|
void emitAssignment(Emitter& e, ExpressionPtr c, int op, bool bind);
|
||||||
void emitListAssignment(Emitter& e, ListAssignmentPtr lst);
|
void emitListAssignment(Emitter& e, ListAssignmentPtr lst);
|
||||||
void postponeMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
|
void postponeMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
|
||||||
ClosureUseVarVec* useVars = NULL);
|
ClosureUseVarVec* useVars = nullptr);
|
||||||
void postponeCtor(InterfaceStatementPtr m, FuncEmitter* fe);
|
void postponeCtor(InterfaceStatementPtr m, FuncEmitter* fe);
|
||||||
void postponePinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
void postponePinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
||||||
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
||||||
@@ -622,7 +639,8 @@ public:
|
|||||||
PreClass::Hoistable emitClass(Emitter& e, ClassScopePtr cNode,
|
PreClass::Hoistable emitClass(Emitter& e, ClassScopePtr cNode,
|
||||||
bool topLevel);
|
bool topLevel);
|
||||||
void emitBreakHandler(Emitter& e, Label& brkTarg, Label& cntTarg,
|
void emitBreakHandler(Emitter& e, Label& brkTarg, Label& cntTarg,
|
||||||
Label& brkHand, Label& cntHand, Id iter = -1);
|
Label& brkHand, Label& cntHand, Id iter = -1,
|
||||||
|
IterKind itKind = KindOfIter);
|
||||||
void emitForeach(Emitter& e, ForEachStatementPtr fe);
|
void emitForeach(Emitter& e, ForEachStatementPtr fe);
|
||||||
void emitRestoreErrorReporting(Emitter& e, Id oldLevelLoc);
|
void emitRestoreErrorReporting(Emitter& e, Id oldLevelLoc);
|
||||||
void emitMakeUnitFatal(Emitter& e, const std::string& message);
|
void emitMakeUnitFatal(Emitter& e, const std::string& message);
|
||||||
+1
-1
@@ -425,7 +425,7 @@ void FunctionContainer::outputCPPCodeInfoTable(
|
|||||||
vector<const char *> funcs;
|
vector<const char *> funcs;
|
||||||
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
|
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||||
if (system) {
|
if (system) {
|
||||||
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, NULL);
|
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, nullptr);
|
||||||
}
|
}
|
||||||
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin(),
|
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin(),
|
||||||
end = functions.end(); iter != end; ++iter) {
|
end = functions.end(); iter != end; ++iter) {
|
||||||
+2
-2
@@ -64,14 +64,14 @@ protected:
|
|||||||
void outputCPPJumpTableSupport(CodeGenerator &cg, AnalysisResultPtr ar,
|
void outputCPPJumpTableSupport(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
const StringToFunctionScopePtrVecMap *redec,
|
const StringToFunctionScopePtrVecMap *redec,
|
||||||
bool &hasRedeclared,
|
bool &hasRedeclared,
|
||||||
std::vector<const char *> *funcs = NULL);
|
std::vector<const char *> *funcs = nullptr);
|
||||||
void outputCPPJumpTableEvalSupport(
|
void outputCPPJumpTableEvalSupport(
|
||||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared);
|
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared);
|
||||||
void outputCPPCallInfoTableSupport(
|
void outputCPPCallInfoTableSupport(
|
||||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
const StringToFunctionScopePtrVecMap *redec,
|
const StringToFunctionScopePtrVecMap *redec,
|
||||||
bool &hasRedeclared, std::vector<const char *> *funcs = NULL);
|
bool &hasRedeclared, std::vector<const char *> *funcs = nullptr);
|
||||||
void outputCPPJumpTableSupportMethod(CodeGenerator &cg, AnalysisResultPtr ar,
|
void outputCPPJumpTableSupportMethod(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
FunctionScopePtr func,
|
FunctionScopePtr func,
|
||||||
const char *funcPrefix);
|
const char *funcPrefix);
|
||||||
+20
-17
@@ -2165,7 +2165,7 @@ void FunctionScope::outputCPPCallInfo(CodeGenerator &cg,
|
|||||||
Option::InvokePrefix, id.c_str(),
|
Option::InvokePrefix, id.c_str(),
|
||||||
Option::InvokeFewArgsPrefix, id.c_str());
|
Option::InvokeFewArgsPrefix, id.c_str());
|
||||||
}
|
}
|
||||||
cg.printf(", %d, %d, 0x%.16llXLL", m_maxParam, flags, refflags);
|
cg.printf(", %d, %d, 0x%.16llXL", m_maxParam, flags, refflags);
|
||||||
if (isRedeclaring()) {
|
if (isRedeclaring()) {
|
||||||
cg_printf("}, %d", getRedeclaringId());
|
cg_printf("}, %d", getRedeclaringId());
|
||||||
}
|
}
|
||||||
@@ -2458,24 +2458,27 @@ FunctionScope::StringToFunctionInfoPtrMap FunctionScope::s_refParamInfo;
|
|||||||
static Mutex s_refParamInfoLock;
|
static Mutex s_refParamInfoLock;
|
||||||
|
|
||||||
void FunctionScope::RecordFunctionInfo(string fname, FunctionScopePtr func) {
|
void FunctionScope::RecordFunctionInfo(string fname, FunctionScopePtr func) {
|
||||||
if (!Option::WholeProgram) return; // Only needed in WholeProgram mode.
|
|
||||||
Lock lock(s_refParamInfoLock);
|
|
||||||
FunctionInfoPtr &info = s_refParamInfo[fname];
|
|
||||||
if (!info) {
|
|
||||||
info = FunctionInfoPtr(new FunctionInfo());
|
|
||||||
}
|
|
||||||
if (func->isStatic()) {
|
|
||||||
info->setMaybeStatic();
|
|
||||||
}
|
|
||||||
if (func->isRefReturn()) {
|
|
||||||
info->setMaybeRefReturn();
|
|
||||||
}
|
|
||||||
if (func->isReferenceVariableArgument()) {
|
|
||||||
info->setRefVarArg(func->getMaxParamCount());
|
|
||||||
}
|
|
||||||
VariableTablePtr variables = func->getVariables();
|
VariableTablePtr variables = func->getVariables();
|
||||||
|
if (Option::WholeProgram) {
|
||||||
|
Lock lock(s_refParamInfoLock);
|
||||||
|
FunctionInfoPtr &info = s_refParamInfo[fname];
|
||||||
|
if (!info) {
|
||||||
|
info = FunctionInfoPtr(new FunctionInfo());
|
||||||
|
}
|
||||||
|
if (func->isStatic()) {
|
||||||
|
info->setMaybeStatic();
|
||||||
|
}
|
||||||
|
if (func->isRefReturn()) {
|
||||||
|
info->setMaybeRefReturn();
|
||||||
|
}
|
||||||
|
if (func->isReferenceVariableArgument()) {
|
||||||
|
info->setRefVarArg(func->getMaxParamCount());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < func->getMaxParamCount(); i++) {
|
||||||
|
if (func->isRefParam(i)) info->setRefParam(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = 0; i < func->getMaxParamCount(); i++) {
|
for (int i = 0; i < func->getMaxParamCount(); i++) {
|
||||||
if (func->isRefParam(i)) info->setRefParam(i);
|
|
||||||
variables->addParam(func->getParamName(i),
|
variables->addParam(func->getParamName(i),
|
||||||
TypePtr(), AnalysisResultPtr(), ConstructPtr());
|
TypePtr(), AnalysisResultPtr(), ConstructPtr());
|
||||||
}
|
}
|
||||||
@@ -407,9 +407,9 @@ public:
|
|||||||
bool voidWrapperOff = false,
|
bool voidWrapperOff = false,
|
||||||
bool fewArgs = false,
|
bool fewArgs = false,
|
||||||
bool ret = true,
|
bool ret = true,
|
||||||
const char *extraArg = NULL,
|
const char *extraArg = nullptr,
|
||||||
bool constructor = false,
|
bool constructor = false,
|
||||||
const char *instance = NULL,
|
const char *instance = nullptr,
|
||||||
const char *class_name = "");
|
const char *class_name = "");
|
||||||
|
|
||||||
void outputCPPDef(CodeGenerator &cg);
|
void outputCPPDef(CodeGenerator &cg);
|
||||||
@@ -452,7 +452,7 @@ const Symbol *SymbolTable::getSymbolImpl(const std::string &name) const {
|
|||||||
if (it != m_symbolMap.end()) {
|
if (it != m_symbolMap.end()) {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *SymbolTable::getSymbol(const std::string &name) {
|
Symbol *SymbolTable::getSymbol(const std::string &name) {
|
||||||
@@ -0,0 +1,876 @@
|
|||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| HipHop for PHP |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.php.net/license/3_01.txt |
|
||||||
|
| If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@php.net so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <compiler/analysis/type.h>
|
||||||
|
#include <compiler/code_generator.h>
|
||||||
|
#include <compiler/analysis/analysis_result.h>
|
||||||
|
#include <compiler/analysis/class_scope.h>
|
||||||
|
#include <compiler/analysis/file_scope.h>
|
||||||
|
#include <compiler/expression/expression.h>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
using namespace HPHP;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// statics
|
||||||
|
|
||||||
|
TypePtr Type::Null (new Type(Type::KindOfVoid ));
|
||||||
|
TypePtr Type::Boolean (new Type(Type::KindOfBoolean ));
|
||||||
|
TypePtr Type::Int32 (new Type(Type::KindOfInt32 ));
|
||||||
|
TypePtr Type::Int64 (new Type(Type::KindOfInt64 ));
|
||||||
|
TypePtr Type::Double (new Type(Type::KindOfDouble ));
|
||||||
|
TypePtr Type::String (new Type(Type::KindOfString ));
|
||||||
|
TypePtr Type::Array (new Type(Type::KindOfArray ));
|
||||||
|
TypePtr Type::Object (new Type(Type::KindOfObject ));
|
||||||
|
TypePtr Type::Variant (new Type(Type::KindOfVariant ));
|
||||||
|
|
||||||
|
TypePtr Type::Numeric (new Type(Type::KindOfNumeric ));
|
||||||
|
TypePtr Type::PlusOperand (new Type(Type::KindOfPlusOperand ));
|
||||||
|
TypePtr Type::Primitive (new Type(Type::KindOfPrimitive ));
|
||||||
|
TypePtr Type::Sequence (new Type(Type::KindOfSequence ));
|
||||||
|
|
||||||
|
TypePtr Type::AutoSequence(new Type(Type::KindOfAutoSequence));
|
||||||
|
TypePtr Type::AutoObject (new Type(Type::KindOfAutoObject ));
|
||||||
|
|
||||||
|
TypePtr Type::Any (new Type(Type::KindOfAny ));
|
||||||
|
TypePtr Type::Some (new Type(Type::KindOfSome ));
|
||||||
|
|
||||||
|
Type::TypePtrMap Type::s_TypeHintTypes;
|
||||||
|
|
||||||
|
void Type::InitTypeHintMap() {
|
||||||
|
assert(s_TypeHintTypes.empty());
|
||||||
|
s_TypeHintTypes["array"] = Type::Array;
|
||||||
|
if (Option::EnableHipHopSyntax) {
|
||||||
|
s_TypeHintTypes["bool"] = Type::Boolean;
|
||||||
|
s_TypeHintTypes["boolean"] = Type::Boolean;
|
||||||
|
s_TypeHintTypes["int"] = Type::Int64;
|
||||||
|
s_TypeHintTypes["integer"] = Type::Int64;
|
||||||
|
s_TypeHintTypes["real"] = Type::Double;
|
||||||
|
s_TypeHintTypes["double"] = Type::Double;
|
||||||
|
s_TypeHintTypes["float"] = Type::Double;
|
||||||
|
s_TypeHintTypes["string"] = Type::String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type::TypePtrMap &Type::GetTypeHintTypes() {
|
||||||
|
return s_TypeHintTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::ResetTypeHintTypes() {
|
||||||
|
s_TypeHintTypes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::CreateObjectType(const std::string &classname) {
|
||||||
|
return TypePtr(new Type(KindOfObject, classname));
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::GetType(KindOf kindOf,
|
||||||
|
const std::string &clsname /* = "" */) {
|
||||||
|
assert(kindOf);
|
||||||
|
if (!clsname.empty()) return TypePtr(new Type(kindOf, clsname));
|
||||||
|
|
||||||
|
switch (kindOf) {
|
||||||
|
case KindOfBoolean: return Type::Boolean;
|
||||||
|
case KindOfInt32: return Type::Int32;
|
||||||
|
case KindOfInt64: return Type::Int64;
|
||||||
|
case KindOfDouble: return Type::Double;
|
||||||
|
case KindOfString: return Type::String;
|
||||||
|
case KindOfArray: return Type::Array;
|
||||||
|
case KindOfVariant: return Type::Variant;
|
||||||
|
case KindOfObject: return Type::Object;
|
||||||
|
case KindOfNumeric: return Type::Numeric;
|
||||||
|
case KindOfPrimitive: return Type::Primitive;
|
||||||
|
case KindOfPlusOperand: return Type::PlusOperand;
|
||||||
|
case KindOfSequence: return Type::Sequence;
|
||||||
|
case KindOfSome: return Type::Some;
|
||||||
|
case KindOfAny: return Type::Any;
|
||||||
|
default: return TypePtr(new Type(kindOf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::Intersection(AnalysisResultConstPtr ar,
|
||||||
|
TypePtr from, TypePtr to) {
|
||||||
|
// Special case: if we're casting to Some or Any, return the "from" type;
|
||||||
|
// if we're casting to Variant, return Variant.
|
||||||
|
if (to->m_kindOf == KindOfSome || to->m_kindOf == KindOfAny) {
|
||||||
|
return from;
|
||||||
|
} else if (to->m_kindOf == KindOfVariant) {
|
||||||
|
return Variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resultKind = to->m_kindOf & from->m_kindOf;
|
||||||
|
std::string resultName = "";
|
||||||
|
|
||||||
|
if (resultKind & KindOfObject) {
|
||||||
|
// if they're the same, or we don't know one's name, then use
|
||||||
|
// the other
|
||||||
|
if (to->m_name == from->m_name || from->m_name.empty()) {
|
||||||
|
resultName = to->m_name;
|
||||||
|
} else if (to->m_name.empty()) {
|
||||||
|
resultName = from->m_name;
|
||||||
|
} else {
|
||||||
|
// make sure there's a subclass relation
|
||||||
|
ClassScopePtr cls = ar->findClass(from->m_name);
|
||||||
|
if (cls) {
|
||||||
|
if (cls->derivesFrom(ar, to->m_name, true, false)) {
|
||||||
|
resultName = to->m_name;
|
||||||
|
} else {
|
||||||
|
resultKind &= ~KindOfObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr res;
|
||||||
|
|
||||||
|
// If there is overlap (for instance, they were the same, or we've narrowed
|
||||||
|
// down something like Sequenece to be more specific), then return the
|
||||||
|
// intersection of the types.
|
||||||
|
if (resultKind) {
|
||||||
|
res = GetType(resultKind, resultName);
|
||||||
|
} else if (from->mustBe(KindOfObject) && to->m_kindOf == KindOfPrimitive) {
|
||||||
|
// Special case Object -> Primitive: can we tostring it?
|
||||||
|
if (!from->m_name.empty()) {
|
||||||
|
ClassScopePtr cls = ar->findClass(from->m_name);
|
||||||
|
if (cls && cls->findFunction(ar, "__tostring", true)) {
|
||||||
|
res = Type::String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, return Int32
|
||||||
|
res = Int32;
|
||||||
|
} else if (from->m_kindOf == KindOfBoolean
|
||||||
|
&& to->mustBe(KindOfNumeric | KindOfArray | KindOfString)
|
||||||
|
&& !IsExactType(to->m_kindOf)) {
|
||||||
|
res = Int32;
|
||||||
|
} else {
|
||||||
|
res = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->mustBe(KindOfBoolean) && to->m_kindOf == KindOfPrimitive) {
|
||||||
|
res = Int32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::IsMappedToVariant(TypePtr t) {
|
||||||
|
if (!t) return true;
|
||||||
|
switch (t->m_kindOf) {
|
||||||
|
case KindOfBoolean:
|
||||||
|
case KindOfInt32 :
|
||||||
|
case KindOfInt64 :
|
||||||
|
case KindOfDouble :
|
||||||
|
case KindOfString :
|
||||||
|
case KindOfArray :
|
||||||
|
case KindOfObject :
|
||||||
|
return false;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::IsCastNeeded(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) {
|
||||||
|
if (SameType(from, to)) return false;
|
||||||
|
if (!from->m_kindOf) return true;
|
||||||
|
if (!to->m_kindOf) return true;
|
||||||
|
|
||||||
|
// Special case: all Sequence operations are implemented on both String and
|
||||||
|
// Array, and vice versa, therefore no need to cast between these types.
|
||||||
|
if ((from->m_kindOf == KindOfSequence && to->mustBe(KindOfSequence))
|
||||||
|
|| (to->m_kindOf == KindOfSequence && from->mustBe(KindOfSequence))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (to->m_kindOf) {
|
||||||
|
case KindOfVariant:
|
||||||
|
case KindOfNumeric:
|
||||||
|
case KindOfPrimitive:
|
||||||
|
case KindOfPlusOperand:
|
||||||
|
case KindOfSome:
|
||||||
|
case KindOfSequence:
|
||||||
|
case KindOfAny:
|
||||||
|
// Currently these types are all mapped to Variant in runtime/base, and
|
||||||
|
// that's why these casting are not needed.
|
||||||
|
return false;
|
||||||
|
case KindOfObject:
|
||||||
|
if (from->m_kindOf == KindOfObject && to->m_name.empty() &&
|
||||||
|
!from->m_name.empty()) return false;
|
||||||
|
else return true;
|
||||||
|
default:
|
||||||
|
// if we don't have a specific type narrowed down, then
|
||||||
|
// it will be a Variant at at runtime, so no cast is needed.
|
||||||
|
return IsExactType(to->m_kindOf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::IsCoercionNeeded(AnalysisResultConstPtr ar, TypePtr t1, TypePtr t2) {
|
||||||
|
if (t1->m_kindOf == KindOfSome ||
|
||||||
|
t1->m_kindOf == KindOfAny ||
|
||||||
|
t2->m_kindOf == KindOfSome ||
|
||||||
|
t2->m_kindOf == KindOfAny) return true;
|
||||||
|
|
||||||
|
// special case: we always coerce to a specific object type so we can
|
||||||
|
// type checking properties and methods
|
||||||
|
if (t1->m_kindOf == KindOfObject && !t1->m_name.empty() &&
|
||||||
|
t2->m_kindOf == KindOfObject && t2->m_name.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Type::IsLegalCast(ar, t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::Coerce(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
|
||||||
|
if (SameType(type1, type2)) return type1;
|
||||||
|
if (type1->m_kindOf == KindOfVariant ||
|
||||||
|
type2->m_kindOf == KindOfVariant) return Type::Variant;
|
||||||
|
if (type1->m_kindOf > type2->m_kindOf) {
|
||||||
|
TypePtr tmp = type1;
|
||||||
|
type1 = type2;
|
||||||
|
type2 = tmp;
|
||||||
|
}
|
||||||
|
if (type1->m_kindOf == KindOfVoid &&
|
||||||
|
(type2->m_kindOf == KindOfString ||
|
||||||
|
type2->m_kindOf == KindOfArray ||
|
||||||
|
type2->m_kindOf == KindOfObject)) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
if (type2->m_kindOf == KindOfSome ||
|
||||||
|
type2->m_kindOf == KindOfAny) return type1;
|
||||||
|
|
||||||
|
if (type2->m_kindOf & KindOfAuto) {
|
||||||
|
if (type1->mustBe(type2->m_kindOf & ~KindOfAuto)) {
|
||||||
|
if (!(type1->m_kindOf & Type::KindOfString)) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
if (type2->m_kindOf == KindOfAutoSequence) {
|
||||||
|
return Type::Sequence;
|
||||||
|
}
|
||||||
|
return GetType((KindOf)(type2->m_kindOf & ~KindOfAuto));
|
||||||
|
}
|
||||||
|
return Type::Variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type1->mustBe(KindOfInteger)) {
|
||||||
|
if (type2->mustBe(KindOfInteger)) {
|
||||||
|
return type2;
|
||||||
|
} else if (type2->mustBe(KindOfDouble)) {
|
||||||
|
return Type::Numeric;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type1->mustBe(Type::KindOfObject) &&
|
||||||
|
type2->mustBe(Type::KindOfObject)) {
|
||||||
|
if (type1->m_name.empty()) return type1;
|
||||||
|
if (type2->m_name.empty()) return type2;
|
||||||
|
ClassScopePtr cls1 = ar->findClass(type1->m_name);
|
||||||
|
if (cls1 && !cls1->isRedeclaring() &&
|
||||||
|
cls1->derivesFrom(ar, type2->m_name, true, false)) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
ClassScopePtr cls2 = ar->findClass(type2->m_name);
|
||||||
|
if (cls2 && !cls2->isRedeclaring() &&
|
||||||
|
cls2->derivesFrom(ar, type1->m_name, true, false)) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
if (cls1 && cls2 &&
|
||||||
|
!cls1->isRedeclaring() && !cls2->isRedeclaring()) {
|
||||||
|
ClassScopePtr parent =
|
||||||
|
ClassScope::FindCommonParent(ar, type1->m_name,
|
||||||
|
type2->m_name);
|
||||||
|
if (parent) {
|
||||||
|
return Type::CreateObjectType(parent->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Type::Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type1->mustBe(type2->m_kindOf)) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(Type::KindOfString < Type::KindOfArray,
|
||||||
|
"Expected Type::KindOfString < Type::KindOfArray");
|
||||||
|
if (type1->m_kindOf == Type::KindOfString &&
|
||||||
|
type2->m_kindOf == Type::KindOfArray) {
|
||||||
|
return Type::Sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type::Variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::Union(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
|
||||||
|
if (SameType(type1, type2)) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resultKind = type1->m_kindOf | type2->m_kindOf;
|
||||||
|
if (resultKind == KindOfObject) {
|
||||||
|
std::string resultName("");
|
||||||
|
|
||||||
|
// if they're the same, or we don't know one's name, then use
|
||||||
|
// the other
|
||||||
|
if (type1->m_name == type2->m_name) {
|
||||||
|
resultName = type1->m_name;
|
||||||
|
} else if (type1->m_name.empty() || type2->m_name.empty()) {
|
||||||
|
// resultName was initialized to "", so leave it as such;
|
||||||
|
// we know it's an object but not what kind.
|
||||||
|
} else {
|
||||||
|
// take the superclass
|
||||||
|
ClassScopePtr res =
|
||||||
|
ClassScope::FindCommonParent(ar, type1->m_name,
|
||||||
|
type2->m_name);
|
||||||
|
if (res) resultName = res->getName();
|
||||||
|
}
|
||||||
|
return TypePtr(Type::CreateObjectType(resultName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetType((KindOf)resultKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::SameType(TypePtr type1, TypePtr type2) {
|
||||||
|
if (!type1 && !type2) return true;
|
||||||
|
if (!type1 || !type2) return false;
|
||||||
|
if (type1->m_kindOf == type2->m_kindOf) {
|
||||||
|
if ((type1->m_kindOf & KindOfObject) &&
|
||||||
|
type1->m_name != type2->m_name) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::SubType(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
|
||||||
|
if (!type1 && !type2) return true;
|
||||||
|
if (!type1 || !type2) return false;
|
||||||
|
if (type1->m_kindOf != type2->m_kindOf) return false;
|
||||||
|
if (!(type1->m_kindOf & KindOfObject)) return true;
|
||||||
|
// both are objects...
|
||||||
|
if (type1->m_name == type2->m_name) return true;
|
||||||
|
// ... with different classnames; check subtype relationship.
|
||||||
|
ClassScopePtr cls1 = ar->findClass(type1->m_name);
|
||||||
|
return cls1 && !cls1->isRedeclaring() &&
|
||||||
|
cls1->derivesFrom(ar, type2->m_name, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::IsExactType(KindOf kindOf) {
|
||||||
|
// clever trick thanks to mwilliams - this will evaluate
|
||||||
|
// to true iff exactly one bit is set in kindOf
|
||||||
|
return kindOf && !(kindOf & (kindOf-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::HasFastCastMethod(TypePtr t) {
|
||||||
|
switch (t->getKindOf()) {
|
||||||
|
case Type::KindOfBoolean:
|
||||||
|
case Type::KindOfInt32:
|
||||||
|
case Type::KindOfInt64:
|
||||||
|
case Type::KindOfDouble:
|
||||||
|
case Type::KindOfString:
|
||||||
|
case Type::KindOfArray:
|
||||||
|
case Type::KindOfObject:
|
||||||
|
return true;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Type::GetFastCastMethod(
|
||||||
|
TypePtr dst, bool allowRef, bool forConst) {
|
||||||
|
const char *prefix0 = allowRef ? "to" : "as";
|
||||||
|
const char *prefix1 = forConst ? "C" : "";
|
||||||
|
const char *prefix2 = "Ref";
|
||||||
|
const char *type ATTRIBUTE_UNUSED;
|
||||||
|
|
||||||
|
switch (dst->getKindOf()) {
|
||||||
|
case Type::KindOfBoolean:
|
||||||
|
case Type::KindOfInt32:
|
||||||
|
case Type::KindOfInt64:
|
||||||
|
case Type::KindOfDouble:
|
||||||
|
prefix0 = "to";
|
||||||
|
prefix1 = "";
|
||||||
|
prefix2 = "Val";
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dst->getKindOf()) {
|
||||||
|
case Type::KindOfBoolean:
|
||||||
|
type = "Boolean";
|
||||||
|
break;
|
||||||
|
case Type::KindOfInt32:
|
||||||
|
case Type::KindOfInt64:
|
||||||
|
type = "Int64";
|
||||||
|
break;
|
||||||
|
case Type::KindOfDouble:
|
||||||
|
type = "Double";
|
||||||
|
break;
|
||||||
|
case Type::KindOfString:
|
||||||
|
type = "Str";
|
||||||
|
break;
|
||||||
|
case Type::KindOfArray:
|
||||||
|
type = "Arr";
|
||||||
|
break;
|
||||||
|
case Type::KindOfObject:
|
||||||
|
type = "Obj";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = ""; // make the compiler happy
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(prefix0) + string(prefix1) + string(type) + string(prefix2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This new IsLegalCast returns true in a few cases where the old version
|
||||||
|
* (which was basically a hardcoded truth table) returned false; it seems
|
||||||
|
* like "true" is in fact the right thing to return. The cases that appear
|
||||||
|
* when compiling www are:
|
||||||
|
* Sequence -> Array
|
||||||
|
* PlusOperand -> Array
|
||||||
|
* String -> PlusOperand
|
||||||
|
* Boolean -> PlusOperand
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Type::IsLegalCast(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) {
|
||||||
|
if (!from->m_kindOf) return true;
|
||||||
|
|
||||||
|
// since both 'from' and 'to' represent sets of types, we do
|
||||||
|
// this by computing the set of types that we could possibly cast 'from'
|
||||||
|
// to, and then determining whether that overlaps with 'to'.
|
||||||
|
int canCastTo = KindOfBoolean | from->m_kindOf;
|
||||||
|
|
||||||
|
if (from->m_kindOf & KindOfVoid) canCastTo |= KindOfVoid;
|
||||||
|
|
||||||
|
// Boolean, Numeric, and String can all be cast among each other
|
||||||
|
if (from->m_kindOf & (KindOfBoolean | KindOfNumeric | KindOfString)) {
|
||||||
|
canCastTo |= KindOfNumeric | KindOfString;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->m_kindOf & KindOfObject) {
|
||||||
|
// Objects can only cast to string if they have __tostring
|
||||||
|
if (from->m_name.empty()) {
|
||||||
|
canCastTo |= KindOfString; // we don't know which class it is
|
||||||
|
} else {
|
||||||
|
ClassScopePtr cls = ar->findClass(from->m_name);
|
||||||
|
if (!cls || cls->isRedeclaring() ||
|
||||||
|
cls->findFunction(ar, "__tostring", true)) {
|
||||||
|
canCastTo |= KindOfString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can only cast between objects if there's a subclass relation
|
||||||
|
if ((to->m_kindOf & KindOfObject) && !to->m_name.empty() &&
|
||||||
|
!from->m_name.empty() && to->m_name != from->m_name) {
|
||||||
|
ClassScopePtr cls = ar->findClass(from->m_name);
|
||||||
|
if (cls && (cls->isRedeclaring() ||
|
||||||
|
!cls->derivesFrom(ar, to->m_name, true, true))) {
|
||||||
|
canCastTo &= ~KindOfObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overlap = (to->m_kindOf & canCastTo);
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Type::Type(KindOf kindOf) : m_kindOf(kindOf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::Type(KindOf kindOf, const std::string &name)
|
||||||
|
: m_kindOf(kindOf), m_name(name) {
|
||||||
|
|
||||||
|
// m_name must not be empty only when this type could
|
||||||
|
// be an object
|
||||||
|
assert(m_name.empty() || (m_kindOf & KindOfObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::isInteger() const {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfInt32:
|
||||||
|
case KindOfInt64:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::isStandardObject() const {
|
||||||
|
return m_kindOf == KindOfObject && m_name.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::isSpecificObject() const {
|
||||||
|
return m_kindOf == KindOfObject && !m_name.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::isNonConvertibleType() const {
|
||||||
|
return m_kindOf == KindOfObject || m_kindOf == KindOfArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type::isNoObjectInvolved() const {
|
||||||
|
if (couldBe(KindOfObject)
|
||||||
|
|| couldBe(KindOfArray))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::combinedArithmeticType(TypePtr t1, TypePtr t2) {
|
||||||
|
KindOf kind = KindOfAny;
|
||||||
|
|
||||||
|
if ((t1 && t1->is(Type::KindOfArray)) ||
|
||||||
|
(t2 && t2->is(Type::KindOfArray))) {
|
||||||
|
return TypePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1 && t1->isPrimitive()) {
|
||||||
|
if (t2 && t2->isPrimitive()) {
|
||||||
|
if (t2->getKindOf() > t1->getKindOf()) {
|
||||||
|
kind = t2->getKindOf();
|
||||||
|
} else {
|
||||||
|
kind = t1->getKindOf();
|
||||||
|
}
|
||||||
|
} else if (t1->is(KindOfDouble)) {
|
||||||
|
kind = KindOfDouble;
|
||||||
|
} else {
|
||||||
|
kind = KindOfNumeric;
|
||||||
|
}
|
||||||
|
} else if (t2 && t2->isPrimitive()) {
|
||||||
|
if (t2->is(KindOfDouble)) {
|
||||||
|
kind = KindOfDouble;
|
||||||
|
} else {
|
||||||
|
kind = KindOfNumeric;
|
||||||
|
}
|
||||||
|
} else if ((t1 && t1->mustBe(KindOfNumeric)) ||
|
||||||
|
(t2 && t2->mustBe(KindOfNumeric))) {
|
||||||
|
kind = KindOfNumeric;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind < KindOfInt64) {
|
||||||
|
kind = KindOfInt64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind != KindOfAny) {
|
||||||
|
return GetType(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ClassScopePtr Type::getClass(AnalysisResultConstPtr ar,
|
||||||
|
BlockScopeRawPtr scope) const {
|
||||||
|
if (m_name.empty()) return ClassScopePtr();
|
||||||
|
ClassScopePtr cls = ar->findClass(m_name);
|
||||||
|
if (cls && cls->isRedeclaring()) {
|
||||||
|
if (!scope) {
|
||||||
|
cls.reset();
|
||||||
|
} else {
|
||||||
|
cls = scope->findExactClass(cls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Type::getCPPDecl(AnalysisResultConstPtr ar,
|
||||||
|
BlockScopeRawPtr scope,
|
||||||
|
CodeGenerator *cg /* = 0 */) {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: return "bool";
|
||||||
|
case KindOfInt32: return "int";
|
||||||
|
case KindOfInt64: return "int64";
|
||||||
|
case KindOfDouble: return "double";
|
||||||
|
case KindOfString: return "String";
|
||||||
|
case KindOfArray: return "Array";
|
||||||
|
case KindOfObject:{
|
||||||
|
ClassScopePtr cls(getClass(ar, scope));
|
||||||
|
if (!cls) return "Object";
|
||||||
|
if (cg && cg->isFileOrClassHeader() && scope) {
|
||||||
|
if (scope->getContainingClass()) {
|
||||||
|
scope->getContainingClass()->addUsedClassHeader(cls);
|
||||||
|
} else if (scope->getContainingFile()) {
|
||||||
|
scope->getContainingFile()->addUsedClassHeader(cls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Option::SmartPtrPrefix + cls->getId();
|
||||||
|
}
|
||||||
|
case KindOfNumeric: return "Numeric";
|
||||||
|
case KindOfPrimitive: return "Primitive";
|
||||||
|
case KindOfPlusOperand: return "PlusOperand";
|
||||||
|
case KindOfSequence: return "Sequence";
|
||||||
|
default:
|
||||||
|
return "Variant";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType Type::getDataType() const {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: return HPHP::KindOfBoolean;
|
||||||
|
case KindOfInt32:
|
||||||
|
case KindOfInt64: return HPHP::KindOfInt64;
|
||||||
|
case KindOfDouble: return HPHP::KindOfDouble;
|
||||||
|
case KindOfString: return HPHP::KindOfString;
|
||||||
|
case KindOfArray: return HPHP::KindOfArray;
|
||||||
|
case KindOfObject: return HPHP::KindOfObject;
|
||||||
|
case KindOfNumeric:
|
||||||
|
case KindOfPrimitive:
|
||||||
|
case KindOfPlusOperand:
|
||||||
|
case KindOfSequence:
|
||||||
|
default: return HPHP::KindOfUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is similar to getDataType() except that it returns
|
||||||
|
// HPHP::KindOfNull for KindOfVoid;
|
||||||
|
DataType Type::getHhvmDataType() const {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfVoid: return HPHP::KindOfNull;
|
||||||
|
default: return getDataType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar,
|
||||||
|
BlockScopeRawPtr scope) {
|
||||||
|
cg_print(getCPPDecl(ar, scope, &cg).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::outputCPPFastObjectCast(CodeGenerator &cg,
|
||||||
|
AnalysisResultConstPtr ar,
|
||||||
|
BlockScopeRawPtr scope,
|
||||||
|
bool isConst) {
|
||||||
|
assert(isSpecificObject());
|
||||||
|
ClassScopePtr cls(getClass(ar, scope));
|
||||||
|
assert(cls);
|
||||||
|
const string &cppClsName = cls->getId();
|
||||||
|
cg_printf("(%s%s%s&)",
|
||||||
|
isConst ? "const " : "",
|
||||||
|
Option::SmartPtrPrefix,
|
||||||
|
cppClsName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar,
|
||||||
|
BlockScopeRawPtr scope) {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: cg_printf("toBoolean"); break;
|
||||||
|
case KindOfInt32: cg_printf("toInt32"); break;
|
||||||
|
case KindOfInt64: cg_printf("toInt64"); break;
|
||||||
|
case KindOfDouble: cg_printf("toDouble"); break;
|
||||||
|
case KindOfString: cg_printf("toString"); break;
|
||||||
|
case KindOfArray: cg_printf("toArray"); break;
|
||||||
|
case KindOfNumeric: cg_printf("Numeric"); break;
|
||||||
|
case KindOfPrimitive: cg_printf("Primitive"); break;
|
||||||
|
case KindOfPlusOperand: cg_printf("PlusOperand"); break;
|
||||||
|
case KindOfSequence: cg_printf("Sequence"); break;
|
||||||
|
case KindOfObject: {
|
||||||
|
ClassScopePtr cls(getClass(ar, scope));
|
||||||
|
if (!cls) {
|
||||||
|
cg_printf("toObject");
|
||||||
|
} else {
|
||||||
|
cg_printf("%s%s", Option::SmartPtrPrefix, cls->getId().c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cg_printf("Variant");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Type::getCPPInitializer() {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: return "false";
|
||||||
|
case KindOfInt32:
|
||||||
|
case KindOfInt64: return "0";
|
||||||
|
case KindOfNumeric:
|
||||||
|
case KindOfPrimitive:
|
||||||
|
case KindOfPlusOperand: return "0";
|
||||||
|
case KindOfDouble: return "0.0";
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type::getPHPName() {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfArray: return "array";
|
||||||
|
case KindOfObject: return m_name;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type::toString() const {
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: return "Boolean";
|
||||||
|
case KindOfInt32: return "Int32";
|
||||||
|
case KindOfInt64: return "Int64";
|
||||||
|
case KindOfDouble: return "Double";
|
||||||
|
case KindOfString: return "String";
|
||||||
|
case KindOfArray: return "Array";
|
||||||
|
case KindOfVariant: return "Variant";
|
||||||
|
case KindOfSome: return "Some";
|
||||||
|
case KindOfAny: return "Any";
|
||||||
|
case KindOfObject: return string("Object - ") + m_name;
|
||||||
|
case KindOfNumeric: return "Numeric";
|
||||||
|
case KindOfPrimitive: return "Primitive";
|
||||||
|
case KindOfPlusOperand: return "PlusOperand";
|
||||||
|
case KindOfSequence: return "Sequence";
|
||||||
|
default:
|
||||||
|
return boost::str(boost::format("[0x%x]") % m_kindOf);
|
||||||
|
}
|
||||||
|
return "(unknown)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::Dump(TypePtr type, const char *fmt /* = "%s" */) {
|
||||||
|
printf(fmt, type ? type->toString().c_str() : "(null)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::Dump(ExpressionPtr exp) {
|
||||||
|
Dump(exp->getExpectedType(), "Expected: %s\t");
|
||||||
|
Dump(exp->getActualType(), "Actual: %s\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::serialize(JSON::CodeError::OutputStream &out) const {
|
||||||
|
out << toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::serialize(JSON::DocTarget::OutputStream &out) const {
|
||||||
|
string s("any");
|
||||||
|
switch (m_kindOf) {
|
||||||
|
case KindOfBoolean: s = "boolean"; break;
|
||||||
|
case KindOfInt32:
|
||||||
|
case KindOfInt64: s = "integer"; break;
|
||||||
|
case KindOfDouble: s = "double"; break;
|
||||||
|
case KindOfString: s = "string"; break;
|
||||||
|
case KindOfArray: s = "array"; break;
|
||||||
|
case KindOfVariant:
|
||||||
|
case KindOfSome:
|
||||||
|
case KindOfAny: s = "any"; break;
|
||||||
|
case KindOfObject:
|
||||||
|
{
|
||||||
|
if (m_name.empty()) s = "object";
|
||||||
|
else {
|
||||||
|
ClassScopePtr c(getClass(out.analysisResult(), BlockScopeRawPtr()));
|
||||||
|
if (c) {
|
||||||
|
s = c->getOriginalName();
|
||||||
|
} else {
|
||||||
|
s = "object";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KindOfNumeric: s = "numeric"; break;
|
||||||
|
case KindOfPrimitive: s = "primitive"; break;
|
||||||
|
case KindOfPlusOperand: s = "any"; break;
|
||||||
|
case KindOfSequence: s = "sequence"; break;
|
||||||
|
}
|
||||||
|
out << s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Type::count(std::map<std::string, int> &counts) {
|
||||||
|
if (is(Type::KindOfObject)) {
|
||||||
|
if (isSpecificObject()) {
|
||||||
|
counts["Object - Specific"]++;
|
||||||
|
} else {
|
||||||
|
counts["Object"]++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
counts[toString()]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsExactType(m_kindOf)) {
|
||||||
|
counts["_strong"]++;
|
||||||
|
} else {
|
||||||
|
counts["_weak"]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
counts["_all"]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr Type::InferredObject(AnalysisResultConstPtr ar,
|
||||||
|
TypePtr type1,
|
||||||
|
TypePtr type2) {
|
||||||
|
assert(type1->m_kindOf == KindOfObject);
|
||||||
|
assert(type2->m_kindOf == KindOfObject);
|
||||||
|
|
||||||
|
TypePtr resultType = Type::Object;
|
||||||
|
// if they're the same, or we don't know one's name, then use
|
||||||
|
// the other
|
||||||
|
if (type1->m_name == type2->m_name || type1->m_name.empty()) {
|
||||||
|
resultType = type2;
|
||||||
|
} else if (type2->m_name.empty()) {
|
||||||
|
resultType = type1;
|
||||||
|
} else {
|
||||||
|
// take the subclass
|
||||||
|
ClassScopePtr cls1 = ar->findClass(type1->m_name);
|
||||||
|
ClassScopePtr cls2 = ar->findClass(type2->m_name);
|
||||||
|
bool c1ok = cls1 && !cls1->isRedeclaring();
|
||||||
|
bool c2ok = cls2 && !cls2->isRedeclaring();
|
||||||
|
|
||||||
|
if (c1ok && cls1->derivesFrom(ar, type2->m_name, true, false)) {
|
||||||
|
resultType = type1;
|
||||||
|
} else if (c2ok && cls2->derivesFrom(ar, type1->m_name, true, false)) {
|
||||||
|
resultType = type2;
|
||||||
|
} else if (c1ok && c2ok && cls1->derivedByDynamic() &&
|
||||||
|
cls2->derivesFromRedeclaring()) {
|
||||||
|
resultType = type2;
|
||||||
|
} else {
|
||||||
|
resultType = type1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have inferred type1 and type2 as the actual types for the same
|
||||||
|
expression.
|
||||||
|
Check that the types are compatible (it cant be both a string and
|
||||||
|
an integer, for example), and return the combined type. If they
|
||||||
|
are not compatible, return a null pointer.
|
||||||
|
*/
|
||||||
|
TypePtr Type::Inferred(AnalysisResultConstPtr ar,
|
||||||
|
TypePtr type1, TypePtr type2) {
|
||||||
|
if (!type1) return type2;
|
||||||
|
if (!type2) return type1;
|
||||||
|
KindOf k1 = type1->m_kindOf;
|
||||||
|
KindOf k2 = type2->m_kindOf;
|
||||||
|
|
||||||
|
if (k1 == k2) {
|
||||||
|
return k1 == KindOfObject ?
|
||||||
|
Type::InferredObject(ar, type1, type2) : type1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one set is a subset of the other, return the subset.
|
||||||
|
if ((k1 & k2) == k1) return type1;
|
||||||
|
if ((k1 & k2) == k2) return type2;
|
||||||
|
|
||||||
|
// If one type must be numeric and the other might be, then assume numeric
|
||||||
|
if (type1->mustBe(KindOfNumeric) && type2->couldBe(KindOfNumeric)) {
|
||||||
|
return type1;
|
||||||
|
}
|
||||||
|
if (type2->mustBe(KindOfNumeric) && type1->couldBe(KindOfNumeric)) {
|
||||||
|
return type2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, take the intersection
|
||||||
|
int resultKind = type1->m_kindOf & type2->m_kindOf;
|
||||||
|
if (resultKind == KindOfObject) {
|
||||||
|
return Type::InferredObject(ar, type1, type2);
|
||||||
|
}
|
||||||
|
return resultKind ? GetType(resultKind) : TypePtr();
|
||||||
|
}
|
||||||
+7
-7
@@ -527,7 +527,7 @@ Symbol *VariableTable::findProperty(ClassScopePtr &cls,
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
assert(!sym->isStatic());
|
assert(!sym->isStatic());
|
||||||
sym = NULL;
|
sym = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
@@ -733,7 +733,7 @@ bool VariableTable::isConvertibleSuperGlobal(const string &name) const {
|
|||||||
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar,
|
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar,
|
||||||
const string &name,
|
const string &name,
|
||||||
const Symbol *&sym) const {
|
const Symbol *&sym) const {
|
||||||
sym = NULL;
|
sym = nullptr;
|
||||||
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
|
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
|
||||||
parent && !parent->isRedeclaring();
|
parent && !parent->isRedeclaring();
|
||||||
parent = parent->getParentScope(ar)) {
|
parent = parent->getParentScope(ar)) {
|
||||||
@@ -1302,7 +1302,7 @@ void VariableTable::outputCPPGVHashTableGetImpl(CodeGenerator &cg,
|
|||||||
string escaped = CodeGenerator::EscapeLabel(name);
|
string escaped = CodeGenerator::EscapeLabel(name);
|
||||||
string varName = string("gvm_") + CodeGenerator::FormatLabel(name);
|
string varName = string("gvm_") + CodeGenerator::FormatLabel(name);
|
||||||
cg_printf(" (const char *)\"%s\",\n"
|
cg_printf(" (const char *)\"%s\",\n"
|
||||||
" (const char *)%lld,\n"
|
" (const char *)%" PRId64 ",\n"
|
||||||
" (const char *)GET_GV_OFFSET(%s),\n"
|
" (const char *)GET_GV_OFFSET(%s),\n"
|
||||||
" (const char *)%u,\n",
|
" (const char *)%u,\n",
|
||||||
escaped.c_str(),
|
escaped.c_str(),
|
||||||
@@ -1625,7 +1625,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
|
|||||||
|
|
||||||
if (m_forcedVariants) {
|
if (m_forcedVariants) {
|
||||||
cg_indentBegin("virtual Variant &getImpl(CStrRef s) {\n");
|
cg_indentBegin("virtual Variant &getImpl(CStrRef s) {\n");
|
||||||
if (!outputCPPJumpTable(cg, ar, NULL, true, true, EitherStatic,
|
if (!outputCPPJumpTable(cg, ar, nullptr, true, true, EitherStatic,
|
||||||
JumpReturnString)) {
|
JumpReturnString)) {
|
||||||
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
|
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1634,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
|
|||||||
|
|
||||||
if (getAttribute(ContainsExtract)) {
|
if (getAttribute(ContainsExtract)) {
|
||||||
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
|
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
|
||||||
if (!outputCPPJumpTable(cg, ar, NULL, true, false,
|
if (!outputCPPJumpTable(cg, ar, nullptr, true, false,
|
||||||
EitherStatic, JumpInitializedString)) {
|
EitherStatic, JumpInitializedString)) {
|
||||||
m_emptyJumpTables.insert(JumpTableLocalExists);
|
m_emptyJumpTables.insert(JumpTableLocalExists);
|
||||||
}
|
}
|
||||||
@@ -1643,7 +1643,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cg_indentBegin("virtual Variant getImpl(CStrRef s) {\n");
|
cg_indentBegin("virtual Variant getImpl(CStrRef s) {\n");
|
||||||
if (!outputCPPJumpTable(cg, ar, NULL, true, false, EitherStatic,
|
if (!outputCPPJumpTable(cg, ar, nullptr, true, false, EitherStatic,
|
||||||
JumpReturnString)) {
|
JumpReturnString)) {
|
||||||
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
|
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
|
||||||
}
|
}
|
||||||
@@ -1653,7 +1653,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
|
|||||||
|
|
||||||
if (getAttribute(ContainsCompact)) {
|
if (getAttribute(ContainsCompact)) {
|
||||||
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
|
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
|
||||||
if (!outputCPPJumpTable(cg, ar, NULL, true, false,
|
if (!outputCPPJumpTable(cg, ar, nullptr, true, false,
|
||||||
EitherStatic, JumpInitializedString)) {
|
EitherStatic, JumpInitializedString)) {
|
||||||
m_emptyJumpTables.insert(JumpTableLocalExists);
|
m_emptyJumpTables.insert(JumpTableLocalExists);
|
||||||
}
|
}
|
||||||
@@ -394,7 +394,7 @@ private:
|
|||||||
bool variantOnly, StaticSelection staticVar,
|
bool variantOnly, StaticSelection staticVar,
|
||||||
JumpTableType type = JumpReturn,
|
JumpTableType type = JumpReturn,
|
||||||
PrivateSelection privateVar = NonPrivate,
|
PrivateSelection privateVar = NonPrivate,
|
||||||
bool *declaredGlobals = NULL);
|
bool *declaredGlobals = nullptr);
|
||||||
bool outputCPPPrivateSelector(CodeGenerator &cg, AnalysisResultPtr ar,
|
bool outputCPPPrivateSelector(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
const char *op, const char *args);
|
const char *op, const char *args);
|
||||||
void outputCPPVariableInit(CodeGenerator &cg, AnalysisResultPtr ar,
|
void outputCPPVariableInit(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||||
@@ -60,21 +60,21 @@ const char *BuiltinSymbols::ExtensionFunctions[] = {
|
|||||||
#define T(t) (const char *)Type::KindOf ## t
|
#define T(t) (const char *)Type::KindOf ## t
|
||||||
#define EXT_TYPE 0
|
#define EXT_TYPE 0
|
||||||
#include <system/ext.inc>
|
#include <system/ext.inc>
|
||||||
NULL,
|
nullptr,
|
||||||
};
|
};
|
||||||
#undef EXT_TYPE
|
#undef EXT_TYPE
|
||||||
|
|
||||||
const char *BuiltinSymbols::ExtensionConsts[] = {
|
const char *BuiltinSymbols::ExtensionConsts[] = {
|
||||||
#define EXT_TYPE 1
|
#define EXT_TYPE 1
|
||||||
#include <system/ext.inc>
|
#include <system/ext.inc>
|
||||||
NULL,
|
nullptr,
|
||||||
};
|
};
|
||||||
#undef EXT_TYPE
|
#undef EXT_TYPE
|
||||||
|
|
||||||
const char *BuiltinSymbols::ExtensionClasses[] = {
|
const char *BuiltinSymbols::ExtensionClasses[] = {
|
||||||
#define EXT_TYPE 2
|
#define EXT_TYPE 2
|
||||||
#include <system/ext.inc>
|
#include <system/ext.inc>
|
||||||
NULL,
|
nullptr,
|
||||||
};
|
};
|
||||||
#undef EXT_TYPE
|
#undef EXT_TYPE
|
||||||
|
|
||||||
@@ -109,14 +109,14 @@ const char *BuiltinSymbols::SystemClasses[] = {
|
|||||||
"directoryiterator",
|
"directoryiterator",
|
||||||
"soapfault",
|
"soapfault",
|
||||||
"fbmysqllexer",
|
"fbmysqllexer",
|
||||||
NULL
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
StringToClassScopePtrMap BuiltinSymbols::s_classes;
|
StringToClassScopePtrMap BuiltinSymbols::s_classes;
|
||||||
VariableTablePtr BuiltinSymbols::s_variables;
|
VariableTablePtr BuiltinSymbols::s_variables;
|
||||||
ConstantTablePtr BuiltinSymbols::s_constants;
|
ConstantTablePtr BuiltinSymbols::s_constants;
|
||||||
StringToTypePtrMap BuiltinSymbols::s_superGlobals;
|
StringToTypePtrMap BuiltinSymbols::s_superGlobals;
|
||||||
void *BuiltinSymbols::s_handle_main = NULL;
|
void *BuiltinSymbols::s_handle_main = nullptr;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ void BuiltinSymbols::ParseExtConsts(AnalysisResultPtr ar, const char **p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypePtr BuiltinSymbols::ParseType(const char **&p) {
|
TypePtr BuiltinSymbols::ParseType(const char **&p) {
|
||||||
const char *clsname = NULL;
|
const char *clsname = nullptr;
|
||||||
Type::KindOf ktype = (Type::KindOf)(long)(*p++);
|
Type::KindOf ktype = (Type::KindOf)(long)(*p++);
|
||||||
if (ktype == CLASS_TYPE) {
|
if (ktype == CLASS_TYPE) {
|
||||||
clsname = *p++;
|
clsname = *p++;
|
||||||
@@ -277,7 +277,7 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
const char *paramName = NULL;
|
const char *paramName = nullptr;
|
||||||
while ((paramName = *p++ /* argName */)) {
|
while ((paramName = *p++ /* argName */)) {
|
||||||
TypePtr argType = ParseType(p);
|
TypePtr argType = ParseType(p);
|
||||||
const char *argDefault = *p++;
|
const char *argDefault = *p++;
|
||||||
@@ -342,11 +342,11 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
|
|||||||
const std::string &soname) {
|
const std::string &soname) {
|
||||||
string mapname = name + "_map";
|
string mapname = name + "_map";
|
||||||
|
|
||||||
const char ***symbols = NULL;
|
const char ***symbols = nullptr;
|
||||||
|
|
||||||
// If we linked with .a, the symbol is already in main program.
|
// If we linked with .a, the symbol is already in main program.
|
||||||
if (s_handle_main == NULL) {
|
if (s_handle_main == nullptr) {
|
||||||
s_handle_main = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
|
s_handle_main = dlopen(nullptr, RTLD_NOW | RTLD_GLOBAL);
|
||||||
if (!s_handle_main) {
|
if (!s_handle_main) {
|
||||||
const char *error = dlerror();
|
const char *error = dlerror();
|
||||||
Logger::Error("Unable to load main program's symbols: %s",
|
Logger::Error("Unable to load main program's symbols: %s",
|
||||||
@@ -358,7 +358,7 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, look for .so to load it.
|
// Otherwise, look for .so to load it.
|
||||||
void *handle = NULL;
|
void *handle = nullptr;
|
||||||
if (!symbols) {
|
if (!symbols) {
|
||||||
handle = dlopen(soname.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
handle = dlopen(soname.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
@@ -60,11 +60,11 @@ const char *CodeGenerator::HASH_INCLUDE =
|
|||||||
CodeGenerator::CodeGenerator(std::ostream *primary,
|
CodeGenerator::CodeGenerator(std::ostream *primary,
|
||||||
Output output /* = PickledPHP */,
|
Output output /* = PickledPHP */,
|
||||||
const std::string *filename /* = NULL */)
|
const std::string *filename /* = NULL */)
|
||||||
: m_out(NULL), m_output(output),
|
: m_out(nullptr), m_output(output),
|
||||||
m_hoistedClasses(0), m_collectHoistedClasses(false),
|
m_hoistedClasses(0), m_collectHoistedClasses(false),
|
||||||
m_context(NoContext), m_insideScalarArray(false), m_itemIndex(-1) {
|
m_context(NoContext), m_insideScalarArray(false), m_itemIndex(-1) {
|
||||||
for (int i = 0; i < StreamCount; i++) {
|
for (int i = 0; i < StreamCount; i++) {
|
||||||
m_streams[i] = NULL;
|
m_streams[i] = nullptr;
|
||||||
m_indentation[i] = 0;
|
m_indentation[i] = 0;
|
||||||
m_indentPending[i] = true;
|
m_indentPending[i] = true;
|
||||||
m_lineNo[i] = 1;
|
m_lineNo[i] = 1;
|
||||||
@@ -87,7 +87,7 @@ void CodeGenerator::useStream(Stream stream) {
|
|||||||
assert(stream >= NullStream && stream < StreamCount);
|
assert(stream >= NullStream && stream < StreamCount);
|
||||||
m_curStream = stream;
|
m_curStream = stream;
|
||||||
if (stream == NullStream) {
|
if (stream == NullStream) {
|
||||||
m_out = NULL;
|
m_out = nullptr;
|
||||||
} else {
|
} else {
|
||||||
m_out = m_streams[stream];
|
m_out = m_streams[stream];
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
CodeGenerator() {} // only for creating a dummy code generator
|
CodeGenerator() {} // only for creating a dummy code generator
|
||||||
CodeGenerator(std::ostream *primary, Output output = PickledPHP,
|
CodeGenerator(std::ostream *primary, Output output = PickledPHP,
|
||||||
const std::string *filename = NULL);
|
const std::string *filename = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ...if it was passed in from constructor.
|
* ...if it was passed in from constructor.
|
||||||
@@ -196,7 +196,7 @@ public:
|
|||||||
void printImplSplitter(); // marker to split .cpp into smaller files
|
void printImplSplitter(); // marker to split .cpp into smaller files
|
||||||
const char *getGlobals(AnalysisResultPtr ar);
|
const char *getGlobals(AnalysisResultPtr ar);
|
||||||
static std::string FormatLabel(const std::string &name);
|
static std::string FormatLabel(const std::string &name);
|
||||||
static std::string EscapeLabel(const std::string &name, bool *binary = NULL);
|
static std::string EscapeLabel(const std::string &name, bool *binary = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make sure PHP variables, functions and typenames are unique and
|
* Make sure PHP variables, functions and typenames are unique and
|
||||||
@@ -887,11 +887,11 @@ void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar) {
|
|||||||
ar->setOutputPath(po.syncDir);
|
ar->setOutputPath(po.syncDir);
|
||||||
}
|
}
|
||||||
// Propagate relevant compiler-specific options to the runtime.
|
// Propagate relevant compiler-specific options to the runtime.
|
||||||
RuntimeOption::RepoLocalPath = ar->getOutputPath() + '/' + po.program;
|
RuntimeOption::RepoCentralPath = ar->getOutputPath() + '/' + po.program;
|
||||||
if (po.format.find("exe") != string::npos) {
|
if (po.format.find("exe") != string::npos) {
|
||||||
RuntimeOption::RepoLocalPath += ".hhbc";
|
RuntimeOption::RepoCentralPath += ".hhbc";
|
||||||
}
|
}
|
||||||
RuntimeOption::RepoLocalMode = "rw";
|
RuntimeOption::RepoLocalMode = "--";
|
||||||
RuntimeOption::RepoDebugInfo = Option::RepoDebugInfo;
|
RuntimeOption::RepoDebugInfo = Option::RepoDebugInfo;
|
||||||
RuntimeOption::RepoJournal = "memory";
|
RuntimeOption::RepoJournal = "memory";
|
||||||
RuntimeOption::EnableHipHopSyntax = Option::EnableHipHopSyntax;
|
RuntimeOption::EnableHipHopSyntax = Option::EnableHipHopSyntax;
|
||||||
@@ -960,7 +960,7 @@ int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
|||||||
const char *argv[] = { "objcopy", "--add-section", repo.c_str(),
|
const char *argv[] = { "objcopy", "--add-section", repo.c_str(),
|
||||||
buf, exe.c_str(), 0 };
|
buf, exe.c_str(), 0 };
|
||||||
string out;
|
string out;
|
||||||
ret = Process::Exec(argv[0], argv, NULL, out, NULL) ? 0 : 1;
|
ret = Process::Exec(argv[0], argv, nullptr, out, nullptr) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1007,7 +1007,7 @@ int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
|||||||
Timer timer(Timer::WallTime, "creating CPP files");
|
Timer timer(Timer::WallTime, "creating CPP files");
|
||||||
if (po.syncDir.empty()) {
|
if (po.syncDir.empty()) {
|
||||||
ar->setOutputPath(po.outputDir);
|
ar->setOutputPath(po.outputDir);
|
||||||
ar->outputAllCPP(format, clusterCount, NULL);
|
ar->outputAllCPP(format, clusterCount, nullptr);
|
||||||
} else {
|
} else {
|
||||||
ar->setOutputPath(po.syncDir);
|
ar->setOutputPath(po.syncDir);
|
||||||
ar->outputAllCPP(format, clusterCount, &po.outputDir);
|
ar->outputAllCPP(format, clusterCount, &po.outputDir);
|
||||||
@@ -1036,7 +1036,7 @@ int buildTarget(const CompilerOptions &po) {
|
|||||||
if (!HPHP_HOME || !*HPHP_HOME) {
|
if (!HPHP_HOME || !*HPHP_HOME) {
|
||||||
throw Exception("Environment variable HPHP_HOME is not set.");
|
throw Exception("Environment variable HPHP_HOME is not set.");
|
||||||
}
|
}
|
||||||
string cmd = string(HPHP_HOME) + "/src/legacy/run.sh";
|
string cmd = string(HPHP_HOME) + "/hphp/legacy/run.sh";
|
||||||
string flags;
|
string flags;
|
||||||
if (getenv("RELEASE")) flags += "RELEASE=1 ";
|
if (getenv("RELEASE")) flags += "RELEASE=1 ";
|
||||||
if (getenv("SHOW_LINK")) flags += "SHOW_LINK=1 ";
|
if (getenv("SHOW_LINK")) flags += "SHOW_LINK=1 ";
|
||||||
@@ -1044,7 +1044,7 @@ int buildTarget(const CompilerOptions &po) {
|
|||||||
if (po.format == "lib") flags += "HPHP_BUILD_LIBRARY=1 ";
|
if (po.format == "lib") flags += "HPHP_BUILD_LIBRARY=1 ";
|
||||||
if (Option::GenerateFFI) flags += "HPHP_BUILD_FFI=1 ";
|
if (Option::GenerateFFI) flags += "HPHP_BUILD_FFI=1 ";
|
||||||
const char *argv[] = {"", po.outputDir.c_str(),
|
const char *argv[] = {"", po.outputDir.c_str(),
|
||||||
po.program.c_str(), flags.c_str(), NULL};
|
po.program.c_str(), flags.c_str(), nullptr};
|
||||||
|
|
||||||
if (getenv("SHOW_COMPILE")) {
|
if (getenv("SHOW_COMPILE")) {
|
||||||
Logger::Info ("Compile command: %s %s %s", po.outputDir.c_str(),
|
Logger::Info ("Compile command: %s %s %s", po.outputDir.c_str(),
|
||||||
@@ -1052,7 +1052,7 @@ int buildTarget(const CompilerOptions &po) {
|
|||||||
}
|
}
|
||||||
Timer timer(Timer::WallTime, "compiling and linking CPP files");
|
Timer timer(Timer::WallTime, "compiling and linking CPP files");
|
||||||
string out, err;
|
string out, err;
|
||||||
bool ret = Process::Exec(cmd.c_str(), argv, NULL, out, &err);
|
bool ret = Process::Exec(cmd.c_str(), argv, nullptr, out, &err);
|
||||||
if (getenv("SHOW_COMPILE")) {
|
if (getenv("SHOW_COMPILE")) {
|
||||||
Logger::Info("%s", out.c_str());
|
Logger::Info("%s", out.c_str());
|
||||||
} else {
|
} else {
|
||||||
@@ -364,7 +364,7 @@ void Construct::dumpNode(int spc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string refstr;
|
string refstr;
|
||||||
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
|
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
|
||||||
if (isReferencedValid()) {
|
if (isReferencedValid()) {
|
||||||
if (isReferenced()) {
|
if (isReferenced()) {
|
||||||
refstr += ",Referenced";
|
refstr += ",Referenced";
|
||||||
@@ -380,7 +380,7 @@ void Construct::dumpNode(int spc) {
|
|||||||
if (refstr != "") refstr = " (" + refstr.substr(1) + ")";
|
if (refstr != "") refstr = " (" + refstr.substr(1) + ")";
|
||||||
|
|
||||||
string objstr;
|
string objstr;
|
||||||
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
|
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
|
||||||
if (isNeededValid()) {
|
if (isNeededValid()) {
|
||||||
if (isNeeded()) {
|
if (isNeeded()) {
|
||||||
objstr += "Object";
|
objstr += "Object";
|
||||||
+1
-1
@@ -164,7 +164,7 @@ bool ArrayPairExpression::outputCPPName(CodeGenerator &cg,
|
|||||||
string s = sc->getLiteralString();
|
string s = sc->getLiteralString();
|
||||||
int64 res;
|
int64 res;
|
||||||
if (is_strictly_integer(s.c_str(), s.size(), res)) {
|
if (is_strictly_integer(s.c_str(), s.size(), res)) {
|
||||||
cg_printf("%sLL", s.c_str());
|
cg_printf("%sL", s.c_str());
|
||||||
} else {
|
} else {
|
||||||
m_name->outputCPP(cg, ar);
|
m_name->outputCPP(cg, ar);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -489,7 +489,7 @@ void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
|
|||||||
|
|
||||||
bool setNull = false;
|
bool setNull = false;
|
||||||
|
|
||||||
if (SpecialAssignment(cg, ar, m_variable, m_value, NULL, ref)) {
|
if (SpecialAssignment(cg, ar, m_variable, m_value, nullptr, ref)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
+1
-1
@@ -37,7 +37,7 @@ ClassConstantExpression::ClassConstantExpression
|
|||||||
ExpressionPtr classExp, const std::string &varName)
|
ExpressionPtr classExp, const std::string &varName)
|
||||||
: Expression(
|
: Expression(
|
||||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClassConstantExpression)),
|
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClassConstantExpression)),
|
||||||
StaticClassName(classExp), m_varName(varName), m_defScope(NULL),
|
StaticClassName(classExp), m_varName(varName), m_defScope(nullptr),
|
||||||
m_valid(false), m_depsSet(false) {
|
m_valid(false), m_depsSet(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
+1
-1
@@ -255,7 +255,7 @@ TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
|||||||
// read value and dynamic-ness together + check() atomically
|
// read value and dynamic-ness together + check() atomically
|
||||||
value = constants->getValue(m_name);
|
value = constants->getValue(m_name);
|
||||||
isDynamic = constants->isDynamic(m_name);
|
isDynamic = constants->isDynamic(m_name);
|
||||||
BlockScope *defScope = NULL;
|
BlockScope *defScope = nullptr;
|
||||||
std::vector<std::string> bases;
|
std::vector<std::string> bases;
|
||||||
actualType = constants->check(getScope(), m_name, type, coerce,
|
actualType = constants->check(getScope(), m_name, type, coerce,
|
||||||
ar, self, bases, defScope);
|
ar, self, bases, defScope);
|
||||||
@@ -484,7 +484,7 @@ TypePtr Expression::inferAssignmentTypes(AnalysisResultPtr ar, TypePtr type,
|
|||||||
// ...as in ClassConstant statement
|
// ...as in ClassConstant statement
|
||||||
ConstantExpressionPtr exp =
|
ConstantExpressionPtr exp =
|
||||||
dynamic_pointer_cast<ConstantExpression>(variable);
|
dynamic_pointer_cast<ConstantExpression>(variable);
|
||||||
BlockScope *defScope = NULL;
|
BlockScope *defScope = nullptr;
|
||||||
std::vector<std::string> bases;
|
std::vector<std::string> bases;
|
||||||
scope->getConstants()->check(getScope(), exp->getName(), ret,
|
scope->getConstants()->check(getScope(), exp->getName(), ret,
|
||||||
true, ar, variable,
|
true, ar, variable,
|
||||||
+2
-2
@@ -124,7 +124,7 @@ bool ExpressionList::isScalar() const {
|
|||||||
bool ExpressionList::isNoObjectInvolved() const {
|
bool ExpressionList::isNoObjectInvolved() const {
|
||||||
for (unsigned int i = 0; i < m_exps.size(); i++) {
|
for (unsigned int i = 0; i < m_exps.size(); i++) {
|
||||||
TypePtr t = m_exps[i]->getActualType();
|
TypePtr t = m_exps[i]->getActualType();
|
||||||
if (t == NULL || !t->isNoObjectInvolved())
|
if (t == nullptr || !t->isNoObjectInvolved())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -674,7 +674,7 @@ void ExpressionList::outputCPPUniqLitKeyArrayInit(
|
|||||||
bool arrayElements /* = true */, unsigned int start /* = 0 */) {
|
bool arrayElements /* = true */, unsigned int start /* = 0 */) {
|
||||||
if (arrayElements) assert(m_arrayElements && !m_collectionType);
|
if (arrayElements) assert(m_arrayElements && !m_collectionType);
|
||||||
unsigned int n = m_exps.size();
|
unsigned int n = m_exps.size();
|
||||||
cg_printf("array_createv%c(%lld, ", litstrKeys ? 's' : 'i', num);
|
cg_printf("array_createv%c(%" PRId64 ", ", litstrKeys ? 's' : 'i', num);
|
||||||
always_assert(n - start == num);
|
always_assert(n - start == num);
|
||||||
for (unsigned int i = start; i < n; i++) {
|
for (unsigned int i = start; i < n; i++) {
|
||||||
ExpressionPtr exp = m_exps[i];
|
ExpressionPtr exp = m_exps[i];
|
||||||
+2
-3
@@ -59,10 +59,9 @@ FunctionCall::FunctionCall
|
|||||||
m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
|
m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
|
||||||
assert(m_name.empty());
|
assert(m_name.empty());
|
||||||
ScalarExpressionPtr c = dynamic_pointer_cast<ScalarExpression>(m_nameExp);
|
ScalarExpressionPtr c = dynamic_pointer_cast<ScalarExpression>(m_nameExp);
|
||||||
m_origName = c->getString();
|
m_origName = c->getOriginalLiteralString();
|
||||||
c->toLower(true /* func call*/);
|
c->toLower(true /* func call*/);
|
||||||
m_name = c->getString();
|
m_name = c->getLiteralString();
|
||||||
assert(!m_name.empty());
|
|
||||||
} else {
|
} else {
|
||||||
m_origName = name;
|
m_origName = name;
|
||||||
m_name = Util::toLower(name);
|
m_name = Util::toLower(name);
|
||||||
+22
-11
@@ -38,7 +38,7 @@ ObjectPropertyExpression::ObjectPropertyExpression
|
|||||||
: Expression(
|
: Expression(
|
||||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ObjectPropertyExpression)),
|
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ObjectPropertyExpression)),
|
||||||
LocalEffectsContainer(AccessorEffect),
|
LocalEffectsContainer(AccessorEffect),
|
||||||
m_object(object), m_property(property), m_propSym(NULL) {
|
m_object(object), m_property(property), m_propSym(nullptr) {
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
m_propSymValid = false;
|
m_propSymValid = false;
|
||||||
m_object->setContext(Expression::ObjectContext);
|
m_object->setContext(Expression::ObjectContext);
|
||||||
@@ -72,7 +72,10 @@ bool ObjectPropertyExpression::isNonPrivate(AnalysisResultPtr ar) {
|
|||||||
}
|
}
|
||||||
ScalarExpressionPtr name =
|
ScalarExpressionPtr name =
|
||||||
dynamic_pointer_cast<ScalarExpression>(m_property);
|
dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||||
string propName = name->getString();
|
string propName = name->getLiteralString();
|
||||||
|
if (propName.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Symbol *sym = cls->getVariables()->getSymbol(propName);
|
Symbol *sym = cls->getVariables()->getSymbol(propName);
|
||||||
if (!sym || sym->isStatic() || !sym->isPrivate()) return true;
|
if (!sym || sym->isStatic() || !sym->isPrivate()) return true;
|
||||||
return false;
|
return false;
|
||||||
@@ -200,20 +203,24 @@ TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar,
|
|||||||
|
|
||||||
if (!m_property->is(Expression::KindOfScalarExpression)) {
|
if (!m_property->is(Expression::KindOfScalarExpression)) {
|
||||||
m_property->inferAndCheck(ar, Type::String, false);
|
m_property->inferAndCheck(ar, Type::String, false);
|
||||||
|
|
||||||
// we also lost track of which class variable an expression is about, hence
|
// we also lost track of which class variable an expression is about, hence
|
||||||
// any type inference could be wrong. Instead, we just force variants on
|
// any type inference could be wrong. Instead, we just force variants on
|
||||||
// all class variables.
|
// all class variables.
|
||||||
if (m_context & (LValue | RefValue)) {
|
if (m_context & (LValue | RefValue)) {
|
||||||
ar->forceClassVariants(getOriginalClass(), false, true);
|
ar->forceClassVariants(getOriginalClass(), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Type::Variant; // we have to use a variant to hold dynamic value
|
return Type::Variant; // we have to use a variant to hold dynamic value
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
|
ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||||
const string &name = exp->getString();
|
const string &name = exp->getLiteralString();
|
||||||
assert(!name.empty());
|
if (name.empty()) {
|
||||||
|
m_property->inferAndCheck(ar, Type::String, false);
|
||||||
|
if (m_context & (LValue | RefValue)) {
|
||||||
|
ar->forceClassVariants(getOriginalClass(), false, true);
|
||||||
|
}
|
||||||
|
return Type::Variant; // we have to use a variant to hold dynamic value
|
||||||
|
}
|
||||||
|
|
||||||
m_property->inferAndCheck(ar, Type::String, false);
|
m_property->inferAndCheck(ar, Type::String, false);
|
||||||
|
|
||||||
@@ -456,7 +463,7 @@ void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
|
|||||||
}
|
}
|
||||||
cg_printf("(((%s%s*)obj_tmp)->%s%s)",
|
cg_printf("(((%s%s*)obj_tmp)->%s%s)",
|
||||||
Option::ClassPrefix, cls->getId().c_str(),
|
Option::ClassPrefix, cls->getId().c_str(),
|
||||||
Option::PropertyPrefix, name->getString().c_str());
|
Option::PropertyPrefix, name->getLiteralString().c_str());
|
||||||
|
|
||||||
if (!write_context) {
|
if (!write_context) {
|
||||||
cg_printf(" : (raise_null_object_prop(),%s)",
|
cg_printf(" : (raise_null_object_prop(),%s)",
|
||||||
@@ -483,7 +490,8 @@ void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
|
|||||||
m_object->getActualType()->isSpecificObject());
|
m_object->getActualType()->isSpecificObject());
|
||||||
ScalarExpressionPtr name =
|
ScalarExpressionPtr name =
|
||||||
dynamic_pointer_cast<ScalarExpression>(m_property);
|
dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||||
cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str());
|
cg_printf("%s%s", Option::PropertyPrefix,
|
||||||
|
name->getLiteralString().c_str());
|
||||||
if (doExist || doUnset) cg_printf(")");
|
if (doExist || doUnset) cg_printf(")");
|
||||||
} else {
|
} else {
|
||||||
cg_printf("%s(", func.c_str());
|
cg_printf("%s(", func.c_str());
|
||||||
@@ -628,10 +636,13 @@ void ObjectPropertyExpression::outputCPPProperty(CodeGenerator &cg,
|
|||||||
if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
|
if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
|
||||||
ScalarExpressionPtr name =
|
ScalarExpressionPtr name =
|
||||||
dynamic_pointer_cast<ScalarExpression>(m_property);
|
dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||||
cg_printString(name->getString(), ar, shared_from_this());
|
string propName = name->getLiteralString();
|
||||||
} else {
|
if (!propName.empty()) {
|
||||||
m_property->outputCPP(cg, ar);
|
cg_printString(propName, ar, shared_from_this());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
m_property->outputCPP(cg, ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectPropertyExpression::outputCPPExistTest(CodeGenerator &cg,
|
void ObjectPropertyExpression::outputCPPExistTest(CodeGenerator &cg,
|
||||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário