Comparar commits
203 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| d660972153 | |||
| ca437add64 | |||
| 3611bf3d58 | |||
| 565c8477f8 | |||
| 8f3512f6d3 | |||
| 7241c247dd | |||
| f06575d4e2 | |||
| cc897749f8 | |||
| b597e3a753 | |||
| 8ec621676d | |||
| a134b25671 | |||
| 15fa1ebfde | |||
| ce75713972 | |||
| adc56c6d8c | |||
| 3fb0fe8a6a | |||
| 38306b527f | |||
| e4e3bee5d3 | |||
| d25adc550b | |||
| 8b23419a37 | |||
| af5623b4fc | |||
| b51003b5aa | |||
| 5f019f5b43 | |||
| 35e347efa5 | |||
| 6169f73d80 | |||
| 96350d1a66 | |||
| f51b3c302b | |||
| 6366959956 | |||
| a7a3c2e8cc | |||
| 9df492da6a | |||
| 8b36e4b067 | |||
| 518ae943da | |||
| f5b168643d | |||
| 4b075be2ee | |||
| 51f986a0ae | |||
| e8d372f813 | |||
| 6ddef58d56 | |||
| 6434422e85 | |||
| aa3124d64d | |||
| b4085ff17b | |||
| 1bcb5de881 | |||
| b5bebbb8b7 | |||
| 20ac715ec2 | |||
| a95a84390e | |||
| e0d098ef70 | |||
| e3c7403906 | |||
| dd83c93a8a | |||
| 9c470aa8ed | |||
| 1569061e8c | |||
| e10f38e7fa | |||
| ba0cc6be65 | |||
| 79af6e51fa | |||
| 5ba5cb3761 | |||
| 089caca5ea | |||
| 23b681e872 | |||
| f1a3410eb5 | |||
| 4a3a5ccc6a | |||
| 2776ebd221 | |||
| 21dab1f587 | |||
| a06a7e07af | |||
| c1c68516c1 | |||
| 477f8330d4 | |||
| 71ee3ea273 | |||
| 60c61ee3e1 | |||
| f10ecaf20d | |||
| ea782cbd3e | |||
| 7fe1c94a7c | |||
| 085040d70f | |||
| 3ea0d8b8e0 | |||
| fd2f07d1f1 | |||
| 3e8cbc356f | |||
| 10f9f6b239 | |||
| a611ac930d | |||
| 94f8158ca5 | |||
| 3c20163337 | |||
| a9926b46d2 | |||
| 26178124a4 | |||
| c7bb7d8eb6 | |||
| 05f5808d81 | |||
| 8e30d1c315 | |||
| 3887bec93f | |||
| 2fb7b0e279 | |||
| fea70b0391 | |||
| a4c6fec8e9 | |||
| f6ac148c09 | |||
| 95fc3dc1c9 | |||
| 2ae5ebf3f5 | |||
| c9f6d8aeb9 | |||
| 6aa91b97c8 | |||
| 830c48eb8a | |||
| e7a57f89c8 | |||
| e5469c9b19 | |||
| 96235149fb | |||
| c59f2ae71f | |||
| 4eaf40d7aa | |||
| 73ebbc2160 | |||
| 181f341d00 | |||
| b9e14c448c | |||
| 2fe9a69916 | |||
| 34ba5330d5 | |||
| 01b29a87df | |||
| cf41a82f42 | |||
| 65119c99a0 | |||
| 10c79adeba | |||
| 35e456c966 | |||
| fd49414b4d | |||
| 6850f3fa89 | |||
| 4286a730c5 | |||
| 6c87ecb74e | |||
| 7eeb594316 | |||
| ef70ffc4e0 | |||
| 1811ef243f | |||
| bdb5a88268 | |||
| 8be4799db9 | |||
| 2f3f5f3c5a | |||
| 3b3f9aa449 | |||
| 7e321f8d5a | |||
| 951d7c0adf | |||
| 7ff582616f | |||
| c4c4404aa9 | |||
| a8e7668189 | |||
| 18a45ba0d0 | |||
| a6104b9d6e | |||
| e355d3de17 | |||
| 99bfd8e9ee | |||
| 30fcc6a0d1 | |||
| 61d3e28392 | |||
| 21c4fbdbf3 | |||
| 33e81ef7bb | |||
| e518130c7b | |||
| 5848c633c3 | |||
| 9be42ffc84 | |||
| e150671d40 | |||
| c9ae7340cf | |||
| a7c629366f | |||
| 45486a934f | |||
| 92c74b141a | |||
| 45a794d7dd | |||
| 883a11fbef | |||
| c6475efbec | |||
| a1baf2d540 | |||
| 0562656c5b | |||
| c1e71c1917 | |||
| 668a9c1da2 | |||
| f4551719a9 | |||
| 3f0a4f7ece | |||
| ecdd06cebe | |||
| 5744173e90 | |||
| 0f3ba86d84 | |||
| 37d974ef83 | |||
| 7f43d78955 | |||
| 1f68fd307f | |||
| 3e12490127 | |||
| 334a83f7b6 | |||
| 8c2a7af8d4 | |||
| b40c724281 | |||
| 157b59cdac | |||
| 7969b8f2ee | |||
| addb01eea4 | |||
| 5eac64e8bd | |||
| 193ddf4a60 | |||
| 3f61cabef2 | |||
| bffeb65b84 | |||
| 6aa9f21425 | |||
| de1249af6e | |||
| f5c0cd21ae | |||
| 9f21844eb5 | |||
| 8c6d77deef | |||
| e5663bd9ec | |||
| 7917779c18 | |||
| a395e9e3dd | |||
| 27d247e976 | |||
| af3c7ac8df | |||
| 7c1503e778 | |||
| ab71559f5a | |||
| aac3f2bfd5 | |||
| 296b2baede | |||
| 2ef2187778 | |||
| e30755ddbe | |||
| bc085bbcf6 | |||
| 09b97f8336 | |||
| 991ca4e231 | |||
| 449ebdc43f | |||
| 6ab2ea2218 | |||
| 0b27530c65 | |||
| cd7b28ad6a | |||
| 943b945e1b | |||
| ab6a6508fb | |||
| c1b7da6a4c | |||
| 1d6df52d09 | |||
| 4507c61901 | |||
| 7f6b1532dc | |||
| 12471034e5 | |||
| 28fc7a3a45 | |||
| a9a021e739 | |||
| 812070e82d | |||
| 8d86116117 | |||
| 520ef90a75 | |||
| c3cd188c6f | |||
| c1a8c937f1 | |||
| 35842e9141 | |||
| fc5b95110f | |||
| 9cb2d7af85 | |||
| 6a311f2fab |
@@ -32,7 +32,6 @@ hphp.log
|
||||
/hphp/runtime/tmp/run.sh
|
||||
/hphp/runtime/tmp/libtest.so
|
||||
/hphp/runtime/vm/repo_schema.h
|
||||
/hphp/runtime/base/compiler_id.h
|
||||
|
||||
/hphp/hphpi/gen
|
||||
/hphp/hphpi/hphpi
|
||||
|
||||
@@ -19,12 +19,7 @@ include(CheckFunctionExists)
|
||||
|
||||
# boost checks
|
||||
|
||||
find_package(Boost 1.37.0 COMPONENTS system;program_options;filesystem REQUIRED)
|
||||
if (BOOST_VERSION EQUAL 104200)
|
||||
# Boost bug #3942 prevents us using 1.42
|
||||
message(FATAL_ERROR "Boost 1.42 is not compatible with HipHop")
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.48.0 COMPONENTS system program_options filesystem regex REQUIRED)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
link_directories(${Boost_LIBRARY_DIRS})
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ add_definitions(-DHHVM_LIB_PATH_DEFAULT="${HPHP_HOME}/bin")
|
||||
|
||||
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||
add_definitions(-DRELEASE=1)
|
||||
add_definitions(-DNDEBUG)
|
||||
message("Generating Release build")
|
||||
else()
|
||||
add_definitions(-DDEBUG)
|
||||
message("Generating DEBUG build")
|
||||
endif()
|
||||
|
||||
if(INFINITE_LOOP_DETECTION)
|
||||
|
||||
+1
-1
@@ -30,5 +30,5 @@ if ("$ENV{USE_HHVM}" STREQUAL "1")
|
||||
message("Building for HHVM")
|
||||
endif()
|
||||
if ("$ENV{USE_HPHPC}" STREQUAL "1")
|
||||
message("Building for HPHPc")
|
||||
message(FATAL_ERROR "Building HPHPc is no longer supported")
|
||||
endif()
|
||||
|
||||
+6
-2
@@ -31,13 +31,17 @@ The latest information is available on the [wiki](http://wiki.github.com/faceboo
|
||||
* libexpat
|
||||
* libmemcached
|
||||
* google-glog (http://code.google.com/p/google-glog/)
|
||||
* libc-client2007
|
||||
* libdwarf
|
||||
* libelf
|
||||
* libunwind
|
||||
|
||||
The following packages have had slight modifications added to them. Patches are provided and should be made against the current source copies.
|
||||
|
||||
* [libcurl](http://curl.haxx.se/download.html)
|
||||
* src/third_party/libcurl.fb-changes.diff
|
||||
* hphp/third_party/libcurl.fb-changes.diff
|
||||
* [libevent 1.4](http://www.monkey.org/~provos/libevent/)
|
||||
* src/third_party/libevent-1.4.13.fb-changes.diff OR src/third_party/libevent-1.4.14.fb-changes.diff
|
||||
* hphp/third_party/libevent-1.4.14.fb-changes.diff
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -5566,17 +5566,6 @@ class XhprofFrame {
|
||||
}
|
||||
}
|
||||
|
||||
// Used as the base class for all closures
|
||||
class Closure {
|
||||
protected $__static_locals;
|
||||
// Adding a dummy __sleep() to return an illegal value to make the code
|
||||
// go through error handling path
|
||||
public function __sleep() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Used as a sentinel type in 86pinit().
|
||||
class __pinitSentinel {
|
||||
}
|
||||
|
||||
+12
-95
@@ -17,26 +17,12 @@
|
||||
|
||||
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\\\"")
|
||||
# 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)
|
||||
set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system util)
|
||||
foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
|
||||
|
||||
auto_sources(files "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
|
||||
@@ -70,70 +56,15 @@ foreach (file ${CXX_SOURCES})
|
||||
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})
|
||||
foreach (file ${CXX_SOURCES})
|
||||
if (${file} MATCHES "ext/sep")
|
||||
list(REMOVE_ITEM CXX_SOURCES ${file})
|
||||
endif()
|
||||
endforeach(file ${CXX_SOURCES})
|
||||
|
||||
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()
|
||||
@@ -156,14 +87,6 @@ foreach (CXX_FILE ${CXX_SOURCES})
|
||||
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
|
||||
@@ -172,11 +95,9 @@ add_custom_command(
|
||||
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})
|
||||
ADD_LIBRARY(hphp_runtime_static STATIC runtime/vm/repo_schema.h ${CXX_SOURCES} ${C_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>")
|
||||
@@ -184,11 +105,7 @@ 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(runtime/ext_hhvm)
|
||||
add_subdirectory(hhvm)
|
||||
|
||||
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
|
||||
|
||||
@@ -1503,7 +1503,8 @@ ExpressionPtr AliasManager::canonicalizeNode(
|
||||
e->is(Expression::KindOfSimpleVariable) &&
|
||||
!e->isThis()) {
|
||||
Symbol *s = spc(SimpleVariable, e)->getSymbol();
|
||||
if (s && !s->isParameter() && !s->isClosureVar()) {
|
||||
if (s && !s->isParameter() && !s->isGeneratorParameter() &&
|
||||
!s->isClosureVar()) {
|
||||
rep = e->makeConstant(m_arp, "null");
|
||||
Compiler::Error(Compiler::UseUndeclaredVariable, e);
|
||||
if (m_variables->getAttribute(VariableTable::ContainsCompact)) {
|
||||
@@ -1562,9 +1563,9 @@ ExpressionPtr AliasManager::canonicalizeNode(
|
||||
}
|
||||
cur = next;
|
||||
}
|
||||
if ((!m_inCall || (!hhvm && !ae->getValue()->hasEffect())) &&
|
||||
if (!m_inCall &&
|
||||
ae->isUnused() && m_accessList.isLast(ae) &&
|
||||
!(hhvm && Option::OutputHHBC &&
|
||||
!(Option::OutputHHBC &&
|
||||
e->hasAnyContext(Expression::AccessContext |
|
||||
Expression::ObjectContext |
|
||||
Expression::ExistContext |
|
||||
@@ -1835,7 +1836,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
|
||||
break;
|
||||
|
||||
case Expression::KindOfSimpleFunctionCall:
|
||||
if (!hhvm || !Option::OutputHHBC) {
|
||||
if (!Option::OutputHHBC) {
|
||||
SimpleFunctionCallPtr f(spc(SimpleFunctionCall, e));
|
||||
if (!f->getClass()) {
|
||||
if (f->getClassName().empty()) {
|
||||
@@ -3324,7 +3325,7 @@ public:
|
||||
b->setBit(DataFlow::PRefIn, it->second);
|
||||
b->setBit(DataFlow::PInitIn, it->second);
|
||||
}
|
||||
updateParamInfo(m->getParams(), hhvm && Option::HardTypeHints);
|
||||
updateParamInfo(m->getParams(), Option::HardTypeHints);
|
||||
updateParamInfo(m->getFunctionScope()->getClosureVars(), false);
|
||||
}
|
||||
}
|
||||
@@ -4146,9 +4147,9 @@ void AliasManager::stringOptsRecur(StatementPtr s) {
|
||||
case Statement::KindOfBreakStatement:
|
||||
{
|
||||
BreakStatementPtr b = spc(BreakStatement, s);
|
||||
int64 depth = b->getDepth();
|
||||
int64_t depth = b->getDepth();
|
||||
if (depth != 1) {
|
||||
int64 s = m_loopInfo.size() - 1;
|
||||
int64_t s = m_loopInfo.size() - 1;
|
||||
if (s >= 0) {
|
||||
if (!depth || depth > s) depth = s;
|
||||
while (depth--) {
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -166,28 +166,6 @@ public:
|
||||
void inferTypes();
|
||||
void postOptimize();
|
||||
|
||||
/**
|
||||
* Scalar array handling.
|
||||
*/
|
||||
int registerScalarArray(bool insideScalarArray, FileScopePtr scope,
|
||||
ExpressionPtr pairs, int &hash, int &index,
|
||||
std::string &text);
|
||||
int checkScalarArray(const std::string &text, int &index);
|
||||
int getScalarArrayId(const std::string &text);
|
||||
void outputCPPNamedScalarArrays(const std::string &file);
|
||||
|
||||
std::string getScalarArrayCompressedText();
|
||||
std::string getScalarArrayName(int hash, int index);
|
||||
std::string getScalarVarArrayName(int hash, int index);
|
||||
|
||||
int checkScalarVarInteger(int64 val, int &index);
|
||||
std::string getScalarVarIntegerName(int hash, int index);
|
||||
void outputCPPNamedScalarVarIntegers(const std::string &file);
|
||||
|
||||
int checkScalarVarDouble(double dval, int &index);
|
||||
std::string getScalarVarDoubleName(int hash, int index);
|
||||
void outputCPPNamedScalarVarDoubles(const std::string &file);
|
||||
|
||||
/**
|
||||
* Force all class variables to be variants, since l-val or reference
|
||||
* of dynamic properties are used.
|
||||
@@ -210,30 +188,6 @@ public:
|
||||
* Code generation functions.
|
||||
*/
|
||||
bool outputAllPHP(CodeGenerator::Output output);
|
||||
void outputAllCPP(CodeGenerator::Output output, int clusterCount,
|
||||
const std::string *compileDir);
|
||||
|
||||
void outputCPPSystemImplementations(CodeGenerator &cg);
|
||||
void getCPPFileRunDecls(CodeGenerator &cg, Type2SymbolSetMap &type2names);
|
||||
void getCPPRedeclaredFunctionDecl(CodeGenerator &cg,
|
||||
Type2SymbolSetMap &type2names);
|
||||
void getCPPRedeclaredClassDecl(CodeGenerator &cg,
|
||||
Type2SymbolSetMap &type2names);
|
||||
void outputCPPRedeclaredClassImpl(CodeGenerator &cg);
|
||||
void getCPPDynamicConstantDecl(CodeGenerator &cg,
|
||||
Type2SymbolSetMap &type2names);
|
||||
void outputCPPDynamicConstantImpl(CodeGenerator &cg);
|
||||
void outputCPPScalarArrayDecl(CodeGenerator &cg);
|
||||
void outputCPPScalarArrayImpl(CodeGenerator &cg);
|
||||
void outputCPPScalarArrayInit(CodeGenerator &cg, int fileCount, int part);
|
||||
void outputCPPScalarArrayId(CodeGenerator &cg, int id, int hash, int index,
|
||||
bool scalarVariant = false);
|
||||
void getCPPClassStaticInitializerFlags(CodeGenerator &cg,
|
||||
Type2SymbolSetMap &type2names);
|
||||
void getCPPClassDeclaredFlags(CodeGenerator &cg,
|
||||
Type2SymbolSetMap &type2names);
|
||||
|
||||
void outputCPPFiniteDouble(CodeGenerator &cg, double dval);
|
||||
|
||||
/**
|
||||
* Parser creates a FileScope upon parsing a new file.
|
||||
@@ -318,68 +272,30 @@ public:
|
||||
return m_outputPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP source info functions.
|
||||
*/
|
||||
void recordSourceInfo(const std::string &file, int line, LocationPtr loc);
|
||||
void recordClassSource(const std::string &clsname, LocationPtr loc,
|
||||
const std::string &filename);
|
||||
void recordFunctionSource(const std::string &funcname, LocationPtr loc,
|
||||
const std::string &filename);
|
||||
|
||||
/**
|
||||
* Literal string to String precomputation
|
||||
*/
|
||||
std::string getLiteralStringName(int64 hash, int index, bool iproxy = false);
|
||||
std::string getLitVarStringName(int64 hash, int index, bool iproxy = false);
|
||||
std::string getLiteralStringName(int64_t hash, int index, bool iproxy = false);
|
||||
std::string getLitVarStringName(int64_t hash, int index, bool iproxy = false);
|
||||
int getLiteralStringId(const std::string &s, int &index);
|
||||
|
||||
/**
|
||||
* Profiling runtime parameter type
|
||||
*/
|
||||
std::string getFuncId(ClassScopePtr cls, FunctionScopePtr func);
|
||||
std::string getParamRTTIEntryKey(ClassScopePtr cls,
|
||||
FunctionScopePtr func,
|
||||
const std::string ¶mName);
|
||||
void addParamRTTIEntry(ClassScopePtr cls,
|
||||
FunctionScopePtr func,
|
||||
const std::string ¶mName);
|
||||
int getParamRTTIEntryId(ClassScopePtr cls,
|
||||
FunctionScopePtr func,
|
||||
const std::string ¶mName);
|
||||
void addRTTIFunction(const std::string &id);
|
||||
void cloneRTTIFuncs(const char *RTTIDirectory);
|
||||
|
||||
std::vector<const char *> &getFuncTableBucket(FunctionScopePtr func);
|
||||
|
||||
/**
|
||||
* Generate default implementation for separable extension classes.
|
||||
*/
|
||||
void outputCPPSepExtensionImpl(const std::string &filename);
|
||||
|
||||
void outputCPPClusterImpl(CodeGenerator &cg, const FileScopePtrVec &files);
|
||||
void outputCPPFileImpl(CodeGenerator &cg, FileScopePtr fs);
|
||||
|
||||
void addPregeneratedCPP(const std::string &name, std::string &code);
|
||||
const std::string &getPregeneratedCPP(const std::string &name);
|
||||
|
||||
std::set<std::string> m_variableTableFunctions;
|
||||
std::set<int> m_concatLengths;
|
||||
int m_arrayLitstrKeyMaxSize;
|
||||
int m_arrayIntegerKeyMaxSize;
|
||||
|
||||
void setSystem() { m_system = true; }
|
||||
bool isSystem() const { return m_system; }
|
||||
|
||||
void setSepExtension() { m_sepExtension = true; }
|
||||
bool isSepExtension() { return m_sepExtension; }
|
||||
|
||||
std::string getHashedName(int64 hash, int index, const char *prefix,
|
||||
std::string getHashedName(int64_t hash, int index, const char *prefix,
|
||||
bool longName = false);
|
||||
void addNamedLiteralVarString(const std::string &s);
|
||||
void addNamedScalarVarArray(const std::string &s);
|
||||
StringToClassScopePtrVecMap getExtensionClasses();
|
||||
void addInteger(int64 n);
|
||||
void addInteger(int64_t n);
|
||||
private:
|
||||
Package *m_package;
|
||||
bool m_parseOnDemand;
|
||||
@@ -405,53 +321,7 @@ private:
|
||||
StatementPtr m_stmt;
|
||||
|
||||
std::string m_outputPath;
|
||||
|
||||
std::map<std::string, int> m_scalarArrays;
|
||||
Mutex m_namedScalarArraysMutex;
|
||||
std::map<int, std::vector<std::string> > m_namedScalarArrays;
|
||||
std::set<std::string> m_namedScalarVarArrays;
|
||||
int m_scalarArraysCounter;
|
||||
std::vector<ExpressionPtr> m_scalarArrayIds;
|
||||
|
||||
Mutex m_namedScalarVarIntegersMutex;
|
||||
std::map<int, std::vector<std::string> > m_namedScalarVarIntegers;
|
||||
Mutex m_allIntegersMutex;
|
||||
std::set<int64> m_allIntegers;
|
||||
|
||||
Mutex m_namedScalarVarDoublesMutex;
|
||||
std::map<int, std::vector<std::string> > m_namedScalarVarDoubles;
|
||||
|
||||
std::map<std::string, int> m_paramRTTIs;
|
||||
std::set<std::string> m_rttiFuncs;
|
||||
int m_paramRTTICounter;
|
||||
|
||||
public:
|
||||
struct ScalarArrayExp {
|
||||
int id;
|
||||
int len;
|
||||
ExpressionPtr exp;
|
||||
};
|
||||
|
||||
void outputCPPDynamicTables(CodeGenerator::Output output);
|
||||
void outputCPPClassMapFile(CodeGenerator::Output output);
|
||||
void outputCPPSourceInfos();
|
||||
void outputCPPNameMaps();
|
||||
void outputRTTIMetaData(const char *filename);
|
||||
void outputCPPClassMap(CodeGenerator &cg, CodeGenerator::Output);
|
||||
void outputCPPSystem();
|
||||
void outputCPPSepExtensionMake();
|
||||
void outputFFI(std::vector<std::string> &additionalCPPs);
|
||||
void repartitionLargeCPP(const std::vector<std::string> &filenames,
|
||||
const std::vector<std::string> &additionals);
|
||||
|
||||
void outputCPPUtilDecl(CodeGenerator::Output output);
|
||||
void outputCPPUtilImpl(CodeGenerator::Output output);
|
||||
void outputCPPGlobalDeclarations();
|
||||
void outputCPPMain();
|
||||
void outputCPPScalarArrays(bool system);
|
||||
void outputCPPGlobalVariablesMethods();
|
||||
void outputCPPGlobalState();
|
||||
|
||||
AnalysisResultPtr shared_from_this() {
|
||||
return boost::static_pointer_cast<AnalysisResult>
|
||||
(BlockScope::shared_from_this());
|
||||
@@ -463,12 +333,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
int m_scalarArraySortedAvgLen;
|
||||
int m_scalarArraySortedIndex;
|
||||
int m_scalarArraySortedSumLen;
|
||||
std::vector<ScalarArrayExp> m_scalarArraySorted;
|
||||
int m_scalarArrayCompressedTextSize;
|
||||
bool m_pregenerating, m_pregenerated;
|
||||
BlockScopePtrVec m_ignoredScopes;
|
||||
|
||||
typedef boost::adjacency_list<boost::setS, boost::vecS> Graph;
|
||||
@@ -478,33 +342,6 @@ private:
|
||||
Graph m_depGraph;
|
||||
typedef std::map<vertex_descriptor, FileScopePtr> VertexToFileScopePtrMap;
|
||||
VertexToFileScopePtrMap m_fileVertMap;
|
||||
void getTrueDeps(FileScopePtr f,
|
||||
std::map<std::string, FileScopePtr> &trueDeps);
|
||||
void clusterByFileSizes(StringToFileScopePtrVecMap &clusters,
|
||||
int clusterCount);
|
||||
void renameStaticNames(std::map<int, std::vector<std::string> > &names,
|
||||
const char *file, const char *prefix);
|
||||
|
||||
typedef std::map<std::string, std::string> StringMap;
|
||||
Mutex m_pregenMapMutex;
|
||||
StringMap m_pregenMap;
|
||||
|
||||
typedef std::map<int, LocationPtr> SourceLocationMap;
|
||||
typedef std::map<std::string, SourceLocationMap> SourceInfo;
|
||||
Mutex m_sourceInfoMutex;
|
||||
SourceInfo m_sourceInfos;
|
||||
SourceInfo m_sourceInfoPregen;
|
||||
std::map<std::string, std::set<std::pair<std::string, int> > > m_clsNameMap;
|
||||
std::map<std::string, std::set<std::pair<std::string, int> > > m_funcNameMap;
|
||||
|
||||
Mutex m_namedStringLiteralsMutex;
|
||||
std::map<int, std::vector<std::string> > m_namedStringLiterals;
|
||||
std::set<std::string> m_namedVarStringLiterals;
|
||||
|
||||
int m_funcTableSize;
|
||||
CodeGenerator::MapIntToStringVec m_funcTable;
|
||||
bool m_system;
|
||||
bool m_sepExtension;
|
||||
|
||||
/**
|
||||
* Checks whether the file is in one of the on-demand parsing directories.
|
||||
@@ -525,100 +362,8 @@ private:
|
||||
*/
|
||||
void checkClassDerivations();
|
||||
|
||||
/**
|
||||
* Creates the global function table. Needs to be called before generating
|
||||
* cpp code for each toplevel function.
|
||||
*/
|
||||
void createGlobalFuncTable();
|
||||
|
||||
void outputCPPScalarArrays(CodeGenerator &cg, int fileCount, int part);
|
||||
|
||||
void collectCPPGlobalSymbols(StringPairSetVec &symbols,
|
||||
CodeGenerator &cg);
|
||||
void outputCPPGlobalStateFileHeader(CodeGenerator &cg);
|
||||
void outputCPPGlobalStateBegin(CodeGenerator &cg, const char *section);
|
||||
void outputCPPGlobalStateEnd(CodeGenerator &cg, const char *section);
|
||||
void outputCPPGlobalStateSection(CodeGenerator &cg,
|
||||
const StringPairSet &names,
|
||||
const char *section,
|
||||
const char *prefix = "g->",
|
||||
const char *name_prefix = "");
|
||||
|
||||
void outputCPPClassIncludes(CodeGenerator &cg);
|
||||
void outputCPPExtClassImpl(CodeGenerator &cg);
|
||||
void outputCPPDynamicTablesHeader(CodeGenerator &cg,
|
||||
bool includeGlobalVars = true,
|
||||
bool includes = true,
|
||||
bool noNamespace = false);
|
||||
void outputCPPGlobalImplementations(CodeGenerator &cg);
|
||||
|
||||
void preGenerateCPP(CodeGenerator::Output output,
|
||||
const FileScopePtrVec &files, int threadCount);
|
||||
void movePregeneratedSourceInfo(const std::string &source,
|
||||
const std::string &target, int offset);
|
||||
int getFileSize(FileScopePtr fs);
|
||||
|
||||
void repartitionCPP(const std::string &filename, int64 targetSize,
|
||||
bool insideHPHP, bool force);
|
||||
|
||||
void outputCPPFFIStubs();
|
||||
void outputHSFFIStubs();
|
||||
|
||||
/**
|
||||
* Outputs Java stubs.
|
||||
*
|
||||
* Each PHP file becomes a Java package, in which the HphpMain class
|
||||
* contains all the toplevel function definitions, and the rest of the
|
||||
* classes are one-to-one corresponding to the php classes declared in
|
||||
* that file.
|
||||
*/
|
||||
void outputJavaFFIStubs();
|
||||
/**
|
||||
* Outputs one .h file that declares all the Java native method stubs,
|
||||
* avoiding javah for performance reason.
|
||||
*/
|
||||
void outputJavaFFICppDecl();
|
||||
/**
|
||||
* Outputs one .cpp file that implements all the native methods declared
|
||||
* in the Java classes generated by outputJavaFFIStubs().
|
||||
*/
|
||||
void outputJavaFFICppImpl();
|
||||
|
||||
void outputSwigFFIStubs();
|
||||
|
||||
void outputHexBuffer(CodeGenerator &cg, const char *name,
|
||||
const char *buf, int len);
|
||||
void outputCPPNamedLiteralStrings(bool genStatic, const std::string &file);
|
||||
void outputCPPSepExtensionIncludes(CodeGenerator &cg);
|
||||
|
||||
void outputCPPInvokeFileHeader(CodeGenerator &cg);
|
||||
void outputCPPEvalHook(CodeGenerator &cg);
|
||||
void outputCPPDefaultInvokeFile(CodeGenerator &cg, const char *file);
|
||||
|
||||
void outputArrayCreateDecl(CodeGenerator &cg);
|
||||
void outputArrayCreateImpl(CodeGenerator &cg);
|
||||
void outputCPPHashTableInvokeFile(CodeGenerator &cg,
|
||||
const std::vector<const char*> &entries,
|
||||
bool needEvalHook);
|
||||
void outputCPPDynamicClassTables(CodeGenerator::Output output);
|
||||
void outputCPPDynamicConstantTable(CodeGenerator::Output output);
|
||||
void outputCPPHashTableGetConstant(CodeGenerator &cg, bool system,
|
||||
const std::map<std::string, TypePtr> &constMap,
|
||||
const hphp_string_map<bool> &dyns);
|
||||
void cloneRTTIFuncs(const StringToFunctionScopePtrMap &functions,
|
||||
const StringToFunctionScopePtrVecMap *redecFunctions);
|
||||
void outputInitLiteralVarStrings(CodeGenerator &cg, int fileIndex,
|
||||
std::vector<int> &litVarStrFileIndices,
|
||||
std::vector<std::pair<int, int> > &litVarStrs);
|
||||
|
||||
void outputInitLiteralVarStrings();
|
||||
void outputStringProxyData(CodeGenerator &cg,
|
||||
int fileIndex, std::vector<std::string> &lStrings,
|
||||
std::vector<std::pair<std::string, int> > &bStrings);
|
||||
void outputVarStringProxyData(CodeGenerator &cg,
|
||||
int fileIndex, std::vector<std::pair<int, int> > &litVarStrs);
|
||||
|
||||
|
||||
public:
|
||||
static DECLARE_THREAD_LOCAL(BlockScopeRawPtr, s_currentScopeThreadLocal);
|
||||
static DECLARE_THREAD_LOCAL(BlockScopeRawPtrFlagsHashMap,
|
||||
@@ -655,7 +400,7 @@ private:
|
||||
class RescheduleException : public Exception {
|
||||
public:
|
||||
RescheduleException(BlockScopeRawPtr scope) :
|
||||
Exception(false), m_scope(scope) {}
|
||||
Exception(), m_scope(scope) {}
|
||||
BlockScopeRawPtr &getScope() { return m_scope; }
|
||||
#ifdef HPHP_INSTRUMENT_TYPE_INF
|
||||
static int s_NumReschedules;
|
||||
|
||||
@@ -225,11 +225,6 @@ void BlockScope::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_variables->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
void BlockScope::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_constants->outputCPP(cg, ar);
|
||||
m_variables->outputCPP(cg, ar);
|
||||
}
|
||||
|
||||
int BlockScope::ScopeCompare::cmp(const BlockScopeRawPtr &p1,
|
||||
const BlockScopeRawPtr &p2) const {
|
||||
int d1 = p1->m_kind - p2->m_kind;
|
||||
|
||||
@@ -218,9 +218,7 @@ public:
|
||||
/**
|
||||
* Code gen
|
||||
*/
|
||||
virtual void outputCPPDef(CodeGenerator &cg) {}
|
||||
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
virtual bool inPseudoMain() const {
|
||||
return false;
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -124,7 +124,6 @@ public:
|
||||
|
||||
void checkDerivation(AnalysisResultPtr ar, hphp_string_iset &seen);
|
||||
const std::string &getOriginalParent() const { return m_parent; }
|
||||
std::string getHeaderFilename();
|
||||
|
||||
/**
|
||||
* Returns topmost parent class that has the method.
|
||||
@@ -212,7 +211,7 @@ public:
|
||||
bool forInvoke = false);
|
||||
|
||||
/**
|
||||
* Whether or not we can directly call c_ObjectData::o_invoke() when lookup
|
||||
* Whether or not we can directly call ObjectData::o_invoke() when lookup
|
||||
* in this class fails. If false, we need to call parent::o_invoke(), which
|
||||
* may be redeclared or may have private methods that need to check class
|
||||
* context.
|
||||
@@ -292,62 +291,6 @@ public:
|
||||
|
||||
ClassScopePtr getParentScope(AnalysisResultConstPtr ar) const;
|
||||
|
||||
void addUsedLiteralStringHeader(const std::string &s) {
|
||||
m_usedLiteralStringsHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedLitVarStringHeader(const std::string &s) {
|
||||
m_usedLitVarStringsHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedScalarVarInteger(int64 i) {
|
||||
m_usedScalarVarIntegers.insert(i);
|
||||
}
|
||||
|
||||
std::set<int64> &getUsedScalarVarIntegers() {
|
||||
return m_usedScalarVarIntegers;
|
||||
}
|
||||
|
||||
void addUsedScalarVarIntegerHeader(int64 i) {
|
||||
m_usedScalarVarIntegersHeader.insert(i);
|
||||
}
|
||||
|
||||
void addUsedScalarVarDouble(double d) {
|
||||
m_usedScalarVarDoubles.insert(d);
|
||||
}
|
||||
|
||||
std::set<double> &getUsedScalarVarDoubles() {
|
||||
return m_usedScalarVarDoubles;
|
||||
}
|
||||
|
||||
void addUsedScalarVarDoubleHeader(double d) {
|
||||
m_usedScalarVarDoublesHeader.insert(d);
|
||||
}
|
||||
|
||||
void addUsedDefaultValueScalarArray(const std::string &s) {
|
||||
m_usedDefaultValueScalarArrays.insert(s);
|
||||
}
|
||||
|
||||
void addUsedDefaultValueScalarVarArray(const std::string &s) {
|
||||
m_usedDefaultValueScalarVarArrays.insert(s);
|
||||
}
|
||||
|
||||
void addUsedConstHeader(const std::string &s) {
|
||||
m_usedConstsHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedClassConstHeader(ClassScopeRawPtr cls, const std::string &s) {
|
||||
m_usedClassConstsHeader.insert(CodeGenerator::UsedClassConst(cls, s));
|
||||
}
|
||||
|
||||
void addUsedClassHeader(ClassScopeRawPtr s) {
|
||||
m_usedClassesHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedClassFullHeader(ClassScopeRawPtr s) {
|
||||
m_usedClassesFullHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedTrait(const std::string &s) {
|
||||
if (!usesTrait(s)) {
|
||||
m_usedTraitNames.push_back(s);
|
||||
@@ -375,42 +318,12 @@ public:
|
||||
|
||||
void importUsedTraits(AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Output class meta info for g_class_map.
|
||||
*/
|
||||
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Serialize the iface, not everything.
|
||||
*/
|
||||
void serialize(JSON::CodeError::OutputStream &out) const;
|
||||
void serialize(JSON::DocTarget::OutputStream &out) const;
|
||||
|
||||
static void outputCPPHashTableClasses
|
||||
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
|
||||
const std::vector<const char*> &classes);
|
||||
static void outputCPPClassVarInitImpl(
|
||||
CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
|
||||
const std::vector<const char *> &classes);
|
||||
|
||||
void outputCPPDynamicClassDecl(CodeGenerator &cg);
|
||||
void outputCPPDynamicClassImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
static void outputCPPDynamicClassCreateDecl(CodeGenerator &cg);
|
||||
static void outputCPPDynamicClassCreateImpl
|
||||
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
|
||||
const std::vector<const char*> &classes);
|
||||
static void outputCPPGetCallInfoStaticMethodImpl
|
||||
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
|
||||
const std::vector<const char*> &classes);
|
||||
static void outputCPPGetStaticPropertyImpl
|
||||
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
|
||||
const std::vector<const char*> &classes);
|
||||
static void outputCPPGetClassConstantImpl
|
||||
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes);
|
||||
static void outputCPPGetClassPropTableImpl
|
||||
(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToClassScopePtrVecMap &classScopes,
|
||||
bool extension = false);
|
||||
bool isInterface() const { return m_kindOf == KindOfInterface; }
|
||||
bool isFinal() const { return m_kindOf == KindOfFinalClass ||
|
||||
m_kindOf == KindOfTrait; }
|
||||
@@ -419,32 +332,6 @@ public:
|
||||
bool isTrait() const { return m_kindOf == KindOfTrait; }
|
||||
bool hasProperty(const std::string &name) const;
|
||||
bool hasConst(const std::string &name) const;
|
||||
void outputCPPDef(CodeGenerator &cg);
|
||||
void outputCPPHeader(AnalysisResultPtr ar,
|
||||
CodeGenerator::Output output);
|
||||
void outputCPPForwardHeader(CodeGenerator &cg,AnalysisResultPtr ar);
|
||||
void outputCPPJumpTableDecl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputMethodWrappers(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* This prints out all the support methods (invoke, create, destructor,
|
||||
* etc.)
|
||||
* This is here instead of ClassStatement because I want to be able to call
|
||||
* these for extension classes that don't have a statement.
|
||||
*/
|
||||
void outputCPPSupportMethodsImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
std::string getClassPropTableId(AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* These output wrappers for class methods so that class definitions don't
|
||||
* have to be used in generating global jump tables.
|
||||
*/
|
||||
void outputCPPGlobalTableWrappersDecl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGlobalTableWrappersImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
static bool NeedStaticArray(ClassScopePtr cls, FunctionScopePtr func);
|
||||
void inheritedMagicMethods(ClassScopePtr super);
|
||||
@@ -461,40 +348,12 @@ public:
|
||||
m_parent = "";
|
||||
}
|
||||
|
||||
void outputCPPStaticMethodWrappers(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
std::set<std::string> &done,
|
||||
const char *cls);
|
||||
/**
|
||||
* Override function container
|
||||
*/
|
||||
bool addFunction(AnalysisResultConstPtr ar,
|
||||
FunctionScopePtr funcScope);
|
||||
|
||||
void outputVolatileCheckBegin(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
BlockScopePtr bs,
|
||||
const std::string &name);
|
||||
void outputVolatileCheckEnd(CodeGenerator &cg);
|
||||
static void OutputVolatileCheckBegin(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
BlockScopePtr bs,
|
||||
const std::string &origName);
|
||||
static void OutputVolatileCheckEnd(CodeGenerator &cg);
|
||||
static void OutputVolatileCheck(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
BlockScopePtr bs,
|
||||
const std::string &origName, bool noThrow);
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not the specified jump table is empty.
|
||||
*/
|
||||
bool hasAllJumpTables() const {
|
||||
return m_emptyJumpTables.empty();
|
||||
}
|
||||
bool hasJumpTable(JumpTableName name) const {
|
||||
return m_emptyJumpTables.find(name) == m_emptyJumpTables.end();
|
||||
}
|
||||
|
||||
void setNeedsCppCtor(bool needsCppCtor) {
|
||||
m_needsCppCtor = needsCppCtor;
|
||||
}
|
||||
@@ -515,29 +374,6 @@ public:
|
||||
bool canSkipCreateMethod(AnalysisResultConstPtr ar) const;
|
||||
bool checkHasPropTable(AnalysisResultConstPtr ar);
|
||||
|
||||
struct IndexedSym {
|
||||
IndexedSym(int i, int p, const Symbol *s) :
|
||||
origIndex(i), privIndex(p), sym(s) {}
|
||||
|
||||
int origIndex;
|
||||
int privIndex;
|
||||
const Symbol *sym;
|
||||
};
|
||||
|
||||
struct ClassPropTableInfo {
|
||||
ClassScopeRawPtr cls;
|
||||
std::vector<int> actualIndex[3];
|
||||
std::vector<int> privateIndex[3];
|
||||
std::map<int, std::vector<IndexedSym> > syms[3];
|
||||
};
|
||||
|
||||
typedef std::map<std::string, ClassPropTableInfo>
|
||||
ClassPropTableMap;
|
||||
|
||||
protected:
|
||||
void findJumpTableMethods(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
std::vector<const char *> &funcs);
|
||||
bool hasJumpTableMethods(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
private:
|
||||
// need to maintain declaration order for ClassInfo map
|
||||
FunctionScopePtrVec m_functionsVec;
|
||||
@@ -546,19 +382,6 @@ private:
|
||||
mutable std::vector<std::string> m_bases;
|
||||
UserAttributeMap m_userAttributes;
|
||||
|
||||
std::set<JumpTableName> m_emptyJumpTables;
|
||||
std::set<std::string> m_usedLiteralStringsHeader;
|
||||
std::set<std::string> m_usedLitVarStringsHeader;
|
||||
std::set<int64> m_usedScalarVarIntegers;
|
||||
std::set<int64> m_usedScalarVarIntegersHeader;
|
||||
std::set<double> m_usedScalarVarDoubles;
|
||||
std::set<double> m_usedScalarVarDoublesHeader;
|
||||
std::set<std::string> m_usedDefaultValueScalarArrays;
|
||||
std::set<std::string> m_usedDefaultValueScalarVarArrays;
|
||||
std::set<std::string> m_usedConstsHeader;
|
||||
CodeGenerator::UsedClassConstSet m_usedClassConstsHeader;
|
||||
CodeGenerator::ClassScopeSet m_usedClassesHeader;
|
||||
CodeGenerator::ClassScopeSet m_usedClassesFullHeader;
|
||||
std::vector<std::string> m_usedTraitNames;
|
||||
// m_traitAliases is used to support ReflectionClass::getTraitAliases
|
||||
std::vector<std::pair<std::string, std::string> > m_traitAliases;
|
||||
@@ -614,6 +437,9 @@ private:
|
||||
|
||||
void addImportTraitMethod(const TraitMethod &traitMethod,
|
||||
const std::string &methName);
|
||||
void informClosuresAboutScopeClone(ConstructPtr root,
|
||||
FunctionScopePtr outerScope,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
void setImportTraitMethodModifiers(const std::string &methName,
|
||||
ClassScopePtr traitCls,
|
||||
@@ -659,23 +485,6 @@ private:
|
||||
void renameCreateContinuationCalls(AnalysisResultPtr ar, ConstructPtr c,
|
||||
ImportedMethodMap &importedMethods);
|
||||
|
||||
std::string getBaseHeaderFilename();
|
||||
|
||||
void outputCPPMethodInvokeBareObjectSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
FunctionScopePtr func, bool fewArgs);
|
||||
|
||||
void outputCPPMethodInvokeTable
|
||||
(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const std::vector <const char*> &keys,
|
||||
const StringToFunctionScopePtrMap &funcScopes, bool fewArgs,
|
||||
bool staticOnly);
|
||||
void outputCPPMethodInvokeTableSupport(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, const std::vector<const char*> &keys,
|
||||
const StringToFunctionScopePtrMap &funcScopes, bool fewArgs);
|
||||
hphp_const_char_imap<int> m_implemented;
|
||||
|
||||
ClassScopePtr getNextParentWithProp(AnalysisResultPtr ar);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -251,185 +251,3 @@ void ConstantTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantTable::getCPPDynamicDecl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
Type2SymbolSetMap &type2names) {
|
||||
const char *prefix = Option::ConstantPrefix;
|
||||
string classId;
|
||||
const char *fmt = "";
|
||||
ClassScopePtr scope = getClassScope();
|
||||
if (scope) {
|
||||
prefix = Option::ClassConstantPrefix;
|
||||
classId = scope->getId();
|
||||
fmt = Option::IdPrefix.c_str();
|
||||
}
|
||||
|
||||
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
|
||||
SymbolSet &symbols = type2names["Variant"];
|
||||
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
|
||||
if (sym->declarationSet() && sym->isDynamic() &&
|
||||
system == sym->isSystem()) {
|
||||
string tmp = string(prefix) + classId + fmt +
|
||||
CodeGenerator::FormatLabel(sym->getName());
|
||||
if (Type::IsMappedToVariant(sym->getFinalType())) {
|
||||
symbols.insert(tmp);
|
||||
} else {
|
||||
type2names[sym->getFinalType()->getCPPDecl(ar, BlockScopeRawPtr())].
|
||||
insert(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantTable::outputCPPDynamicImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
|
||||
if (sym->declarationSet() && sym->isDynamic()) {
|
||||
cg_printf("%s%s = \"%s\";\n", Option::ConstantPrefix,
|
||||
CodeGenerator::FormatLabel(sym->getName()).c_str(),
|
||||
CodeGenerator::EscapeLabel(sym->getName()).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantTable::collectCPPGlobalSymbols(StringPairSet &symbols,
|
||||
CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
|
||||
if (sym->declarationSet() && sym->isDynamic()) {
|
||||
string varname = Option::ConstantPrefix +
|
||||
CodeGenerator::FormatLabel(sym->getName());
|
||||
symbols.insert(StringPair(varname, varname));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool newline /* = true */) const {
|
||||
bool printed = false;
|
||||
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
|
||||
if (outputCPP(cg, ar, sym)) printed = true;
|
||||
}
|
||||
if (newline && printed) {
|
||||
cg_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const Symbol *sym) const {
|
||||
bool decl = true;
|
||||
if (cg.getContext() == CodeGenerator::CppConstantsDecl) {
|
||||
decl = false;
|
||||
}
|
||||
|
||||
if (!const_cast<Symbol*>(sym)->checkDefined() ||
|
||||
sym->isDynamic()) {
|
||||
return false;
|
||||
}
|
||||
if (sym->isSystem() && cg.getOutput() != CodeGenerator::SystemCPP) {
|
||||
return false;
|
||||
}
|
||||
const string &name = sym->getName();
|
||||
ConstructPtr value = sym->getValue();
|
||||
|
||||
cg_printf(decl ? "extern const " : "const ");
|
||||
TypePtr type = sym->getFinalType();
|
||||
bool isString = type->is(Type::KindOfString);
|
||||
if (isString) {
|
||||
cg_printf("StaticString");
|
||||
} else {
|
||||
type->outputCPPDecl(cg, ar, getBlockScope());
|
||||
}
|
||||
ClassScope *cls = dynamic_cast<ClassScope*>(&m_blockScope);
|
||||
if (decl) {
|
||||
if (!cls) {
|
||||
cg_printf(" %s%s", Option::ConstantPrefix,
|
||||
CodeGenerator::FormatLabel(name).c_str());
|
||||
} else {
|
||||
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
|
||||
cls->getId().c_str(),
|
||||
Option::IdPrefix.c_str(),
|
||||
CodeGenerator::FormatLabel(name).c_str());
|
||||
}
|
||||
} else {
|
||||
if (!cls) {
|
||||
cg_printf(" %s%s", Option::ConstantPrefix,
|
||||
CodeGenerator::FormatLabel(name).c_str());
|
||||
} else {
|
||||
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
|
||||
cls->getId().c_str(),
|
||||
Option::IdPrefix.c_str(),
|
||||
CodeGenerator::FormatLabel(name).c_str());
|
||||
}
|
||||
cg_printf(isString ? "(" : " = ");
|
||||
if (value) {
|
||||
ExpressionPtr exp = dynamic_pointer_cast<Expression>(value);
|
||||
if (isString && exp->isScalar()) {
|
||||
ScalarExpressionPtr scalarExp =
|
||||
dynamic_pointer_cast<ScalarExpression>(exp);
|
||||
if (scalarExp) {
|
||||
cg_printf("LITSTR_INIT(%s)",
|
||||
scalarExp->getCPPLiteralString().c_str());
|
||||
} else {
|
||||
Variant v;
|
||||
exp->getScalarValue(v);
|
||||
cg_printf("LITSTR_INIT(\"%s\")",
|
||||
CodeGenerator::EscapeLabel(v.toString().data()).c_str());
|
||||
}
|
||||
} else {
|
||||
exp->outputCPP(cg, ar);
|
||||
}
|
||||
} else {
|
||||
cg_printf("\"%s\"", CodeGenerator::EscapeLabel(name).c_str());
|
||||
}
|
||||
if (isString) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
cg_printf(";\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConstantTable::outputSingleConstant(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
const std::string &name) const {
|
||||
const Symbol *sym = getSymbol(name);
|
||||
return sym && outputCPP(cg, ar, sym);
|
||||
}
|
||||
|
||||
void ConstantTable::outputCPPConstantSymbol(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
Symbol *sym) {
|
||||
ClassScopeRawPtr cls = getClassScope();
|
||||
if (sym->valueSet() &&
|
||||
(cls || (!sym->isDynamic() &&
|
||||
!ar->isConstantRedeclared(sym->getName())))) {
|
||||
ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue());
|
||||
Variant v;
|
||||
if (value && value->getScalarValue(v)) {
|
||||
int len;
|
||||
string output = getEscapedText(v, len);
|
||||
cg_printf("\"%s\", (const char *)%d, \"%s\",\n",
|
||||
CodeGenerator::EscapeLabel(sym->getName()).c_str(),
|
||||
len, output.c_str());
|
||||
} else if (cls) {
|
||||
cg_printf("\"%s\", (const char *)&%s%s, NULL,\n",
|
||||
CodeGenerator::EscapeLabel(sym->getName()).c_str(),
|
||||
Option::ClassStaticsCallbackPrefix, cls->getId().c_str());
|
||||
} else {
|
||||
cg_printf("\"%s\", (const char *)0, NULL,\n",
|
||||
CodeGenerator::EscapeLabel(sym->getName()).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantTable::outputCPPClassMap(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool last /* = true */) {
|
||||
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
|
||||
outputCPPConstantSymbol(cg, ar, m_symbolVec[i]);
|
||||
}
|
||||
if (last) cg_printf("NULL,\n");
|
||||
}
|
||||
|
||||
@@ -81,22 +81,6 @@ public:
|
||||
* Generate all constant declarations for this symbol table.
|
||||
*/
|
||||
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool newline = true) const;
|
||||
void getCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
Type2SymbolSetMap &type2names);
|
||||
void outputCPPDynamicImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool outputSingleConstant(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const std::string &name) const;
|
||||
|
||||
void collectCPPGlobalSymbols(StringPairSet &symbols, CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Generate all class constants in class info map.
|
||||
*/
|
||||
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool last = true);
|
||||
|
||||
bool isRecursivelyDeclared(AnalysisResultConstPtr ar,
|
||||
const std::string &name) const;
|
||||
@@ -115,10 +99,6 @@ private:
|
||||
ClassScopeRawPtr findBase(AnalysisResultConstPtr ar,
|
||||
const std::string &name,
|
||||
const std::vector<std::string> &bases) const;
|
||||
bool outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const Symbol *sym) const;
|
||||
void outputCPPConstantSymbol(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
Symbol *sym);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -296,10 +296,10 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
|
||||
#define DEC_MA std::vector<uchar>
|
||||
#define DEC_BLA std::vector<Label*>&
|
||||
#define DEC_SLA std::vector<StrOff>&
|
||||
#define DEC_IVA int32
|
||||
#define DEC_HA int32
|
||||
#define DEC_IA int32
|
||||
#define DEC_I64A int64
|
||||
#define DEC_IVA int32_t
|
||||
#define DEC_HA int32_t
|
||||
#define DEC_IA int32_t
|
||||
#define DEC_I64A int64_t
|
||||
#define DEC_DA double
|
||||
#define DEC_SA const StringData*
|
||||
#define DEC_AA ArrayData*
|
||||
@@ -650,7 +650,11 @@ static void checkJmpTargetEvalStack(const SymbolicStack& source,
|
||||
if (source.size() != dest.size()) {
|
||||
Logger::Warning("Emitter detected a point in the bytecode where the "
|
||||
"depth of the stack is not the same for all possible "
|
||||
"control flow paths");
|
||||
"control flow paths. source size: %d. dest size: %d",
|
||||
source.size(),
|
||||
dest.size());
|
||||
Logger::Warning("src stack : %s", source.pretty().c_str());
|
||||
Logger::Warning("dest stack: %s", dest.pretty().c_str());
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
@@ -784,7 +788,7 @@ bool SymbolicStack::getNotRef() const {
|
||||
return se.notRef;
|
||||
}
|
||||
|
||||
void SymbolicStack::setInt(int64 v) {
|
||||
void SymbolicStack::setInt(int64_t v) {
|
||||
assert(m_symStack.size());
|
||||
m_symStack.back().intval = v;
|
||||
}
|
||||
@@ -930,7 +934,7 @@ int SymbolicStack::getLoc(int index) const {
|
||||
return m_symStack[index].intval;
|
||||
}
|
||||
|
||||
int64 SymbolicStack::getInt(int index) const {
|
||||
int64_t SymbolicStack::getInt(int index) const {
|
||||
assert(m_symStack.size() > size_t(index));
|
||||
assert(StackSym::GetSymFlavor(m_symStack[index].sym) == StackSym::I);
|
||||
return m_symStack[index].intval;
|
||||
@@ -1092,7 +1096,7 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
|
||||
|
||||
vector<Offset> index1;
|
||||
vector<Offset> index2;
|
||||
vector<uint8> data;
|
||||
vector<uint8_t> data;
|
||||
index1.push_back(entries);
|
||||
|
||||
size_t sz1 = (2 + entries) * sizeof(Offset);
|
||||
@@ -1112,8 +1116,8 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
|
||||
data.push_back(mi.m_data << 1);
|
||||
} else {
|
||||
union {
|
||||
uint32 val;
|
||||
uint8 bytes[4];
|
||||
uint32_t val;
|
||||
uint8_t bytes[4];
|
||||
} u;
|
||||
u.val = (mi.m_data << 1) | 1;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
@@ -1126,7 +1130,7 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
|
||||
index2.push_back(sz1 + sz2 + data.size());
|
||||
|
||||
size_t size = sz1 + sz2 + data.size();
|
||||
uint8* meta = (uint8*)malloc(size);
|
||||
uint8_t* meta = (uint8_t*)malloc(size);
|
||||
memcpy(meta, &index1[0], sz1);
|
||||
memcpy(meta + sz1, &index2[0], sz2);
|
||||
memcpy(meta + sz1 + sz2, &data[0], data.size());
|
||||
@@ -1723,10 +1727,8 @@ void EmitterVisitor::visit(FileScopePtr file) {
|
||||
tvWriteUninit(&mainReturn);
|
||||
tvAsVariant(&mainReturn) = 1;
|
||||
}
|
||||
// Use _count as a flag for VMExecutionContext::evalUnit
|
||||
// since its otherwise unused
|
||||
mainReturn._count = !notMergeOnly;
|
||||
m_ue.setMainReturn(&mainReturn);
|
||||
m_ue.setMergeOnly(!notMergeOnly);
|
||||
// If the exitHnd label was used, we need to emit some extra code
|
||||
// to handle stray breaks
|
||||
Label exit;
|
||||
@@ -1953,7 +1955,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
case Statement::KindOfContinueStatement:
|
||||
case Statement::KindOfBreakStatement: {
|
||||
BreakStatementPtr bs(static_pointer_cast<BreakStatement>(s));
|
||||
int64 n = bs->getDepth();
|
||||
int64_t n = bs->getDepth();
|
||||
if (n == 1) {
|
||||
// Plain old "break;" or "continue;"
|
||||
if (m_contTargets.empty()) {
|
||||
@@ -1985,7 +1987,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
emitConvertToCell(e);
|
||||
} else {
|
||||
// Dynamic break/continue with statically known depth.
|
||||
if (n > (int64)m_contTargets.size()) {
|
||||
if (n > (int64_t)m_contTargets.size()) {
|
||||
std::ostringstream msg;
|
||||
msg << "Cannot break/continue " << n << " levels";
|
||||
e.String(StringData::GetStaticString(msg.str()));
|
||||
@@ -3647,7 +3649,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
// Key.
|
||||
assert(key->isScalar());
|
||||
TypedValue tvKey;
|
||||
tvKey._count = 0;
|
||||
if (key->is(Expression::KindOfConstantExpression)) {
|
||||
ConstantExpressionPtr c(
|
||||
static_pointer_cast<ConstantExpression>(key));
|
||||
@@ -3671,11 +3672,11 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
ScalarExpressionPtr sval(
|
||||
static_pointer_cast<ScalarExpression>(key));
|
||||
const std::string* s;
|
||||
int64 i;
|
||||
int64_t i;
|
||||
double d;
|
||||
if (sval->getString(s)) {
|
||||
StringData* sd = StringData::GetStaticString(*s);
|
||||
int64 n = 0;
|
||||
int64_t n = 0;
|
||||
if (sd->isStrictlyInteger(n)) {
|
||||
tvKey.m_data.num = n;
|
||||
tvKey.m_type = KindOfInt64;
|
||||
@@ -3781,7 +3782,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
|
||||
StringData* className = newClosureName();
|
||||
const static StringData* parentName =
|
||||
StringData::GetStaticString("closure");
|
||||
StringData::GetStaticString("Closure");
|
||||
const Location* sLoc = ce->getLocation().get();
|
||||
PreClassEmitter* pce = m_ue.newPreClassEmitter(
|
||||
className, PreClass::AlwaysHoistable);
|
||||
@@ -4003,9 +4004,9 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
|
||||
encodeIvaToVector(vectorImm, m_evalStack.getLoc(i));
|
||||
} else if (symFlavor == StackSym::T) {
|
||||
assert(strid != -1);
|
||||
encodeToVector<int32>(vectorImm, strid);
|
||||
encodeToVector<int32_t>(vectorImm, strid);
|
||||
} else if (symFlavor == StackSym::I) {
|
||||
encodeToVector<int64>(vectorImm, m_evalStack.getInt(i));
|
||||
encodeToVector<int64_t>(vectorImm, m_evalStack.getInt(i));
|
||||
}
|
||||
|
||||
++i;
|
||||
@@ -4839,7 +4840,7 @@ DataType EmitterVisitor::analyzeSwitch(SwitchStatementPtr sw,
|
||||
} else {
|
||||
return KindOfInvalid;
|
||||
}
|
||||
int64 n;
|
||||
int64_t n;
|
||||
bool isNonZero;
|
||||
if (t == KindOfInt64) {
|
||||
n = cval.asInt64Val();
|
||||
@@ -4873,8 +4874,8 @@ DataType EmitterVisitor::analyzeSwitch(SwitchStatementPtr sw,
|
||||
}
|
||||
|
||||
if (t == KindOfInt64) {
|
||||
int64 base = caseMap.begin()->first;
|
||||
int64 nTargets = caseMap.rbegin()->first - base + 1;
|
||||
int64_t base = caseMap.begin()->first;
|
||||
int64_t nTargets = caseMap.rbegin()->first - base + 1;
|
||||
// Fail if the cases are too sparse
|
||||
if ((float)caseMap.size() / nTargets < 0.5) {
|
||||
return KindOfInvalid;
|
||||
@@ -4892,8 +4893,8 @@ void EmitterVisitor::emitIntegerSwitch(Emitter& e, SwitchStatementPtr sw,
|
||||
std::vector<Label>& caseLabels,
|
||||
Label& done, const SwitchState& state) {
|
||||
auto& caseMap = state.cases;
|
||||
int64 base = caseMap.begin()->first;
|
||||
int64 nTargets = caseMap.rbegin()->first - base + 1;
|
||||
int64_t base = caseMap.begin()->first;
|
||||
int64_t nTargets = caseMap.rbegin()->first - base + 1;
|
||||
|
||||
// It's on. Map case values to Labels, filling in the blanks as
|
||||
// appropriate.
|
||||
@@ -6081,9 +6082,17 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
||||
PreClassEmitter* pce = m_ue.newPreClassEmitter(className, hoistable);
|
||||
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), attr, parentName,
|
||||
classDoc);
|
||||
LocationPtr loc(new Location(*sLoc));
|
||||
loc->line1 = loc->line0;
|
||||
loc->char1 = loc->char0;
|
||||
e.setTempLocation(loc);
|
||||
if (hoistable != PreClass::AlwaysHoistable) {
|
||||
e.DefCls(pce->id());
|
||||
} else {
|
||||
// To atatch the line number to for error reporting...
|
||||
e.Nop();
|
||||
}
|
||||
e.setTempLocation(LocationPtr());
|
||||
for (int i = firstInterface; i < nInterfaces; ++i) {
|
||||
pce->addInterface(StringData::GetStaticString(bases[i]));
|
||||
}
|
||||
@@ -6150,6 +6159,9 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
|
||||
} else {
|
||||
tvWriteUninit(&tvVal);
|
||||
if (!(attrs & AttrStatic)) {
|
||||
if (requiresDeepInit(vNode)) {
|
||||
attrs = (Attr)(attrs | AttrDeepInit);
|
||||
}
|
||||
if (nonScalarPinitVec == nullptr) {
|
||||
nonScalarPinitVec = new NonScalarVec();
|
||||
}
|
||||
@@ -6668,7 +6680,6 @@ StringData* EmitterVisitor::newClosureName() {
|
||||
void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
|
||||
assert(val->isScalar());
|
||||
tvVal.m_type = KindOfUninit;
|
||||
tvVal._count = 0;
|
||||
switch (val->getKindOf()) {
|
||||
case Expression::KindOfConstantExpression: {
|
||||
ConstantExpressionPtr ce(static_pointer_cast<ConstantExpression>(val));
|
||||
@@ -6694,7 +6705,7 @@ void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
|
||||
tvVal.m_type = KindOfString;
|
||||
break;
|
||||
}
|
||||
int64 i;
|
||||
int64_t i;
|
||||
if (sval->getInt(i)) {
|
||||
tvVal.m_data.num = i;
|
||||
tvVal.m_type = KindOfInt64;
|
||||
@@ -6743,6 +6754,41 @@ void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterVisitor::requiresDeepInit(ExpressionPtr initExpr) const {
|
||||
switch (initExpr->getKindOf()) {
|
||||
case Expression::KindOfScalarExpression:
|
||||
case Expression::KindOfConstantExpression:
|
||||
case Expression::KindOfClassConstantExpression:
|
||||
return false;
|
||||
case Expression::KindOfUnaryOpExpression: {
|
||||
UnaryOpExpressionPtr u(
|
||||
static_pointer_cast<UnaryOpExpression>(initExpr));
|
||||
if (u->getOp() == T_ARRAY) {
|
||||
ExpressionListPtr el =
|
||||
static_pointer_cast<ExpressionList>(u->getExpression());
|
||||
if (el) {
|
||||
int n = el->getCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
ArrayPairExpressionPtr ap =
|
||||
static_pointer_cast<ArrayPairExpression>((*el)[i]);
|
||||
ExpressionPtr key = ap->getName();
|
||||
if (requiresDeepInit(ap->getValue()) ||
|
||||
(key && requiresDeepInit(key))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (u->getOp() == '+' || u->getOp() == '-') {
|
||||
return requiresDeepInit(u->getExpression());
|
||||
}
|
||||
// fall through
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thunklet::~Thunklet() {}
|
||||
|
||||
using HPHP::Eval::PhpFile;
|
||||
@@ -6952,9 +6998,8 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
||||
TypedValue mainReturn;
|
||||
mainReturn.m_data.num = 1;
|
||||
mainReturn.m_type = KindOfBoolean;
|
||||
// _count is the "Unit::isMergeOnly()" flag
|
||||
mainReturn._count = 1;
|
||||
ue->setMainReturn(&mainReturn);
|
||||
ue->setMergeOnly(true);
|
||||
|
||||
MetaInfoBuilder metaInfo;
|
||||
|
||||
@@ -7075,6 +7120,27 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
||||
cnsInfo->name.get(), (TypedValue*)(&val), empty_string.get());
|
||||
}
|
||||
}
|
||||
{
|
||||
ClassInfo::PropertyVec propVec = e.ci->getPropertiesVec();
|
||||
for (unsigned i = 0; i < propVec.size(); ++i) {
|
||||
const ClassInfo::PropertyInfo* propInfo = propVec[i];
|
||||
assert(propInfo);
|
||||
int attr = AttrNone;
|
||||
if (propInfo->attribute & ClassInfo::IsProtected) attr |= AttrProtected;
|
||||
else if (propInfo->attribute & ClassInfo::IsPrivate) attr |= AttrPrivate;
|
||||
else attr |= AttrPublic;
|
||||
if (propInfo->attribute & ClassInfo::IsStatic) attr |= AttrStatic;
|
||||
|
||||
TypedValue tvNull;
|
||||
tvWriteNull(&tvNull);
|
||||
pce->addProperty(
|
||||
propInfo->name.get(),
|
||||
Attr(attr),
|
||||
propInfo->docComment ? StringData::GetStaticString(propInfo->docComment) : nullptr,
|
||||
&tvNull
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Peephole peephole(*ue, metaInfo);
|
||||
@@ -7114,7 +7180,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
|
||||
Logger::Error("Unable to open %s for write", fullPath.c_str());
|
||||
} else {
|
||||
CodeGenerator cg(&f, CodeGenerator::TextHHBC);
|
||||
cg.printf("Hash: %llx%016llx\n", md5.q[0], md5.q[1]);
|
||||
cg.printf("Hash: %" PRIx64 "%016" PRIx64 "\n", md5.q[0], md5.q[1]);
|
||||
cg.printRaw(unit->toString().c_str());
|
||||
f.close();
|
||||
}
|
||||
|
||||
@@ -110,10 +110,10 @@ public:
|
||||
#define MA std::vector<uchar>
|
||||
#define BLA std::vector<Label*>&
|
||||
#define SLA std::vector<StrOff>&
|
||||
#define IVA int32
|
||||
#define HA int32
|
||||
#define IA int32
|
||||
#define I64A int64
|
||||
#define IVA int32_t
|
||||
#define HA int32_t
|
||||
#define IA int32_t
|
||||
#define I64A int64_t
|
||||
#define DA double
|
||||
#define SA const StringData*
|
||||
#define AA ArrayData*
|
||||
@@ -200,7 +200,7 @@ private:
|
||||
DataType dt; // META_DATA_TYPE
|
||||
} metaData;
|
||||
const StringData* className;
|
||||
int64 intval; // used for L and I symbolic flavors
|
||||
int64_t intval; // used for L and I symbolic flavors
|
||||
|
||||
// If intval is an unnamed local temporary, this offset is the start
|
||||
// of the region we are using it (which we will need to have a
|
||||
@@ -237,7 +237,7 @@ public:
|
||||
std::string pretty() const;
|
||||
|
||||
void push(char sym);
|
||||
void setInt(int64 v);
|
||||
void setInt(int64_t v);
|
||||
void setString(const StringData* s);
|
||||
void setKnownCls(const StringData* s, bool nonNull);
|
||||
void setNotRef();
|
||||
@@ -274,7 +274,7 @@ public:
|
||||
|
||||
ClassBaseType getClsBaseType(int index) const;
|
||||
int getLoc(int index) const;
|
||||
int64 getInt(int index) const;
|
||||
int64_t getInt(int index) const;
|
||||
Offset getUnnamedLocStart(int index) const;
|
||||
|
||||
void pushFDesc();
|
||||
@@ -494,7 +494,7 @@ private:
|
||||
typedef std::pair<Id, int> StrCase;
|
||||
struct SwitchState : private boost::noncopyable {
|
||||
SwitchState() : nonZeroI(-1), defI(-1) {}
|
||||
std::map<int64, int> cases; // a map from int (or litstr id) to case index
|
||||
std::map<int64_t, int> cases; // a map from int (or litstr id) to case index
|
||||
std::vector<StrCase> caseOrder; // for string switches, a list of the
|
||||
// <litstr id, case index> in the order
|
||||
// they appear in the source
|
||||
@@ -656,6 +656,7 @@ public:
|
||||
StringData* newClosureName();
|
||||
|
||||
void initScalar(TypedValue& tvVal, ExpressionPtr val);
|
||||
bool requiresDeepInit(ExpressionPtr initExpr) const;
|
||||
|
||||
void emitClassTraitPrecRule(PreClassEmitter* pce, TraitPrecStatementPtr rule);
|
||||
void emitClassTraitAliasRule(PreClassEmitter* pce,
|
||||
|
||||
@@ -206,20 +206,6 @@ ExpressionPtr FileScope::getEffectiveImpl(AnalysisResultConstPtr ar) const {
|
||||
return ExpressionPtr();
|
||||
}
|
||||
|
||||
bool FileScope::canUseDummyPseudoMain(AnalysisResultConstPtr ar) const {
|
||||
if (!m_pseudoMain) {
|
||||
return false;
|
||||
}
|
||||
assert(!m_pseudoMain->isVolatile());
|
||||
if (!Option::GenerateDummyPseudoMain ||
|
||||
Option::KeepStatementsWithNoEffect) {
|
||||
return false;
|
||||
}
|
||||
ExpressionPtr exp = getEffectiveImpl(ar);
|
||||
Variant val;
|
||||
return (exp && exp->getScalarValue(val) && val.same(true));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FileScope::declareConstant(AnalysisResultPtr ar, const string &name) {
|
||||
@@ -238,7 +224,6 @@ void FileScope::addConstant(const string &name, TypePtr type,
|
||||
void FileScope::addIncludeDependency(AnalysisResultPtr ar,
|
||||
const string &file, bool byInlined) {
|
||||
ar->addIncludeDependency(shared_from_this(), file);
|
||||
if (byInlined) m_usedIncludesInline.insert(file);
|
||||
}
|
||||
void FileScope::addClassDependency(AnalysisResultPtr ar,
|
||||
const string &classname) {
|
||||
@@ -247,7 +232,6 @@ void FileScope::addClassDependency(AnalysisResultPtr ar,
|
||||
void FileScope::addFunctionDependency(AnalysisResultPtr ar,
|
||||
const string &funcname, bool byInlined) {
|
||||
ar->addFunctionDependency(shared_from_this(), funcname);
|
||||
if (byInlined) m_usedFuncsInline.insert(funcname);
|
||||
}
|
||||
void FileScope::addConstantDependency(AnalysisResultPtr ar,
|
||||
const string &decname) {
|
||||
@@ -507,455 +491,3 @@ void FileScope::serialize(JSON::DocTarget::OutputStream &out) const {
|
||||
ms.done();
|
||||
}
|
||||
|
||||
void FileScope::outputCPPHelper(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool classes /* = true */) {
|
||||
if (classes) {
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
cls->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
|
||||
it != m_functions.end(); ++it) {
|
||||
FunctionScopePtr func = it->second;
|
||||
if (func->isLocalRedeclaring()) {
|
||||
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
|
||||
func->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
} else {
|
||||
func->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
assert(cg.getContext() == CodeGenerator::CppImplementation);
|
||||
|
||||
cg.setContext(CodeGenerator::CppConstantsDecl);
|
||||
getConstants()->outputCPP(cg, ar);
|
||||
|
||||
cg.setContext(CodeGenerator::CppImplementation);
|
||||
cg_printf("/* preface starts */\n");
|
||||
|
||||
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
|
||||
it != m_functions.end(); ++it) {
|
||||
FunctionScopePtr func = it->second;
|
||||
if (func->isLocalRedeclaring()) {
|
||||
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
|
||||
func->outputCPPPreface(cg, ar);
|
||||
}
|
||||
} else {
|
||||
func->outputCPPPreface(cg, ar);
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(FunctionScopeRawPtr closure, m_usedClosures) {
|
||||
closure->outputCPPPreface(cg, ar);
|
||||
}
|
||||
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
const FunctionScopePtrVec &funcs = cls->getFunctionsVec();
|
||||
for (int i = 0, size = funcs.size(); i < size; ++i) {
|
||||
FunctionScopePtr func = funcs[i];
|
||||
func->outputCPPPreface(cg, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cg_printf("/* preface finishes */\n");
|
||||
|
||||
outputCPPHelper(cg, ar);
|
||||
|
||||
if (Option::GenerateCPPMacros) {
|
||||
bool hasRedec;
|
||||
outputCPPJumpTableSupport(cg, ar, m_redeclaredFunctions, hasRedec);
|
||||
if (Option::EnableEval >= Option::LimitedEval) {
|
||||
outputCPPJumpTableEvalSupport(cg, ar, m_redeclaredFunctions, hasRedec);
|
||||
}
|
||||
outputCPPCallInfoTableSupport(cg, ar, m_redeclaredFunctions, hasRedec);
|
||||
outputCPPHelperClassAllocSupport(cg, ar, m_redeclaredFunctions);
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
if (!cls->isInterface()) {
|
||||
cls->outputCPPDynamicClassImpl(cg, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::outputCPPPseudoMain(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
assert(cg.getContext() == CodeGenerator::CppPseudoMain);
|
||||
outputCPPHelper(cg, ar, false);
|
||||
}
|
||||
|
||||
void FileScope::outputCPPForwardDeclarations(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
cg.setContext(CodeGenerator::CppForwardDeclaration);
|
||||
|
||||
BOOST_FOREACH(ClassScopeRawPtr cls, m_usedClassesFullHeader) {
|
||||
if (cls->isUserClass()) {
|
||||
cg_printInclude(cls->getHeaderFilename());
|
||||
}
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
BOOST_FOREACH(const string &str, m_usedLiteralStringsHeader) {
|
||||
int index = -1;
|
||||
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
|
||||
always_assert(index != -1);
|
||||
string lisnam = ar->getLiteralStringName(stringId, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
if (Option::UseStaticStringProxy) {
|
||||
string proxyNam = ar->getLiteralStringName(stringId, index, true);
|
||||
cg_printf("extern StaticStringProxy %s;\n", proxyNam.c_str());
|
||||
cg_printf("#ifndef %s\n", lisnam.c_str());
|
||||
cg_printf("#define %s (*(StaticString *)(&%s))\n",
|
||||
lisnam.c_str(), proxyNam.c_str());
|
||||
cg_printf("#endif\n");
|
||||
} else {
|
||||
cg_printf("extern StaticString %s;\n", lisnam.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const int64 &val, m_usedScalarVarIntegersHeader) {
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarVarInteger(val, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarIntegerName(hash, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
cg_printf("extern const VarNR &%s;\n", name.c_str());
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const double &val, m_usedScalarVarDoublesHeader) {
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarVarDouble(val, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarDoubleName(hash, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
cg_printf("extern const VarNR &%s;\n", name.c_str());
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const string &str, m_usedLitVarStringsHeader) {
|
||||
int index = -1;
|
||||
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
|
||||
always_assert(index != -1);
|
||||
string lisnam = ar->getLitVarStringName(stringId, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
if (Option::UseStaticStringProxy) {
|
||||
string proxyName = ar->getLitVarStringName(stringId, index, true);
|
||||
cg_printf("extern VariantProxy %s;\n", proxyName.c_str());
|
||||
cg_printf("#ifndef %s\n", lisnam.c_str());
|
||||
cg_printf("#define %s (*(Variant *)&%s)\n",
|
||||
lisnam.c_str(), proxyName.c_str());
|
||||
cg_printf("#endif\n");
|
||||
} else {
|
||||
cg_printf("extern VarNR %s;\n", lisnam.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const string &str, m_usedDefaultValueScalarArrays) {
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarArray(str, index);
|
||||
always_assert(hash != -1 && index != -1);
|
||||
string name = ar->getScalarArrayName(hash, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
cg_printf("extern StaticArray %s;\n", name.c_str());
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const string &str, m_usedDefaultValueScalarVarArrays) {
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarArray(str, index);
|
||||
always_assert(hash != -1 && index != -1);
|
||||
string name = ar->getScalarVarArrayName(hash, index);
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
cg_printf("extern VarNR %s;\n", name.c_str());
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const string &str, m_usedConstsHeader) {
|
||||
BlockScopeConstPtr block = ar->findConstantDeclarer(str);
|
||||
always_assert(block);
|
||||
ConstantTableConstPtr constants = block->getConstants();
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
constants->outputSingleConstant(cg, ar, str);
|
||||
}
|
||||
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(const CodeGenerator::UsedClassConst& item,
|
||||
m_usedClassConstsHeader) {
|
||||
ClassScopePtr cls = item.first;
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
cls->getConstants()->outputSingleConstant(cg, ar, item.second);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(ClassScopeRawPtr usedClass, m_usedClassesHeader) {
|
||||
if (!cg.ensureInNamespace() && first) cg_printf("\n");
|
||||
first = false;
|
||||
usedClass->outputForwardDeclaration(cg);
|
||||
}
|
||||
|
||||
cg.ensureOutOfNamespace();
|
||||
}
|
||||
|
||||
void FileScope::outputCPPDeclarations(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
cg.printSection("Declarations");
|
||||
cg.setContext(CodeGenerator::CppDeclaration);
|
||||
|
||||
if (cg.getOutput() == CodeGenerator::MonoCPP) {
|
||||
cg.namespaceBegin();
|
||||
outputCPPHelper(cg, ar);
|
||||
cg.namespaceEnd();
|
||||
} else {
|
||||
std::set<FileScopePtr> done;
|
||||
done.insert(shared_from_this());
|
||||
|
||||
// Class declarations cunningly expressed as includes so I don't
|
||||
// have to worry about inheritance dependencies.
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
cg_printInclude(cls->getHeaderFilename());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(string name, m_usedFuncsInline) {
|
||||
FunctionScopePtr func = ar->findFunction(name);
|
||||
if (func) {
|
||||
FileScopePtr fs = func->getContainingFile();
|
||||
if (fs && done.find(fs) == done.end()) {
|
||||
done.insert(fs);
|
||||
cg_printInclude(fs->outputFilebase());
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(string name, m_usedIncludesInline) {
|
||||
FileScopePtr fs = ar->findFileScope(name);
|
||||
if (fs && done.find(fs) == done.end()) {
|
||||
done.insert(fs);
|
||||
cg_printInclude(fs->outputFilebase());
|
||||
}
|
||||
}
|
||||
|
||||
cg.namespaceBegin();
|
||||
cg.setContext(CodeGenerator::CppForwardDeclaration);
|
||||
cg.printSection("Includes and Functions", false);
|
||||
outputCPPHelper(cg, ar, false); // function forward declarations
|
||||
cg.setContext(CodeGenerator::CppDeclaration);
|
||||
outputCPPHelper(cg, ar, false); // function declarations (only inline)
|
||||
|
||||
cg.printSection("Constants");
|
||||
if (cg.getOutput() != CodeGenerator::MonoCPP) {
|
||||
getConstants()->outputCPP(cg, ar, false);
|
||||
} else {
|
||||
cg_printf("// (omitted in MonoCPP mode)\n");
|
||||
}
|
||||
|
||||
cg.namespaceEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::outputCPPForwardStaticDecl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
string header = outputFilebase() + ".fws.h";
|
||||
cg.headerBegin(header);
|
||||
cg.namespaceBegin();
|
||||
cg.printSection("1. Static Strings", false);
|
||||
string str;
|
||||
BOOST_FOREACH(str, m_usedLiteralStrings) {
|
||||
if (m_usedLiteralStringsHeader.find(str) !=
|
||||
m_usedLiteralStringsHeader.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
|
||||
always_assert(index != -1);
|
||||
string lisnam = ar->getLiteralStringName(stringId, index);
|
||||
if (Option::UseStaticStringProxy) {
|
||||
string proxyNam = ar->getLiteralStringName(stringId, index, true);
|
||||
cg_printf("extern StaticStringProxy %s;\n", proxyNam.c_str());
|
||||
cg_printf("#ifndef %s\n", lisnam.c_str());
|
||||
cg_printf("#define %s (*(StaticString *)(&%s))\n",
|
||||
lisnam.c_str(), proxyNam.c_str());
|
||||
cg_printf("#endif\n");
|
||||
} else {
|
||||
cg_printf("extern StaticString %s;\n", lisnam.c_str());
|
||||
}
|
||||
}
|
||||
cg_printf("\n");
|
||||
cg.printSection("2. Static Arrays", false);
|
||||
BOOST_FOREACH(str, m_usedScalarArrays) {
|
||||
if (m_usedDefaultValueScalarArrays.find(str) !=
|
||||
m_usedDefaultValueScalarArrays.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarArray(str, index);
|
||||
always_assert(hash != -1 && index != -1);
|
||||
string name = ar->getScalarArrayName(hash, index);
|
||||
cg_printf("extern StaticArray %s;\n", name.c_str());
|
||||
}
|
||||
if (Option::UseScalarVariant) {
|
||||
cg_printf("\n");
|
||||
cg.printSection("3. Static Variants", false);
|
||||
int64 val;
|
||||
BOOST_FOREACH(val, m_usedScalarVarIntegers) {
|
||||
if (m_usedScalarVarIntegersHeader.find(val) !=
|
||||
m_usedScalarVarIntegersHeader.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarVarInteger(val, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarIntegerName(hash, index);
|
||||
cg_printf("extern const VarNR &%s;\n", name.c_str());
|
||||
}
|
||||
cg_printf("\n");
|
||||
double dval;
|
||||
BOOST_FOREACH(dval, m_usedScalarVarDoubles) {
|
||||
if (m_usedScalarVarDoublesHeader.find(dval) !=
|
||||
m_usedScalarVarDoublesHeader.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarVarDouble(dval, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarDoubleName(hash, index);
|
||||
cg_printf("extern const VarNR &%s;\n", name.c_str());
|
||||
}
|
||||
cg_printf("\n");
|
||||
BOOST_FOREACH(str, m_usedLitVarStrings) {
|
||||
if (m_usedLitVarStringsHeader.find(str) !=
|
||||
m_usedLitVarStringsHeader.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
|
||||
always_assert(index != -1);
|
||||
string lisnam = ar->getLitVarStringName(stringId, index);
|
||||
if (Option::UseStaticStringProxy) {
|
||||
string proxyName = ar->getLitVarStringName(stringId, index, true);
|
||||
cg_printf("extern VariantProxy %s;\n", proxyName.c_str());
|
||||
cg_printf("#ifndef %s\n", lisnam.c_str());
|
||||
cg_printf("#define %s (*(Variant *)&%s)\n",
|
||||
lisnam.c_str(), proxyName.c_str());
|
||||
cg_printf("#endif\n");
|
||||
} else {
|
||||
cg_printf("extern VarNR %s;\n", lisnam.c_str());
|
||||
}
|
||||
}
|
||||
cg_printf("\n");
|
||||
BOOST_FOREACH(str, m_usedScalarVarArrays) {
|
||||
if (m_usedDefaultValueScalarVarArrays.find(str) !=
|
||||
m_usedDefaultValueScalarVarArrays.end()) {
|
||||
continue;
|
||||
}
|
||||
int index = -1;
|
||||
int hash = ar->checkScalarArray(str, index);
|
||||
always_assert(hash != -1 && index != -1);
|
||||
string name = ar->getScalarVarArrayName(hash, index);
|
||||
cg_printf("extern VarNR %s;\n", name.c_str());
|
||||
}
|
||||
cg_printf("\n");
|
||||
}
|
||||
cg.namespaceEnd();
|
||||
cg_printf("\n");
|
||||
cg.headerEnd(header);
|
||||
}
|
||||
|
||||
void FileScope::outputCPPDeclHeader(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg.setFileOrClassHeader(true);
|
||||
string header = outputFilebase() + ".h";
|
||||
cg.headerBegin(header);
|
||||
if (Option::GenerateCppLibCode ||
|
||||
cg.getOutput() == CodeGenerator::SystemCPP) {
|
||||
cg.printBasicIncludes();
|
||||
}
|
||||
outputCPPForwardDeclarations(cg, ar);
|
||||
outputCPPDeclarations(cg, ar);
|
||||
cg.headerEnd(header);
|
||||
}
|
||||
|
||||
void FileScope::outputCPPClassHeaders(AnalysisResultPtr ar,
|
||||
CodeGenerator::Output output) {
|
||||
ClassScopePtr cls;
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
cls->outputCPPHeader(ar, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::outputCPPFFI(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
cg.setContext(CodeGenerator::CppFFIDecl);
|
||||
cg.useStream(CodeGenerator::PrimaryStream);
|
||||
outputCPPHelper(cg, ar, true);
|
||||
cg.useStream(CodeGenerator::ImplFile);
|
||||
cg.setContext(CodeGenerator::CppFFIImpl);
|
||||
cg_printInclude(outputFilebase() + ".h");
|
||||
outputCPPHelper(cg, ar, true);
|
||||
}
|
||||
|
||||
void FileScope::outputHSFFI(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
cg.setContext(CodeGenerator::HsFFI);
|
||||
outputCPPHelper(cg, ar, false);
|
||||
}
|
||||
|
||||
void FileScope::outputJavaFFI(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
// first, generate methods in HphpMain.java
|
||||
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
|
||||
it != m_functions.end(); ++it) {
|
||||
FunctionScopePtr func = it->second;
|
||||
if (func->isLocalRedeclaring()) {
|
||||
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
|
||||
func->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
} else {
|
||||
func->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
|
||||
// for each php class or interface, generate a Java file
|
||||
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
cls->getStmt()->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::outputJavaFFICPPStub(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (cg.getContext() == CodeGenerator::JavaFFICppImpl) {
|
||||
// java_stubs.h doesn't need the extra include
|
||||
cg_printInclude(outputFilebase() + ".h");
|
||||
}
|
||||
outputCPPHelper(cg, ar, true);
|
||||
}
|
||||
|
||||
void FileScope::outputSwigFFIStubs(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
// currently only support toplevel functions
|
||||
outputCPPHelper(cg, ar, false);
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ public:
|
||||
ContainsDynamicVariable = 0x001,
|
||||
ContainsLDynamicVariable = 0x002,
|
||||
VariableArgument = 0x004,
|
||||
ContainsExtract = 0x008, // need special VariableTable
|
||||
ContainsCompact = 0x010, // need RVariableTable + exists()
|
||||
ContainsExtract = 0x008, // contains call to extract()
|
||||
ContainsCompact = 0x010, // contains call to compact()
|
||||
ContainsReference = 0x020, // returns ref or has ref parameters
|
||||
ReferenceVariableArgument = 0x040, // like sscanf or fscanf
|
||||
ContainsUnset = 0x080, // need special handling
|
||||
@@ -100,8 +100,6 @@ public:
|
||||
*/
|
||||
ExpressionPtr getEffectiveImpl(AnalysisResultConstPtr ar) const;
|
||||
|
||||
bool canUseDummyPseudoMain(AnalysisResultConstPtr ar) const;
|
||||
|
||||
/**
|
||||
* Parser functions. Parser only deals with a FileScope object, and these
|
||||
* are the only functions a parser calls upon analysis results.
|
||||
@@ -115,73 +113,6 @@ public:
|
||||
const StringToFunctionScopePtrVecMap *getRedecFunctions() {
|
||||
return m_redeclaredFunctions;
|
||||
}
|
||||
void addUsedClosure(FunctionScopeRawPtr closure) {
|
||||
m_usedClosures.insert(closure);
|
||||
}
|
||||
void addUsedLiteralString(std::string s) {
|
||||
m_usedLiteralStrings.insert(s);
|
||||
}
|
||||
void addUsedLitVarString(std::string s) {
|
||||
m_usedLitVarStrings.insert(s);
|
||||
}
|
||||
std::set<std::string> &getUsedLiteralStrings() {
|
||||
return m_usedLiteralStrings;
|
||||
}
|
||||
std::set<std::string> &getUsedLitVarStrings() {
|
||||
return m_usedLitVarStrings;
|
||||
}
|
||||
void addUsedLiteralStringHeader(std::string s) {
|
||||
m_usedLiteralStringsHeader.insert(s);
|
||||
}
|
||||
void addUsedLitVarStringHeader(std::string s) {
|
||||
m_usedLitVarStringsHeader.insert(s);
|
||||
}
|
||||
void addUsedScalarVarInteger(int64 i) {
|
||||
m_usedScalarVarIntegers.insert(i);
|
||||
}
|
||||
std::set<int64> &getUsedScalarVarIntegers() {
|
||||
return m_usedScalarVarIntegers;
|
||||
}
|
||||
void addUsedScalarVarIntegerHeader(int64 i) {
|
||||
m_usedScalarVarIntegersHeader.insert(i);
|
||||
}
|
||||
void addUsedScalarVarDouble(double d) {
|
||||
m_usedScalarVarDoubles.insert(d);
|
||||
}
|
||||
std::set<double> &getUsedScalarVarDoubles() {
|
||||
return m_usedScalarVarDoubles;
|
||||
}
|
||||
void addUsedScalarVarDoubleHeader(double d) {
|
||||
m_usedScalarVarDoublesHeader.insert(d);
|
||||
}
|
||||
void addUsedScalarArray(std::string s) {
|
||||
m_usedScalarArrays.insert(s);
|
||||
}
|
||||
void addUsedScalarVarArray(std::string s) {
|
||||
m_usedScalarVarArrays.insert(s);
|
||||
}
|
||||
void addUsedDefaultValueScalarArray(std::string s) {
|
||||
m_usedDefaultValueScalarArrays.insert(s);
|
||||
}
|
||||
void addUsedDefaultValueScalarVarArray(std::string s) {
|
||||
m_usedDefaultValueScalarVarArrays.insert(s);
|
||||
}
|
||||
|
||||
void addUsedConstHeader(const std::string &s) {
|
||||
m_usedConstsHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedClassConstHeader(ClassScopeRawPtr cls, const std::string &s) {
|
||||
m_usedClassConstsHeader.insert(CodeGenerator::UsedClassConst(cls, s));
|
||||
}
|
||||
|
||||
void addUsedClassHeader(ClassScopeRawPtr s) {
|
||||
m_usedClassesHeader.insert(s);
|
||||
}
|
||||
|
||||
void addUsedClassFullHeader(ClassScopeRawPtr s) {
|
||||
m_usedClassesFullHeader.insert(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* For separate compilation
|
||||
@@ -244,22 +175,6 @@ public:
|
||||
FunctionScopeRawPtr getPseudoMain() const {
|
||||
return m_pseudoMain;
|
||||
}
|
||||
void outputCPPForwardStaticDecl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPDeclHeader(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPForwardDeclarations(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPDeclarations(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPClassHeaders(AnalysisResultPtr ar,
|
||||
CodeGenerator::Output output);
|
||||
void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPPseudoMain(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputCPPFFI(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputHSFFI(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputJavaFFI(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputJavaFFICPPStub(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputSwigFFIStubs(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
FileScopePtr shared_from_this() {
|
||||
return boost::static_pointer_cast<FileScope>
|
||||
@@ -282,25 +197,6 @@ private:
|
||||
|
||||
vertex_descriptor m_vertex;
|
||||
|
||||
std::set<FunctionScopeRawPtr> m_usedClosures;
|
||||
std::set<std::string> m_usedFuncsInline;
|
||||
CodeGenerator::ClassScopeSet m_usedClassesHeader;
|
||||
CodeGenerator::ClassScopeSet m_usedClassesFullHeader;
|
||||
std::set<std::string> m_usedConstsHeader;
|
||||
CodeGenerator::UsedClassConstSet m_usedClassConstsHeader;
|
||||
std::set<std::string> m_usedIncludesInline;
|
||||
std::set<std::string> m_usedLiteralStrings;
|
||||
std::set<std::string> m_usedLitVarStrings;
|
||||
std::set<std::string> m_usedLiteralStringsHeader;
|
||||
std::set<std::string> m_usedLitVarStringsHeader;
|
||||
std::set<int64> m_usedScalarVarIntegers;
|
||||
std::set<int64> m_usedScalarVarIntegersHeader;
|
||||
std::set<double> m_usedScalarVarDoubles;
|
||||
std::set<double> m_usedScalarVarDoublesHeader;
|
||||
std::set<std::string> m_usedScalarArrays;
|
||||
std::set<std::string> m_usedScalarVarArrays;
|
||||
std::set<std::string> m_usedDefaultValueScalarArrays;
|
||||
std::set<std::string> m_usedDefaultValueScalarVarArrays;
|
||||
std::string m_pseudoMainName;
|
||||
std::set<std::string> m_pseudoMainVariables;
|
||||
BlockScopeSet m_providedDefs;
|
||||
@@ -308,8 +204,6 @@ private:
|
||||
|
||||
FunctionScopePtr createPseudoMain(AnalysisResultConstPtr ar);
|
||||
void setFileLevel(StatementListPtr stmt);
|
||||
void outputCPPHelper(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool classes = true);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -78,405 +78,3 @@ void FunctionContainer::getFunctionsFlattened(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionIterator {
|
||||
public:
|
||||
FunctionIterator(const StringToFunctionScopePtrVecMap &mmap,
|
||||
bool &hasRedec) : m_mmap(&mmap), m_smap(0),
|
||||
m_miter(mmap.begin()),
|
||||
m_hasRedec(hasRedec) {
|
||||
setup();
|
||||
}
|
||||
FunctionIterator(const StringToFunctionScopePtrMap &smap,
|
||||
const StringToFunctionScopePtrVecMap *mmap,
|
||||
bool &hasRedec) : m_mmap(mmap), m_smap(&smap),
|
||||
m_siter(smap.begin()),
|
||||
m_hasRedec(hasRedec) {
|
||||
setup();
|
||||
}
|
||||
|
||||
bool ready() const {
|
||||
if (m_smap) {
|
||||
return m_siter != m_smap->end();
|
||||
} else {
|
||||
return m_miter != m_mmap->end();
|
||||
}
|
||||
}
|
||||
|
||||
bool firstInner() const {
|
||||
if (m_smap && !m_siter->second->isLocalRedeclaring()) {
|
||||
return true;
|
||||
}
|
||||
return m_innerIter == m_miter->second.begin();
|
||||
}
|
||||
|
||||
void next() {
|
||||
if (m_smap && !m_siter->second->isLocalRedeclaring()) {
|
||||
++m_siter;
|
||||
setup();
|
||||
return;
|
||||
}
|
||||
|
||||
++m_innerIter;
|
||||
if (m_innerIter == m_miter->second.end()) {
|
||||
if (m_smap) {
|
||||
++m_siter;
|
||||
} else {
|
||||
++m_miter;
|
||||
}
|
||||
setup();
|
||||
}
|
||||
}
|
||||
const string &name() const {
|
||||
return m_smap ? m_siter->first : m_miter->first;
|
||||
}
|
||||
FunctionScopePtr get() const {
|
||||
return m_smap && !m_siter->second->isLocalRedeclaring() ?
|
||||
m_siter->second : *m_innerIter;
|
||||
}
|
||||
|
||||
private:
|
||||
const StringToFunctionScopePtrVecMap *m_mmap;
|
||||
const StringToFunctionScopePtrMap *m_smap;
|
||||
StringToFunctionScopePtrVecMap::const_iterator m_miter;
|
||||
FunctionScopePtrVec::const_iterator m_innerIter;
|
||||
StringToFunctionScopePtrMap::const_iterator m_siter;
|
||||
bool &m_hasRedec;
|
||||
void setup() {
|
||||
if (ready()) {
|
||||
if (m_smap) {
|
||||
if (!m_siter->second->isRedeclaring()) {
|
||||
return;
|
||||
}
|
||||
m_hasRedec = true;
|
||||
if (!m_siter->second->isLocalRedeclaring()) {
|
||||
return;
|
||||
}
|
||||
m_miter = m_mmap->find(m_siter->first);
|
||||
} else {
|
||||
if (m_miter->second.size() != 1) {
|
||||
m_hasRedec = true;
|
||||
}
|
||||
}
|
||||
m_innerIter = m_miter->second.begin();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void FunctionContainer::outputCPPJumpTableSupportMethod
|
||||
(CodeGenerator &cg, AnalysisResultPtr ar, FunctionScopePtr func,
|
||||
const char *funcPrefix) {
|
||||
string name = func->getId();
|
||||
const char *cname = name.c_str();
|
||||
|
||||
string origName = !func->inPseudoMain() ? func->getOriginalName() :
|
||||
("run_init::" + func->getContainingFile()->getName());
|
||||
cg_printf("Variant");
|
||||
if (Option::FunctionSections.find(origName) !=
|
||||
Option::FunctionSections.end()) {
|
||||
string funcSection = Option::FunctionSections[origName];
|
||||
if (!funcSection.empty()) {
|
||||
cg_printf(" __attribute__ ((section (\".text.%s\")))",
|
||||
funcSection.c_str());
|
||||
}
|
||||
}
|
||||
cg_indentBegin(" %s%s(void *extra, int count, "
|
||||
"INVOKE_FEW_ARGS_IMPL_ARGS) {\n",
|
||||
Option::InvokeFewArgsPrefix, cname);
|
||||
func->outputCPPDynamicInvoke(cg, ar, funcPrefix, cname, false, true);
|
||||
cg_indentEnd("}\n");
|
||||
|
||||
cg_indentBegin("Variant %s%s(void *extra, CArrRef params) {\n",
|
||||
Option::InvokePrefix, cname);
|
||||
if (func->getMaxParamCount() <= Option::InvokeFewArgsCount &&
|
||||
!func->isVariableArgument()) {
|
||||
if (Option::InvokeWithSpecificArgs && !func->getMaxParamCount() &&
|
||||
!ar->isSystem() && !ar->isSepExtension()) {
|
||||
// For functions with no parameter, we can combine the i_ wrapper and
|
||||
// the ifa_ wrapper.
|
||||
cg_printf("return ((CallInfo::FuncInvoker0Args)&%s%s)(extra, 0);\n",
|
||||
Option::InvokeFewArgsPrefix, cname);
|
||||
} else {
|
||||
cg_printf("return invoke_func_few_handler(extra, params, &%s%s);\n",
|
||||
Option::InvokeFewArgsPrefix, cname);
|
||||
}
|
||||
} else {
|
||||
FunctionScope::OutputCPPDynamicInvokeCount(cg);
|
||||
func->outputCPPDynamicInvoke(cg, ar, funcPrefix, cname);
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
|
||||
void
|
||||
FunctionContainer::outputCPPHelperClassAllocSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec) {
|
||||
bool hasRedeclared;
|
||||
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
|
||||
fit.next()) {
|
||||
FunctionScopePtr func = fit.get();
|
||||
func->outputCPPHelperClassAlloc(cg, ar);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionContainer::outputCPPJumpTableSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared,
|
||||
vector<const char *> *funcs /* = NULL */) {
|
||||
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
const char *funcPrefix = Option::FunctionPrefix;
|
||||
if (systemcpp) funcPrefix = Option::BuiltinFunctionPrefix;
|
||||
// output invoke support methods
|
||||
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
|
||||
fit.next()) {
|
||||
FunctionScopePtr func = fit.get();
|
||||
if (func->inPseudoMain() || !(systemcpp || func->isDynamic())) continue;
|
||||
if (funcs && fit.firstInner()) {
|
||||
funcs->push_back(fit.name().c_str());
|
||||
}
|
||||
|
||||
outputCPPJumpTableSupportMethod(cg, ar, func, funcPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionContainer::outputCPPCallInfoTableSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared,
|
||||
vector<const char *> *funcs /* = NULL */) {
|
||||
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
|
||||
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
|
||||
fit.next()) {
|
||||
FunctionScopePtr func = fit.get();
|
||||
|
||||
if (func->inPseudoMain() || !(systemcpp || func->isDynamic())) continue;
|
||||
if (funcs && fit.firstInner()) {
|
||||
funcs->push_back(fit.name().c_str());
|
||||
}
|
||||
func->outputCPPCallInfo(cg, ar);
|
||||
}
|
||||
}
|
||||
void FunctionContainer::outputCPPJumpTableEvalSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec,
|
||||
bool &hasRedeclared) {
|
||||
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
// output invoke support methods
|
||||
|
||||
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
|
||||
fit.next()) {
|
||||
FunctionScopePtr func = fit.get();
|
||||
if (func->inPseudoMain() ||
|
||||
(!systemcpp && (!func->isUserFunction() ||
|
||||
!(func->isSepExtension() || func->isDynamic())))) {
|
||||
continue;
|
||||
}
|
||||
string sname = func->getId();
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionContainer::outputGetCallInfoHeader(CodeGenerator &cg,
|
||||
const char *suffix,
|
||||
bool needGlobals) {
|
||||
cg_indentBegin("bool get_call_info%s(const CallInfo *&ci, void *&extra, "
|
||||
"const char *s, strhash_t hash) {\n", suffix ? suffix : "");
|
||||
|
||||
if (needGlobals) cg.printDeclareGlobals();
|
||||
cg_printf("extra = NULL;\n");
|
||||
|
||||
if (!suffix && (!Option::DynamicInvokeFunctions.empty() ||
|
||||
Option::EnableEval == Option::FullEval)) {
|
||||
cg_printf("const char *ss = get_renamed_function(s);\n");
|
||||
cg_printf("if (ss != s) { s = ss; hash = -1;};\n");
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionContainer::outputGetCallInfoTail(CodeGenerator &cg,
|
||||
bool system) {
|
||||
if (system) {
|
||||
cg_printf("return false;\n");
|
||||
} else {
|
||||
cg_printf("return get_call_info_builtin(ci, extra, s, hash);\n");
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
|
||||
void FunctionContainer::outputCPPHashTableGetCallInfo(
|
||||
CodeGenerator &cg, bool system, bool noEval,
|
||||
const StringToFunctionScopePtrMap *functions,
|
||||
const vector<const char *> &funcs) {
|
||||
assert(cg.getCurrentIndentation() == 0);
|
||||
const char text1[] =
|
||||
"\n"
|
||||
"struct hashNodeFunc {\n"
|
||||
" strhash_t hash;\n"
|
||||
" bool offset;\n"
|
||||
" bool end;\n"
|
||||
" const char *name;\n"
|
||||
" const void *data;\n"
|
||||
"};\n"
|
||||
"static const hashNodeFunc funcBuckets[] = {\n";
|
||||
|
||||
const char text3[] =
|
||||
"static inline const hashNodeFunc *"
|
||||
"findFunc(const char *name, strhash_t hash) {\n"
|
||||
" const hashNodeFunc *p = funcMapTable[hash & %d];\n"
|
||||
" if (UNLIKELY(!p)) return NULL;\n"
|
||||
" do {\n"
|
||||
" if (LIKELY(p->hash == hash) && (LIKELY(p->name==name)||"
|
||||
"LIKELY(!strcasecmp(p->name, name)))) return p;\n"
|
||||
" } while (!p++->end);\n"
|
||||
" return NULL;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
const char text4[] =
|
||||
" if (hash < 0) hash = hash_string(s);\n"
|
||||
" const hashNodeFunc *p = findFunc(s, hash);\n"
|
||||
" if (LIKELY(p!=0)) {\n"
|
||||
" if (UNLIKELY(p->offset)) {\n"
|
||||
" DECLARE_GLOBAL_VARIABLES(g);\n"
|
||||
" const char *addr = (const char *)g + (int64)p->data;\n"
|
||||
" ci = *(const CallInfo **)addr;\n"
|
||||
" return ci != 0;\n"
|
||||
" } else {\n"
|
||||
" ci = (const CallInfo *)p->data;\n"
|
||||
" return true;\n"
|
||||
" }\n"
|
||||
" }\n";
|
||||
|
||||
const char text4s[] =
|
||||
" if (hash < 0) hash = hash_string(s);\n"
|
||||
" const hashNodeFunc *p = findFunc(s, hash);\n"
|
||||
" if (LIKELY(p!=0)) {\n"
|
||||
" ci = (const CallInfo *)p->data;\n"
|
||||
" return true;\n"
|
||||
" }\n";
|
||||
|
||||
int numEntries = funcs.size();
|
||||
if (!noEval && numEntries > 0) {
|
||||
JumpTable jt(cg, funcs, true, true, true, true);
|
||||
cg_print(text1);
|
||||
|
||||
vector<int> offsets;
|
||||
int prev = -1;
|
||||
for (int n = 0; jt.ready(); ++n, jt.next()) {
|
||||
int cur = jt.current();
|
||||
if (prev != cur) {
|
||||
while (++prev != cur) {
|
||||
offsets.push_back(-1);
|
||||
}
|
||||
offsets.push_back(n);
|
||||
}
|
||||
const char *name = jt.key();
|
||||
|
||||
StringToFunctionScopePtrMap::const_iterator iterFuncs =
|
||||
functions->find(name);
|
||||
assert(iterFuncs != functions->end());
|
||||
// We have assumptions that function names do not contain ".."
|
||||
// (e.g., call_user_func0 ~ call_user_func6)
|
||||
always_assert(!strstr(name, ".."));
|
||||
FunctionScopePtr func = iterFuncs->second;
|
||||
cg_printf(" {" STRHASH_FMT ",%d,%d,\"%s\",",
|
||||
hash_string_i(name),
|
||||
(int)func->isRedeclaring(), (int)jt.last(),
|
||||
CodeGenerator::EscapeLabel(name).c_str());
|
||||
|
||||
if (func->isRedeclaring()) {
|
||||
always_assert(!system);
|
||||
string lname(CodeGenerator::FormatLabel(name));
|
||||
cg_printf("(const void *)(offsetof(GlobalVariables, GCI(%s)))",
|
||||
lname.c_str());
|
||||
} else {
|
||||
cg_printf("&%s%s",
|
||||
Option::CallInfoPrefix, func->getId().c_str());
|
||||
}
|
||||
cg_printf("},\n");
|
||||
}
|
||||
cg_printf("};\n");
|
||||
cg_indentBegin("static const hashNodeFunc *funcMapTable[] = {\n");
|
||||
for (int i = 0, e = jt.size(), s = offsets.size(); i < e; i++) {
|
||||
int o = i < s ? offsets[i] : -1;
|
||||
if (o < 0) {
|
||||
cg_printf("0,");
|
||||
} else {
|
||||
cg_printf("funcBuckets+%d,", o);
|
||||
}
|
||||
if ((i & 7) == 7) cg_printf("\n");
|
||||
}
|
||||
cg_printf("\n");
|
||||
cg_indentEnd("};\n");
|
||||
cg_printf(text3, jt.size() - 1);
|
||||
}
|
||||
outputGetCallInfoHeader(cg, system ? "_builtin" : noEval ? "_no_eval" : 0,
|
||||
false);
|
||||
cg_indentEnd();
|
||||
if (numEntries > 0) {
|
||||
cg_print(system ? text4s : text4);
|
||||
}
|
||||
cg_indentBegin(" ");
|
||||
outputGetCallInfoTail(cg, system);
|
||||
}
|
||||
|
||||
void FunctionContainer::outputCPPCodeInfoTable(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar, bool useSwitch,
|
||||
const StringToFunctionScopePtrMap &functions) {
|
||||
bool needGlobals = false;
|
||||
vector<const char *> funcs;
|
||||
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
if (system) {
|
||||
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, nullptr);
|
||||
}
|
||||
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin(),
|
||||
end = functions.end(); iter != end; ++iter) {
|
||||
FunctionScopePtr func = iter->second;
|
||||
if (!func->inPseudoMain() &&
|
||||
(system || func->isDynamic() || func->isSepExtension())) {
|
||||
funcs.push_back(iter->first.c_str());
|
||||
if (!system && !func->isRedeclaring() && !func->isSepExtension()) {
|
||||
cg_printf("extern const CallInfo %s%s;\n",
|
||||
Option::CallInfoPrefix, func->getId().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!useSwitch) {
|
||||
outputCPPHashTableGetCallInfo(cg, system, false, &functions, funcs);
|
||||
if (!system) {
|
||||
outputCPPHashTableGetCallInfo(cg, system, true, &functions, funcs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!system) cg_printf("static ");
|
||||
outputGetCallInfoHeader(cg, system ? "_builtin" : "_impl", needGlobals);
|
||||
|
||||
for (JumpTable fit(cg, funcs, true, true, false); fit.ready(); fit.next()) {
|
||||
const char *name = fit.key();
|
||||
StringToFunctionScopePtrMap::const_iterator iterFuncs =
|
||||
functions.find(name);
|
||||
assert(iterFuncs != functions.end());
|
||||
cg_indentBegin("HASH_GUARD(" STRHASH_FMT ", %s) {\n",
|
||||
hash_string_i(name),
|
||||
CodeGenerator::EscapeLabel(name).c_str());
|
||||
if (iterFuncs->second->isRedeclaring()) {
|
||||
string lname(CodeGenerator::FormatLabel(name));
|
||||
cg_printf("ci = &g->GCI(%s)->ci;\n", lname.c_str());
|
||||
} else {
|
||||
cg_printf("ci = &%s%s;\n", Option::CallInfoPrefix,
|
||||
iterFuncs->second->getId().c_str());
|
||||
}
|
||||
cg_printf("return true;\n");
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
outputGetCallInfoTail(cg, system);
|
||||
|
||||
if (system) return;
|
||||
|
||||
outputGetCallInfoHeader(cg, 0, false);
|
||||
cg_printf("return get_call_info_impl(ci, extra, s, hash);\n");
|
||||
cg_indentEnd("}\n");
|
||||
|
||||
outputGetCallInfoHeader(cg, "_no_eval", false);
|
||||
cg_printf("return get_call_info_impl(ci, extra, s, hash);\n");
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define __FUNCTION_CONTAINER_H__
|
||||
|
||||
#include <compiler/hphp.h>
|
||||
#include <compiler/util/jump_table.h>
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -43,49 +42,16 @@ public:
|
||||
void countReturnTypes(std::map<std::string, int> &counts,
|
||||
const StringToFunctionScopePtrVecMap *redec);
|
||||
|
||||
/**
|
||||
* Code generation functions.
|
||||
*/
|
||||
void outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec);
|
||||
const StringToFunctionScopePtrMap &getFunctions() const {
|
||||
return m_functions;
|
||||
}
|
||||
void getFunctionsFlattened(const StringToFunctionScopePtrVecMap *redec,
|
||||
FunctionScopePtrVec &funcs,
|
||||
bool excludePseudoMains = false) const;
|
||||
void outputCPPCodeInfoTable(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar, bool useSwitch,
|
||||
const StringToFunctionScopePtrMap &functions);
|
||||
|
||||
protected:
|
||||
// name => functions. Order of declaration
|
||||
StringToFunctionScopePtrMap m_functions;
|
||||
void outputCPPJumpTableSupport(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec,
|
||||
bool &hasRedeclared,
|
||||
std::vector<const char *> *funcs = nullptr);
|
||||
void outputCPPJumpTableEvalSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared);
|
||||
void outputCPPCallInfoTableSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec,
|
||||
bool &hasRedeclared, std::vector<const char *> *funcs = nullptr);
|
||||
void outputCPPJumpTableSupportMethod(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
FunctionScopePtr func,
|
||||
const char *funcPrefix);
|
||||
void outputCPPHelperClassAllocSupport(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const StringToFunctionScopePtrVecMap *redec);
|
||||
private:
|
||||
void outputGetCallInfoHeader(CodeGenerator &cg, const char *suffix,
|
||||
bool needGlobals);
|
||||
void outputGetCallInfoTail(CodeGenerator &cg, bool system);
|
||||
void outputCPPHashTableGetCallInfo(
|
||||
CodeGenerator &cg, bool system, bool noEval,
|
||||
const StringToFunctionScopePtrMap *functions,
|
||||
const std::vector<const char *> &funcs);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -176,6 +176,13 @@ public:
|
||||
m_volatile = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell this function about another outer scope that contains it.
|
||||
*/
|
||||
void addClonedTraitOuterScope(FunctionScopePtr scope) {
|
||||
m_clonedTraitOuterScope.push_back(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/set original name of the function, without case being lowered.
|
||||
*/
|
||||
@@ -237,16 +244,10 @@ public:
|
||||
* Whether this function contains a usage of $this
|
||||
*/
|
||||
bool containsThis() const { return m_containsThis;}
|
||||
void setContainsThis(bool f=true) { m_containsThis = f;}
|
||||
void setContainsThis(bool f = true);
|
||||
bool containsBareThis() const { return m_containsBareThis; }
|
||||
bool containsRefThis() const { return m_containsBareThis & 2; }
|
||||
void setContainsBareThis(bool f, bool ref = false) {
|
||||
if (f) {
|
||||
m_containsBareThis |= ref ? 2 : 1;
|
||||
} else {
|
||||
m_containsBareThis = 0;
|
||||
}
|
||||
}
|
||||
void setContainsBareThis(bool f, bool ref = false);
|
||||
/**
|
||||
* How many parameters a caller should provide.
|
||||
*/
|
||||
@@ -270,7 +271,6 @@ public:
|
||||
void fixRetExprs();
|
||||
|
||||
bool needsTypeCheckWrapper() const;
|
||||
const char *getPrefix(AnalysisResultPtr ar, ExpressionListPtr params);
|
||||
|
||||
void setOptFunction(FunctionOptPtr fn) { m_optFunction = fn; }
|
||||
FunctionOptPtr getOptFunction() const { return m_optFunction; }
|
||||
@@ -352,92 +352,6 @@ public:
|
||||
* Override BlockScope::outputPHP() to generate return type.
|
||||
*/
|
||||
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Override to preface with call temps.
|
||||
*/
|
||||
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
/**
|
||||
* Generate parameter declaration.
|
||||
*/
|
||||
void outputCPPParamsDecl(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
ExpressionListPtr params, bool showDefault);
|
||||
/**
|
||||
* This one is a special version that doesn't require a params expression.
|
||||
* It's for use with extension functions. It only works for the
|
||||
* implementation since it ignores optional arguments.
|
||||
*/
|
||||
void outputCPPParamsImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
/**
|
||||
* If inside this function, we have to make a call to an implementation
|
||||
* function that has the same signature, how does the parameter list
|
||||
* look like?
|
||||
*/
|
||||
void outputCPPParamsCall(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool aggregateParams);
|
||||
|
||||
/**
|
||||
* How does a caller prepare parameters.
|
||||
*/
|
||||
static void OutputCPPArguments(ExpressionListPtr params,
|
||||
FunctionScopePtr func,
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int extraArg, bool variableArgument,
|
||||
int extraArgArrayId = -1,
|
||||
int extraArgArrayHash = -1,
|
||||
int extraArgArrayIndex = -1,
|
||||
bool ignoreFuncParamTypes = false);
|
||||
|
||||
/**
|
||||
* Only generate arguments that have effects. This is for keeping those
|
||||
* parameters around when generating a error-raising function call, so to
|
||||
* avoid "unused" variable compiler warnings.
|
||||
*/
|
||||
static void OutputCPPEffectiveArguments(ExpressionListPtr params,
|
||||
CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Generate invoke proxy.
|
||||
*/
|
||||
static void OutputCPPDynamicInvokeCount(CodeGenerator &cg);
|
||||
void outputCPPDynamicInvoke(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const char *funcPrefix,
|
||||
const char *name,
|
||||
bool voidWrapperOff = false,
|
||||
bool fewArgs = false,
|
||||
bool ret = true,
|
||||
const char *extraArg = nullptr,
|
||||
bool constructor = false,
|
||||
const char *instance = nullptr,
|
||||
const char *class_name = "");
|
||||
|
||||
void outputCPPDef(CodeGenerator &cg);
|
||||
|
||||
/**
|
||||
* ...so ClassStatement can call them for classes that don't have
|
||||
* constructors defined
|
||||
*/
|
||||
void outputCPPCreateDecl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPCreateImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* output functions
|
||||
*/
|
||||
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputMethodWrapper(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const char *clsToConstruct);
|
||||
|
||||
/**
|
||||
* Output CallInfo instance for this function.
|
||||
*/
|
||||
void outputCPPCallInfo(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputCPPPreface(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
void outputCPPHelperClassAlloc(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Serialize the iface, not everything.
|
||||
*/
|
||||
@@ -518,14 +432,6 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
bool outputCPPArrayCreate(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int m_maxParam);
|
||||
|
||||
void outputCPPSubClassParam(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
ParameterExpressionPtr param);
|
||||
|
||||
void init(AnalysisResultConstPtr ar);
|
||||
|
||||
static StringToFunctionInfoPtrMap s_refParamInfo;
|
||||
@@ -582,13 +488,12 @@ private:
|
||||
StatementPtr m_stmtCloned; // cloned method body stmt
|
||||
int m_inlineIndex;
|
||||
FunctionOptPtr m_optFunction;
|
||||
int outputCPPInvokeArgCountCheck(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool ret, bool constructor, int maxCount);
|
||||
ExpressionPtrVec m_retExprsToFix;
|
||||
ExpressionListPtr m_closureVars;
|
||||
ExpressionListPtr m_closureValues;
|
||||
ReadWriteMutex m_inlineMutex;
|
||||
unsigned m_nextID; // used when cloning generators for traits
|
||||
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -461,25 +461,11 @@ bool LiveDict::color(TypePtr type) {
|
||||
if (Type::SameType(type, e->getCPPType())) {
|
||||
SimpleVariablePtr sv(
|
||||
static_pointer_cast<SimpleVariable>(e));
|
||||
bool isGenParam = false;
|
||||
if (sv->getFunctionScope()->isGenerator()) {
|
||||
// do not allow coalescing of symbols which are parameters/use vars
|
||||
// in the generator (sym->isParameter() will be false b/c we are in
|
||||
// the scope of the generator function)
|
||||
FunctionScopeRawPtr origScope(sv->getFunctionScope()->getOrigGenFS());
|
||||
assert(origScope);
|
||||
Symbol *origSym =
|
||||
origScope->getVariables()->getSymbol(sv->getName());
|
||||
if (origSym &&
|
||||
(origSym->isParameter() || origSym->isClosureVar())) {
|
||||
isGenParam = true;
|
||||
}
|
||||
}
|
||||
Symbol *sym = sv->getSymbol();
|
||||
if (sym &&
|
||||
!sym->isGlobal() &&
|
||||
!sym->isParameter() &&
|
||||
!isGenParam &&
|
||||
!sym->isGeneratorParameter() &&
|
||||
!sym->isClosureVar() &&
|
||||
!sym->isStatic() &&
|
||||
!e->isThis()) {
|
||||
@@ -623,9 +609,8 @@ public:
|
||||
always_assert(e && e->is(Expression::KindOfSimpleVariable));
|
||||
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
|
||||
Symbol *sym = sv->getSymbol();
|
||||
bool inGen = sv->getFunctionScope()->isGenerator();
|
||||
if (!sym || sym->isGlobal() || sym->isStatic() || sym->isParameter() ||
|
||||
sym->isClosureVar() || sv->isThis() || inGen) {
|
||||
sym->isGeneratorParameter() || sym->isClosureVar() || sv->isThis()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,8 @@ public:
|
||||
bool isIndirectAltered() const { return m_flags.m_indirectAltered; }
|
||||
bool isReferenced() const { return !m_flags.m_notReferenced; }
|
||||
bool isHidden() const { return m_flags.m_hidden; }
|
||||
bool isGeneratorParameter() const { return m_flags.m_generatorParameter; }
|
||||
bool isRefGeneratorParameter() const { return m_flags.m_refGeneratorParameter; }
|
||||
bool isClosureVar() const { return m_flags.m_closureVar; }
|
||||
bool isRefClosureVar() const { return m_flags.m_refClosureVar; }
|
||||
bool isPassClosureVar() const { return m_flags.m_passClosureVar; }
|
||||
@@ -140,6 +142,8 @@ public:
|
||||
void setIndirectAltered() { m_flags.m_indirectAltered = true; }
|
||||
void setReferenced() { m_flags.m_notReferenced = false; }
|
||||
void setHidden() { m_flags.m_hidden = true; }
|
||||
void setGeneratorParameter() { m_flags.m_generatorParameter = true; }
|
||||
void setRefGeneratorParameter() { m_flags.m_refGeneratorParameter = true; }
|
||||
void setClosureVar() { m_flags.m_closureVar = true; }
|
||||
void setRefClosureVar() { m_flags.m_refClosureVar = true; }
|
||||
void setPassClosureVar() { m_flags.m_passClosureVar = true; }
|
||||
@@ -185,7 +189,7 @@ private:
|
||||
std::string m_name;
|
||||
unsigned int m_hash;
|
||||
union {
|
||||
unsigned m_flags_val;
|
||||
uint64_t m_flags_val;
|
||||
struct {
|
||||
/* internal */
|
||||
unsigned m_declaration_set : 1;
|
||||
@@ -219,6 +223,8 @@ private:
|
||||
unsigned m_indirectAltered : 1;
|
||||
unsigned m_notReferenced : 1;
|
||||
unsigned m_hidden : 1;
|
||||
unsigned m_generatorParameter : 1;
|
||||
unsigned m_refGeneratorParameter : 1;
|
||||
unsigned m_closureVar : 1;
|
||||
unsigned m_refClosureVar : 1;
|
||||
unsigned m_passClosureVar : 1;
|
||||
@@ -227,6 +233,10 @@ private:
|
||||
unsigned m_stashedVal : 1;
|
||||
unsigned m_reseated : 1;
|
||||
} m_flags;
|
||||
|
||||
static_assert(
|
||||
sizeof(m_flags_val) == sizeof(m_flags),
|
||||
"m_flags_val must cover all the flags");
|
||||
};
|
||||
ConstructPtr m_declaration;
|
||||
ConstructPtr m_value;
|
||||
|
||||
@@ -589,37 +589,6 @@ ClassScopePtr Type::getClass(AnalysisResultConstPtr ar,
|
||||
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;
|
||||
@@ -646,66 +615,6 @@ DataType Type::getHhvmDataType() const {
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
@@ -225,35 +225,9 @@ public:
|
||||
ClassScopePtr getClass(AnalysisResultConstPtr ar,
|
||||
BlockScopeRawPtr scope) const;
|
||||
|
||||
/**
|
||||
* Generate type specifier in C++.
|
||||
*/
|
||||
std::string getCPPDecl(AnalysisResultConstPtr ar,
|
||||
BlockScopeRawPtr scope,
|
||||
CodeGenerator *cg = 0);
|
||||
DataType getDataType() const;
|
||||
DataType getHhvmDataType() const;
|
||||
|
||||
void outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar,
|
||||
BlockScopeRawPtr scope);
|
||||
|
||||
/**
|
||||
* Generate type conversion in C++.
|
||||
*/
|
||||
|
||||
void outputCPPFastObjectCast(CodeGenerator &cg,
|
||||
AnalysisResultConstPtr ar,
|
||||
BlockScopeRawPtr scope,
|
||||
bool isConst);
|
||||
|
||||
void outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar,
|
||||
BlockScopeRawPtr scope);
|
||||
|
||||
/**
|
||||
* Generate variable initialization code.
|
||||
*/
|
||||
const char *getCPPInitializer();
|
||||
|
||||
/**
|
||||
* Type hint names in PHP.
|
||||
*/
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -137,15 +137,6 @@ public:
|
||||
|
||||
virtual bool isInherited(const std::string &name) const;
|
||||
|
||||
const char *getVariablePrefix(const std::string &name) const;
|
||||
const char *getVariablePrefix(const Symbol *sym) const;
|
||||
std::string getVariableName(AnalysisResultConstPtr ar,
|
||||
const std::string &name) const;
|
||||
std::string getVariableName(AnalysisResultConstPtr ar,
|
||||
const Symbol *sym) const;
|
||||
std::string getGlobalVariableName(AnalysisResultConstPtr ar,
|
||||
const std::string &name) const;
|
||||
|
||||
void getLocalVariableNames(std::vector<std::string> &syms) const;
|
||||
|
||||
/**
|
||||
@@ -289,33 +280,6 @@ public:
|
||||
* Generate all variable declarations for this symbol table.
|
||||
*/
|
||||
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool outputCPPPropertyDecl(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool dynamicObject = false);
|
||||
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPStaticVariables(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPStaticLocals(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool forInitList);
|
||||
|
||||
void outputCPPGlobalVariablesDtorIncludes(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesDtor(CodeGenerator &cg);
|
||||
void outputCPPGVHashTableGetImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesGetImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGVHashTableExists(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesExists(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGVHashTableGetIndex(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesGetIndex(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesMethods(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
void collectCPPGlobalSymbols(StringPairSetVec &symbols, CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Whether or not the specified jump table is empty.
|
||||
*/
|
||||
@@ -383,22 +347,6 @@ private:
|
||||
TypePtr type, bool coerce);
|
||||
virtual void dumpStats(std::map<std::string, int> &typeCounts);
|
||||
|
||||
void outputCPPGlobalVariablesHeader(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar);
|
||||
void outputCPPGlobalVariablesImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPVariableTable(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const char *paramPrefix);
|
||||
bool outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const char *prefix, bool defineHash,
|
||||
bool variantOnly, StaticSelection staticVar,
|
||||
JumpTableType type = JumpReturn,
|
||||
PrivateSelection privateVar = NonPrivate,
|
||||
bool *declaredGlobals = nullptr);
|
||||
bool outputCPPPrivateSelector(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const char *op, const char *args);
|
||||
void outputCPPVariableInit(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool inPseudoMain, const std::string &name);
|
||||
void checkSystemGVOrder(SymbolSet &variants, unsigned int max);
|
||||
};
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
|
||||
if (sep) {
|
||||
fs->setSepExtension();
|
||||
}
|
||||
int flags = (int)(int64)(*p++);
|
||||
int flags = (int)(int64_t)(*p++);
|
||||
if (flags & ClassInfo::IsAbstract) {
|
||||
fs->addModifier(T_ABSTRACT);
|
||||
}
|
||||
@@ -209,7 +209,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
|
||||
p++;
|
||||
// Parse properties
|
||||
while (*p) {
|
||||
int flags = (int)(int64)(*p++);
|
||||
int flags = (int)(int64_t)(*p++);
|
||||
ModifierExpressionPtr modifiers(
|
||||
new ModifierExpression(BlockScopePtr(), LocationPtr()));
|
||||
if (flags & ClassInfo::IsProtected) {
|
||||
@@ -233,7 +233,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
|
||||
}
|
||||
p++;
|
||||
|
||||
int flags = (int)(int64)(*p++);
|
||||
int flags = (int)(int64_t)(*p++);
|
||||
cl->setClassInfoAttribute(flags);
|
||||
if (flags & ClassInfo::HasDocComment) {
|
||||
cl->setDocComment(*p++);
|
||||
@@ -295,7 +295,7 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
|
||||
index++;
|
||||
}
|
||||
|
||||
int flags = (int)(int64)(*p++);
|
||||
int flags = (int)(int64_t)(*p++);
|
||||
f->setClassInfoAttribute(flags);
|
||||
if (flags & ClassInfo::HasDocComment) {
|
||||
f->setDocComment(*p++);
|
||||
|
||||
@@ -61,8 +61,7 @@ CodeGenerator::CodeGenerator(std::ostream *primary,
|
||||
Output output /* = PickledPHP */,
|
||||
const std::string *filename /* = NULL */)
|
||||
: m_out(nullptr), m_output(output),
|
||||
m_hoistedClasses(0), m_collectHoistedClasses(false),
|
||||
m_context(NoContext), m_insideScalarArray(false), m_itemIndex(-1) {
|
||||
m_context(NoContext), m_itemIndex(-1) {
|
||||
for (int i = 0; i < StreamCount; i++) {
|
||||
m_streams[i] = nullptr;
|
||||
m_indentation[i] = 0;
|
||||
@@ -140,46 +139,6 @@ void CodeGenerator::indentEnd() {
|
||||
m_indentation[m_curStream]--;
|
||||
}
|
||||
|
||||
bool CodeGenerator::wrapExpressionBegin() {
|
||||
if (!m_wrappedExpression[m_curStream]) {
|
||||
m_wrappedExpression[m_curStream] = true;
|
||||
m_referenceTempsUsed[m_curStream] = false;
|
||||
m_localId[m_curStream] = 0;
|
||||
setInExpression(true);
|
||||
indentBegin("{\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CodeGenerator::wrapExpressionEnd() {
|
||||
if (m_wrappedExpression[m_curStream]) {
|
||||
if (m_referenceTempsUsed[m_curStream]) {
|
||||
printf("%s.unset();\n", m_referenceTemps[m_curStream].c_str());
|
||||
}
|
||||
m_wrappedExpression[m_curStream] = false;
|
||||
indentEnd("}\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CodeGenerator::genReferenceTemp(ConstructPtr cp) {
|
||||
string &rt = m_referenceTemps[m_curStream];
|
||||
rt = (string)Option::TempPrefix + "_ref";
|
||||
printf("Variant %s;\n", rt.c_str());
|
||||
}
|
||||
|
||||
const string &CodeGenerator::getReferenceTemp() {
|
||||
static string empty = "";
|
||||
if (m_wrappedExpression[m_curStream] &&
|
||||
!m_referenceTemps[m_curStream].empty()) {
|
||||
m_referenceTempsUsed[m_curStream] = true;
|
||||
return m_referenceTemps[m_curStream];
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
bool CodeGenerator::inComments() const {
|
||||
return m_inComments[m_curStream] > 0;
|
||||
}
|
||||
@@ -248,20 +207,6 @@ bool CodeGenerator::ensureOutOfNamespace() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodeGenerator::headerBegin(const std::string &file) {
|
||||
string formatted = getFormattedName(file);
|
||||
printf("\n");
|
||||
printf("#ifndef __GENERATED_%s__\n", formatted.c_str());
|
||||
printf("#define __GENERATED_%s__\n", formatted.c_str());
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void CodeGenerator::headerEnd(const std::string &file) {
|
||||
string formatted = getFormattedName(file);
|
||||
printf("\n");
|
||||
printf("#endif // __GENERATED_%s__\n", formatted.c_str());
|
||||
}
|
||||
|
||||
void CodeGenerator::ifdefBegin(bool ifdef, const char *fmt, ...) {
|
||||
printf(ifdef ? "#ifdef " : "#ifndef ");
|
||||
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
|
||||
@@ -274,59 +219,6 @@ void CodeGenerator::ifdefEnd(const char *fmt, ...) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void CodeGenerator::printInclude(const std::string &file) {
|
||||
assert(!file.empty());
|
||||
|
||||
string formatted = file;
|
||||
if (file[0] != '"' && file[0] != '<') {
|
||||
if (file.substr(file.length() - 2) != ".h") {
|
||||
formatted += ".h";
|
||||
}
|
||||
formatted = string("<") + formatted + '>';
|
||||
}
|
||||
printf("%s %s\n", HASH_INCLUDE, formatted.c_str());
|
||||
}
|
||||
|
||||
void CodeGenerator::printBasicIncludes() {
|
||||
if (Option::GenerateCPPMain) {
|
||||
printInclude("<runtime/base/hphp.h>");
|
||||
printInclude(string(Option::SystemFilePrefix) +
|
||||
"literal_strings_remap.h");
|
||||
printInclude(string(Option::SystemFilePrefix) +
|
||||
"scalar_arrays_remap.h");
|
||||
if (Option::UseScalarVariant) {
|
||||
printInclude(string(Option::SystemFilePrefix) +
|
||||
"scalar_integers_remap.h");
|
||||
}
|
||||
printInclude(string(Option::SystemFilePrefix) + "global_variables.h");
|
||||
if (Option::GenArrayCreate) {
|
||||
printInclude(string(Option::SystemFilePrefix) + "cpputil.h");
|
||||
}
|
||||
} else if (getOutput() == CodeGenerator::SystemCPP) {
|
||||
printInclude("<runtime/base/hphp_system.h>");
|
||||
printInclude(string("system/gen/") + Option::SystemFilePrefix +
|
||||
"literal_strings_remap.h");
|
||||
printInclude(string("system/gen/") + Option::SystemFilePrefix +
|
||||
"scalar_arrays_remap.h");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::printDeclareGlobals() {
|
||||
if (getOutput() == SystemCPP) {
|
||||
printf("DECLARE_SYSTEM_GLOBALS(g);\n");
|
||||
} else {
|
||||
printf("DECLARE_GLOBAL_VARIABLES(g);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::printStartOfJumpTable(int tableSize) {
|
||||
if (Util::isPowerOfTwo(tableSize)) {
|
||||
indentBegin("switch (hash & %d) {\n", tableSize-1);
|
||||
} else {
|
||||
indentBegin("switch (hash %% %d) {\n", tableSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::printDocComment(const std::string comment) {
|
||||
if (comment.empty()) return;
|
||||
string escaped;
|
||||
@@ -342,24 +234,6 @@ void CodeGenerator::printDocComment(const std::string comment) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void CodeGenerator::printImplStarter() {
|
||||
printf("%s\n", STARTER_MARKER);
|
||||
}
|
||||
|
||||
void CodeGenerator::printImplSplitter() {
|
||||
printf("%s\n", SPLITTER_MARKER);
|
||||
}
|
||||
|
||||
const char *CodeGenerator::getGlobals(AnalysisResultPtr ar) {
|
||||
if (m_context == CppParameterDefaultValueDecl ||
|
||||
m_context == CppParameterDefaultValueImpl) {
|
||||
return (m_output == CodeGenerator::SystemCPP) ?
|
||||
"get_system_globals()" : "get_global_variables()";
|
||||
}
|
||||
if (m_output == CodeGenerator::SystemCPP) return "get_system_globals()";
|
||||
return "g";
|
||||
}
|
||||
|
||||
std::string CodeGenerator::FormatLabel(const std::string &name) {
|
||||
string ret;
|
||||
ret.reserve(name.size());
|
||||
@@ -523,14 +397,6 @@ int CodeGenerator::callInfoTop() {
|
||||
return m_callInfos.back();
|
||||
}
|
||||
|
||||
bool CodeGenerator::getInsideScalarArray() {
|
||||
return m_insideScalarArray;
|
||||
}
|
||||
|
||||
void CodeGenerator::setInsideScalarArray(bool flag) {
|
||||
m_insideScalarArray = flag;
|
||||
}
|
||||
|
||||
void CodeGenerator::addLabelId(const char *name, int labelId) {
|
||||
if (!strcmp(name, "break")) {
|
||||
m_breakLabelIds.insert(labelId);
|
||||
@@ -552,107 +418,6 @@ bool CodeGenerator::findLabelId(const char *name, int labelId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int CodeGenerator::checkLiteralString(const std::string &str, int &index,
|
||||
AnalysisResultPtr ar, BlockScopePtr bs,
|
||||
bool scalarVariant /* = false */) {
|
||||
always_assert(getContext() != CodeGenerator::CppConstantsDecl &&
|
||||
getContext() != CodeGenerator::CppClassConstantsImpl);
|
||||
int stringId = ar->getLiteralStringId(str, index);
|
||||
if (m_literalScope) {
|
||||
bs = m_literalScope;
|
||||
}
|
||||
if (bs && bs != ar) {
|
||||
FileScopePtr fs = bs->getContainingFile();
|
||||
if (fs) {
|
||||
fs->addUsedLiteralString(str);
|
||||
if (scalarVariant) fs->addUsedLitVarString(str);
|
||||
if (isFileOrClassHeader()) {
|
||||
ClassScopePtr cs = bs->getContainingClass();
|
||||
if (cs) {
|
||||
cs->addUsedLiteralStringHeader(str);
|
||||
if (scalarVariant) cs->addUsedLitVarStringHeader(str);
|
||||
} else {
|
||||
fs->addUsedLiteralStringHeader(str);
|
||||
if (scalarVariant) fs->addUsedLitVarStringHeader(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringId;
|
||||
}
|
||||
|
||||
string CodeGenerator::printNamedString(const string &str,
|
||||
const string &escaped, AnalysisResultPtr ar, BlockScopeRawPtr bs,
|
||||
bool print) {
|
||||
int index = -1;
|
||||
bool scalarVariant = !print;
|
||||
int stringId = checkLiteralString(str, index, ar, bs, scalarVariant);
|
||||
always_assert(index >= 0);
|
||||
string lisnam = ar->getLiteralStringName(stringId, index);
|
||||
if (print) {
|
||||
printf("NAMSTR(%s, \"%s\")", lisnam.c_str(), escaped.c_str());
|
||||
}
|
||||
return lisnam;
|
||||
}
|
||||
|
||||
string CodeGenerator::printString(const string &str, AnalysisResultPtr ar,
|
||||
BlockScopeRawPtr bs,
|
||||
bool stringWrapper /* = true */) {
|
||||
bool isBinary = false;
|
||||
string escaped = EscapeLabel(str, &isBinary);
|
||||
if (bs) {
|
||||
return printNamedString(str, escaped, ar, bs, true);
|
||||
}
|
||||
if (isBinary) {
|
||||
if (stringWrapper) {
|
||||
printf("String(\"%s\", %d, AttachLiteral)",
|
||||
escaped.c_str(), (int)str.length());
|
||||
} else {
|
||||
printf("\"%s\", %d", escaped.c_str(), (int)str.length());
|
||||
}
|
||||
} else {
|
||||
printf("\"%s\"", escaped.c_str());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string CodeGenerator::printString(const std::string &str, AnalysisResultPtr ar,
|
||||
ConstructPtr cs,
|
||||
bool stringWrapper /* = true */) {
|
||||
return printString(str, ar, (BlockScopePtr)cs->getScope(), stringWrapper);
|
||||
}
|
||||
|
||||
void CodeGenerator::beginHoistedClasses() {
|
||||
m_hoistedClasses = new std::set<string,stdltistr>();
|
||||
m_collectHoistedClasses = true;
|
||||
}
|
||||
|
||||
void CodeGenerator::endHoistedClasses() {
|
||||
delete m_hoistedClasses;
|
||||
m_hoistedClasses = 0;
|
||||
}
|
||||
|
||||
void CodeGenerator::collectHoistedClasses(bool flag) {
|
||||
m_collectHoistedClasses = flag;
|
||||
}
|
||||
|
||||
void CodeGenerator::addHoistedClass(const string &cls) {
|
||||
if (m_hoistedClasses && m_collectHoistedClasses) {
|
||||
m_hoistedClasses->insert(cls);
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeGenerator::checkHoistedClass(const string &cls) {
|
||||
if (m_hoistedClasses) {
|
||||
if (m_hoistedClasses->find(cls) != m_hoistedClasses->end()) {
|
||||
return true;
|
||||
}
|
||||
addHoistedClass(cls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CodeGenerator::ClassScopeCompare::cmp(const ClassScopeRawPtr &p1,
|
||||
const ClassScopeRawPtr &p2) const {
|
||||
int d = p1->getRedeclaringId() - p2->getRedeclaringId();
|
||||
|
||||
@@ -163,17 +163,6 @@ public:
|
||||
void indentEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
|
||||
void indentEnd();
|
||||
void printRaw(const char *msg) { print(msg, false);}
|
||||
bool wrapExpressionBegin();
|
||||
bool wrapExpressionEnd();
|
||||
void genReferenceTemp(ConstructPtr scope);
|
||||
void clearRefereceTemp() { m_referenceTemps[m_curStream].clear(); }
|
||||
const std::string &getReferenceTemp();
|
||||
bool hasReferenceTemp() const {
|
||||
return !m_referenceTemps[m_curStream].empty();
|
||||
}
|
||||
void setReferenceTempUsed(bool flag) {
|
||||
m_referenceTempsUsed[m_curStream] = flag;
|
||||
}
|
||||
/**
|
||||
* Pre-formatted outputs.
|
||||
*/
|
||||
@@ -183,17 +172,9 @@ public:
|
||||
void namespaceEnd();
|
||||
bool ensureInNamespace();
|
||||
bool ensureOutOfNamespace();
|
||||
void headerBegin(const std::string &file);
|
||||
void headerEnd(const std::string &file);
|
||||
void ifdefBegin(bool ifdef, const char *fmt, ...) ATTRIBUTE_PRINTF(3,4);
|
||||
void ifdefEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
|
||||
void printInclude(const std::string &file);
|
||||
void printBasicIncludes();
|
||||
void printDeclareGlobals();
|
||||
void printStartOfJumpTable(int tableSize);
|
||||
void printDocComment(const std::string comment);
|
||||
void printImplStarter(); // end of includes
|
||||
void printImplSplitter(); // marker to split .cpp into smaller files
|
||||
const char *getGlobals(AnalysisResultPtr ar);
|
||||
static std::string FormatLabel(const std::string &name);
|
||||
static std::string EscapeLabel(const std::string &name, bool *binary = nullptr);
|
||||
@@ -268,31 +249,13 @@ public:
|
||||
m_loopStatement = loop;
|
||||
}
|
||||
|
||||
void setInsideScalarArray(bool flag);
|
||||
bool getInsideScalarArray();
|
||||
|
||||
void setFileOrClassHeader(bool value) { m_inFileOrClassHeader = value; }
|
||||
bool isFileOrClassHeader() { return m_inFileOrClassHeader; }
|
||||
|
||||
void beginHoistedClasses();
|
||||
void endHoistedClasses();
|
||||
void collectHoistedClasses(bool flag);
|
||||
void addHoistedClass(const std::string &cls);
|
||||
bool checkHoistedClass(const std::string &cls);
|
||||
|
||||
void setScalarVariant() { m_scalarVariant = true; }
|
||||
bool hasScalarVariant() { return m_scalarVariant; }
|
||||
void clearScalarVariant() { m_scalarVariant = false; }
|
||||
|
||||
void setInitListFirstElem() { m_initListFirstElem = true; }
|
||||
bool hasInitListFirstElem() { return m_initListFirstElem; }
|
||||
void clearInitListFirstElem() { m_initListFirstElem = false; }
|
||||
|
||||
const StringToClassScopePtrVecMap &getClasses() const { return m_classes; }
|
||||
void addClass(const std::string &name, ClassScopePtr cls) {
|
||||
m_classes[name].push_back(cls);
|
||||
}
|
||||
void clearClasses() { m_classes.clear(); }
|
||||
bool insertDeclaredClosure(const FunctionScope *f) {
|
||||
return m_declaredClosures.insert(f).second;
|
||||
}
|
||||
@@ -321,8 +284,6 @@ private:
|
||||
bool m_inFileOrClassHeader;
|
||||
bool m_inNamespace;
|
||||
int m_localId[StreamCount];
|
||||
std::set<std::string, stdltistr> *m_hoistedClasses;
|
||||
bool m_collectHoistedClasses;
|
||||
|
||||
static int s_idLambda;
|
||||
std::map<std::string, int> m_idCounters;
|
||||
@@ -332,7 +293,6 @@ private:
|
||||
std::set<int> m_contLabelIds; // continue labels referenced
|
||||
std::deque<int> m_callInfos;
|
||||
LoopStatementPtr m_loopStatement;
|
||||
bool m_insideScalarArray;
|
||||
StringToClassScopePtrVecMap m_classes;
|
||||
std::set<const FunctionScope*> m_declaredClosures;
|
||||
FileScopeRawPtr m_literalScope;
|
||||
|
||||
+26
-146
@@ -38,10 +38,10 @@
|
||||
#include <util/timer.h>
|
||||
#include <util/hdf.h>
|
||||
#include <util/async_func.h>
|
||||
#include <runtime/base/program_functions.h>
|
||||
#include <runtime/base/memory/smart_allocator.h>
|
||||
#include <runtime/base/externals.h>
|
||||
#include <runtime/base/thread_init_fini.h>
|
||||
#include <runtime/base/compiler_id.h>
|
||||
#include <runtime/vm/repo.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -49,6 +49,8 @@
|
||||
#include <system/lib/systemlib.h>
|
||||
#include <compiler/compiler.h>
|
||||
|
||||
#include "hhvm/process_init.h"
|
||||
|
||||
using namespace boost::program_options;
|
||||
using std::cout;
|
||||
|
||||
@@ -97,9 +99,7 @@ struct CompilerOptions {
|
||||
int clusterCount;
|
||||
int optimizeLevel;
|
||||
string filecache;
|
||||
string rttiDirectory;
|
||||
string javaRoot;
|
||||
bool generateFFI;
|
||||
bool dump;
|
||||
string docjson;
|
||||
bool coredump;
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
struct stat sb;
|
||||
stat(m_name, &sb);
|
||||
Logger::Info("%dMB %s saved", (int64)sb.st_size/(1024*1024), m_name);
|
||||
Logger::Info("%dMB %s saved", (int64_t)sb.st_size/(1024*1024), m_name);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -144,13 +144,10 @@ int phpTarget(const CompilerOptions &po, AnalysisResultPtr ar);
|
||||
void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar);
|
||||
int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
AsyncFileCacheSaver &fcThread);
|
||||
int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
AsyncFileCacheSaver &fcThread, bool allowSys = true);
|
||||
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
AsyncFileCacheSaver &fcThread);
|
||||
int buildTarget(const CompilerOptions &po);
|
||||
int runTarget(const CompilerOptions &po);
|
||||
int generateSepExtCpp(const CompilerOptions &po, AnalysisResultPtr ar);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -186,11 +183,7 @@ int compiler_main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
if (po.target == "cpp") {
|
||||
if (po.format == "exe" || po.format == "lib") {
|
||||
ret = buildTarget(po);
|
||||
}
|
||||
} else if (po.target == "run") {
|
||||
if (po.target == "run") {
|
||||
ret = runTarget(po);
|
||||
}
|
||||
}
|
||||
@@ -224,8 +217,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
"analyze | "
|
||||
"php | "
|
||||
"hhbc | "
|
||||
"cpp | "
|
||||
"sep-ext-cpp | "
|
||||
"filecache | "
|
||||
"run (default)")
|
||||
("format,f", value<string>(&po.format),
|
||||
@@ -234,7 +225,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
"php: trimmed (default) | inlined | pickled | typeinfo |"
|
||||
" <any combination of them by any separator>; \n"
|
||||
"hhbc: binary (default) | text; \n"
|
||||
"cpp: cluster (default) | file | sys | exe | lib; \n"
|
||||
"run: cluster (default) | file")
|
||||
("cluster-count", value<int>(&po.clusterCount)->default_value(0),
|
||||
"Cluster by file sizes and output roughly these many number of files. "
|
||||
@@ -327,14 +317,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
("file-cache",
|
||||
value<string>(&po.filecache),
|
||||
"if specified, generate a static file cache with this file name")
|
||||
("rtti-directory", value<string>(&po.rttiDirectory)->default_value(""),
|
||||
"the directory of rtti profiling data")
|
||||
("java-root",
|
||||
value<string>(&po.javaRoot)->default_value("php"),
|
||||
"the root package of generated Java FFI classes")
|
||||
("generate-ffi",
|
||||
value<bool>(&po.generateFFI)->default_value(false),
|
||||
"generate ffi stubs")
|
||||
("dump",
|
||||
value<bool>(&po.dump)->default_value(false),
|
||||
"dump the program graph")
|
||||
@@ -361,9 +343,7 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
"files according to preprocessed file sizes, instead of original file "
|
||||
"sizes (default). Run bin/ppp.php to generate an HDF configuration file "
|
||||
"to specify here.")
|
||||
#ifdef COMPILER_ID
|
||||
("compiler-id", "display the git hash for the compiler id")
|
||||
#endif
|
||||
("repo-schema", "display the repo schema id used by this app")
|
||||
("taint-status", "check if the compiler was built with taint enabled")
|
||||
;
|
||||
@@ -402,19 +382,15 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
#define HPHP_VERSION(v) cout << HPHP_COMPILER_STR #v << "\n";
|
||||
#include "../version"
|
||||
|
||||
#ifdef COMPILER_ID
|
||||
cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
#endif
|
||||
cout << "Compiler: " << kCompilerId << "\n";
|
||||
cout << "Repo schema: " << VM::Repo::kSchemaId << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef COMPILER_ID
|
||||
if (vm.count("compiler-id")) {
|
||||
cout << COMPILER_ID << "\n";
|
||||
cout << kCompilerId << "\n";
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vm.count("repo-schema")) {
|
||||
cout << VM::Repo::kSchemaId << "\n";
|
||||
@@ -428,8 +404,7 @@ cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (hhvm &&
|
||||
(po.target == "hhbc" || po.target == "run") &&
|
||||
if ((po.target == "hhbc" || po.target == "run") &&
|
||||
po.format.find("exe") == string::npos) {
|
||||
if (po.program == "program") {
|
||||
po.program = "hhvm.hhbc";
|
||||
@@ -445,12 +420,6 @@ cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
Logger::LogLevel = Logger::LogInfo;
|
||||
}
|
||||
|
||||
// config and system
|
||||
Option::GenerateCPPMain = true;
|
||||
if (po.noMetaInfo) {
|
||||
Option::GenerateCPPMetaInfo = false;
|
||||
Option::GenerateCPPMacros = false;
|
||||
}
|
||||
Option::FlAnnotate = po.fl_annotate;
|
||||
|
||||
Hdf config;
|
||||
@@ -504,14 +473,8 @@ cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
(Util::format_pattern(po.excludeStaticPatterns[i], true));
|
||||
}
|
||||
|
||||
if (po.target == "cpp" && po.format == "sys") {
|
||||
BuiltinSymbols::NoSuperGlobals = true; // so to generate super globals
|
||||
Option::AnalyzePerfectVirtuals = false;
|
||||
}
|
||||
Option::SystemGen = (po.target == "cpp" && po.format == "sys") ;
|
||||
|
||||
if (hhvm && (po.target == "hhbc" || po.target == "run")) {
|
||||
Option::OutputHHBC = true;
|
||||
Option::OutputHHBC = true;
|
||||
if (po.target == "hhbc" || po.target == "run") {
|
||||
Option::AnalyzePerfectVirtuals = false;
|
||||
}
|
||||
|
||||
@@ -519,24 +482,22 @@ cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
Option::PreprocessedPartitionConfig = po.ppp;
|
||||
|
||||
if (po.format.empty()) {
|
||||
if (po.target == "cpp") {
|
||||
po.format = "cluster";
|
||||
} else if (po.target == "php") {
|
||||
if (po.target == "php") {
|
||||
po.format = "trimmed";
|
||||
} else if (po.target == "run") {
|
||||
po.format = hhvm ? "binary" : "cluster";
|
||||
} else if (hhvm && po.target == "hhbc") {
|
||||
po.format = "binary";
|
||||
} else if (po.target == "hhbc") {
|
||||
po.format = "binary";
|
||||
}
|
||||
}
|
||||
|
||||
if (!po.docjson.empty()) {
|
||||
if (po.target != "cpp" &&
|
||||
po.target != "run" &&
|
||||
if (po.target != "run" &&
|
||||
po.target != "hhbc" &&
|
||||
po.target != "analyze") {
|
||||
Logger::Error(
|
||||
"Cannot generate doc JSON file unless target is "
|
||||
"'cpp', 'run', or 'analyze'");
|
||||
"'hhbc', 'run', or 'analyze'");
|
||||
} else {
|
||||
Option::DocJson = po.docjson;
|
||||
}
|
||||
@@ -561,11 +522,6 @@ cout << "Compiler: " << COMPILER_ID << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (po.generateFFI) {
|
||||
Option::GenerateFFI = true;
|
||||
Option::JavaFFIRootPackage = po.javaRoot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -597,6 +553,7 @@ int process(const CompilerOptions &po) {
|
||||
return lintTarget(po);
|
||||
}
|
||||
|
||||
register_process_init();
|
||||
init_thread_locals();
|
||||
|
||||
Timer timer(Timer::WallTime);
|
||||
@@ -606,7 +563,7 @@ int process(const CompilerOptions &po) {
|
||||
Package package(po.inputDir.c_str());
|
||||
ar = package.getAnalysisResult();
|
||||
|
||||
if (hhvm && (po.target == "hhbc" || po.target == "run")) {
|
||||
if (po.target == "hhbc" || po.target == "run") {
|
||||
hhbcTargetInit(po, ar);
|
||||
}
|
||||
|
||||
@@ -621,14 +578,10 @@ int process(const CompilerOptions &po) {
|
||||
BuiltinSymbols::LoadSuperGlobals();
|
||||
ClassInfo::Load();
|
||||
|
||||
if (po.format == "sys") ar->setSystem();
|
||||
|
||||
bool isPickledPHP = (po.target == "php" && po.format == "pickled");
|
||||
if (!isPickledPHP) {
|
||||
if (!BuiltinSymbols::Load(ar,
|
||||
(po.target == "cpp" && po.format == "sys")
|
||||
|| (po.target == "hhbc" && !Option::WholeProgram)
|
||||
)) {
|
||||
po.target == "hhbc" && !Option::WholeProgram)) {
|
||||
return false;
|
||||
}
|
||||
if (po.target == "hhbc" && !Option::WholeProgram) {
|
||||
@@ -636,6 +589,9 @@ int process(const CompilerOptions &po) {
|
||||
} else {
|
||||
ar->loadBuiltins();
|
||||
}
|
||||
if (!Option::SystemGen) {
|
||||
hphp_process_init();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -702,17 +658,12 @@ int process(const CompilerOptions &po) {
|
||||
ret = analyzeTarget(po, ar);
|
||||
} else if (po.target == "php") {
|
||||
ret = phpTarget(po, ar);
|
||||
} else if (hhvm && po.target == "hhbc") {
|
||||
} else if (po.target == "hhbc") {
|
||||
ret = hhbcTarget(po, ar, fileCacheThread);
|
||||
} else if (po.target == "cpp") {
|
||||
ret = cppTarget(po, ar, fileCacheThread);
|
||||
} else if (po.target == "run") {
|
||||
ret = runTargetCheck(po, ar, fileCacheThread);
|
||||
} else if (po.target == "filecache") {
|
||||
// do nothing
|
||||
} else if (po.target == "sep-ext-cpp") {
|
||||
ar->setSepExtension();
|
||||
ret = generateSepExtCpp(po, ar);
|
||||
} else {
|
||||
Logger::Error("Unknown target: %s", po.target.c_str());
|
||||
return 1;
|
||||
@@ -968,69 +919,6 @@ int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
AsyncFileCacheSaver &fcThread, bool allowSys /* = true */) {
|
||||
int ret = 0;
|
||||
int clusterCount = po.clusterCount;
|
||||
// format
|
||||
CodeGenerator::Output format = CodeGenerator::InvalidOutput;
|
||||
if (po.format == "file") {
|
||||
clusterCount = 0;
|
||||
format = CodeGenerator::FileCPP;
|
||||
} else if (po.format == "cluster") {
|
||||
format = CodeGenerator::ClusterCPP;
|
||||
} else if (po.format == "sys" && allowSys) {
|
||||
clusterCount = 0;
|
||||
format = CodeGenerator::SystemCPP;
|
||||
ar->setSystem();
|
||||
} else if (po.format == "exe" || po.format == "lib") {
|
||||
format = CodeGenerator::ClusterCPP;
|
||||
}
|
||||
|
||||
if (format == CodeGenerator::InvalidOutput) {
|
||||
Logger::Error("Unknown format for CPP target: %s", po.format.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Option::RTTIOutputFile.empty()) {
|
||||
if (!po.rttiDirectory.empty()) {
|
||||
Option::UseRTTIProfileData = true;
|
||||
ar->cloneRTTIFuncs(po.rttiDirectory.c_str());
|
||||
} else {
|
||||
Option::GenRTTIProfileData = true;
|
||||
}
|
||||
}
|
||||
|
||||
ret = analyzeTarget(po, ar);
|
||||
|
||||
{
|
||||
Timer timer(Timer::WallTime, "creating CPP files");
|
||||
if (po.syncDir.empty()) {
|
||||
ar->setOutputPath(po.outputDir);
|
||||
ar->outputAllCPP(format, clusterCount, nullptr);
|
||||
} else {
|
||||
ar->setOutputPath(po.syncDir);
|
||||
ar->outputAllCPP(format, clusterCount, &po.outputDir);
|
||||
if (!po.filecache.empty()) {
|
||||
fcThread.waitForEnd();
|
||||
}
|
||||
Util::syncdir(po.outputDir, po.syncDir);
|
||||
boost::filesystem::remove_all(po.syncDir);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int generateSepExtCpp(const CompilerOptions &po, AnalysisResultPtr ar) {
|
||||
ar->outputCPPSepExtensionImpl(po.outputFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int buildTarget(const CompilerOptions &po) {
|
||||
const char *HPHP_HOME = getenv("HPHP_HOME");
|
||||
if (!HPHP_HOME || !*HPHP_HOME) {
|
||||
@@ -1042,7 +930,6 @@ int buildTarget(const CompilerOptions &po) {
|
||||
if (getenv("SHOW_LINK")) flags += "SHOW_LINK=1 ";
|
||||
if (getenv("SHOW_COMPILE")) flags += "SHOW_COMPILE=1 ";
|
||||
if (po.format == "lib") flags += "HPHP_BUILD_LIBRARY=1 ";
|
||||
if (Option::GenerateFFI) flags += "HPHP_BUILD_FFI=1 ";
|
||||
const char *argv[] = {"", po.outputDir.c_str(),
|
||||
po.program.c_str(), flags.c_str(), nullptr};
|
||||
|
||||
@@ -1071,11 +958,7 @@ int buildTarget(const CompilerOptions &po) {
|
||||
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
AsyncFileCacheSaver &fcThread) {
|
||||
// generate code
|
||||
if (po.format == "sep") return 1;
|
||||
|
||||
if (hhvm ?
|
||||
hhbcTarget(po, ar, fcThread) :
|
||||
cppTarget(po, ar, fcThread, false)) {
|
||||
if (hhbcTarget(po, ar, fcThread)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1089,10 +972,7 @@ int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
int runTarget(const CompilerOptions &po) {
|
||||
int ret = hhvm ? 0 : buildTarget(po);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
// If there are more than one input files, we need one extra arg to run.
|
||||
// If it's missing, we will stop right here, with compiled code.
|
||||
@@ -1103,7 +983,7 @@ int runTarget(const CompilerOptions &po) {
|
||||
|
||||
// run the executable
|
||||
string cmd;
|
||||
if (hhvm && po.format.find("exe") == string::npos) {
|
||||
if (po.format.find("exe") == string::npos) {
|
||||
char buf[PATH_MAX];
|
||||
if (!realpath("/proc/self/exe", buf)) return -1;
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ void Construct::dumpNode(int spc) {
|
||||
}
|
||||
|
||||
std::cout << "-> 0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(10) << (int64)this << std::dec;
|
||||
<< std::setw(10) << (int64_t)this << std::dec;
|
||||
|
||||
std::cout << " " << name << "(" << type << ") ";
|
||||
if (id) {
|
||||
@@ -322,12 +322,12 @@ void Construct::dumpNode(int spc) {
|
||||
if (idPtr) {
|
||||
std::cout << "idp=0x" <<
|
||||
std::hex << std::setfill('0') << std::setw(10) <<
|
||||
(int64)idPtr.get() << " ";
|
||||
(int64_t)idPtr.get() << " ";
|
||||
}
|
||||
if (idCsePtr) {
|
||||
std::cout << "idcsep=0x" <<
|
||||
std::hex << std::setfill('0') << std::setw(10) <<
|
||||
(int64)idCsePtr.get() << " ";
|
||||
(int64_t)idCsePtr.get() << " ";
|
||||
}
|
||||
|
||||
if (value != "") {
|
||||
|
||||
@@ -246,7 +246,6 @@ public:
|
||||
* Called when generating code.
|
||||
*/
|
||||
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
|
||||
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
|
||||
|
||||
/**
|
||||
* Implements JSON::CodeError::ISerializable.
|
||||
|
||||
@@ -79,8 +79,7 @@ void ArrayElementExpression::setContext(Context context) {
|
||||
if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
|
||||
m_variable->clearContext(Expression::NoLValueWrapper);
|
||||
}
|
||||
// special case for $GLOBALS[], see the if (m_global) check in
|
||||
// ArrayElementExpression::outputCPPImpl, we do not need lvalue wrapper
|
||||
// special case for $GLOBALS[], we do not need lvalue wrapper
|
||||
if (m_variable->is(Expression::KindOfSimpleVariable)) {
|
||||
SimpleVariablePtr var =
|
||||
dynamic_pointer_cast<SimpleVariable>(m_variable);
|
||||
@@ -410,209 +409,3 @@ void ArrayElementExpression::outputPHP(CodeGenerator &cg,
|
||||
cg_printf("]");
|
||||
}
|
||||
}
|
||||
|
||||
bool ArrayElementExpression::preOutputCPP(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int state) {
|
||||
return preOutputOffsetLHS(cg, ar, state);
|
||||
}
|
||||
|
||||
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_global) {
|
||||
if (!m_globalName.empty()) {
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
string name = variables->getGlobalVariableName(ar, m_globalName);
|
||||
cg_printf("g->%s", name.c_str());
|
||||
} else {
|
||||
cg_printf("((LVariableTable *)g)->get(");
|
||||
m_offset->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
} else {
|
||||
TypePtr type = m_variable->getType();
|
||||
if (hasContext(UnsetContext)) {
|
||||
cg_printf("unsetLval(");
|
||||
m_variable->outputCPP(cg, ar);
|
||||
cg_printf(", ");
|
||||
} else {
|
||||
if (m_variable->is(Expression::KindOfScalarExpression) ||
|
||||
(type && (type->isInteger() ||
|
||||
type->is(Type::KindOfDouble) ||
|
||||
type->is(Type::KindOfObject) ||
|
||||
type->is(Type::KindOfBoolean)))) {
|
||||
cg_printf(type && type->is(Type::KindOfString) ? "((String)" :
|
||||
"((Variant)");
|
||||
m_variable->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
} else {
|
||||
m_variable->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
if (m_offset) {
|
||||
bool lvalAt = false;
|
||||
bool rvalAt = false;
|
||||
bool byRef = false;
|
||||
bool arrRef = false;
|
||||
const char *sep = ", AccessFlags::";
|
||||
bool isArrayType = type && type->is(Type::KindOfArray);
|
||||
bool isStringType = type && type->is(Type::KindOfString);
|
||||
bool isRealChainRoot = isChainRoot() && hasCPPCseTemp();
|
||||
|
||||
TypePtr t;
|
||||
bool hasCseStore = isRealChainRoot && GetCseTempInfo(
|
||||
ar,
|
||||
static_pointer_cast<Expression>(shared_from_this()),
|
||||
t);
|
||||
|
||||
if (hasContext(UnsetContext)) {
|
||||
// do nothing
|
||||
} else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
|
||||
assert(!isRealChainRoot); // TODO: handle this case
|
||||
cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
|
||||
} else if (m_context & (LValue|RefValue|DeepReference)) {
|
||||
// if we see an array access element in LValue context, the
|
||||
// type inference pass will never infer its type to be a string
|
||||
assert(!isStringType);
|
||||
if (isRealChainRoot && !isArrayType) {
|
||||
// chain roots for non array types (variants) should call
|
||||
// lvalRef()
|
||||
cg_printf(".lvalRef(");
|
||||
} else {
|
||||
cg_printf(".lvalAt(");
|
||||
}
|
||||
lvalAt = true;
|
||||
} else {
|
||||
byRef =
|
||||
((m_context & AccessContext) || isRealChainRoot) && !isStringType;
|
||||
arrRef = byRef && isArrayType;
|
||||
cg_printf(".rval%s%s(",
|
||||
arrRef || !byRef ? "At" : "", byRef ? "Ref" : "");
|
||||
rvalAt = true;
|
||||
}
|
||||
m_offset->outputCPP(cg, ar);
|
||||
if (!isStringType) {
|
||||
if (rvalAt) {
|
||||
if (byRef && !arrRef) {
|
||||
string tmp;
|
||||
if (hasCseStore) {
|
||||
tmp = string(Option::CseTempStoragePrefix) + m_cppCseTemp;
|
||||
} else {
|
||||
tmp = cg.getReferenceTemp();
|
||||
}
|
||||
cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str());
|
||||
}
|
||||
if (!hasContext(ExistContext)) {
|
||||
cg_printf(", AccessFlags::Error"); // raise undefined index error
|
||||
sep = "_";
|
||||
}
|
||||
} else if (lvalAt) {
|
||||
if (hasCseStore && !isArrayType) {
|
||||
cg_printf(", %s%s",
|
||||
Option::CseTempStoragePrefix, m_cppCseTemp.c_str());
|
||||
}
|
||||
if (hasContext(AccessContext)) {
|
||||
// Dont copy the array if the element is an object, or
|
||||
// is referenced.
|
||||
// This is safe in AccessContext (the parent is an ArrayElement,
|
||||
// or an ObjectProperty) because applying [] to an object will
|
||||
// either invoke OffsetGet, or fatal, and modifications to a
|
||||
// referenced element would be reflected in all copies
|
||||
// of the array anyway.
|
||||
cg_printf(", AccessFlags::CheckExist");
|
||||
sep = "_";
|
||||
}
|
||||
}
|
||||
ScalarExpressionPtr sc =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_offset);
|
||||
if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) {
|
||||
String s(sc->getLiteralString());
|
||||
int64 n;
|
||||
if (!s.get()->isStrictlyInteger(n)) {
|
||||
if (lvalAt || rvalAt) {
|
||||
cg_printf("%sKey", sep);
|
||||
} else {
|
||||
cg_printf(", true"); // skip toKey() at run time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_printf(")");
|
||||
} else {
|
||||
cg_printf(".lvalAt()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayElementExpression::outputCPPExistTest(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int op) {
|
||||
switch (op) {
|
||||
case T_ISSET: cg_printf("isset("); break;
|
||||
case T_EMPTY: cg_printf("empty("); break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
if (m_global) {
|
||||
if (!m_globalName.empty()) {
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
string name = variables->getGlobalVariableName(ar, m_globalName);
|
||||
cg_printf("g->%s", name.c_str());
|
||||
} else {
|
||||
cg_printf("((LVariableTable *)g)->get(");
|
||||
m_offset->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
} else {
|
||||
m_variable->outputCPP(cg, ar);
|
||||
cg_printf(", ");
|
||||
m_offset->outputCPP(cg, ar);
|
||||
ScalarExpressionPtr sc =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_offset);
|
||||
if (sc) {
|
||||
if (sc->isLiteralString()) {
|
||||
String s(sc->getLiteralString());
|
||||
int64 n;
|
||||
if (!s.get()->isStrictlyInteger(n)) {
|
||||
cg_printf(", true"); // skip toKey() at run time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_printf(")");
|
||||
}
|
||||
void ArrayElementExpression::outputCPPUnset(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (isSuperGlobal()) {
|
||||
Expression::outputCPPUnset(cg, ar);
|
||||
} else {
|
||||
TypePtr expected = m_variable->getExpectedType();
|
||||
TypePtr implemented = m_variable->getImplementedType();
|
||||
bool wrap = false;
|
||||
if (TypePtr t = m_variable->getActualType()) {
|
||||
if (t->is(Type::KindOfObject)) {
|
||||
if (!m_variable->getImplementedType() ||
|
||||
!m_variable->getImplementedType()->is(Type::KindOfVariant)) {
|
||||
cg_printf("((Variant)(");
|
||||
wrap = true;
|
||||
}
|
||||
m_variable->setImplementedType(TypePtr());
|
||||
m_variable->setExpectedType(TypePtr());
|
||||
}
|
||||
}
|
||||
m_variable->outputCPP(cg, ar);
|
||||
if (wrap) cg_printf("))");
|
||||
m_variable->setExpectedType(expected);
|
||||
m_variable->setImplementedType(implemented);
|
||||
cg_printf(".weakRemove(");
|
||||
m_offset->outputCPP(cg, ar);
|
||||
ScalarExpressionPtr sc =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_offset);
|
||||
if (sc && sc->isLiteralString()) {
|
||||
String s(sc->getLiteralString());
|
||||
int64 n;
|
||||
if (!s->isStrictlyInteger(n)) {
|
||||
cg_printf(", true");
|
||||
}
|
||||
}
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
bool appendClass(ExpressionPtr cls,
|
||||
AnalysisResultConstPtr ar, FileScopePtr file);
|
||||
|
||||
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int op);
|
||||
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -126,13 +126,6 @@ bool ArrayPairExpression::canonCompare(ExpressionPtr e) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void ArrayPairExpression::preOutputStash(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (m_name) m_name->preOutputStash(cg, ar, state);
|
||||
m_value->preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
void ArrayPairExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_name) {
|
||||
m_name->outputPHP(cg, ar);
|
||||
@@ -141,40 +134,3 @@ void ArrayPairExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_ref) cg_printf("&");
|
||||
m_value->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
void ArrayPairExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
bool keyConverted = false;
|
||||
if (m_name) {
|
||||
keyConverted = outputCPPName(cg, ar);
|
||||
cg_printf(", ");
|
||||
}
|
||||
m_value->outputCPP(cg, ar);
|
||||
if (m_name && keyConverted && !m_collection) {
|
||||
cg_printf(", true");
|
||||
}
|
||||
}
|
||||
|
||||
bool ArrayPairExpression::outputCPPName(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
assert(m_name);
|
||||
ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(m_name);
|
||||
if (sc) {
|
||||
if (sc->isLiteralString()) {
|
||||
string s = sc->getLiteralString();
|
||||
int64 res;
|
||||
if (is_strictly_integer(s.c_str(), s.size(), res)) {
|
||||
cg_printf("%sL", s.c_str());
|
||||
} else {
|
||||
m_name->outputCPP(cg, ar);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (sc->isLiteralInteger()) {
|
||||
m_name->outputCPP(cg, ar);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_name->outputCPP(cg, ar);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,9 +40,6 @@ public:
|
||||
virtual int getLocalEffects() const { return NoEffect; }
|
||||
bool isScalarArrayPair() const;
|
||||
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
|
||||
bool isRef() const { return m_ref; }
|
||||
|
||||
bool canonCompare(ExpressionPtr e) const;
|
||||
@@ -51,8 +48,6 @@ private:
|
||||
ExpressionPtr m_value;
|
||||
bool m_ref;
|
||||
bool m_collection;
|
||||
|
||||
bool outputCPPName(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -301,237 +301,3 @@ void AssignmentExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_ref) cg_printf("&");
|
||||
m_value->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
ExpressionPtr exp, bool ref, bool array, bool varnr) {
|
||||
bool close = false;
|
||||
if (ref) {
|
||||
cg_printf("ref(");
|
||||
close = true;
|
||||
} else if (array && !exp->hasCPPTemp() &&
|
||||
!exp->isTemporary() && !exp->isScalar() &&
|
||||
exp->getActualType() && !exp->getActualType()->isPrimitive() &&
|
||||
exp->getActualType()->getKindOf() != Type::KindOfString) {
|
||||
cg_printf("wrap_variant(");
|
||||
close = true;
|
||||
} else if (varnr && exp->getCPPType()->isExactType()) {
|
||||
bool isScalar = exp->isScalar();
|
||||
if (!isScalar || !Option::UseScalarVariant) {
|
||||
cg_printf("VarNR(");
|
||||
close = true;
|
||||
} else if (isScalar) {
|
||||
assert(!cg.hasScalarVariant());
|
||||
cg.setScalarVariant();
|
||||
}
|
||||
}
|
||||
exp->outputCPP(cg, ar);
|
||||
cg.clearScalarVariant();
|
||||
if (close) cg_printf(")");
|
||||
}
|
||||
|
||||
void AssignmentExpression::preOutputStash(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int state) {
|
||||
if (hasCPPTemp()) return;
|
||||
if (m_value->hasCPPTemp() &&
|
||||
(Type::SameType(getType(), m_value->getType()) ||
|
||||
(Type::IsMappedToVariant(getType()) &&
|
||||
Type::IsMappedToVariant(m_value->getType())))) {
|
||||
setUnused(true);
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(";\n");
|
||||
setCPPTemp(m_value->cppTemp());
|
||||
return;
|
||||
}
|
||||
TypePtr at(getActualType());
|
||||
TypePtr et(getExpectedType());
|
||||
TypePtr it(getImplementedType());
|
||||
if (at && !Type::IsMappedToVariant(at) &&
|
||||
!et && it && Type::IsMappedToVariant(it)) {
|
||||
m_value->preOutputStash(cg, ar, state);
|
||||
if (!m_value->hasCPPTemp()) {
|
||||
// preOutputStash did no work, so we need to
|
||||
// explicitly do a stash
|
||||
TypePtr t(m_value->getType());
|
||||
bool constRef = !t->isPrimitive() &&
|
||||
(m_value->isTemporary() || !m_value->isLocalExprAltered());
|
||||
const string &tmp = m_value->genCPPTemp(cg, ar);
|
||||
if (constRef) cg_printf("const ");
|
||||
t->outputCPPDecl(cg, ar, getScope());
|
||||
const char *ref = constRef ? "&" : "";
|
||||
cg_printf(" %s%s((", ref, tmp.c_str());
|
||||
m_value->outputCPP(cg, ar);
|
||||
cg_printf("));\n");
|
||||
m_value->setCPPTemp(tmp);
|
||||
}
|
||||
assert(m_value->hasCPPTemp());
|
||||
setUnused(true);
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(";\n");
|
||||
setCPPTemp(m_value->cppTemp());
|
||||
return;
|
||||
}
|
||||
return Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (hasContext(RefValue) && !m_ref) {
|
||||
if (!cg.inExpression()) return true;
|
||||
state |= FixOrder | ForceTemp;
|
||||
}
|
||||
if (m_variable->is(Expression::KindOfArrayElementExpression)) {
|
||||
ExpressionPtr exp = m_value;
|
||||
ExpressionPtr vv(
|
||||
static_pointer_cast<ArrayElementExpression>(m_variable)->getVariable());
|
||||
if ((vv->is(KindOfArrayElementExpression) ||
|
||||
vv->is(KindOfObjectPropertyExpression)) &&
|
||||
(vv->getContainedEffects() && (CreateEffect|AccessorEffect))) {
|
||||
/*
|
||||
We are in a case such as
|
||||
$a->b['c'] = ...;
|
||||
$a['b']['c'] = ...;
|
||||
Where evaluating m_variable may modify $a. Unless we can prove that
|
||||
the rhs is not referring to the same thing as $a, we must generate
|
||||
a temporary for it (note that we could do better with the following
|
||||
checks).
|
||||
*/
|
||||
if (!(m_ref && exp->isRefable()) &&
|
||||
!exp->isTemporary() && !exp->isScalar() &&
|
||||
exp->getActualType() && !exp->getActualType()->isPrimitive() &&
|
||||
exp->getActualType()->getKindOf() != Type::KindOfString) {
|
||||
state |= Expression::StashAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
bool AssignmentExpression::SpecialAssignment(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
ExpressionPtr lval,
|
||||
ExpressionPtr rval,
|
||||
const char *rvalStr, bool ref) {
|
||||
if (lval->is(KindOfArrayElementExpression)) {
|
||||
ArrayElementExpressionPtr exp =
|
||||
dynamic_pointer_cast<ArrayElementExpression>(lval);
|
||||
if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
|
||||
exp->getVariable()->outputCPP(cg, ar);
|
||||
if (exp->getOffset()) {
|
||||
cg_printf(".set(");
|
||||
exp->getOffset()->outputCPP(cg, ar);
|
||||
cg_printf(", (");
|
||||
} else {
|
||||
cg_printf(".append((");
|
||||
}
|
||||
if (rval) {
|
||||
wrapValue(cg, ar, rval, ref,
|
||||
(exp->getVariable()->is(KindOfArrayElementExpression) ||
|
||||
exp->getVariable()->is(KindOfObjectPropertyExpression)) &&
|
||||
(exp->getVariable()->getContainedEffects() &&
|
||||
(CreateEffect|AccessorEffect)), true);
|
||||
} else {
|
||||
cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
|
||||
}
|
||||
cg_printf(")");
|
||||
ExpressionPtr off = exp->getOffset();
|
||||
if (off) {
|
||||
ScalarExpressionPtr sc =
|
||||
dynamic_pointer_cast<ScalarExpression>(off);
|
||||
if (sc) {
|
||||
if (sc->isLiteralString()) {
|
||||
String s(sc->getLiteralString());
|
||||
int64 n;
|
||||
if (!s.get()->isStrictlyInteger(n)) {
|
||||
cg_printf(", true"); // skip toKey() at run time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_printf(")");
|
||||
return true;
|
||||
}
|
||||
} else if (lval->is(KindOfObjectPropertyExpression)) {
|
||||
ObjectPropertyExpressionPtr var(
|
||||
dynamic_pointer_cast<ObjectPropertyExpression>(lval));
|
||||
if (!var->isValid()) {
|
||||
bool nonPrivate = var->isNonPrivate(ar);
|
||||
var->outputCPPObject(cg, ar);
|
||||
if (nonPrivate) {
|
||||
cg_printf("o_setPublic(");
|
||||
} else {
|
||||
cg_printf("o_set(");
|
||||
}
|
||||
var->outputCPPProperty(cg, ar);
|
||||
cg_printf(", %s", ref ? "ref(" : "");
|
||||
if (rval) {
|
||||
rval->outputCPP(cg, ar);
|
||||
} else {
|
||||
cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
|
||||
}
|
||||
if (nonPrivate) {
|
||||
cg_printf("%s)", ref ? ")" : "");
|
||||
}
|
||||
else {
|
||||
cg_printf("%s%s)",
|
||||
ref ? ")" : "",
|
||||
lval->originalClassName(cg, true).c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
bool ref = (m_ref && m_value->isRefable());
|
||||
|
||||
bool setNull = false;
|
||||
|
||||
if (SpecialAssignment(cg, ar, m_variable, m_value, nullptr, ref)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_value->isLiteralNull()) {
|
||||
if (m_variable->is(Expression::KindOfSimpleVariable)) {
|
||||
setNull = true;
|
||||
} else {
|
||||
TypePtr t = m_variable->getCPPType();
|
||||
if (t && (t->is(Type::KindOfArray) ||
|
||||
t->is(Type::KindOfObject) ||
|
||||
t->is(Type::KindOfString))) {
|
||||
setNull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wrapped = true;
|
||||
if (setNull) {
|
||||
cg_printf("setNull(");
|
||||
m_variable->outputCPP(cg, ar);
|
||||
} else {
|
||||
if (!m_variable->getCPPType()->isExactType() &&
|
||||
!(m_value->hasCPPTemp() ?
|
||||
m_value->getType() : m_value->getCPPType())->isExactType()) {
|
||||
m_variable->outputCPP(cg, ar);
|
||||
cg_printf(".assign%s(", ref ? "Ref" : "Val");
|
||||
wrapped = true;
|
||||
ref = false;
|
||||
} else {
|
||||
if (m_variable->getCPPType()->isExactType()) {
|
||||
ref = false;
|
||||
}
|
||||
if ((wrapped = !isUnused())) {
|
||||
cg_printf("(");
|
||||
}
|
||||
m_variable->outputCPP(cg, ar);
|
||||
cg_printf(" = ");
|
||||
}
|
||||
|
||||
wrapValue(cg, ar, m_value, ref, false, false);
|
||||
}
|
||||
if (wrapped) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +48,6 @@ public:
|
||||
ExpressionPtr getValue() { return m_value;}
|
||||
void setValue(ExpressionPtr v) { m_value = v; }
|
||||
int getLocalEffects() const;
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
static bool SpecialAssignment(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
ExpressionPtr lval,
|
||||
ExpressionPtr rval,
|
||||
const char *rvalStr, bool ref);
|
||||
|
||||
// $GLOBALS[<literal-string>] = <scalar>;
|
||||
bool isSimpleGlobalAssign(StringData **name, TypedValue *tv) const;
|
||||
|
||||
@@ -284,7 +284,7 @@ ExpressionPtr BinaryOpExpression::simplifyArithmetic(
|
||||
Variant v2;
|
||||
if (m_exp1->getScalarValue(v1)) {
|
||||
if (v1.isInteger()) {
|
||||
int64 ival1 = v1.toInt64();
|
||||
int64_t ival1 = v1.toInt64();
|
||||
// 1 * $a => $a, 0 + $a => $a
|
||||
if ((ival1 == 1 && m_op == '*') || (ival1 == 0 && m_op == '+')) {
|
||||
TypePtr actType2 = m_exp2->getActualType();
|
||||
@@ -317,7 +317,7 @@ ExpressionPtr BinaryOpExpression::simplifyArithmetic(
|
||||
}
|
||||
if (m_exp2->getScalarValue(v2)) {
|
||||
if (v2.isInteger()) {
|
||||
int64 ival2 = v2.toInt64();
|
||||
int64_t ival2 = v2.toInt64();
|
||||
// $a * 1 => $a, $a + 0 => $a
|
||||
if ((ival2 == 1 && m_op == '*') || (ival2 == 0 && m_op == '+')) {
|
||||
TypePtr actType1 = m_exp1->getActualType();
|
||||
@@ -484,8 +484,7 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
|
||||
if (m_exp1->isScalar()) {
|
||||
if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
|
||||
try {
|
||||
if (hhvm &&
|
||||
Option::OutputHHBC &&
|
||||
if (Option::OutputHHBC &&
|
||||
(!Option::WholeProgram || !Option::ParseTimeOpts)) {
|
||||
// In the VM, don't optimize __CLASS__ if within a trait, since
|
||||
// __CLASS__ is not resolved yet.
|
||||
@@ -524,11 +523,11 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
|
||||
case '<':
|
||||
result = less(v1, v2); break;
|
||||
case T_IS_SMALLER_OR_EQUAL:
|
||||
result = not_more(v1, v2); break;
|
||||
result = less_or_equal(v1, v2); break;
|
||||
case '>':
|
||||
result = more(v1, v2); break;
|
||||
case T_IS_GREATER_OR_EQUAL:
|
||||
result = not_less(v1, v2); break;
|
||||
result = more_or_equal(v1, v2); break;
|
||||
case '+':
|
||||
result = plus(v1, v2); break;
|
||||
case '-':
|
||||
@@ -908,284 +907,6 @@ void BinaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_exp2->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
static bool castIfNeeded(TypePtr top, TypePtr arg,
|
||||
CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
BlockScopeRawPtr scope) {
|
||||
if (top) {
|
||||
if (top->isPrimitive()) {
|
||||
if (!arg || !arg->isPrimitive()) {
|
||||
top->outputCPPCast(cg, ar, scope);
|
||||
cg_printf("(");
|
||||
return true;
|
||||
}
|
||||
} else if (top->is(Type::KindOfArray)) {
|
||||
if (arg && arg->isExactType() && !arg->is(Type::KindOfArray)) {
|
||||
cg_printf("((Variant)");
|
||||
return true;
|
||||
}
|
||||
} else if (top->mustBe(Type::KindOfNumeric)) {
|
||||
if (arg && arg->is(Type::KindOfArray)) {
|
||||
cg_printf("((Variant)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BinaryOpExpression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (hasCPPTemp() || isScalar()) return;
|
||||
if (m_op == '.' && (state & FixOrder)) {
|
||||
if (m_exp1) {
|
||||
if (!m_exp1->getActualType() && m_exp1->hasCPPTemp()) {
|
||||
cg_printf("id(%s);\n", m_exp1->cppTemp().c_str());
|
||||
}
|
||||
m_exp1->preOutputStash(cg, ar, state|StashVars);
|
||||
}
|
||||
if (m_exp2) {
|
||||
if (!m_exp2->getActualType() && m_exp2->hasCPPTemp()) {
|
||||
cg_printf("id(%s);\n", m_exp2->cppTemp().c_str());
|
||||
}
|
||||
m_exp2->preOutputStash(cg, ar, state|StashVars);
|
||||
}
|
||||
} else {
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *stringBufferPrefix(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
ExpressionPtr var) {
|
||||
if (var->is(Expression::KindOfSimpleVariable)) {
|
||||
if (LoopStatementPtr loop = cg.getLoopStatement()) {
|
||||
SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(var);
|
||||
if (loop->checkStringBuf(sv->getName())) {
|
||||
return loop->getScope()->getVariables()->
|
||||
getVariablePrefix(sv->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string stringBufferName(const char *temp, const char *prefix,
|
||||
const char *name)
|
||||
{
|
||||
return std::string(temp) + "_sbuf_" + prefix + name;
|
||||
}
|
||||
|
||||
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
|
||||
bool &hasVoid) {
|
||||
if (!exp->hasCPPTemp()) {
|
||||
if (exp->is(Expression::KindOfUnaryOpExpression)) {
|
||||
UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp);
|
||||
if (u->getOp() == '(') {
|
||||
return getConcatList(ev, u->getExpression(), hasVoid);
|
||||
}
|
||||
} else if (exp->is(Expression::KindOfBinaryOpExpression)) {
|
||||
BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp);
|
||||
if (b->getOp() == '.') {
|
||||
if (b->getExp1()->is(Expression::KindOfSimpleVariable) &&
|
||||
b->getExp1()->isLocalExprAltered() &&
|
||||
!b->getExp1()->hasCPPTemp() &&
|
||||
b->getExp2()->hasEffect() &&
|
||||
!b->getExp2()->hasCPPTemp()) {
|
||||
/*
|
||||
In this case, the simple variable must be evaluated
|
||||
after b->getExp2(). But when we output a concat list we
|
||||
explicitly order the expressions from left to right.
|
||||
*/
|
||||
} else {
|
||||
return getConcatList(ev, b->getExp1(), hasVoid) +
|
||||
getConcatList(ev, b->getExp2(), hasVoid);
|
||||
}
|
||||
}
|
||||
} else if (exp->is(Expression::KindOfEncapsListExpression)) {
|
||||
EncapsListExpressionPtr e =
|
||||
static_pointer_cast<EncapsListExpression>(exp);
|
||||
if (e->getType() != '`') {
|
||||
ExpressionListPtr el = e->getExpressions();
|
||||
int num = 0;
|
||||
for (int i = 0, s = el->getCount(); i < s; i++) {
|
||||
ExpressionPtr exp = (*el)[i];
|
||||
num += getConcatList(ev, exp, hasVoid);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
} else if (!exp->getActualType()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev.push_back(exp);
|
||||
bool isVoid = !exp->getActualType();
|
||||
hasVoid |= isVoid;
|
||||
return isVoid ? 0 : 1;
|
||||
}
|
||||
|
||||
static void outputStringExpr(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
ExpressionPtr exp, bool asLitStr) {
|
||||
if (asLitStr && exp->isLiteralString()) {
|
||||
const std::string &s = exp->getLiteralString();
|
||||
std::string enc = string_cplus_escape(s.c_str(), s.size());
|
||||
cg_printf("\"%s\", %d", enc.c_str(), (int)s.size());
|
||||
return;
|
||||
}
|
||||
|
||||
TypePtr et(exp->getExpectedType());
|
||||
exp->setExpectedType(Type::String);
|
||||
exp->outputCPP(cg, ar);
|
||||
exp->setExpectedType(et);
|
||||
}
|
||||
|
||||
static void outputStringBufExprs(ExpressionPtrVec &ev,
|
||||
CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
for (size_t i = 0; i < ev.size(); i++) {
|
||||
ExpressionPtr exp = ev[i];
|
||||
cg_printf(".addWithTaint(");
|
||||
outputStringExpr(cg, ar, exp, true);
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
bool BinaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (isOpEqual() && (m_exp1->is(KindOfArrayElementExpression) ||
|
||||
m_exp1->is(KindOfObjectPropertyExpression))) {
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
bool effect2 = m_exp2->hasEffect();
|
||||
const char *prefix = 0;
|
||||
if (effect2 || m_exp1->hasEffect()) {
|
||||
ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
|
||||
ExpressionPtrVec ev;
|
||||
bool hasVoid = false;
|
||||
int numConcat = 0;
|
||||
bool ok = false;
|
||||
if (m_op == '.') {
|
||||
numConcat = getConcatList(ev, self, hasVoid);
|
||||
ok = hasVoid || (numConcat > MAX_CONCAT_ARGS);
|
||||
} else if (effect2 && m_op == T_CONCAT_EQUAL) {
|
||||
prefix = stringBufferPrefix(cg, ar, m_exp1);
|
||||
ok = prefix;
|
||||
if (!ok) {
|
||||
if (m_exp1->is(KindOfSimpleVariable)) {
|
||||
ok = true;
|
||||
ev.push_back(m_exp1);
|
||||
numConcat++;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
numConcat += getConcatList(ev, m_exp2, hasVoid);
|
||||
if (numConcat <= 2 && !prefix) {
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (!cg.inExpression()) return true;
|
||||
|
||||
cg.wrapExpressionBegin();
|
||||
std::string buf;
|
||||
if (prefix) {
|
||||
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(m_exp1));
|
||||
buf = stringBufferName(Option::TempPrefix, prefix,
|
||||
sv->getName().c_str());
|
||||
m_cppTemp = "/**/";
|
||||
} else if (numConcat) {
|
||||
buf = m_cppTemp = genCPPTemp(cg, ar);
|
||||
buf += "_buf";
|
||||
if (numConcat > 1) {
|
||||
cg_printf("StringBuffer %s;\n", buf.c_str());
|
||||
}
|
||||
} else {
|
||||
m_cppTemp = "\"\"";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ev.size(); i++) {
|
||||
ExpressionPtr exp = ev[i];
|
||||
bool is_void = !exp->getActualType();
|
||||
exp->preOutputCPP(cg, ar, 0);
|
||||
if (!is_void) {
|
||||
bool asLit = true;
|
||||
if (numConcat > 1 || prefix) {
|
||||
cg_printf("%s.appendWithTaint(", buf.c_str());
|
||||
} else {
|
||||
asLit = false;
|
||||
cg_printf("CStrRef %s = (", m_cppTemp.c_str());
|
||||
}
|
||||
outputStringExpr(cg, ar, exp, asLit);
|
||||
cg_printf(")");
|
||||
} else {
|
||||
exp->outputCPPUnneeded(cg, ar);
|
||||
}
|
||||
cg_printf(";\n");
|
||||
}
|
||||
|
||||
if (numConcat > 1 && !prefix) {
|
||||
cg_printf("CStrRef %s(%s.detachWithTaint());\n",
|
||||
m_cppTemp.c_str(), buf.c_str());
|
||||
if (m_op == T_CONCAT_EQUAL) {
|
||||
m_exp1->outputCPP(cg, ar);
|
||||
cg_printf(" = %s;\n", m_cppTemp.c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isShortCircuitOperator()) {
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
if (!effect2) {
|
||||
bool ret = m_exp1->preOutputCPP(cg, ar, 0);
|
||||
if (state & FixOrder) {
|
||||
ret = true;
|
||||
if (cg.inExpression()) {
|
||||
preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool fix_e1 = m_exp1->preOutputCPP(cg, ar, 0);
|
||||
if (!cg.inExpression()) {
|
||||
return fix_e1 || m_exp2->preOutputCPP(cg, ar, 0);
|
||||
}
|
||||
|
||||
cg.setInExpression(false);
|
||||
bool fix_e2 = m_exp2->preOutputCPP(cg, ar, 0);
|
||||
cg.setInExpression(true);
|
||||
|
||||
if (fix_e2) {
|
||||
cg.wrapExpressionBegin();
|
||||
std::string tmp = genCPPTemp(cg, ar);
|
||||
cg_printf("bool %s = (", tmp.c_str());
|
||||
m_exp1->outputCPP(cg, ar);
|
||||
cg_printf(");\n");
|
||||
cg_indentBegin("if (%s%s) {\n",
|
||||
m_op == T_LOGICAL_OR || m_op == T_BOOLEAN_OR ? "!" : "",
|
||||
tmp.c_str());
|
||||
m_exp2->preOutputCPP(cg, ar, 0);
|
||||
if (isUnused()) {
|
||||
if (m_exp2->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
|
||||
} else {
|
||||
cg_printf("%s = (", tmp.c_str());
|
||||
m_exp2->outputCPP(cg, ar);
|
||||
cg_printf(");\n");
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
m_cppTemp = tmp;
|
||||
} else if (state & FixOrder) {
|
||||
preOutputStash(cg, ar, state);
|
||||
fix_e1 = true;
|
||||
}
|
||||
return fix_e1 || fix_e2;
|
||||
}
|
||||
|
||||
bool BinaryOpExpression::isOpEqual() {
|
||||
switch (m_op) {
|
||||
case T_CONCAT_EQUAL:
|
||||
@@ -1206,291 +927,3 @@ bool BinaryOpExpression::isOpEqual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BinaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_exp1->is(Expression::KindOfArrayElementExpression)) {
|
||||
ArrayElementExpressionPtr exp =
|
||||
dynamic_pointer_cast<ArrayElementExpression>(m_exp1);
|
||||
if (exp->isSuperGlobal() || exp->isDynamicGlobal()) return false;
|
||||
if (TypePtr t = exp->getVariable()->getActualType()) {
|
||||
TypePtr it(exp->getVariable()->getImplementedType());
|
||||
if (t->is(Type::KindOfArray) &&
|
||||
(!it ||
|
||||
it->is(Type::KindOfArray) ||
|
||||
Type::IsMappedToVariant(it) /* fast cast will kick in */)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// turning $a['elem'] Op= $b into $a.setOpEqual('elem', $b);
|
||||
exp->getVariable()->outputCPP(cg, ar);
|
||||
if (exp->getOffset()) {
|
||||
cg_printf(".setOpEqual(%d, ", m_op);
|
||||
exp->getOffset()->outputCPP(cg, ar);
|
||||
cg_printf(", (");
|
||||
} else {
|
||||
cg_printf(".appendOpEqual(%d, (", m_op);
|
||||
}
|
||||
m_exp2->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
ExpressionPtr off = exp->getOffset();
|
||||
if (off) {
|
||||
ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(off);
|
||||
if (sc) {
|
||||
if (sc->isLiteralString()) {
|
||||
String s(sc->getLiteralString());
|
||||
int64 n;
|
||||
if (!s.get()->isStrictlyInteger(n)) {
|
||||
cg_printf(", true"); // skip toKey() at run time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_printf(")");
|
||||
|
||||
return true;
|
||||
}
|
||||
if (m_exp1->is(Expression::KindOfObjectPropertyExpression)) {
|
||||
ObjectPropertyExpressionPtr var(
|
||||
dynamic_pointer_cast<ObjectPropertyExpression>(m_exp1));
|
||||
if (var->isValid()) return false;
|
||||
var->outputCPPObject(cg, ar);
|
||||
cg_printf("o_assign_op<%s,%d>(",
|
||||
isUnused() ? "void" : "Variant", m_op);
|
||||
var->outputCPPProperty(cg, ar);
|
||||
cg_printf(", ");
|
||||
m_exp2->outputCPP(cg, ar);
|
||||
cg_printf("%s)", originalClassName(cg, true).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
|
||||
if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return;
|
||||
|
||||
bool wrapped = true;
|
||||
switch (m_op) {
|
||||
case T_CONCAT_EQUAL:
|
||||
if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) {
|
||||
SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1);
|
||||
if (m_exp2->hasCPPTemp()) {
|
||||
cg_printf("%s.appendWithTaint(%s)",
|
||||
stringBufferName(Option::TempPrefix, prefix,
|
||||
sv->getName().c_str()).c_str(),
|
||||
m_exp2->cppTemp().c_str());
|
||||
return;
|
||||
} else {
|
||||
ExpressionPtrVec ev;
|
||||
bool hasVoid = false;
|
||||
getConcatList(ev, m_exp2, hasVoid);
|
||||
if (!hasVoid) {
|
||||
cg_printf("%s", stringBufferName(Option::TempPrefix, prefix,
|
||||
sv->getName().c_str()).c_str());
|
||||
outputStringBufExprs(ev, cg, ar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_printf("concat_assign");
|
||||
break;
|
||||
case '.':
|
||||
{
|
||||
ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
|
||||
ExpressionPtrVec ev;
|
||||
bool hasVoid = false;
|
||||
int num = getConcatList(ev, self, hasVoid);
|
||||
if (num < 2) {
|
||||
cg_printf("concat");
|
||||
break;
|
||||
}
|
||||
always_assert(!hasVoid);
|
||||
if (num <= MAX_CONCAT_ARGS) {
|
||||
if (num == 2) {
|
||||
cg_printf("concat(");
|
||||
} else {
|
||||
if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num);
|
||||
cg_printf("concat%d(", num);
|
||||
}
|
||||
for (size_t i = 0; i < ev.size(); i++) {
|
||||
ExpressionPtr exp = ev[i];
|
||||
if (i) cg_printf(", ");
|
||||
outputStringExpr(cg, ar, exp, false);
|
||||
}
|
||||
cg_printf(")");
|
||||
} else {
|
||||
cg_printf("StringBuffer()");
|
||||
outputStringBufExprs(ev, cg, ar);
|
||||
cg_printf(".detachWithTaint()");
|
||||
}
|
||||
}
|
||||
return;
|
||||
case T_LOGICAL_XOR: cg_printf("logical_xor"); break;
|
||||
case '|': cg_printf("bitwise_or"); break;
|
||||
case '&': cg_printf("bitwise_and"); break;
|
||||
case '^': cg_printf("bitwise_xor"); break;
|
||||
case T_IS_IDENTICAL: cg_printf("same"); break;
|
||||
case T_IS_NOT_IDENTICAL: cg_printf("!same"); break;
|
||||
case T_IS_EQUAL: cg_printf("equal"); break;
|
||||
case T_IS_NOT_EQUAL: cg_printf("!equal"); break;
|
||||
case '<': cg_printf("less"); break;
|
||||
case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break;
|
||||
case '>': cg_printf("more"); break;
|
||||
case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break;
|
||||
case '/': cg_printf("divide"); break;
|
||||
case '%': cg_printf("modulo"); break;
|
||||
case T_INSTANCEOF: cg_printf("instanceOf"); break;
|
||||
case T_COLLECTION: cg_printf("Object"); break;
|
||||
default:
|
||||
wrapped = !isUnused();
|
||||
break;
|
||||
}
|
||||
|
||||
if (wrapped) cg_printf("(");
|
||||
|
||||
ExpressionPtr first = m_exp1;
|
||||
ExpressionPtr second = m_exp2;
|
||||
|
||||
// we could implement these functions natively on String and Array classes
|
||||
switch (m_op) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
if (!first->outputCPPArithArg(cg, ar, m_op == '+')) {
|
||||
TypePtr argType = first->hasCPPTemp() ?
|
||||
first->getType() : first->getActualType();
|
||||
bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
|
||||
first->outputCPP(cg, ar);
|
||||
if (flag) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_SL:
|
||||
case T_SR:
|
||||
assert(first->getType()->is(Type::KindOfInt64));
|
||||
first->outputCPP(cg, ar);
|
||||
break;
|
||||
case T_COLLECTION:
|
||||
/* do nothing */
|
||||
break;
|
||||
default:
|
||||
first->outputCPP(cg, ar);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (m_op) {
|
||||
case T_PLUS_EQUAL: cg_printf(" += "); break;
|
||||
case T_MINUS_EQUAL: cg_printf(" -= "); break;
|
||||
case T_MUL_EQUAL: cg_printf(" *= "); break;
|
||||
case T_DIV_EQUAL: cg_printf(" /= "); break;
|
||||
case T_MOD_EQUAL: cg_printf(" %%= "); break;
|
||||
case T_AND_EQUAL: cg_printf(" &= "); break;
|
||||
case T_OR_EQUAL: cg_printf(" |= "); break;
|
||||
case T_XOR_EQUAL: cg_printf(" ^= "); break;
|
||||
case T_SL_EQUAL: cg_printf(" <<= "); break;
|
||||
case T_SR_EQUAL: cg_printf(" >>= "); break;
|
||||
case T_BOOLEAN_OR: cg_printf(" || "); break;
|
||||
case T_BOOLEAN_AND: cg_printf(" && "); break;
|
||||
case T_LOGICAL_OR: cg_printf(" || "); break;
|
||||
case T_LOGICAL_AND: cg_printf(" && "); break;
|
||||
case T_COLLECTION: /* print nothing */ break;
|
||||
default:
|
||||
switch (m_op) {
|
||||
case '+': cg_printf(" + "); break;
|
||||
case '-': cg_printf(" - "); break;
|
||||
case '*': cg_printf(" * "); break;
|
||||
case T_SL: cg_printf(" << "); break;
|
||||
case T_SR: cg_printf(" >> "); break;
|
||||
default:
|
||||
cg_printf(", ");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (m_op) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
if (!second->outputCPPArithArg(cg, ar, m_op == '+')) {
|
||||
TypePtr argType = second->hasCPPTemp() ?
|
||||
second->getType() : second->getActualType();
|
||||
bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
|
||||
second->outputCPP(cg, ar);
|
||||
if (flag) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_INSTANCEOF:
|
||||
{
|
||||
if (second->isScalar()) {
|
||||
ScalarExpressionPtr scalar =
|
||||
dynamic_pointer_cast<ScalarExpression>(second);
|
||||
bool notQuoted = scalar && !scalar->isQuoted();
|
||||
std::string s = second->getLiteralString();
|
||||
if (s == "static" && notQuoted) {
|
||||
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
|
||||
} else if (s != "") {
|
||||
if (s == "self" && notQuoted) {
|
||||
ClassScopeRawPtr cls = getOriginalClass();
|
||||
if (cls) {
|
||||
s = cls->getOriginalName();
|
||||
}
|
||||
} else if (s == "parent" && notQuoted) {
|
||||
ClassScopeRawPtr cls = getOriginalClass();
|
||||
if (cls && !cls->getOriginalParent().empty()) {
|
||||
s = cls->getOriginalParent();
|
||||
}
|
||||
}
|
||||
cg_printString(s, ar, shared_from_this());
|
||||
} else {
|
||||
second->outputCPP(cg, ar);
|
||||
}
|
||||
} else {
|
||||
second->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_PLUS_EQUAL:
|
||||
case T_MINUS_EQUAL:
|
||||
case T_MUL_EQUAL:
|
||||
{
|
||||
TypePtr t1 = first->getCPPType();
|
||||
TypePtr t2 = second->getType();
|
||||
if (t1 && !t1->is(Type::KindOfArray) &&
|
||||
t2 && Type::IsCastNeeded(ar, t2, t1)) {
|
||||
t1->outputCPPCast(cg, ar, getScope());
|
||||
cg_printf("(");
|
||||
second->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
} else {
|
||||
second->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_BOOLEAN_OR:
|
||||
case T_BOOLEAN_AND:
|
||||
case T_LOGICAL_AND:
|
||||
case T_LOGICAL_OR:
|
||||
if (isUnused()) {
|
||||
cg_printf("(");
|
||||
if (second->outputCPPUnneeded(cg, ar)) {
|
||||
cg_printf(",");
|
||||
}
|
||||
cg_printf("false)");
|
||||
} else {
|
||||
second->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
second->outputCPP(cg, ar);
|
||||
}
|
||||
|
||||
if (wrapped) cg_printf(")");
|
||||
}
|
||||
|
||||
@@ -51,13 +51,6 @@ public:
|
||||
virtual ExpressionPtr unneededHelper();
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
|
||||
bool outputCPPImplOpEqual(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
static int getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
|
||||
bool &hasVoid);
|
||||
bool isAssignmentOp() const { return m_assign; }
|
||||
|
||||
@@ -199,7 +199,7 @@ TypePtr ClassConstantExpression::inferTypes(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
unsigned ClassConstantExpression::getCanonHash() const {
|
||||
int64 val =
|
||||
int64_t val =
|
||||
hash_string(Util::toLower(m_varName).c_str(), m_varName.size()) -
|
||||
hash_string(Util::toLower(m_className).c_str(), m_className.size());
|
||||
return ~unsigned(val) ^ unsigned(val >> 32);
|
||||
@@ -225,79 +225,3 @@ bool ClassConstantExpression::isDynamic() const {
|
||||
if (!m_valid) return true;
|
||||
return m_defScope->getConstants()->isDynamic(m_varName);
|
||||
}
|
||||
|
||||
void ClassConstantExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_class) {
|
||||
cg_printf("get_class_constant(");
|
||||
if (m_class->is(KindOfScalarExpression)) {
|
||||
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
|
||||
getString().c_str(), "static") == 0);
|
||||
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
|
||||
} else {
|
||||
cg_printf("get_static_class_name(");
|
||||
m_class->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(", \"%s\")", m_varName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
bool outsideClass = !isPresent();
|
||||
if (m_valid) {
|
||||
string trueClassName;
|
||||
|
||||
assert(m_defScope);
|
||||
ClassScope *cls = dynamic_cast<ClassScope*>(m_defScope);
|
||||
trueClassName = cls->getName();
|
||||
assert(!trueClassName.empty());
|
||||
if (outsideClass) {
|
||||
cls->outputVolatileCheckBegin(cg, ar, getScope(), m_origClassName);
|
||||
}
|
||||
if (cls->getConstants()->isDynamic(m_varName)) {
|
||||
cg_printf("%s%s->lazy_initializer(%s)->",
|
||||
Option::ClassStaticsCallbackPrefix, cls->getId().c_str(),
|
||||
cg.getGlobals(ar));
|
||||
if (cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedClassFullHeader(ClassScopeRawPtr(cls));
|
||||
} else {
|
||||
getFileScope()->addUsedClassFullHeader(ClassScopeRawPtr(cls));
|
||||
}
|
||||
}
|
||||
} else if (cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedClassConstHeader(ClassScopeRawPtr(cls),
|
||||
m_varName);
|
||||
} else {
|
||||
getFileScope()->addUsedClassConstHeader(ClassScopeRawPtr(cls),
|
||||
m_varName);
|
||||
}
|
||||
}
|
||||
cg_printf("%s%s%s%s",
|
||||
Option::ClassConstantPrefix, cls->getId().c_str(),
|
||||
Option::IdPrefix.c_str(), m_varName.c_str());
|
||||
if (outsideClass) {
|
||||
cls->outputVolatileCheckEnd(cg);
|
||||
}
|
||||
} else if (isRedeclared()) {
|
||||
if (outsideClass) {
|
||||
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(), m_origClassName);
|
||||
}
|
||||
const string &clsName = CodeGenerator::FormatLabel(m_className);
|
||||
cg_printf("%s->%s%s->os_constant(\"%s\")", cg.getGlobals(ar),
|
||||
Option::ClassStaticsCallbackPrefix,
|
||||
clsName.c_str(), m_varName.c_str());
|
||||
if (outsideClass) {
|
||||
ClassScope::OutputVolatileCheckEnd(cg);
|
||||
}
|
||||
} else if (m_defScope) { // !m_valid && m_defScope -> derives from redeclaring
|
||||
cg_printf("%s%s->os_constant(\"%s\")",
|
||||
Option::ClassStaticsCallbackPrefix, m_defScope->getId().c_str(),
|
||||
m_varName.c_str());
|
||||
} else {
|
||||
cg_printf("throw_fatal(\"unknown class constant %s::%s\")",
|
||||
CodeGenerator::EscapeLabel(m_className).c_str(),
|
||||
m_varName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <compiler/expression/expression_list.h>
|
||||
#include <compiler/expression/simple_variable.h>
|
||||
#include <compiler/statement/function_statement.h>
|
||||
#include <compiler/statement/static_statement.h>
|
||||
#include <compiler/analysis/variable_table.h>
|
||||
#include <compiler/analysis/function_scope.h>
|
||||
#include <compiler/analysis/file_scope.h>
|
||||
@@ -151,9 +152,6 @@ void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
return;
|
||||
}
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
|
||||
if (m_func->getFileScope() != getFileScope()) {
|
||||
getFileScope()->addUsedClosure(m_func->getFunctionScope());
|
||||
}
|
||||
// closure function's variable table (not containing function's)
|
||||
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
@@ -232,6 +230,34 @@ TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
return s_ClosureType;
|
||||
}
|
||||
|
||||
bool ClosureExpression::hasStaticLocals() {
|
||||
ConstructPtr cons(m_func);
|
||||
return hasStaticLocalsImpl(cons);
|
||||
}
|
||||
|
||||
bool ClosureExpression::hasStaticLocalsImpl(ConstructPtr root) {
|
||||
if (!root) {
|
||||
return false;
|
||||
}
|
||||
if (root->getFunctionScope() != m_func->getFunctionScope()) {
|
||||
// new scope, new statics
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < root->getKidCount(); i++) {
|
||||
ConstructPtr cons = root->getNthKid(i);
|
||||
if (StatementPtr s = dynamic_pointer_cast<Statement>(cons)) {
|
||||
if (s->is(Statement::KindOfStaticStatement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (hasStaticLocalsImpl(cons)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
@@ -244,75 +270,3 @@ void ClosureExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
m_func->outputPHPBody(cg, ar);
|
||||
}
|
||||
|
||||
bool ClosureExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
FunctionScopeRawPtr cfunc(m_func->getFunctionScope());
|
||||
bool output = false;
|
||||
for (BlockScopePtr sc = cfunc->getOuterScope(); sc;
|
||||
sc = sc->getOuterScope()) {
|
||||
if (sc->is(BlockScope::ClassScope)) {
|
||||
ClassScopePtr cls = boost::static_pointer_cast<ClassScope>(sc);
|
||||
if (cls->isTrait()) {
|
||||
output = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cg.inExpression()) {
|
||||
return output || Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
if (output) {
|
||||
cg.wrapExpressionBegin();
|
||||
cfunc->outputCPPPreface(cg, ar);
|
||||
}
|
||||
return Expression::preOutputCPP(cg, ar, state) || output;
|
||||
}
|
||||
|
||||
void ClosureExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
|
||||
|
||||
FunctionScopeRawPtr cfunc(m_func->getFunctionScope());
|
||||
VariableTablePtr vt(cfunc->getVariables());
|
||||
ParameterExpressionPtrIdxPairVec useVars;
|
||||
bool needsAnonCls = cfunc->needsAnonClosureClass(useVars);
|
||||
|
||||
const string &origName = m_func->getOriginalName();
|
||||
|
||||
if (needsAnonCls) {
|
||||
cg_printf("%sClosure$%s(NEWOBJ(%sClosure$%s)(&%s%s, \"%s\"",
|
||||
Option::SmartPtrPrefix, origName.c_str(),
|
||||
Option::ClassPrefix, origName.c_str(),
|
||||
Option::CallInfoPrefix, origName.c_str(),
|
||||
origName.c_str());
|
||||
} else {
|
||||
// no use vars, so can use the generic closure
|
||||
cg_printf("%sClosure(NEWOBJ(%sClosure)(&%s%s, \"%s\"",
|
||||
Option::SmartPtrPrefix, Option::ClassPrefix,
|
||||
Option::CallInfoPrefix, origName.c_str(),
|
||||
origName.c_str());
|
||||
}
|
||||
|
||||
bool hasEmit = false;
|
||||
if (needsAnonCls) {
|
||||
if (!useVars.empty()) cg_printf(", ");
|
||||
BOOST_FOREACH(ParameterExpressionPtrIdxPair paramPair, useVars) {
|
||||
ParameterExpressionPtr param(paramPair.first);
|
||||
ExpressionPtr value((*m_values)[paramPair.second]);
|
||||
if (!hasEmit) hasEmit = true;
|
||||
else cg_printf(", ");
|
||||
bool ref = param->isRef() && value->isRefable();
|
||||
if (ref) {
|
||||
value->setContext(NoRefWrapper);
|
||||
cg_printf("strongBind(");
|
||||
}
|
||||
value->outputCPP(cg, ar);
|
||||
if (ref) cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
cg_printf("))");
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
FunctionStatementPtr func, ExpressionListPtr vars);
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
|
||||
virtual ConstructPtr getNthKid(int n) const;
|
||||
virtual void setNthKid(int n, ConstructPtr cp);
|
||||
@@ -41,12 +40,16 @@ public:
|
||||
FunctionStatementPtr getClosureFunction() { return m_func; }
|
||||
ExpressionListPtr getClosureVariables() { return m_vars; }
|
||||
ExpressionListPtr getClosureValues() { return m_values; }
|
||||
bool hasStaticLocals();
|
||||
|
||||
private:
|
||||
FunctionStatementPtr m_func;
|
||||
ExpressionListPtr m_vars;
|
||||
ExpressionListPtr m_values;
|
||||
|
||||
static TypePtr s_ClosureType;
|
||||
|
||||
bool hasStaticLocalsImpl(ConstructPtr root);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -100,7 +100,7 @@ bool ConstantExpression::getScalarValue(Variant &value) {
|
||||
}
|
||||
|
||||
unsigned ConstantExpression::getCanonHash() const {
|
||||
int64 val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
|
||||
int64_t val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
|
||||
return ~unsigned(val) ^ unsigned(val >> 32);
|
||||
}
|
||||
|
||||
@@ -285,57 +285,3 @@ TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
void ConstantExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("%s", m_name.c_str());
|
||||
}
|
||||
|
||||
void ConstantExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
// special cases: STDIN, STDOUT, STDERR, INF, and NAN
|
||||
if (m_name == "STDIN" || m_name == "STDOUT" || m_name == "STDERR") {
|
||||
cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_name == "INF" || m_name == "NAN") {
|
||||
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
|
||||
cg_printf("%s_varNR", m_name.c_str());
|
||||
} else {
|
||||
cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
string lower = Util::toLower(m_name);
|
||||
bool requireFwDeclaration = false;
|
||||
if (lower == "true" || lower == "false" || lower == "null") {
|
||||
if (cg.hasScalarVariant()) {
|
||||
cg_printf((Option::UseScalarVariant ? "%s_varNR" : "%s"), lower.c_str());
|
||||
} else {
|
||||
cg_printf("%s", lower.c_str());
|
||||
}
|
||||
} else if (m_valid) {
|
||||
if (m_dynamic) {
|
||||
cg_printf("getDynamicConstant(%s->%s%s, ",
|
||||
cg.getGlobals(ar), Option::ConstantPrefix,
|
||||
CodeGenerator::FormatLabel(m_name).c_str());
|
||||
cg_printString(m_name, ar, shared_from_this());
|
||||
cg_printf(")");
|
||||
} else {
|
||||
cg_printf("%s%s", Option::ConstantPrefix,
|
||||
CodeGenerator::FormatLabel(m_name).c_str());
|
||||
requireFwDeclaration = true;
|
||||
}
|
||||
} else {
|
||||
cg_printf("getUndefinedConstant(");
|
||||
cg_printString(CodeGenerator::FormatLabel(m_name).c_str(), ar,
|
||||
shared_from_this());
|
||||
cg_printf(")");
|
||||
requireFwDeclaration = true;
|
||||
}
|
||||
|
||||
if (requireFwDeclaration && cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedConstHeader(m_name);
|
||||
} else {
|
||||
getFileScope()->addUsedConstHeader(m_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
const std::string &getDocComment() const {
|
||||
return m_docComment;
|
||||
}
|
||||
|
||||
bool isNull() const;
|
||||
bool isBoolean() const;
|
||||
bool isDouble() const;
|
||||
|
||||
@@ -120,8 +120,6 @@ TypePtr DynamicFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
outputLineMap(cg, ar);
|
||||
|
||||
if (m_class || !m_className.empty()) {
|
||||
StaticClassName::outputPHP(cg, ar);
|
||||
cg_printf("::");
|
||||
@@ -144,172 +142,3 @@ void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_params) m_params->outputPHP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
bool DynamicFunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
bool nonStatic = !m_class && m_className.empty();
|
||||
if (!nonStatic && !m_class && !m_classScope && !isRedeclared()) {
|
||||
// call to an unknown class
|
||||
// set m_noStatic to avoid pointlessly wrapping the call
|
||||
// in STATIC_CLASS_NAME_CALL()
|
||||
m_noStatic = true;
|
||||
cg.pushCallInfo(-1);
|
||||
bool ret = FunctionCall::preOutputCPP(cg, ar, state);
|
||||
cg.popCallInfo();
|
||||
return ret;
|
||||
}
|
||||
// Short circuit out if inExpression() returns false
|
||||
if (!cg.inExpression()) return true;
|
||||
|
||||
cg.wrapExpressionBegin();
|
||||
|
||||
m_ciTemp = cg.createNewLocalId(shared_from_this());
|
||||
|
||||
if (!m_classScope && !m_className.empty() && m_cppTemp.empty() &&
|
||||
!isSelf() && ! isParent() && !isStatic()) {
|
||||
// Create a temporary to hold the class name, in case it is not a
|
||||
// StaticString.
|
||||
m_clsNameTemp = cg.createNewLocalId(shared_from_this());
|
||||
cg_printf("CStrRef clsName%d(", m_clsNameTemp);
|
||||
cg_printString(m_origClassName, ar, shared_from_this());
|
||||
cg_printf(");\n");
|
||||
}
|
||||
|
||||
if (m_class) {
|
||||
int s = m_class->hasEffect() || m_nameExp->hasEffect() ?
|
||||
FixOrder : 0;
|
||||
m_class->preOutputCPP(cg, ar, s);
|
||||
}
|
||||
m_nameExp->preOutputCPP(cg, ar, 0);
|
||||
|
||||
if (nonStatic) {
|
||||
cg_printf("const CallInfo *cit%d;\n", m_ciTemp);
|
||||
cg_printf("void *vt%d;\n", m_ciTemp);
|
||||
cg_printf("get_call_info_or_fail(cit%d, vt%d, ", m_ciTemp, m_ciTemp);
|
||||
|
||||
if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
} else {
|
||||
cg_printf("(");
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(");\n");
|
||||
} else {
|
||||
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
|
||||
if (m_class) {
|
||||
if (m_class->is(KindOfScalarExpression)) {
|
||||
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
|
||||
getString().c_str(), "static") == 0);
|
||||
cg_printf("CStrRef cls%d = "
|
||||
"FrameInjection::GetStaticClassName(fi.getThreadInfo())",
|
||||
m_ciTemp);
|
||||
} else {
|
||||
cg_printf("C%sRef cls%d = ",
|
||||
m_class->getActualType() &&
|
||||
m_class->getActualType()->is(Type::KindOfString) ?
|
||||
"Str" : "Var", m_ciTemp);
|
||||
m_class->outputCPP(cg, ar);
|
||||
}
|
||||
} else if (m_classScope) {
|
||||
cg_printf("CStrRef cls%d = ", m_ciTemp);
|
||||
cg_printString(m_classScope->getId(), ar, shared_from_this());
|
||||
} else {
|
||||
cg_printf("CStrRef cls%d = ", m_ciTemp);
|
||||
cg_printString(m_className, ar, shared_from_this());
|
||||
}
|
||||
cg_printf(";\n");
|
||||
|
||||
cg_printf("CStrRef mth%d = ", m_ciTemp);
|
||||
if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
} else {
|
||||
cg_printf("(");
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(";\n");
|
||||
|
||||
bool dynamic = true;
|
||||
if (!m_class) {
|
||||
ClassScopeRawPtr origClass = getOriginalClass();
|
||||
if (!origClass) {
|
||||
dynamic = false;
|
||||
} else {
|
||||
FunctionScopeRawPtr origFunc = getOriginalFunction();
|
||||
if (origFunc) {
|
||||
if (origFunc->isStatic() ||
|
||||
(m_classScope != origClass &&
|
||||
(m_className.empty() || !origClass->derivesFrom(
|
||||
ar, m_className, true, true)))) {
|
||||
dynamic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic) {
|
||||
if ((m_class && (!m_class->getActualType() ||
|
||||
!m_class->getActualType()->is(Type::KindOfString))) ||
|
||||
!getOriginalFunction() ||
|
||||
!getOriginalClass() ||
|
||||
getOriginalFunction()->isStatic()) {
|
||||
cg_printf("mcp%d.dynamicNamedCall(cls%d, mth%d);\n",
|
||||
m_ciTemp, m_ciTemp, m_ciTemp);
|
||||
} else {
|
||||
cg_printf("mcp%d.isObj = true;\n", m_ciTemp);
|
||||
cg_printf("mcp%d.rootObj = this;\n", m_ciTemp);
|
||||
cg_printf("mcp%d.name = &mth%d;\n", m_ciTemp, m_ciTemp);
|
||||
cg_printf("o_get_call_info_ex(cls%d, mcp%d);\n", m_ciTemp, m_ciTemp);
|
||||
}
|
||||
} else {
|
||||
cg_printf("mcp%d.staticMethodCall(cls%d, mth%d);\n",
|
||||
m_ciTemp,
|
||||
m_ciTemp, m_ciTemp);
|
||||
|
||||
if (m_classScope) {
|
||||
cg_printf("%s%s.%sget_call_info(mcp%d);\n",
|
||||
Option::ClassStaticsCallbackPrefix,
|
||||
m_classScope->getId().c_str(),
|
||||
Option::ObjectStaticPrefix, m_ciTemp);
|
||||
} else if (isRedeclared()) {
|
||||
cg_printf("g->%s%s->%sget_call_info(mcp%d);\n",
|
||||
Option::ClassStaticsCallbackPrefix, m_className.c_str(),
|
||||
Option::ObjectStaticPrefix, m_ciTemp);
|
||||
} else {
|
||||
not_reached();
|
||||
}
|
||||
}
|
||||
cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp);
|
||||
}
|
||||
|
||||
if (m_params && m_params->getCount() > 0) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
m_params->preOutputCPP(cg, ar, 0);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
if (state & FixOrder) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
preOutputStash(cg, ar, state);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DynamicFunctionCall::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
bool method = false;
|
||||
if (m_class || !m_className.empty()) {
|
||||
if (!m_class && !m_classScope && !isRedeclared()) {
|
||||
const string &name = CodeGenerator::EscapeLabel(m_className);
|
||||
cg_printf("throw_fatal(\"unknown class %s\")", name.c_str());
|
||||
return;
|
||||
}
|
||||
method = true;
|
||||
}
|
||||
|
||||
cg_printf("(cit%d->", m_ciTemp);
|
||||
outputDynamicCall(cg, ar, method);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -95,9 +95,3 @@ void DynamicVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_exp->outputPHP(cg, ar);
|
||||
cg_printf("}");
|
||||
}
|
||||
|
||||
void DynamicVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("variables->get(");
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
@@ -136,55 +136,3 @@ void EncapsListExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
|
||||
if (m_type == '`') cg_printf(")");
|
||||
}
|
||||
|
||||
static void outputListElement(ExpressionPtr exp, CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (exp->is(Expression::KindOfScalarExpression)) {
|
||||
TypePtr actType = exp->getActualType();
|
||||
bool str = actType && actType->is(Type::KindOfString);
|
||||
if (!str) cg_printf("toString(");
|
||||
exp->outputCPP(cg, ar);
|
||||
if (!str) cg_printf(")");
|
||||
} else {
|
||||
exp->outputCPP(cg, ar);
|
||||
}
|
||||
}
|
||||
|
||||
void EncapsListExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_type == '`') cg_printf("f_shell_exec(");
|
||||
|
||||
if (m_exps) {
|
||||
int n = m_exps->getCount();
|
||||
always_assert(n > 0);
|
||||
if (n == 1) {
|
||||
ExpressionPtr exp = (*m_exps)[0];
|
||||
outputListElement(exp, cg, ar);
|
||||
} else if (n <= MAX_CONCAT_ARGS) {
|
||||
if (n == 2) {
|
||||
cg_printf("concat(");
|
||||
} else {
|
||||
cg_printf("concat%d(", n);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
ExpressionPtr exp = (*m_exps)[i];
|
||||
if (i > 0) cg_printf(", ");
|
||||
outputListElement(exp, cg, ar);
|
||||
}
|
||||
cg_printf(")");
|
||||
} else {
|
||||
cg_printf("StringBuffer()");
|
||||
for (int i = 0; i < n; i++) {
|
||||
ExpressionPtr exp = (*m_exps)[i];
|
||||
cg_printf(".addWithTaint(");
|
||||
outputListElement(exp, cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(".detachWithTaint()");
|
||||
}
|
||||
} else {
|
||||
cg_printf("\"\"");
|
||||
}
|
||||
|
||||
if (m_type == '`') cg_printf(")");
|
||||
}
|
||||
|
||||
@@ -308,22 +308,6 @@ FunctionScopeRawPtr Expression::getOriginalFunction() {
|
||||
return scope ? scope->getContainingFunction() : FunctionScopeRawPtr();
|
||||
}
|
||||
|
||||
string Expression::originalClassName(CodeGenerator &cg, bool withComma) {
|
||||
ClassScopeRawPtr cls = getOriginalClass();
|
||||
string ret = withComma ? ", " : "";
|
||||
if (cls) {
|
||||
if (cls == getClassScope()) {
|
||||
return ret + "s_class_name";
|
||||
}
|
||||
return ret + Option::ClassPrefix + cls->getId() + "::s_class_name";
|
||||
} else if (FunctionScopePtr funcScope = getOriginalFunction()) {
|
||||
if (!funcScope->inPseudoMain()) {
|
||||
return ret + "empty_string";
|
||||
}
|
||||
}
|
||||
return withComma ? "" : "null_string";
|
||||
}
|
||||
|
||||
void Expression::resetTypes() {
|
||||
m_actualType .reset();
|
||||
m_expectedType .reset();
|
||||
@@ -547,11 +531,11 @@ void Expression::CheckPassByReference(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
unsigned Expression::getCanonHash() const {
|
||||
int64 val = hash_int64(getKindOf());
|
||||
int64_t val = hash_int64(getKindOf());
|
||||
for (int i = getKidCount(); i--; ) {
|
||||
ExpressionPtr k = getNthExpr(i);
|
||||
if (k) {
|
||||
val = hash_int64(val ^ (((int64)k->getKindOf()<<32)+k->getCanonID()));
|
||||
val = hash_int64(val ^ (((int64_t)k->getKindOf()<<32)+k->getCanonID()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,487 +710,6 @@ ExpressionPtr Expression::MakeScalarExpression(AnalysisResultConstPtr ar,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Expression::outputLineMap(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool force /* = false */) {
|
||||
switch (cg.getOutput()) {
|
||||
case CodeGenerator::TrimmedPHP:
|
||||
if (cg.getStream(CodeGenerator::MapFile) &&
|
||||
cg.usingStream(CodeGenerator::PrimaryStream)) {
|
||||
cg.useStream(CodeGenerator::MapFile);
|
||||
cg_printf("%d => '%s:%d',", cg.getLineNo(CodeGenerator::PrimaryStream),
|
||||
getLocation()->file, getLocation()->line1);
|
||||
cg.useStream(CodeGenerator::PrimaryStream);
|
||||
}
|
||||
break;
|
||||
case CodeGenerator::ClusterCPP:
|
||||
{
|
||||
if (!force &&
|
||||
!(getLocalEffects() & (Construct::CanThrow|
|
||||
Construct::AccessorEffect|
|
||||
Construct::DiagnosticEffect))) {
|
||||
return false;
|
||||
}
|
||||
int line = cg.getLineNo(CodeGenerator::PrimaryStream);
|
||||
LocationPtr loc = getLocation();
|
||||
if (loc) {
|
||||
ar->recordSourceInfo(cg.getFileName(), line, loc);
|
||||
if (cg.getPHPLineNo() != loc->line1) {
|
||||
cg.setPHPLineNo(loc->line1);
|
||||
cg_printf("LINE(%d,", loc->line1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Expression::outputCPPArithArg(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool arrayOk) {
|
||||
TypePtr at = getActualType();
|
||||
if (at &&
|
||||
(at->is(Type::KindOfString) ||
|
||||
at->is(Type::KindOfObject) ||
|
||||
(at->is(Type::KindOfArray) && !arrayOk)) &&
|
||||
(!hasCPPTemp() || getCPPType()->isExactType())) {
|
||||
if (!hasCPPTemp() && !getCPPType()->isExactType()) {
|
||||
TypePtr et = getExpectedType();
|
||||
setExpectedType(TypePtr());
|
||||
setActualType(getCPPType());
|
||||
outputCPP(cg, ar);
|
||||
setActualType(at);
|
||||
setExpectedType(et);
|
||||
} else {
|
||||
cg_printf("(Variant)(");
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Expression::outputCPPCast(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_expectedType) {
|
||||
m_expectedType->outputCPPCast(cg, ar, getScope());
|
||||
}
|
||||
}
|
||||
|
||||
void Expression::outputCPPDecl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
TypePtr type = m_actualType;
|
||||
if (!type) type = Type::Variant;
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
}
|
||||
|
||||
std::string Expression::genCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
std::ostringstream os;
|
||||
os << Option::TempPrefix << cg.createNewLocalId(shared_from_this());
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void Expression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (hasCPPTemp() || isScalar()) return;
|
||||
bool fastCast = needsFastCastTemp(ar);
|
||||
if (!isLocalExprAltered() && !hasEffect() &&
|
||||
!fastCast && !(state & StashAll)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool killCast = false;
|
||||
|
||||
TypePtr srcType, dstType, dstType0;
|
||||
bool needsCast = getTypeCastPtrs(ar, srcType, dstType);
|
||||
|
||||
bool isLvalue = (m_context & LValue);
|
||||
bool isTemp = isTemporary();
|
||||
|
||||
bool isReferenced = true;
|
||||
|
||||
if (fastCast) {
|
||||
isTemp = true;
|
||||
killCast = true;
|
||||
dstType0 = dstType;
|
||||
dstType = Type::Variant;
|
||||
isReferenced = couldCppTypeBeReferenced();
|
||||
} else if (needsCast) {
|
||||
isTemp = true;
|
||||
} else {
|
||||
killCast = true;
|
||||
dstType = srcType;
|
||||
}
|
||||
|
||||
if (dstType) {
|
||||
if (isUnused()) {
|
||||
dstType.reset();
|
||||
} else switch (dstType->getKindOf()) {
|
||||
case Type::KindOfAny:
|
||||
case Type::KindOfSome:
|
||||
dstType = Type::Variant;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool eltOrPropArg = hasContext(InvokeArgument) &&
|
||||
(is(KindOfArrayElementExpression) || is(KindOfObjectPropertyExpression));
|
||||
bool constRef = dstType &&
|
||||
((m_context & (RefValue|RefParameter)) ||
|
||||
(isTemp && !dstType->isPrimitive()) || eltOrPropArg ||
|
||||
(isLvalue && dynamic_cast<FunctionCall*>(this)));
|
||||
|
||||
cg.wrapExpressionBegin();
|
||||
// make LINE macro separate to not interfere with persistance of expression.
|
||||
// and because nested LINE macros dont work
|
||||
if (outputLineMap(cg, ar)) cg_printf("0);\n");
|
||||
|
||||
if (constRef) {
|
||||
cg_printf("const ");
|
||||
}
|
||||
|
||||
if (dstType) {
|
||||
bool inlinedRefReturn = hasAllContext(LValue|ReturnContext) &&
|
||||
!hasAnyContext(InvokeArgument|RefValue);
|
||||
bool refParam = hasContext(RefValue) &&
|
||||
!hasAnyContext(InvokeArgument|AssignmentRHS|ReturnContext) &&
|
||||
(is(KindOfObjectPropertyExpression) ||
|
||||
is(KindOfArrayElementExpression));
|
||||
if (inlinedRefReturn) {
|
||||
cg_printf("Variant");
|
||||
} else if (refParam) {
|
||||
cg_printf("VRefParamValue");
|
||||
} else {
|
||||
dstType->outputCPPDecl(cg, ar, getScope());
|
||||
}
|
||||
std::string t = genCPPTemp(cg, ar);
|
||||
const char *ref =
|
||||
(!inlinedRefReturn &&
|
||||
(isLvalue || constRef) &&
|
||||
!(state & ForceTemp)) ? "&" : "";
|
||||
/*
|
||||
Note that double parens are necessary:
|
||||
type_name1 tmp27(type_name2(foo));
|
||||
type_name1 tmp28((type_name2(foo)));
|
||||
|
||||
tmp27 is a function returning a type_name1 taking a parameter of
|
||||
type type_name2 (not what we want!)
|
||||
|
||||
tmp28 is an object of type type_name1, initialized by type_name2(foo)
|
||||
*/
|
||||
cg_printf(" %s%s((", ref, t.c_str());
|
||||
|
||||
/*
|
||||
In c++ a temporary bound to a reference gets the lifetime of the
|
||||
reference.
|
||||
So "const Variant &tmp27 = foo()" generates a temporary, and binds it
|
||||
to v, with the lifetime of v.
|
||||
But "const Variant &tmp27 = ref(foo())", creates a temporary, binds it
|
||||
to ref's parameter, returns a reference to that, and binds that to v;
|
||||
but the temporary gets destroyed at the end of the statement.
|
||||
|
||||
So we clear the ref context here, and output the ref when we output the
|
||||
use of the temporary (top of outputCPP, below), but in that case, we also
|
||||
need to set the lval context, otherwise, rvalAt would be generated for
|
||||
array elements and object properties.
|
||||
*/
|
||||
int save = m_context;
|
||||
if (inlinedRefReturn) {
|
||||
cg_printf("strongBind(");
|
||||
} else if (refParam) {
|
||||
m_context &= ~RefParameter;
|
||||
} else if (hasContext(RefValue)) {
|
||||
m_context &= ~RefValue;
|
||||
if (is(KindOfObjectPropertyExpression) ||
|
||||
(is(KindOfArrayElementExpression) &&
|
||||
!(m_context & InvokeArgument))) {
|
||||
m_context |= LValue;
|
||||
m_context &= ~NoLValueWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr et = m_expectedType;
|
||||
TypePtr at = m_actualType;
|
||||
TypePtr it = m_implementedType;
|
||||
if (killCast) {
|
||||
m_actualType = dstType;
|
||||
m_implementedType.reset();
|
||||
m_expectedType.reset();
|
||||
}
|
||||
outputCPP(cg, ar);
|
||||
if (killCast) {
|
||||
m_actualType = at;
|
||||
m_expectedType = et;
|
||||
m_implementedType = it;
|
||||
}
|
||||
m_context = save;
|
||||
|
||||
if (inlinedRefReturn) cg_printf(")");
|
||||
cg_printf("));\n");
|
||||
if (!refParam && constRef &&
|
||||
(isLvalue || hasContext(DeepReference) || hasContext(UnsetContext))) {
|
||||
dstType->outputCPPDecl(cg, ar, getScope());
|
||||
cg_printf(" &%s_lv = const_cast<", t.c_str());
|
||||
dstType->outputCPPDecl(cg, ar, getScope());
|
||||
cg_printf("&>(%s);\n", t.c_str());
|
||||
t += "_lv";
|
||||
}
|
||||
if (fastCast) {
|
||||
assert(dstType0);
|
||||
assert(srcType == m_implementedType);
|
||||
dstType = dstType0;
|
||||
|
||||
if (constRef && !dstType->isPrimitive()) {
|
||||
cg_printf("const ");
|
||||
}
|
||||
dstType->outputCPPDecl(cg, ar, getScope());
|
||||
cg_printf(" %s%s_vv = ",
|
||||
dstType->isPrimitive() ? "" : "&",
|
||||
t.c_str());
|
||||
|
||||
int closeParen = 0;
|
||||
string method = Type::GetFastCastMethod(
|
||||
m_actualType, isReferenced, constRef);
|
||||
if (!Type::SameType(m_actualType, dstType)) {
|
||||
dstType->outputCPPCast(cg, ar, getScope());
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
if (m_actualType->is(Type::KindOfObject)) {
|
||||
method = "getObjectDataOrNull";
|
||||
} else if (m_actualType->is(Type::KindOfString)) {
|
||||
method = "getStringDataOrNull";
|
||||
} else if (m_actualType->is(Type::KindOfArray)) {
|
||||
method = "getArrayDataOrNull";
|
||||
}
|
||||
} else if (m_actualType->isSpecificObject()) {
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
m_actualType->outputCPPFastObjectCast(
|
||||
cg, ar, getScope(), constRef);
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
}
|
||||
|
||||
cg_printf("%s.%s()", t.c_str(), method.c_str());
|
||||
|
||||
for (int i = 0; i < closeParen; i++) cg_printf(")");
|
||||
cg_printf(";\n");
|
||||
|
||||
t += "_vv";
|
||||
}
|
||||
m_cppTemp = t;
|
||||
} else {
|
||||
if (outputCPPUnneeded(cg, ar)) {
|
||||
cg_printf(";\n");
|
||||
}
|
||||
m_cppTemp = "null";
|
||||
}
|
||||
}
|
||||
|
||||
bool Expression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (isScalar()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paramList =
|
||||
is(KindOfExpressionList) &&
|
||||
static_cast<ExpressionList*>(this)->getListKind() ==
|
||||
ExpressionList::ListKindParam;
|
||||
|
||||
bool stashAll = state & StashAll;
|
||||
state &= ~StashAll;
|
||||
bool doStash = (state & FixOrder) != 0 || needsFastCastTemp(ar);
|
||||
bool ret = doStash;
|
||||
int kidState = (state & ~(StashKidVars|StashVars|FixOrder|ForceTemp));
|
||||
if (state & StashKidVars) kidState |= StashVars;
|
||||
int lastEffect = -1, i;
|
||||
int n = getKidCount();
|
||||
if (hasEffect()) {
|
||||
int j;
|
||||
for (i = j = 0; i < n; i++) {
|
||||
ExpressionPtr k = getNthExpr(i);
|
||||
if (k && !k->isScalar()) {
|
||||
if (k->hasEffect()) {
|
||||
lastEffect = i;
|
||||
if (!j && (n > 1 || paramList) && k->isTemporary() &&
|
||||
(!k->hasContext(ExistContext) ||
|
||||
(!k->is(KindOfObjectPropertyExpression) &&
|
||||
!k->is(KindOfArrayElementExpression)))) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (lastEffect >= 0 && j > 1) {
|
||||
kidState |= FixOrder;
|
||||
if (stashAll) {
|
||||
lastEffect = n - 1;
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret || cg.inExpression()) {
|
||||
if (paramList) kidState |= FixOrder;
|
||||
bool skipLast = !stashAll;
|
||||
int lastState = kidState | StashByRef;
|
||||
if (stashAll) lastState |= StashVars;
|
||||
for (i = 0; i <= lastEffect; i++) {
|
||||
ExpressionPtr k = getNthExpr(i);
|
||||
if (k && !k->isScalar()) {
|
||||
int s = kidState;
|
||||
if (i == n - 1 && skipLast) s = 0;
|
||||
bool noEffect = false;
|
||||
if (m_kindOf == KindOfExpressionList) {
|
||||
ExpressionList *el = static_cast<ExpressionList*>(this);
|
||||
if (i >= el->getOutputCount()) {
|
||||
s = lastState = 0;
|
||||
noEffect = true;
|
||||
}
|
||||
}
|
||||
if (k->is(KindOfSimpleVariable)) {
|
||||
skipLast = false;
|
||||
}
|
||||
if (k->preOutputCPP(cg, ar, i == lastEffect ? lastState : s)) {
|
||||
ret = true;
|
||||
if (!cg.inExpression()) break;
|
||||
}
|
||||
if (noEffect) {
|
||||
k->outputCPPUnneeded(cg, ar);
|
||||
k->setCPPTemp("0");
|
||||
cg_printf(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doStash) {
|
||||
if (cg.inExpression()) {
|
||||
preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool checkOffsetChain(CodeGenerator &cg, ExpressionPtr e,
|
||||
bool &needsRefTemp) {
|
||||
bool isArray = e->is(Expression::KindOfArrayElementExpression);
|
||||
if (isArray || e->is(Expression::KindOfObjectPropertyExpression)) {
|
||||
if (cg.hasReferenceTemp()) {
|
||||
bool lval =
|
||||
e->hasContext(Expression::LValue) ||
|
||||
e->hasContext(Expression::RefValue) ||
|
||||
e->hasContext(Expression::DeepReference) ||
|
||||
e->hasContext(Expression::UnsetContext);
|
||||
|
||||
if (isArray) {
|
||||
if (!lval && !e->hasContext(Expression::InvokeArgument) &&
|
||||
!static_pointer_cast<ArrayElementExpression>(e)->isSuperGlobal()) {
|
||||
TypePtr type = e->getNthExpr(0)->getActualType();
|
||||
if (!type ||
|
||||
(!type->is(Type::KindOfString) && !type->is(Type::KindOfArray))) {
|
||||
needsRefTemp = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lval &&
|
||||
!static_pointer_cast<ObjectPropertyExpression>(e)->isValid()) {
|
||||
needsRefTemp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ExpressionPtr e1 = e->getNthExpr(1)) {
|
||||
if (e1->hasEffect()) return true;
|
||||
}
|
||||
return checkOffsetChain(cg, e->getNthExpr(0), needsRefTemp);
|
||||
}
|
||||
return e->hasEffect();
|
||||
}
|
||||
|
||||
bool Expression::preOutputOffsetLHS(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int state) {
|
||||
bool ret = (state & FixOrder);
|
||||
bool needRefTemp = false;
|
||||
if (!hasContext(AccessContext)) {
|
||||
if (!ret) {
|
||||
ret = checkOffsetChain(cg, getNthExpr(0), needRefTemp);
|
||||
if (!ret &&
|
||||
(m_context & (LValue | OprLValue |
|
||||
RefValue | DeepReference | RefParameter))) {
|
||||
if (ExpressionPtr e1 = getNthExpr(1)) {
|
||||
if (e1->hasEffect()) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if this elem has a CSE substitution
|
||||
// or is a chain root. in this case, we need to force a temp
|
||||
// since we will be taking a reference out, if we need to
|
||||
// fix our order
|
||||
bool forceTemp = false;
|
||||
bool hasCse = false;
|
||||
ExpressionPtr p(getCanonCsePtr());
|
||||
if (p && p->hasCPPCseTemp()) {
|
||||
assert(p->isChainRoot() && !isChainRoot());
|
||||
if (!isLocalExprAltered()) return false;
|
||||
hasCse = forceTemp = true;
|
||||
} else if (hasCPPCseTemp() && isChainRoot()) {
|
||||
forceTemp = isLocalExprAltered();
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
if (hasCse) return false;
|
||||
if (needRefTemp && cg.inExpression()) {
|
||||
cg.wrapExpressionBegin();
|
||||
}
|
||||
return Expression::preOutputCPP(cg, ar, state) || needRefTemp;
|
||||
}
|
||||
|
||||
if (forceTemp) {
|
||||
// if a cast was needed, then no need to force temp
|
||||
TypePtr srcType, dstType;
|
||||
if (getTypeCastPtrs(ar, srcType, dstType)) {
|
||||
forceTemp = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cg.inExpression()) {
|
||||
cg.wrapExpressionBegin();
|
||||
state |= FixOrder;
|
||||
|
||||
if (!hasCse) {
|
||||
if (ExpressionPtr e0 = getNthExpr(0)) {
|
||||
e0->preOutputCPP(cg, ar, state & ~(StashVars));
|
||||
}
|
||||
|
||||
if (ExpressionPtr e1 = getNthExpr(1)) {
|
||||
e1->preOutputCPP(cg, ar, state & ~(StashVars));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasContext(AccessContext)) {
|
||||
if (!(m_context & (AssignmentLHS | OprLValue |
|
||||
ExistContext | UnsetContext))) {
|
||||
if (forceTemp) state |= ForceTemp;
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Expression::collectCPPTemps(ExpressionPtrVec &collection) {
|
||||
if (isChainRoot()) {
|
||||
collection.push_back(static_pointer_cast<Expression>(shared_from_this()));
|
||||
@@ -1340,59 +843,6 @@ ExpressionPtr Expression::getCanonCsePtr() const {
|
||||
return ExpressionPtr();
|
||||
}
|
||||
|
||||
bool Expression::preOutputCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool emitTemps) {
|
||||
ExpressionPtrVec temps;
|
||||
collectCPPTemps(temps);
|
||||
if (temps.empty()) return false;
|
||||
if (emitTemps) {
|
||||
for (ExpressionPtrVec::iterator it(temps.begin());
|
||||
it != temps.end();
|
||||
++it) {
|
||||
ExpressionPtr p(*it);
|
||||
if (p->hasCPPCseTemp()) continue;
|
||||
|
||||
p->m_cppCseTemp = genCPPTemp(cg, ar);
|
||||
TypePtr t;
|
||||
bool needsStorage = Expression::GetCseTempInfo(ar, p, t);
|
||||
bool useConst = !p->hasContext(Expression::LValue);
|
||||
bool isString = t && t->is(Type::KindOfString);
|
||||
const char *s = isString ? "String" : "Variant";
|
||||
if (!isString) {
|
||||
cg_printf("%s%s *%s%s;\n",
|
||||
useConst ? "const " : "",
|
||||
s,
|
||||
Option::CseTempVariablePrefix,
|
||||
p->m_cppCseTemp.c_str());
|
||||
if (needsStorage) {
|
||||
cg_printf("%s %s%s;\n",
|
||||
s,
|
||||
Option::CseTempStoragePrefix,
|
||||
p->m_cppCseTemp.c_str());
|
||||
}
|
||||
} else {
|
||||
cg_printf("%s %s%s;\n",
|
||||
s,
|
||||
Option::CseTempVariablePrefix,
|
||||
p->m_cppCseTemp.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Expression::outputCPPBegin(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
preOutputCPPTemp(cg, ar, !cg.inExpression());
|
||||
cg.setInExpression(true);
|
||||
return preOutputCPP(cg, ar, 0);
|
||||
}
|
||||
|
||||
bool Expression::outputCPPEnd(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
bool ret = cg.wrapExpressionEnd();
|
||||
cg.setInExpression(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Expression::getTypeCastPtrs(
|
||||
AnalysisResultPtr ar, TypePtr &srcType, TypePtr &dstType) {
|
||||
srcType = m_actualType;
|
||||
@@ -1464,253 +914,3 @@ bool Expression::canUseFastCast(AnalysisResultPtr ar) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Expression::outputCPPGuardedObjectPtr(CodeGenerator &cg) {
|
||||
if (is(KindOfSimpleVariable) &&
|
||||
static_cast<SimpleVariable*>(this)->isGuarded()) {
|
||||
TypePtr at = getActualType();
|
||||
if (at && at->is(Type::KindOfObject)) {
|
||||
TypePtr it = getImplementedType();
|
||||
if (it && !it->is(Type::KindOfObject)) {
|
||||
TypePtr et = getExpectedType();
|
||||
if (!et || !et->is(Type::KindOfObject)) {
|
||||
cg_printf(".getObjectData()");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cg_printf(".get()");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Expression::outputCPPInternal(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (hasError(Expression::BadPassByRef)) {
|
||||
cg_printf("throw_fatal(\"bad pass by reference\")");
|
||||
return;
|
||||
}
|
||||
int closeParen = 0;
|
||||
TypePtr srcType, dstType;
|
||||
bool needsCast = getTypeCastPtrs(ar, srcType, dstType);
|
||||
|
||||
bool useFastCast = false;
|
||||
bool isReferenced = true;
|
||||
bool isLval = (m_context & LValue);
|
||||
|
||||
if (canUseFastCast(ar)) {
|
||||
useFastCast = true;
|
||||
isReferenced = couldCppTypeBeReferenced();
|
||||
}
|
||||
|
||||
if (needsCast) {
|
||||
assert(dstType);
|
||||
bool isSpecObj = m_actualType && m_actualType->isSpecificObject();
|
||||
if (!useFastCast ||
|
||||
!Type::SameType(m_actualType, dstType) ||
|
||||
isSpecObj) {
|
||||
if (useFastCast && isSpecObj) {
|
||||
if (!Type::SameType(m_actualType, dstType)) {
|
||||
dstType->outputCPPCast(cg, ar, getScope());
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
} else {
|
||||
// specific object is special, since we do not have
|
||||
// a fast cast method into a specific object on Variant,
|
||||
// we must emit an additional (but also fast) cast.
|
||||
// In the end, the cast will look like (for example):
|
||||
//
|
||||
// (const X&)(v_var.asCObjRef())
|
||||
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
m_actualType->outputCPPFastObjectCast(cg, ar, getScope(), !isLval);
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
}
|
||||
} else {
|
||||
dstType->outputCPPCast(cg, ar, getScope());
|
||||
cg_printf("(");
|
||||
closeParen++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (hasContext(RefValue) && !hasContext(NoRefWrapper) &&
|
||||
isRefable()) {
|
||||
if (hasContext(RefParameter)) {
|
||||
cg_printf("strongBind(");
|
||||
} else {
|
||||
cg_printf("ref(");
|
||||
}
|
||||
useFastCast = false; // cannot ref() or strongBind() a non-variant
|
||||
closeParen++;
|
||||
}
|
||||
if (is(Expression::KindOfArrayElementExpression)) {
|
||||
if (((m_context & LValue) || ((m_context & RefValue) &&
|
||||
!(m_context & InvokeArgument))) &&
|
||||
!(m_context & NoLValueWrapper)) {
|
||||
isLval = true;
|
||||
cg_printf("lval(");
|
||||
closeParen++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool needsDeref = false;
|
||||
if (hasCPPCseTemp()) {
|
||||
TypePtr t;
|
||||
GetCseTempInfo(
|
||||
ar,
|
||||
static_pointer_cast<Expression>(shared_from_this()),
|
||||
t);
|
||||
if (!t || !t->is(Type::KindOfString)) needsDeref = true;
|
||||
if (isChainRoot()) {
|
||||
if (!needsDeref) {
|
||||
cg_printf("(%s%s = (",
|
||||
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
|
||||
closeParen += 2;
|
||||
} else {
|
||||
cg_printf("(*(%s%s = &(",
|
||||
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
|
||||
closeParen += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCPPCseTemp() && !isChainRoot()) {
|
||||
if (needsDeref) cg_printf("(*");
|
||||
cg_printf("%s%s",
|
||||
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
|
||||
if (needsDeref) cg_printf(")");
|
||||
} else {
|
||||
outputCPPImpl(cg, ar);
|
||||
}
|
||||
|
||||
if (useFastCast) {
|
||||
assert(srcType == m_implementedType);
|
||||
string method;
|
||||
if (!Type::SameType(m_actualType, dstType)) {
|
||||
if (m_actualType->is(Type::KindOfObject)) {
|
||||
method = "getObjectDataOrNull";
|
||||
} else if (m_actualType->is(Type::KindOfString)) {
|
||||
method = "getStringDataOrNull";
|
||||
} else if (m_actualType->is(Type::KindOfArray)) {
|
||||
method = "getArrayDataOrNull";
|
||||
}
|
||||
}
|
||||
if (method.empty()) {
|
||||
method = Type::GetFastCastMethod(
|
||||
m_actualType, isReferenced,
|
||||
!isLval && !(m_context & UnsetContext));
|
||||
}
|
||||
cg_printf(".%s()", method.c_str());
|
||||
}
|
||||
|
||||
for (int i = 0; i < closeParen; i++) {
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
string comment;
|
||||
if (is(Expression::KindOfScalarExpression)) {
|
||||
ScalarExpressionPtr exp =
|
||||
dynamic_pointer_cast<ScalarExpression>(shared_from_this());
|
||||
comment = exp->getComment();
|
||||
} else if (is(Expression::KindOfConstantExpression)) {
|
||||
ConstantExpressionPtr exp =
|
||||
dynamic_pointer_cast<ConstantExpression>(shared_from_this());
|
||||
comment = exp->getComment();
|
||||
}
|
||||
|
||||
if (!comment.empty()) {
|
||||
if (cg.inComments()) {
|
||||
cg_printf(" (%s)", comment.c_str());
|
||||
} else {
|
||||
cg_printf(" /* %s */", comment.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Expression::outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (hasEffect() && m_cppTemp.empty()) {
|
||||
setUnused(true);
|
||||
outputCPP(cg, ar);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Expression::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
bool inExpression = cg.inExpression();
|
||||
bool wrapped = false;
|
||||
TypePtr et = m_expectedType;
|
||||
TypePtr at = m_actualType;
|
||||
TypePtr it = m_implementedType;
|
||||
if (isUnused()) {
|
||||
if (et) {
|
||||
m_expectedType.reset();
|
||||
}
|
||||
if (it) {
|
||||
m_implementedType.reset();
|
||||
m_actualType = it;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inExpression) {
|
||||
wrapped = outputCPPBegin(cg, ar);
|
||||
}
|
||||
|
||||
ExpressionPtr p(getCanonCsePtr());
|
||||
if (p && p->hasCPPCseTemp() && !hasCPPCseTemp()) {
|
||||
assert(p->isChainRoot() && !isChainRoot());
|
||||
m_cppCseTemp = p->m_cppCseTemp;
|
||||
}
|
||||
|
||||
if (!m_cppTemp.empty()) {
|
||||
bool ref = hasContext(RefValue) &&
|
||||
!hasContext(NoRefWrapper) &&
|
||||
(hasAnyContext(ReturnContext|AssignmentRHS|RefParameter) ||
|
||||
!(is(KindOfObjectPropertyExpression) ||
|
||||
is(KindOfArrayElementExpression))) &&
|
||||
isRefable();
|
||||
if (ref) {
|
||||
if (m_context & RefParameter) {
|
||||
cg_printf("strongBind(");
|
||||
} else {
|
||||
cg_printf("ref(");
|
||||
}
|
||||
}
|
||||
cg_printf("%s", m_cppTemp.c_str());
|
||||
if (ref) cg_printf(")");
|
||||
} else {
|
||||
bool linemap = outputLineMap(cg, ar);
|
||||
if (linemap) cg_printf("(");
|
||||
outputCPPInternal(cg, ar);
|
||||
if (linemap) cg_printf("))");
|
||||
}
|
||||
|
||||
m_implementedType = it;
|
||||
m_actualType = at;
|
||||
m_expectedType = et;
|
||||
|
||||
if (!inExpression) {
|
||||
if (wrapped) cg_printf(";");
|
||||
cg.wrapExpressionEnd();
|
||||
cg.setInExpression(inExpression);
|
||||
}
|
||||
}
|
||||
|
||||
void Expression::outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int op) {
|
||||
switch (op) {
|
||||
case T_ISSET: cg_printf("isset("); break;
|
||||
case T_EMPTY: cg_printf("empty("); break;
|
||||
default: assert(false);
|
||||
}
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
void Expression::outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("unset(");
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@
|
||||
virtual ExpressionPtr clone(); \
|
||||
virtual TypePtr inferTypes(AnalysisResultPtr ar, TypePtr type, \
|
||||
bool coerce); \
|
||||
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar); \
|
||||
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar)
|
||||
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
#define DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS \
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS; \
|
||||
virtual ConstructPtr getNthKid(int n) const; \
|
||||
@@ -186,28 +185,9 @@ public:
|
||||
/**
|
||||
* Implementing Construct.
|
||||
*/
|
||||
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
|
||||
void outputCPPCast(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
virtual void outputCPPDecl(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int op);
|
||||
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
virtual void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
virtual bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool outputCPPBegin(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool outputCPPEnd(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void collectCPPTemps(ExpressionPtrVec &collection);
|
||||
void disableCSE();
|
||||
bool hasChainRoots();
|
||||
bool preOutputCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool emitTemps);
|
||||
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool preOutputOffsetLHS(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool hasCPPTemp() const { return !m_cppTemp.empty(); }
|
||||
const std::string &cppTemp() const { return m_cppTemp; }
|
||||
std::string genCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
@@ -216,7 +196,6 @@ public:
|
||||
void setOriginalScope(BlockScopeRawPtr scope);
|
||||
ClassScopeRawPtr getOriginalClass();
|
||||
FunctionScopeRawPtr getOriginalFunction();
|
||||
std::string originalClassName(CodeGenerator &cg, bool withComma);
|
||||
|
||||
/**
|
||||
* For generic walks
|
||||
@@ -390,7 +369,6 @@ public:
|
||||
static bool GetCseTempInfo(
|
||||
AnalysisResultPtr ar, ExpressionPtr p, TypePtr &t);
|
||||
|
||||
bool outputCPPArithArg(CodeGenerator &cg, AnalysisResultPtr ar, bool arrayOk);
|
||||
bool isUnused() const { return m_unused; }
|
||||
void setUnused(bool u) { m_unused = u; }
|
||||
ExpressionPtr fetchReplacement();
|
||||
@@ -400,8 +378,6 @@ public:
|
||||
* Correctly compute the local expression altered bit
|
||||
*/
|
||||
void computeLocalExprAltered();
|
||||
|
||||
bool outputCPPGuardedObjectPtr(CodeGenerator &cg);
|
||||
protected:
|
||||
static bool IsIdentifier(const std::string &value);
|
||||
|
||||
@@ -432,13 +408,9 @@ protected:
|
||||
TypePtr expectedType);
|
||||
void setDynamicByIdentifier(AnalysisResultPtr ar,
|
||||
const std::string &value);
|
||||
bool outputLineMap(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool force = false);
|
||||
|
||||
void resetTypes();
|
||||
private:
|
||||
static ExprClass Classes[];
|
||||
void outputCPPInternal(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
* Returns true if a type cast is needed, and sets src/dst type
|
||||
|
||||
@@ -494,144 +494,6 @@ void ExpressionList::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionList::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (hasCPPTemp() || m_kind == ListKindParam || m_arrayElements) {
|
||||
return;
|
||||
}
|
||||
int n = m_exps.size();
|
||||
int i = m_kind == ListKindLeft ? 0 : n - 1;
|
||||
if (m_exps[i]->hasCPPTemp() &&
|
||||
Type::SameType(getType(), m_exps[i]->getType())) {
|
||||
setUnused(true);
|
||||
outputCPP(cg, ar);
|
||||
cg_printf(";\n");
|
||||
m_cppTemp = m_exps[i]->cppTemp();
|
||||
}
|
||||
return Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (m_kind == ListKindParam && !m_arrayElements) {
|
||||
return Expression::preOutputCPP(cg, ar, state|StashKidVars);
|
||||
}
|
||||
|
||||
unsigned n = m_exps.size();
|
||||
bool inExpression = cg.inExpression();
|
||||
if (!inExpression && (state & FixOrder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cg.setInExpression(false);
|
||||
bool ret = false;
|
||||
if (m_arrayElements) {
|
||||
/*
|
||||
* would like to do:
|
||||
* ret = Expression::preOutputCPP(cg, ar, state);
|
||||
* but icc has problems with the generated code.
|
||||
*/
|
||||
ret = hasEffect();
|
||||
} else if (n > 1 && m_kind == ListKindLeft) {
|
||||
ret = true;
|
||||
} else {
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
if (m_exps[i]->preOutputCPP(cg, ar, 0)) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
ExpressionPtr e = m_exps[n - 1];
|
||||
if (hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
|
||||
!(e->hasContext(LValue) &&
|
||||
!e->hasAnyContext(RefValue|InvokeArgument))) {
|
||||
ret = true;
|
||||
} else if (hasContext(RefValue) &&
|
||||
!e->hasAllContext(LValue|ReturnContext) &&
|
||||
!e->hasContext(RefValue)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!inExpression) return ret;
|
||||
|
||||
cg.setInExpression(true);
|
||||
if (!ret) {
|
||||
if (state & FixOrder) {
|
||||
preOutputStash(cg, ar, state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
cg.wrapExpressionBegin();
|
||||
if (m_arrayElements) {
|
||||
setCPPTemp(genCPPTemp(cg, ar));
|
||||
outputCPPInternal(cg, ar, true, true);
|
||||
} else {
|
||||
unsigned ix = isUnused() ? (unsigned)-1 :
|
||||
m_kind == ListKindLeft ? 0 : n - 1;
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
ExpressionPtr e = m_exps[i];
|
||||
if (i != ix) e->setUnused(true);
|
||||
e->preOutputCPP(cg, ar, i == ix ? state : 0);
|
||||
if (i != ix) {
|
||||
if (e->outputCPPUnneeded(cg, ar)) {
|
||||
cg_printf(";\n");
|
||||
}
|
||||
e->setCPPTemp("/**/");
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
We inlined a by-value function into the rhs of a by-ref assignment.
|
||||
*/
|
||||
bool noRef = hasContext(RefValue) &&
|
||||
!e->hasAllContext(LValue|ReturnContext) &&
|
||||
!e->hasContext(RefValue) &&
|
||||
!e->isTemporary() &&
|
||||
Type::IsMappedToVariant(e->getActualType());
|
||||
/*
|
||||
If we need a non-const reference, but the expression is
|
||||
going to generate a const reference, fix it
|
||||
*/
|
||||
bool lvSwitch =
|
||||
hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
|
||||
!(e->hasContext(LValue) &&
|
||||
!e->hasAnyContext(RefValue|InvokeArgument));
|
||||
|
||||
if (e->hasAllContext(LValue|ReturnContext) && i + 1 == n) {
|
||||
e->clearContext(ReturnContext);
|
||||
}
|
||||
|
||||
if (noRef || lvSwitch || (!i && n > 1)) {
|
||||
e->Expression::preOutputStash(cg, ar, state | FixOrder | StashAll);
|
||||
if (!(state & FixOrder)) {
|
||||
cg_printf("id(%s);\n", e->cppTemp().c_str());
|
||||
}
|
||||
}
|
||||
if (e->hasCPPTemp() &&
|
||||
Type::SameType(e->getGenType(), getGenType())) {
|
||||
string t = e->cppTemp();
|
||||
if (noRef) {
|
||||
cg_printf("CVarRef %s_nr = wrap_variant(%s);\n",
|
||||
t.c_str(), t.c_str());
|
||||
t += "_nr";
|
||||
}
|
||||
|
||||
if (lvSwitch) {
|
||||
cg_printf("Variant &%s_lv = const_cast<Variant&>(%s);\n",
|
||||
t.c_str(), t.c_str());
|
||||
t += "_lv";
|
||||
}
|
||||
setCPPTemp(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int ExpressionList::checkLitstrKeys() const {
|
||||
assert(m_arrayElements && !m_collectionType);
|
||||
std::set<string> keys;
|
||||
@@ -652,235 +514,3 @@ unsigned int ExpressionList::checkLitstrKeys() const {
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
bool ExpressionList::hasNonArrayCreateValue(
|
||||
bool arrayElements /* = true */, unsigned int start /* = 0 */) const {
|
||||
for (unsigned int i = start; i < m_exps.size(); i++) {
|
||||
ExpressionPtr value = m_exps[i];
|
||||
if (arrayElements) {
|
||||
ArrayPairExpressionPtr ap =
|
||||
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
|
||||
value = ap->getValue();
|
||||
}
|
||||
assert(value);
|
||||
if (value->hasContext(RefValue)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExpressionList::outputCPPUniqLitKeyArrayInit(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar, bool litstrKeys, int64 num,
|
||||
bool arrayElements /* = true */, unsigned int start /* = 0 */) {
|
||||
if (arrayElements) assert(m_arrayElements && !m_collectionType);
|
||||
unsigned int n = m_exps.size();
|
||||
cg_printf("array_createv%c(%" PRId64 ", ", litstrKeys ? 's' : 'i', num);
|
||||
always_assert(n - start == num);
|
||||
for (unsigned int i = start; i < n; i++) {
|
||||
ExpressionPtr exp = m_exps[i];
|
||||
always_assert(exp);
|
||||
ExpressionPtr name;
|
||||
ExpressionPtr value = exp;
|
||||
if (arrayElements) {
|
||||
ArrayPairExpressionPtr ap =
|
||||
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
|
||||
name = ap->getName();
|
||||
value = ap->getValue();
|
||||
}
|
||||
if (name) {
|
||||
always_assert(litstrKeys);
|
||||
cg_printf("toSPOD(");
|
||||
name->outputCPP(cg, ar);
|
||||
cg_printf("), ");
|
||||
}
|
||||
cg_printf("toVPOD(");
|
||||
if (value->isScalar()) {
|
||||
always_assert(!cg.hasScalarVariant());
|
||||
cg.setScalarVariant();
|
||||
if (!Option::UseScalarVariant) cg_printf("VarNR(");
|
||||
value->outputCPP(cg, ar);
|
||||
if (!Option::UseScalarVariant) cg_printf(")");
|
||||
cg.clearScalarVariant();
|
||||
} else {
|
||||
bool wrap = Expression::CheckVarNR(value, Type::Variant);
|
||||
if (wrap) cg_printf("VarNR(");
|
||||
value->outputCPP(cg, ar);
|
||||
if (wrap) cg_printf(")");
|
||||
}
|
||||
cg_printf(")");
|
||||
if (i < n-1) {
|
||||
cg_printf(", ");
|
||||
} else {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool isVector,
|
||||
bool pre) {
|
||||
assert(pre == !m_cppTemp.empty());
|
||||
if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) {
|
||||
return false;
|
||||
}
|
||||
if (hasNonArrayCreateValue()) return false;
|
||||
|
||||
unsigned int n = isVector ? m_exps.size() : 0;
|
||||
bool uniqLitstrKeys = false;
|
||||
if (isVector) {
|
||||
n = m_exps.size();
|
||||
} else {
|
||||
n = checkLitstrKeys();
|
||||
if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true;
|
||||
}
|
||||
if (isVector) {
|
||||
if (ar->m_arrayIntegerKeyMaxSize < (int)n) ar->m_arrayIntegerKeyMaxSize = n;
|
||||
} else if (uniqLitstrKeys) {
|
||||
if (ar->m_arrayLitstrKeyMaxSize < (int)n) ar->m_arrayLitstrKeyMaxSize = n;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (pre) {
|
||||
Expression::preOutputCPP(cg, ar, StashKidVars);
|
||||
cg_printf("ArrayInit %s(", m_cppTemp.c_str());
|
||||
outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
|
||||
cg_printf(");\n");
|
||||
} else {
|
||||
outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpressionList::outputCPPInternal(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool needed, bool pre) {
|
||||
bool needsComma = false;
|
||||
bool anyOutput = false;
|
||||
if (m_arrayElements) {
|
||||
if (!m_collectionType) {
|
||||
bool isVector = true;
|
||||
for (unsigned int i = 0; i < m_exps.size(); i++) {
|
||||
ArrayPairExpressionPtr ap =
|
||||
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
|
||||
if (ap->getName()) {
|
||||
isVector = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (outputCPPArrayCreate(cg, ar, isVector, pre)) return true;
|
||||
cg_printf("ArrayInit");
|
||||
if (pre) {
|
||||
cg_printf(" %s", m_cppTemp.c_str());
|
||||
}
|
||||
cg_printf("(%d)", (int)m_exps.size());
|
||||
if (pre) cg_printf(";\n");
|
||||
needsComma = true;
|
||||
anyOutput = true;
|
||||
} else {
|
||||
cg_printf("CollectionInit");
|
||||
if (pre) {
|
||||
cg_printf(" %s", m_cppTemp.c_str());
|
||||
}
|
||||
cg_printf("(%d, %luLL)", m_collectionType, m_exps.size());
|
||||
if (pre) cg_printf(";\n");
|
||||
needsComma = true;
|
||||
anyOutput = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool trailingComma = false;
|
||||
unsigned i = 0, s = m_exps.size();
|
||||
unsigned ix = m_kind == ListKindLeft ? 0 : s - 1;
|
||||
bool uniqueStringKeys =
|
||||
m_arrayElements && !m_collectionType &&
|
||||
(checkLitstrKeys() == s); // TODO integer keys as well
|
||||
for ( ; i < s; i++) {
|
||||
if (ExpressionPtr exp = m_exps[i]) {
|
||||
if (pre) {
|
||||
exp->preOutputCPP(cg, ar, 0);
|
||||
cg_printf("%s", m_cppTemp.c_str());
|
||||
}
|
||||
if (needsComma) {
|
||||
cg_printf(m_arrayElements ? "." : ", ");
|
||||
trailingComma = true;
|
||||
}
|
||||
if (m_arrayElements) {
|
||||
ArrayPairExpressionPtr ap =
|
||||
dynamic_pointer_cast<ArrayPairExpression>(exp);
|
||||
if (ap->isRef()) {
|
||||
cg_printf("setRef(");
|
||||
// The value itself shouldn't be wrapped with ref() any more.
|
||||
ap->getValue()->setContext(NoRefWrapper);
|
||||
} else {
|
||||
cg_printf(uniqueStringKeys ? "add(" : "set(");
|
||||
}
|
||||
exp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
if (pre) {
|
||||
cg_printf(";\n");
|
||||
}
|
||||
needsComma = true;
|
||||
} else if (m_kind != ListKindParam && (i != ix || !needed)) {
|
||||
needsComma = exp->outputCPPUnneeded(cg, ar);
|
||||
} else {
|
||||
bool wrap =
|
||||
exp->hasCPPTemp() &&
|
||||
hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
|
||||
!(exp->hasContext(LValue) &&
|
||||
!exp->hasAnyContext(RefValue|InvokeArgument));
|
||||
if (wrap) cg_printf("const_cast<Variant&>(");
|
||||
bool noRef = !exp->hasCPPTemp() &&
|
||||
hasContext(RefValue) &&
|
||||
!exp->hasAllContext(LValue|ReturnContext) &&
|
||||
!exp->hasContext(RefValue) &&
|
||||
!exp->isTemporary() &&
|
||||
Type::IsMappedToVariant(exp->getActualType());
|
||||
if (noRef) cg_printf("wrap_variant(");
|
||||
exp->outputCPP(cg, ar);
|
||||
if (noRef) cg_printf(")");
|
||||
if (wrap) cg_printf(")");
|
||||
needsComma = true;
|
||||
}
|
||||
if (needsComma) {
|
||||
trailingComma = false;
|
||||
anyOutput = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trailingComma) {
|
||||
cg_printf("id(0)");
|
||||
}
|
||||
if (m_arrayElements && !pre) {
|
||||
cg_printf(".create()");
|
||||
anyOutput = true;
|
||||
}
|
||||
return anyOutput;
|
||||
}
|
||||
|
||||
void ExpressionList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
bool wrapped = m_kind == ListKindWrapped ||
|
||||
(m_kind == ListKindComma && getCount() > 1);
|
||||
if (wrapped) cg_printf("(");
|
||||
outputCPPInternal(cg, ar, true, false);
|
||||
if (wrapped) cg_printf(")");
|
||||
}
|
||||
|
||||
bool ExpressionList::outputCPPUnneeded(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
bool inExpression = cg.inExpression();
|
||||
bool wrapped = false;
|
||||
if (!inExpression) {
|
||||
cg.setInExpression(true);
|
||||
wrapped = preOutputCPP(cg, ar, 0);
|
||||
}
|
||||
|
||||
bool ret = outputCPPInternal(cg, ar, false, false);
|
||||
|
||||
if (!inExpression) {
|
||||
if (wrapped) cg_printf(";\n");
|
||||
cg.wrapExpressionEnd();
|
||||
cg.setInExpression(inExpression);
|
||||
}
|
||||
return ret || wrapped;
|
||||
}
|
||||
|
||||
@@ -85,19 +85,6 @@ public:
|
||||
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool hasNonArrayCreateValue(bool arrayElements = true,
|
||||
unsigned int start = 0) const;
|
||||
void outputCPPUniqLitKeyArrayInit(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool litstrKeys,
|
||||
int64 max,
|
||||
bool arrayElements = true,
|
||||
unsigned int start = 0);
|
||||
/**
|
||||
* Checks whether the expression list contains only literal strings and
|
||||
* (recursive) arrays of literal strings. Also returns the list of strings
|
||||
@@ -108,10 +95,6 @@ public:
|
||||
private:
|
||||
void optimize(AnalysisResultConstPtr ar);
|
||||
unsigned int checkLitstrKeys() const;
|
||||
bool outputCPPArrayCreate(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool isVector, bool pre);
|
||||
bool outputCPPInternal(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, bool needed, bool pre);
|
||||
|
||||
ExpressionPtrVec m_exps;
|
||||
int m_outputCount;
|
||||
|
||||
@@ -584,183 +584,3 @@ TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
bool FunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
optimizeArgArray(ar);
|
||||
bool noLSB = m_noStatic || (!m_class && m_className.empty()) ||
|
||||
isSelf() || isParent();
|
||||
if (!noLSB) {
|
||||
if (m_funcScope && !m_funcScope->usesLSB()) {
|
||||
noLSB = true;
|
||||
}
|
||||
}
|
||||
if (noLSB || isUnused()) {
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
if (!cg.inExpression()) {
|
||||
return true;
|
||||
}
|
||||
Expression::preOutputCPP(cg, ar, state & ~FixOrder);
|
||||
cg.wrapExpressionBegin();
|
||||
if (m_classScope) {
|
||||
string className = m_classScope->getId();
|
||||
cg_printf("fi.setStaticClassName(%s%s::s_class_name);\n",
|
||||
Option::ClassPrefix, className.c_str());
|
||||
} else {
|
||||
m_clsNameTemp = cg.createNewLocalId(shared_from_this());
|
||||
cg_printf("CStrRef clsName%d(", m_clsNameTemp);
|
||||
cg_printString(m_origClassName, ar, shared_from_this());
|
||||
cg_printf(");\n");
|
||||
cg_printf("fi.setStaticClassName(clsName%d);\n", m_clsNameTemp);
|
||||
}
|
||||
m_noStatic = true;
|
||||
preOutputStash(cg, ar, FixOrder);
|
||||
m_noStatic = false;
|
||||
cg_printf("fi.resetStaticClassName();\n");
|
||||
|
||||
if (!(state & FixOrder)) {
|
||||
cg_printf("id(%s);\n", cppTemp().c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FunctionCall::outputDynamicCall(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, bool method) {
|
||||
const char *kind = method ? "Meth" : "Func";
|
||||
const char *var = method ? "mcp" : "vt";
|
||||
|
||||
int pcount = m_params ? m_params->getCount() : 0;
|
||||
if (canInvokeFewArgs()) {
|
||||
if (Option::InvokeWithSpecificArgs) {
|
||||
cg_printf("get%s%dArgs())(%s%d, ", kind, pcount, var, m_ciTemp);
|
||||
} else {
|
||||
cg_printf("get%sFewArgs())(%s%d, ", kind, var, m_ciTemp);
|
||||
}
|
||||
if (pcount) {
|
||||
for (int i = 0; i < pcount; i++) {
|
||||
(*m_params)[i]->setContext(NoRefWrapper);
|
||||
}
|
||||
cg_printf("%d, ", pcount);
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
FunctionScope::OutputCPPArguments(m_params, FunctionScopePtr(),
|
||||
cg, ar, 0, false);
|
||||
cg.popCallInfo();
|
||||
} else {
|
||||
cg_printf("0");
|
||||
}
|
||||
if (!Option::InvokeWithSpecificArgs) {
|
||||
for (int i = pcount; i < Option::InvokeFewArgsCount; i++) {
|
||||
cg_printf(", null_variant");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cg_printf("get%s())(%s%d, ", kind, var, m_ciTemp);
|
||||
|
||||
if (pcount) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
FunctionScope::OutputCPPArguments(m_params, FunctionScopePtr(),
|
||||
cg, ar, -1, false);
|
||||
cg.popCallInfo();
|
||||
} else {
|
||||
cg_printf("Array()");
|
||||
}
|
||||
}
|
||||
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
void FunctionCall::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
optimizeArgArray(ar);
|
||||
bool staticClassName = false;
|
||||
bool noLSB = !m_cppTemp.empty() || m_noStatic ||
|
||||
(!m_class && m_className.empty()) ||
|
||||
isSelf() || isParent() || isStatic();
|
||||
if (!noLSB) {
|
||||
if (m_funcScope && !m_funcScope->usesLSB()) {
|
||||
noLSB = true;
|
||||
}
|
||||
}
|
||||
if (!noLSB) {
|
||||
if (!m_className.empty()) {
|
||||
cg_printf("STATIC_CLASS_NAME_CALL(");
|
||||
if (m_classScope) {
|
||||
string className = m_classScope->getId();
|
||||
cg_printf("%s%s::s_class_name, ",
|
||||
Option::ClassPrefix, className.c_str());
|
||||
} else {
|
||||
assert(m_clsNameTemp >= 0);
|
||||
cg_printf("clsName%d, ", m_clsNameTemp);
|
||||
}
|
||||
} else {
|
||||
cg_printf("STATIC_CLASS_INVOKE_CALL(mcp%d.getClassName(), ",
|
||||
m_ciTemp);
|
||||
}
|
||||
if (m_voidReturn) m_voidWrapper = true;
|
||||
staticClassName = true;
|
||||
}
|
||||
|
||||
if (m_voidReturn) clearContext(RefValue);
|
||||
TypePtr eType = getExpectedType();
|
||||
bool wrap = m_voidWrapper && m_cppTemp.empty() && !isUnused();
|
||||
if (wrap) {
|
||||
cg_printf("(");
|
||||
setExpectedType(TypePtr());
|
||||
}
|
||||
Expression::outputCPP(cg, ar);
|
||||
if (wrap) {
|
||||
setExpectedType(eType);
|
||||
if (eType && !Type::IsMappedToVariant(eType)) {
|
||||
if (eType->is(Type::KindOfBoolean)) {
|
||||
cg_printf(", false)");
|
||||
} else if (eType->isInteger()) {
|
||||
cg_printf(", 0)");
|
||||
} else if (eType->is(Type::KindOfDouble)) {
|
||||
cg_printf(", 0.0)");
|
||||
} else if (eType->is(Type::KindOfString)) {
|
||||
cg_printf(", empty_string)");
|
||||
} else {
|
||||
cg_printf(", ");
|
||||
eType->outputCPPCast(cg, ar, getScope());
|
||||
cg_printf("(null))");
|
||||
}
|
||||
} else {
|
||||
cg_printf(", null)");
|
||||
}
|
||||
}
|
||||
|
||||
if (staticClassName) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionCall::optimizeArgArray(AnalysisResultPtr ar) {
|
||||
if (m_extraArg <= 0 || m_argArrayId >= 0) return;
|
||||
int paramCount = m_params->getOutputCount();
|
||||
int iMax = paramCount - m_extraArg;
|
||||
bool isScalar = true;
|
||||
for (int i = iMax; i < paramCount; i++) {
|
||||
ExpressionPtr param = (*m_params)[i];
|
||||
if (!param->isScalar()) {
|
||||
isScalar = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isScalar) {
|
||||
ExpressionPtr argArrayPairs =
|
||||
ExpressionListPtr(new ExpressionList(getScope(), getLocation()));
|
||||
for (int i = iMax; i < paramCount; i++) {
|
||||
ExpressionPtr param = (*m_params)[i];
|
||||
argArrayPairs->addElement(
|
||||
ArrayPairExpressionPtr(new ArrayPairExpression(
|
||||
getScope(), param->getLocation(),
|
||||
ExpressionPtr(), param, false)));
|
||||
}
|
||||
string text;
|
||||
m_argArrayId =
|
||||
ar->registerScalarArray(false, getFileScope(), argArrayPairs,
|
||||
m_argArrayHash, m_argArrayIndex, text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ protected:
|
||||
public:
|
||||
void analyzeProgram(AnalysisResultPtr ar);
|
||||
|
||||
// overriding Expression::outputCPP to implement void wrapper
|
||||
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
virtual bool isRefable(bool checkError = false) const { return true;}
|
||||
virtual bool isTemporary() const;
|
||||
|
||||
@@ -52,8 +50,6 @@ public:
|
||||
ExpressionPtr getNameExp() const { return m_nameExp; }
|
||||
const ExpressionListPtr& getParams() const { return m_params; }
|
||||
void setNoInline() { m_noInline = true; }
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
void deepCopy(FunctionCallPtr exp);
|
||||
|
||||
FunctionScopeRawPtr getFuncScope() const { return m_funcScope; }
|
||||
@@ -62,8 +58,6 @@ public:
|
||||
bool isValid() const { return m_valid; }
|
||||
|
||||
protected:
|
||||
void outputDynamicCall(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, bool method);
|
||||
ExpressionPtr m_nameExp;
|
||||
std::string m_name;
|
||||
std::string m_origName;
|
||||
|
||||
@@ -286,7 +286,7 @@ ExpressionPtr IncludeExpression::postOptimize(AnalysisResultConstPtr ar) {
|
||||
return replaceValue(rep->clone());
|
||||
}
|
||||
}
|
||||
if (!hhvm || !Option::OutputHHBC) {
|
||||
if (!Option::OutputHHBC) {
|
||||
m_exp.reset();
|
||||
}
|
||||
} else {
|
||||
@@ -307,53 +307,3 @@ TypePtr IncludeExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
void IncludeExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
UnaryOpExpression::outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
void IncludeExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
// Includes aren't really supported in system mode
|
||||
if (cg.getOutput() == CodeGenerator::SystemCPP) {
|
||||
cg_printf("true");
|
||||
return;
|
||||
}
|
||||
const char *vars = m_privateScope ?
|
||||
"lvar_ptr(LVariableTable())" : "variables";
|
||||
bool require = (m_op == T_REQUIRE || m_op == T_REQUIRE_ONCE);
|
||||
bool once = (m_op == T_INCLUDE_ONCE || m_op == T_REQUIRE_ONCE);
|
||||
if (!m_include.empty()) {
|
||||
FileScopePtr fs = ar->findFileScope(m_include);
|
||||
if (fs) {
|
||||
if (!fs->canUseDummyPseudoMain(ar)) {
|
||||
if (!fs->needPseudoMainVariables()) {
|
||||
vars = "NULL";
|
||||
}
|
||||
cg_printf("%s%s(%s, %s, %s)", Option::PseudoMainPrefix,
|
||||
fs->pseudoMainName().c_str(),
|
||||
once ? "true" : "false",
|
||||
vars, cg.getGlobals(ar));
|
||||
} else {
|
||||
cg_printf("true");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// include() and require() need containing file's directory
|
||||
string currentDir = "\"\"";
|
||||
if (m_loc && m_loc->file && *m_loc->file) {
|
||||
string file = m_loc->file;
|
||||
size_t pos = file.rfind('/');
|
||||
if (pos != string::npos) {
|
||||
currentDir = '"';
|
||||
currentDir += file.substr(0, pos + 1);
|
||||
currentDir += '"';
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to dynamic include
|
||||
cg_printf("%s(", require ? "require" : "include");
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(", %s, %s, %s)",
|
||||
once ? "true" : "false",
|
||||
vars,
|
||||
currentDir.c_str());
|
||||
}
|
||||
|
||||
@@ -263,154 +263,3 @@ void ListAssignment::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
static string getArrRef(const string &arrTmp, int index) {
|
||||
if (arrTmp == "null_variant") return arrTmp;
|
||||
return arrTmp + "[" + lexical_cast<string>(index) + "]";
|
||||
}
|
||||
|
||||
bool ListAssignment::outputCPPAssignment(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
const string &arrTmp, bool subRef) {
|
||||
if (!m_variables) return false;
|
||||
|
||||
bool ret = false;
|
||||
for (int i = m_variables->getCount() - 1; i >= 0; --i) {
|
||||
ExpressionPtr exp = (*m_variables)[i];
|
||||
if (exp) {
|
||||
if (exp->is(Expression::KindOfListAssignment)) {
|
||||
ListAssignmentPtr sublist = dynamic_pointer_cast<ListAssignment>(exp);
|
||||
string subTmp;
|
||||
if (arrTmp == "null_variant") {
|
||||
subTmp = arrTmp;
|
||||
} else {
|
||||
subTmp = genCPPTemp(cg, ar);
|
||||
cg_printf("Variant %s((%s(%s[%d])));\n",
|
||||
subTmp.c_str(), subRef ? "strongBind" : "",
|
||||
arrTmp.c_str(), i);
|
||||
}
|
||||
if (sublist->outputCPPAssignment(cg, ar, subTmp, subRef)) ret = true;
|
||||
} else {
|
||||
ret = true;
|
||||
bool done = false;
|
||||
if (exp->is(Expression::KindOfArrayElementExpression)) {
|
||||
ArrayElementExpressionPtr arrExp =
|
||||
dynamic_pointer_cast<ArrayElementExpression>(exp);
|
||||
if (!arrExp->isSuperGlobal() && !arrExp->isDynamicGlobal()) {
|
||||
arrExp->getVariable()->outputCPP(cg, ar);
|
||||
if (arrExp->getOffset()) {
|
||||
cg_printf(".set(");
|
||||
arrExp->getOffset()->outputCPP(cg, ar);
|
||||
cg_printf(", ");
|
||||
} else {
|
||||
cg_printf(".append(");
|
||||
}
|
||||
cg_printf("%s);\n", getArrRef(arrTmp, i).c_str());
|
||||
done = true;
|
||||
}
|
||||
} else if (exp->is(Expression::KindOfObjectPropertyExpression)) {
|
||||
ObjectPropertyExpressionPtr var(
|
||||
dynamic_pointer_cast<ObjectPropertyExpression>(exp));
|
||||
if (!var->isValid()) {
|
||||
var->outputCPPObject(cg, ar);
|
||||
cg_printf("o_set(");
|
||||
var->outputCPPProperty(cg, ar);
|
||||
cg_printf(", %s, %s);\n",
|
||||
getArrRef(arrTmp, i).c_str(),
|
||||
getClassScope() ? "s_class_name" : "empty_string");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
exp->outputCPP(cg, ar);
|
||||
cg_printf(" = %s;\n", getArrRef(arrTmp, i).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ListAssignment::preOutputVariables(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int state) {
|
||||
for (int i = 0, c = m_variables->getCount(); i < c; ) {
|
||||
if (ExpressionPtr exp = (*m_variables)[i++]) {
|
||||
if (i == c) {
|
||||
state = 0;
|
||||
}
|
||||
if (exp->is(Expression::KindOfListAssignment)) {
|
||||
static_pointer_cast<ListAssignment>(exp)->
|
||||
preOutputVariables(cg, ar, state);
|
||||
} else {
|
||||
exp->preOutputCPP(cg, ar, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ListAssignment::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
assert(m_array);
|
||||
|
||||
if (!cg.inExpression()) return true;
|
||||
|
||||
if (m_variables) {
|
||||
preOutputVariables(cg, ar, m_variables->hasEffect() ||
|
||||
m_array->hasEffect() ? FixOrder : 0);
|
||||
}
|
||||
m_array->preOutputCPP(cg, ar, 0);
|
||||
|
||||
bool isArray = false, notArray = false;
|
||||
bool simpleVar = m_array->is(KindOfSimpleVariable) &&
|
||||
!static_pointer_cast<SimpleVariable>(m_array)->getAlwaysStash();
|
||||
bool needsUse = false;
|
||||
if (TypePtr type = m_array->getActualType()) {
|
||||
isArray = type->is(Type::KindOfArray);
|
||||
notArray = !isArray &&
|
||||
(type->isPrimitive() ||
|
||||
m_rhsKind == Null ||
|
||||
(m_rhsKind == Checked && (type->is(Type::KindOfString) ||
|
||||
type->is(Type::KindOfObject))));
|
||||
}
|
||||
cg.wrapExpressionBegin();
|
||||
if (outputLineMap(cg, ar)) cg_printf("0);\n");
|
||||
if (notArray && isUnused()) {
|
||||
if (m_array->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
|
||||
m_cppTemp = "null";
|
||||
} else {
|
||||
m_cppTemp = genCPPTemp(cg, ar);
|
||||
needsUse = simpleVar || m_array->isTemporary();
|
||||
const char *decl;
|
||||
if (isArray && m_array->getCPPType()->is(Type::KindOfArray)) {
|
||||
decl = needsUse ? "CArrRef" : "Array";
|
||||
} else {
|
||||
decl = needsUse ? "CVarRef" : "Variant";
|
||||
}
|
||||
cg_printf("%s %s((", decl, m_cppTemp.c_str());
|
||||
m_array->outputCPP(cg, ar);
|
||||
cg_printf("));\n");
|
||||
}
|
||||
std::string tmp;
|
||||
if (notArray) {
|
||||
tmp = "null_variant";
|
||||
if (needsUse) cg_printf("id(%s);\n", m_cppTemp.c_str());
|
||||
needsUse = false;
|
||||
} else if (m_rhsKind != Checked || isArray) {
|
||||
tmp = m_cppTemp;
|
||||
} else {
|
||||
tmp = genCPPTemp(cg, ar);
|
||||
cg_printf("CVarRef %s(f_is_array(%s)?%s:null_variant);\n",
|
||||
tmp.c_str(), m_cppTemp.c_str(), m_cppTemp.c_str());
|
||||
needsUse = true;
|
||||
}
|
||||
if (!outputCPPAssignment(cg, ar, tmp, simpleVar) && needsUse) {
|
||||
cg_printf("id(%s);\n", tmp.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ListAssignment::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
not_reached();
|
||||
}
|
||||
|
||||
@@ -49,11 +49,6 @@ private:
|
||||
RHSKind m_rhsKind;
|
||||
|
||||
void setLValue();
|
||||
bool outputCPPAssignment(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
const std::string &arrTmp, bool subRef);
|
||||
|
||||
void preOutputVariables(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -134,20 +134,3 @@ void ModifierExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModifierExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
/**
|
||||
* Not sure if we can bar access coding errors...
|
||||
if (isPublic()) {
|
||||
cg_printf("public: ");
|
||||
} else if (isProtected()) {
|
||||
cg_printf("protected: ");
|
||||
} else {
|
||||
cg_printf("private: ");
|
||||
}
|
||||
*/
|
||||
cg_printf("public: ");
|
||||
|
||||
if (isStatic()) cg_printf("static ");
|
||||
}
|
||||
|
||||
@@ -157,231 +157,9 @@ TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
// code generation functions
|
||||
|
||||
void NewObjectExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
outputLineMap(cg, ar);
|
||||
|
||||
cg_printf("new ");
|
||||
m_nameExp->outputPHP(cg, ar);
|
||||
cg_printf("(");
|
||||
if (m_params) m_params->outputPHP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
void NewObjectExpression::preOutputStash(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int state) {
|
||||
if (hasCPPTemp()) return;
|
||||
if (!m_receiverTemp.empty()) {
|
||||
TypePtr e = getExpectedType();
|
||||
if (!e || !Type::IsCastNeeded(ar, getActualType(), e)) {
|
||||
bool unused = isUnused();
|
||||
setUnused(true);
|
||||
outputCPPImpl(cg, ar);
|
||||
setUnused(unused);
|
||||
setCPPTemp(m_receiverTemp);
|
||||
cg_printf(";\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
optimizeArgArray(ar);
|
||||
FunctionCall::preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
void NewObjectExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
string &cname = isSelf() || isParent() ? m_name : m_origName;
|
||||
bool outsideClass = !isPresent();
|
||||
if (m_classScope &&
|
||||
(m_classScope->isAbstract() ||
|
||||
m_classScope->isTrait() ||
|
||||
m_classScope->isInterface())) {
|
||||
cg_printf("throw_fatal(\"Cannot instantiate %s %s\").toObject()",
|
||||
m_classScope->isTrait() ? "trait" :
|
||||
m_classScope->isInterface() ? "interface" : "abstract class",
|
||||
CodeGenerator::EscapeLabel(
|
||||
m_classScope->getOriginalName()).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_name.empty() && m_classScope && !m_dynamic) {
|
||||
ClassScopePtr cls = m_classScope;
|
||||
|
||||
const string& lClassName = cls->getId();
|
||||
bool skipCreate = cls->canSkipCreateMethod(ar);
|
||||
if (skipCreate && m_params && m_params->getCount()) {
|
||||
cg_printf("(");
|
||||
for (int i = 0; i < m_params->getCount(); i++) {
|
||||
ExpressionPtr e = (*m_params)[i];
|
||||
if (!e->isScalar() && !e->hasCPPTemp()) {
|
||||
cg_printf("id(");
|
||||
e->outputCPP(cg, ar);
|
||||
cg_printf("), ");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_receiverTemp.empty()) {
|
||||
if (outsideClass) {
|
||||
cls->outputVolatileCheckBegin(cg, ar, getScope(), cname);
|
||||
}
|
||||
cg_printf("%s%s(((%s%s*)%s%s())",
|
||||
Option::SmartPtrPrefix, lClassName.c_str(),
|
||||
Option::ClassPrefix, lClassName.c_str(),
|
||||
Option::CreateObjectOnlyPrefix, lClassName.c_str());
|
||||
} else {
|
||||
cg_printf("((%s%s*)%s.get()",
|
||||
Option::ClassPrefix, lClassName.c_str(),
|
||||
m_receiverTemp.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (skipCreate) {
|
||||
assert(!m_params || m_params->getOutputCount() == 0);
|
||||
} else {
|
||||
cg_printf("->create(");
|
||||
FunctionScope::OutputCPPArguments(m_params, m_funcScope, cg, ar,
|
||||
m_extraArg, m_variableArgument,
|
||||
m_argArrayId, m_argArrayHash,
|
||||
m_argArrayIndex);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
if (cls->needsEnableDestructor(ar)) {
|
||||
cg_printf("->clearNoDestruct()");
|
||||
}
|
||||
if (m_receiverTemp.empty()) {
|
||||
cg_printf(")");
|
||||
if (outsideClass) {
|
||||
cls->outputVolatileCheckEnd(cg);
|
||||
}
|
||||
} else {
|
||||
if (!isUnused()) {
|
||||
cg_printf(", %s", m_receiverTemp.c_str());
|
||||
}
|
||||
cg_printf(")");
|
||||
}
|
||||
if (skipCreate && m_params && m_params->getCount()) {
|
||||
cg_printf(")");
|
||||
}
|
||||
} else {
|
||||
bool wrap = false;
|
||||
wrap = m_actualType && m_actualType->is(Type::KindOfVariant) &&
|
||||
!m_expectedType && !m_implementedType;
|
||||
if (wrap) {
|
||||
cg_printf("((Variant)");
|
||||
}
|
||||
cg_printf("id(obj%d)", m_objectTemp);
|
||||
if (wrap) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NewObjectExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (m_classScope &&
|
||||
(m_classScope->isAbstract() ||
|
||||
m_classScope->isInterface() ||
|
||||
m_classScope->isTrait())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string &cname = isSelf() || isParent() ? m_name : m_origName;
|
||||
if (m_name.empty() || !m_classScope || m_dynamic) {
|
||||
// Short circuit out if inExpression() returns false
|
||||
if (!cg.inExpression()) return true;
|
||||
|
||||
if (m_nameExp) m_nameExp->preOutputCPP(cg, ar, 0);
|
||||
cg.wrapExpressionBegin();
|
||||
m_ciTemp = cg.createNewLocalId(shared_from_this());
|
||||
m_objectTemp = cg.createNewLocalId(shared_from_this());
|
||||
cg_printf("Object obj%d(", m_objectTemp);
|
||||
if (isRedeclared()) {
|
||||
bool outsideClass = !isPresent();
|
||||
if (outsideClass) {
|
||||
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(), cname);
|
||||
}
|
||||
cg_printf("g->%s%s->createOnly()", Option::ClassStaticsCallbackPrefix,
|
||||
m_name.c_str());
|
||||
if (outsideClass) {
|
||||
ClassScope::OutputVolatileCheckEnd(cg);
|
||||
}
|
||||
} else {
|
||||
cg_printf("create_object_only(");
|
||||
if (isStatic()) {
|
||||
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
|
||||
} else if (!cname.empty()) {
|
||||
cg_printString(cname, ar, getScope(), true);
|
||||
} else if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
} else {
|
||||
cg_printf("(");
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(")");
|
||||
}
|
||||
cg_printf(");\n");
|
||||
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
|
||||
cg_printf("mcp%d.construct(obj%d);\n", m_ciTemp, m_objectTemp);
|
||||
cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp);
|
||||
|
||||
int pcount = m_params ? m_params->getCount() : 0;
|
||||
if (pcount > 0) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
m_params->preOutputCPP(cg, ar, 0);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
cg_printf("(cit%d->", m_ciTemp);
|
||||
outputDynamicCall(cg, ar, true);
|
||||
cg_printf(";\n");
|
||||
if (!m_classScope ||
|
||||
m_classScope->derivesFromRedeclaring() ||
|
||||
m_classScope->hasAttribute(ClassScope::HasDestructor, ar)) {
|
||||
cg_printf("obj%d.get()->clearNoDestruct();\n", m_objectTemp);
|
||||
}
|
||||
|
||||
if (state & FixOrder) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
preOutputStash(cg, ar, state);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
bool tempRcvr = true;
|
||||
|
||||
bool paramEffect = false;
|
||||
if (m_params && m_params->getCount() > 0) {
|
||||
for (int i = m_params->getCount(); i--; ) {
|
||||
if (!(*m_params)[i]->isScalar()) {
|
||||
paramEffect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!paramEffect) {
|
||||
tempRcvr = false;
|
||||
}
|
||||
|
||||
if (tempRcvr && cg.inExpression()) {
|
||||
bool outsideClass = !isPresent();
|
||||
cg.wrapExpressionBegin();
|
||||
m_receiverTemp = genCPPTemp(cg, ar);
|
||||
cg_printf("%s%s %s = ",
|
||||
Option::SmartPtrPrefix, m_classScope->getId().c_str(),
|
||||
m_receiverTemp.c_str());
|
||||
if (outsideClass) {
|
||||
m_classScope->outputVolatileCheckBegin(cg, ar, getScope(), cname);
|
||||
}
|
||||
cg_printf("%s%s()",
|
||||
Option::CreateObjectOnlyPrefix,
|
||||
m_classScope->getId().c_str());
|
||||
if (outsideClass) {
|
||||
m_classScope->outputVolatileCheckEnd(cg);
|
||||
}
|
||||
cg_printf(";\n");
|
||||
}
|
||||
|
||||
return FunctionCall::preOutputCPP(cg, ar, state) || tempRcvr || isUnused();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,7 @@ public:
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
virtual bool isRefable(bool checkError = false) const { return checkError; }
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
bool isTemporary() const { return true; }
|
||||
private:
|
||||
bool m_dynamic;
|
||||
|
||||
@@ -73,7 +73,7 @@ void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
if (func &&
|
||||
!cls->isInterface() &&
|
||||
!(func->isVirtual() &&
|
||||
(ar->isSystem() || func->isAbstract() ||
|
||||
(func->isAbstract() ||
|
||||
(func->hasOverride() &&
|
||||
cls->getAttribute(ClassScope::NotFinal))) &&
|
||||
!func->isPerfectVirtual())) {
|
||||
@@ -156,7 +156,7 @@ ExpressionPtr ObjectMethodExpression::preOptimize(AnalysisResultConstPtr ar) {
|
||||
|
||||
if (m_classScope && m_funcScope &&
|
||||
(!m_funcScope->isVirtual() ||
|
||||
(!ar->isSystem() && !m_funcScope->hasOverride()))) {
|
||||
(Option::WholeProgram && !m_funcScope->hasOverride()))) {
|
||||
|
||||
if (Option::DynamicInvokeFunctions.size()) {
|
||||
if (Option::DynamicInvokeFunctions.find(
|
||||
@@ -257,7 +257,7 @@ TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
|
||||
// invoke() will return Variant
|
||||
if (cls->isInterface() ||
|
||||
(func->isVirtual() &&
|
||||
(ar->isSystem() || func->isAbstract() ||
|
||||
(!Option::WholeProgram || func->isAbstract() ||
|
||||
(func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) &&
|
||||
!func->isPerfectVirtual())) {
|
||||
valid = false;
|
||||
@@ -283,8 +283,6 @@ TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
|
||||
|
||||
void ObjectMethodExpression::outputPHP(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
outputLineMap(cg, ar);
|
||||
|
||||
m_object->outputPHP(cg, ar);
|
||||
cg_printf("->");
|
||||
if (m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
|
||||
@@ -298,193 +296,3 @@ void ObjectMethodExpression::outputPHP(CodeGenerator &cg,
|
||||
m_params->outputPHP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
void ObjectMethodExpression::outputCPPObject(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
bool isThis = m_object->isThis();
|
||||
if (isThis) {
|
||||
TypePtr thisImplType(m_object->getImplementedType());
|
||||
TypePtr thisActType (m_object->getActualType());
|
||||
bool close = false;
|
||||
bool checkedThis = getFunctionScope()->isStatic();
|
||||
if (thisImplType) {
|
||||
assert(thisActType);
|
||||
assert(!Type::SameType(thisActType, thisImplType));
|
||||
ClassScopePtr implCls(thisImplType->getClass(ar, getScope()));
|
||||
if (implCls &&
|
||||
!implCls->derivesFrom(ar, thisActType->getName(), true, false)) {
|
||||
// This happens in this case:
|
||||
// if ($this instanceof Y) {
|
||||
// ... $this->meth() ...
|
||||
// }
|
||||
ClassScopePtr cls(thisActType->getClass(ar, getScope()));
|
||||
assert(cls && !cls->derivedByDynamic()); // since we don't do type
|
||||
// assertions for these
|
||||
if (!cls->derivesFrom(ar, thisImplType->getName(), true, false)) {
|
||||
assert(cls->derivesFromRedeclaring() &&
|
||||
implCls->derivedByDynamic());
|
||||
checkedThis = true;
|
||||
}
|
||||
cg_printf("static_cast<%s%s*>(",
|
||||
Option::ClassPrefix,
|
||||
cls->getId().c_str());
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
if (checkedThis) {
|
||||
if (close) {
|
||||
cg_printf("GET_THIS_VALID()");
|
||||
} else {
|
||||
cg_printf("GET_THIS_ARROW()");
|
||||
}
|
||||
} else {
|
||||
if (close) cg_printf("this");
|
||||
}
|
||||
if (close) {
|
||||
cg_printf(")->");
|
||||
}
|
||||
} else {
|
||||
TypePtr t = m_object->getType();
|
||||
bool ok = !t || t->is(Type::KindOfObject) || t->is(Type::KindOfVariant);
|
||||
if (!ok) cg_printf("Variant(");
|
||||
m_object->outputCPP(cg, ar);
|
||||
if (!ok) cg_printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMethodExpression::outputCPPObjectCall(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
outputCPPObject(cg, ar);
|
||||
bool isThis = m_object->isThis();
|
||||
if (!isThis) {
|
||||
m_object->outputCPPGuardedObjectPtr(cg);
|
||||
cg_printf("->");
|
||||
}
|
||||
|
||||
if (m_bindClass && m_classScope) {
|
||||
cg_printf("bindThis(fi.getThreadInfo()), %s%s::",
|
||||
Option::ClassPrefix, m_classScope->getId().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectMethodExpression::preOutputCPP(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int state) {
|
||||
if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
|
||||
if (m_object->hasEffect()) {
|
||||
if (cg.inExpression()) {
|
||||
m_object->preOutputCPP(cg, ar, FixOrder);
|
||||
if (m_params) m_params->preOutputCPP(cg, ar, 0);
|
||||
if (state & FixOrder) {
|
||||
preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return FunctionCall::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
// Short circuit out if inExpression() returns false
|
||||
if (!cg.inExpression()) return true;
|
||||
cg.wrapExpressionBegin();
|
||||
m_ciTemp = cg.createNewLocalId(shared_from_this());
|
||||
|
||||
if (outputLineMap(cg, ar)) cg_printf("0);\n");
|
||||
|
||||
bool isThis = m_object->isThis();
|
||||
if (!isThis) {
|
||||
int s = 0;
|
||||
if (m_name.empty() &&
|
||||
m_nameExp->hasEffect() && !m_object->isScalar()) {
|
||||
s = FixOrder;
|
||||
}
|
||||
m_object->preOutputCPP(cg, ar, s);
|
||||
}
|
||||
if (m_name.empty()) {
|
||||
m_nameExp->preOutputCPP(cg, ar, 0);
|
||||
}
|
||||
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
|
||||
|
||||
if (!isThis) {
|
||||
TypePtr t = m_object->getType();
|
||||
if (t && t->is(Type::KindOfObject)) {
|
||||
cg_printf("CObjRef obj%d = ", m_ciTemp);
|
||||
} else {
|
||||
cg_printf("CVarRef obj%d = ", m_ciTemp);
|
||||
}
|
||||
outputCPPObject(cg, ar);
|
||||
cg_printf(";\n");
|
||||
}
|
||||
if (m_name.empty()) {
|
||||
cg_printf("CStrRef mth%d = ", m_ciTemp);
|
||||
m_nameExp->outputCPP(cg, ar);
|
||||
cg_printf(";\n");
|
||||
}
|
||||
|
||||
cg_printf("mcp%d.methodCall((", m_ciTemp);
|
||||
if (isThis) {
|
||||
if (!getClassScope() || getClassScope()->derivedByDynamic() ||
|
||||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded()) {
|
||||
cg_printf("GET_THIS_VALID()");
|
||||
} else {
|
||||
cg_printf("this");
|
||||
}
|
||||
} else {
|
||||
cg_printf("obj%d", m_ciTemp);
|
||||
m_object->outputCPPGuardedObjectPtr(cg);
|
||||
}
|
||||
cg_printf("), ");
|
||||
if (!m_name.empty()) {
|
||||
strhash_t hash = hash_string_i(m_name.c_str());
|
||||
cg_printString(m_origName, ar, shared_from_this());
|
||||
cg_printf(", " STRHASH_FMT ");\n", hash);
|
||||
} else {
|
||||
cg_printf("mth%d, -1);\n", m_ciTemp);
|
||||
}
|
||||
cg_printf("const CallInfo *cit%d ATTRIBUTE_UNUSED = mcp%d.ci;\n",
|
||||
m_ciTemp, m_ciTemp);
|
||||
|
||||
if (m_params && m_params->getCount() > 0) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
m_params->preOutputCPP(cg, ar, 0);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
if (state & FixOrder) {
|
||||
cg.pushCallInfo(m_ciTemp);
|
||||
preOutputStash(cg, ar, state);
|
||||
cg.popCallInfo();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectMethodExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
|
||||
// Direct method call
|
||||
ClassScopePtr cls(m_object->getType()->getClass(ar, getScope()));
|
||||
if (cls) getFileScope()->addUsedClassFullHeader(cls);
|
||||
|
||||
if (m_bindClass && m_classScope) cg_printf("(");
|
||||
outputCPPObjectCall(cg, ar);
|
||||
cg_printf("%s%s(", m_funcScope ?
|
||||
m_funcScope->getPrefix(ar, m_params) : Option::MethodPrefix,
|
||||
m_name.c_str());
|
||||
|
||||
FunctionScope::OutputCPPArguments(m_params, m_funcScope, cg, ar,
|
||||
m_extraArg, m_variableArgument,
|
||||
m_argArrayId, m_argArrayHash,
|
||||
m_argArrayIndex);
|
||||
cg_printf(")");
|
||||
if (m_bindClass && m_classScope) cg_printf(")");
|
||||
} else {
|
||||
bool maybeStatic = true;
|
||||
if (Option::WholeProgram && !ar->isSystem() && !m_name.empty()) {
|
||||
FunctionScope::FunctionInfoPtr info =
|
||||
FunctionScope::GetFunctionInfo(m_name);
|
||||
if (info && !info->getMaybeStatic()) maybeStatic = false;
|
||||
}
|
||||
cg_printf("(mcp%d.%s->",
|
||||
m_ciTemp, maybeStatic ? "bindClass(fi)" : "ci" );
|
||||
outputDynamicCall(cg, ar, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,6 @@ public:
|
||||
|
||||
virtual TypePtr inferAndCheck(AnalysisResultPtr ar, TypePtr type,
|
||||
bool coerce);
|
||||
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
|
||||
ExpressionPtr getObject() const { return m_object; }
|
||||
private:
|
||||
ExpressionPtr m_object;
|
||||
@@ -50,9 +47,6 @@ private:
|
||||
// for avoiding code generate toObject(Variant)
|
||||
bool directVariantProxy(AnalysisResultPtr ar);
|
||||
bool m_bindClass;
|
||||
|
||||
void outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPObjectCall(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -357,301 +357,3 @@ void ObjectPropertyExpression::outputPHP(CodeGenerator &cg,
|
||||
cg_printf("}");
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectPropertyExpression::preOutputCPP(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, int state) {
|
||||
return preOutputOffsetLHS(cg, ar, state);
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
outputCPPObjProperty(cg, ar, false);
|
||||
}
|
||||
|
||||
static string nullName(AnalysisResultPtr ar, TypePtr type) {
|
||||
if (!type || Type::IsMappedToVariant(type)) {
|
||||
return "null_variant";
|
||||
}
|
||||
if (type->is(Type::KindOfArray)) {
|
||||
return "null_array";
|
||||
}
|
||||
if (type->is(Type::KindOfObject)) {
|
||||
return "null_object";
|
||||
}
|
||||
if (type->is(Type::KindOfString)) {
|
||||
return "null_string";
|
||||
}
|
||||
return type->getCPPDecl(ar, BlockScopeRawPtr()) + "()";
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int doExist) {
|
||||
if (m_valid) {
|
||||
TypePtr type = m_object->getActualType();
|
||||
if (type->isSpecificObject()) {
|
||||
ClassScopePtr cls(type->getClass(ar, getScope()));
|
||||
if (cls) getFileScope()->addUsedClassFullHeader(cls);
|
||||
}
|
||||
}
|
||||
|
||||
string func = Option::ObjectPrefix;
|
||||
const char *error = ", true";
|
||||
std::string context = "";
|
||||
bool doUnset = m_context & LValue && m_context & UnsetContext;
|
||||
bool needTemp = false;
|
||||
|
||||
if (cg.getOutput() != CodeGenerator::SystemCPP) {
|
||||
context = originalClassName(cg, true);
|
||||
}
|
||||
if (doUnset) {
|
||||
func = "o_unset";
|
||||
error = "";
|
||||
} else if (doExist) {
|
||||
func = doExist > 0 ? "o_isset" : "o_empty";
|
||||
error = "";
|
||||
} else {
|
||||
if (m_context & ExistContext) {
|
||||
error = ", false";
|
||||
}
|
||||
if (m_context & InvokeArgument) {
|
||||
if (cg.callInfoTop() != -1) {
|
||||
func += "argval";
|
||||
} else {
|
||||
func += "get";
|
||||
}
|
||||
} else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) {
|
||||
if (m_context & UnsetContext) {
|
||||
always_assert(!(m_context & LValue)); // handled by doUnset
|
||||
func += "unsetLval";
|
||||
} else {
|
||||
func += "lval";
|
||||
}
|
||||
error = "";
|
||||
needTemp = true;
|
||||
} else {
|
||||
func += "get";
|
||||
if (isNonPrivate(ar)) {
|
||||
func += "Public";
|
||||
context = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid && !m_object->isThis() &&
|
||||
(!m_object->is(KindOfSimpleVariable) ||
|
||||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded())) {
|
||||
cg_printf("(obj_tmp = ");
|
||||
outputCPPValidObject(cg, ar, false);
|
||||
bool write_context = hasAnyContext(LValue | RefValue | DeepReference |
|
||||
UnsetContext | OprLValue |
|
||||
DeepOprLValue | DeepAssignmentLHS |
|
||||
AssignmentLHS) && !doUnset;
|
||||
cg_printf(", LIKELY(obj_tmp != 0) %s ", write_context ? "||" : "?");
|
||||
always_assert(m_property->is(KindOfScalarExpression));
|
||||
ScalarExpressionPtr name =
|
||||
static_pointer_cast<ScalarExpression>(m_property);
|
||||
if (doExist || doUnset) {
|
||||
cg_printf(doUnset ? "unset" : doExist > 0 ? "isset" : "empty");
|
||||
}
|
||||
ClassScopePtr cls =
|
||||
ar->findExactClass(shared_from_this(),
|
||||
m_object->getActualType()->getName());
|
||||
|
||||
if (write_context) {
|
||||
cg_printf("(throw_null_object_prop(),false),");
|
||||
}
|
||||
cg_printf("(((%s%s*)obj_tmp)->%s%s)",
|
||||
Option::ClassPrefix, cls->getId().c_str(),
|
||||
Option::PropertyPrefix, name->getLiteralString().c_str());
|
||||
|
||||
if (!write_context) {
|
||||
cg_printf(" : (raise_null_object_prop(),%s)",
|
||||
doUnset ? "null_variant" :
|
||||
doExist ? doExist > 0 ? "false" : "true" :
|
||||
nullName(ar, getCPPType()).c_str());
|
||||
}
|
||||
cg_printf(")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_valid && (doExist || doUnset)) {
|
||||
cg_printf(doUnset ? "unset(" : doExist > 0 ? "isset(" : "empty(");
|
||||
}
|
||||
bool flag = outputCPPObject(cg, ar, !m_valid && (doUnset || doExist));
|
||||
if (flag) {
|
||||
cg_printf("id(");
|
||||
outputCPPProperty(cg, ar);
|
||||
cg_printf(")");
|
||||
if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true");
|
||||
cg_printf(")");
|
||||
} else if (m_valid) {
|
||||
always_assert(m_object->getActualType() &&
|
||||
m_object->getActualType()->isSpecificObject());
|
||||
ScalarExpressionPtr name =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||
cg_printf("%s%s", Option::PropertyPrefix,
|
||||
name->getLiteralString().c_str());
|
||||
if (doExist || doUnset) cg_printf(")");
|
||||
} else {
|
||||
cg_printf("%s(", func.c_str());
|
||||
if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
|
||||
cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
|
||||
}
|
||||
outputCPPProperty(cg, ar);
|
||||
if (needTemp) {
|
||||
const string &tmp = cg.getReferenceTemp();
|
||||
context = ", " + (tmp.empty() ? "Variant()" : tmp) + context;
|
||||
}
|
||||
cg_printf("%s%s)", error, context.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPValidObject(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool guarded) {
|
||||
TypePtr act;
|
||||
bool close = false;
|
||||
if (!m_object->hasCPPTemp() && m_object->getImplementedType() &&
|
||||
!Type::SameType(m_object->getImplementedType(),
|
||||
m_object->getActualType())) {
|
||||
act = m_object->getActualType();
|
||||
m_object->setActualType(m_object->getImplementedType());
|
||||
if (guarded) {
|
||||
ClassScopePtr cls = ar->findExactClass(shared_from_this(),
|
||||
act->getName());
|
||||
cg_printf("((%s%s*)", Option::ClassPrefix, cls->getId().c_str());
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
m_object->outputCPP(cg, ar);
|
||||
if (act) {
|
||||
if (m_object->getImplementedType()->is(Type::KindOfObject)) {
|
||||
cg_printf(".get()");
|
||||
} else {
|
||||
cg_printf(".getObjectData%s()", guarded ? "" : "OrNull");
|
||||
}
|
||||
if (close) cg_printf(")");
|
||||
m_object->setActualType(act);
|
||||
} else {
|
||||
cg_printf(".get()");
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectPropertyExpression::outputCPPObject(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
bool noEvalOnError) {
|
||||
if (m_object->isThis()) {
|
||||
TypePtr thisImplType(m_object->getImplementedType());
|
||||
TypePtr thisActType (m_object->getActualType());
|
||||
bool close = false;
|
||||
if (m_valid && thisImplType) {
|
||||
assert(thisActType);
|
||||
assert(!Type::SameType(thisActType, thisImplType));
|
||||
ClassScopePtr implCls(thisImplType->getClass(ar, getScope()));
|
||||
if (implCls &&
|
||||
!implCls->derivesFrom(ar, thisActType->getName(), true, false)) {
|
||||
// This happens in this case:
|
||||
// if ($this instanceof Y) {
|
||||
// ... $this->prop ...
|
||||
// }
|
||||
ClassScopePtr cls(thisActType->getClass(ar, getScope()));
|
||||
assert(cls && cls->derivesFrom(ar, thisImplType->getName(),
|
||||
true, false));
|
||||
|
||||
cg_printf("static_cast<%s%s*>(",
|
||||
Option::ClassPrefix,
|
||||
cls->getId().c_str());
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
if (m_valid) {
|
||||
if (!m_object->getOriginalClass()) {
|
||||
m_valid = false;
|
||||
} else {
|
||||
FunctionScopeRawPtr fs = m_object->getOriginalFunction();
|
||||
if (!fs || fs->isStatic()) {
|
||||
m_valid = false;
|
||||
} else if (m_object->getOriginalClass() != getClassScope()) {
|
||||
if (m_object->getOriginalClass()->isRedeclaring()) {
|
||||
m_valid = false;
|
||||
} else {
|
||||
m_objectClass = getClassScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_valid) {
|
||||
if (close) cg_printf("this");
|
||||
} else {
|
||||
if (!getClassScope() || getClassScope()->derivedByDynamic() ||
|
||||
(getFunctionScope() && getFunctionScope()->isStatic()) ||
|
||||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded()) {
|
||||
if (close) {
|
||||
cg_printf("GET_THIS_VALID()");
|
||||
} else {
|
||||
cg_printf("GET_THIS_ARROW()");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (close) {
|
||||
cg_printf(")->");
|
||||
}
|
||||
} else if (m_valid) {
|
||||
assert(m_object->is(KindOfSimpleVariable) &&
|
||||
static_pointer_cast<SimpleVariable>(m_object)->isGuarded());
|
||||
outputCPPValidObject(cg, ar, true);
|
||||
cg_printf("->");
|
||||
} else {
|
||||
TypePtr t = m_object->getType();
|
||||
bool ok = t && (t->is(Type::KindOfObject) || t->is(Type::KindOfVariant));
|
||||
if (noEvalOnError && !ok) {
|
||||
if (!t || !t->is(Type::KindOfArray)) {
|
||||
cg_printf("(");
|
||||
if (m_object->outputCPPUnneeded(cg, ar)) cg_printf(", ");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ok = ok || !t;
|
||||
if (!ok) cg_printf("Variant(");
|
||||
m_object->outputCPP(cg, ar);
|
||||
if (!ok) cg_printf(")");
|
||||
if (ok && m_object->outputCPPGuardedObjectPtr(cg)) {
|
||||
cg_printf("->");
|
||||
} else {
|
||||
cg_printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid && m_propSym->isPrivate() &&
|
||||
m_objectClass != getOriginalClass()) {
|
||||
cg_printf("%s%s::",
|
||||
Option::ClassPrefix, getOriginalClass()->getId().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPProperty(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
|
||||
ScalarExpressionPtr name =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_property);
|
||||
string propName = name->getLiteralString();
|
||||
if (!propName.empty()) {
|
||||
cg_printString(propName, ar, shared_from_this());
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_property->outputCPP(cg, ar);
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPExistTest(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int op) {
|
||||
outputCPPObjProperty(cg, ar, op == T_ISSET ? 1 : -1);
|
||||
}
|
||||
|
||||
void ObjectPropertyExpression::outputCPPUnset(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
outputCPPObjProperty(cg, ar, 0);
|
||||
}
|
||||
|
||||
@@ -45,18 +45,9 @@ public:
|
||||
ExpressionPtr getObject() { return m_object;}
|
||||
ExpressionPtr getProperty() { return m_property;}
|
||||
|
||||
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int op);
|
||||
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
bool isTemporary() const;
|
||||
bool isNonPrivate(AnalysisResultPtr ar);
|
||||
bool isValid() const { return m_valid; }
|
||||
void outputCPPProperty(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
bool outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool noEvalOnError = false);
|
||||
void outputCPPValidObject(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
bool guarded);
|
||||
private:
|
||||
ExpressionPtr m_object;
|
||||
ExpressionPtr m_property;
|
||||
@@ -70,8 +61,6 @@ private:
|
||||
|
||||
// for avoiding code generate toObject(Variant)
|
||||
bool directVariantProxy(AnalysisResultPtr ar);
|
||||
void outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int doExist);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -34,7 +34,7 @@ ParameterExpression::ParameterExpression
|
||||
const std::string &type, const std::string &name, bool ref,
|
||||
ExpressionPtr defaultValue, ExpressionPtr attributeList)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ParameterExpression)),
|
||||
m_originalType(type), m_name(name), m_ref(ref), m_hasRTTI(false),
|
||||
m_originalType(type), m_name(name), m_ref(ref),
|
||||
m_defaultValue(defaultValue), m_attributeList(attributeList) {
|
||||
m_type = Util::toLower(type);
|
||||
if (m_defaultValue) {
|
||||
@@ -285,102 +285,3 @@ void ParameterExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_defaultValue->outputPHP(cg, ar);
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
FunctionScopePtr func = getFunctionScope();
|
||||
VariableTablePtr variables = func->getVariables();
|
||||
Symbol *sym = variables->getSymbol(m_name);
|
||||
always_assert(sym && sym->isParameter());
|
||||
|
||||
bool inHeader = cg.isFileOrClassHeader();
|
||||
cg.setFileOrClassHeader(true);
|
||||
CodeGenerator::Context context = cg.getContext();
|
||||
bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
|
||||
context == CodeGenerator::CppTypedParamsWrapperDecl);
|
||||
|
||||
TypePtr paramType =
|
||||
typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
|
||||
Type::Variant : func->getParamType(sym->getParameterIndex());
|
||||
bool wrapper = typedWrapper ||
|
||||
context == CodeGenerator::CppFunctionWrapperImpl ||
|
||||
context == CodeGenerator::CppFunctionWrapperDecl;
|
||||
|
||||
bool isCVarRef = false;
|
||||
const char *prefix = "";
|
||||
if (m_ref) {
|
||||
cg_printf("VRefParam");
|
||||
if (!wrapper) {
|
||||
prefix = "r";
|
||||
}
|
||||
} else if (wrapper ||
|
||||
(!variables->isLvalParam(m_name) &&
|
||||
!variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
|
||||
!variables->getAttribute(VariableTable::ContainsExtract))) {
|
||||
if (paramType->is(Type::KindOfVariant) ||
|
||||
paramType->is(Type::KindOfSome)) {
|
||||
cg_printf("CVarRef");
|
||||
isCVarRef = true;
|
||||
}
|
||||
else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef");
|
||||
else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
|
||||
else paramType->outputCPPDecl(cg, ar, getScope());
|
||||
} else {
|
||||
paramType->outputCPPDecl(cg, ar, getScope());
|
||||
}
|
||||
|
||||
cg_printf(" %s%s%s",
|
||||
prefix, Option::VariablePrefix,
|
||||
CodeGenerator::FormatLabel(m_name).c_str());
|
||||
if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
|
||||
bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
|
||||
context == CodeGenerator::CppFunctionWrapperImpl ||
|
||||
context == CodeGenerator::CppImplementation ||
|
||||
(context == CodeGenerator::CppDeclaration && func->isInlined());
|
||||
if (comment) {
|
||||
cg_printf(" // ");
|
||||
}
|
||||
cg_printf(" = ");
|
||||
ConstantExpressionPtr con =
|
||||
dynamic_pointer_cast<ConstantExpression>(m_defaultValue);
|
||||
|
||||
bool done = false;
|
||||
if (con && con->isNull()) {
|
||||
done = true;
|
||||
if (isCVarRef) {
|
||||
cg_printf("null_variant");
|
||||
} else if (paramType->is(Type::KindOfVariant) ||
|
||||
paramType->is(Type::KindOfSome)) {
|
||||
cg_printf("null");
|
||||
} else if (paramType->is(Type::KindOfObject)) {
|
||||
cg_printf("Object()");
|
||||
} else if (paramType->is(Type::KindOfArray)) {
|
||||
cg_printf("Array()");
|
||||
} else if (paramType->is(Type::KindOfString)) {
|
||||
cg_printf("String()");
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
if (comment) {
|
||||
cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
|
||||
} else {
|
||||
cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
|
||||
}
|
||||
bool isScalar = m_defaultValue->isScalar();
|
||||
if (isCVarRef && isScalar) {
|
||||
assert(!cg.hasScalarVariant());
|
||||
cg.setScalarVariant();
|
||||
}
|
||||
m_defaultValue->outputCPP(cg, ar);
|
||||
if (isCVarRef && isScalar) cg.clearScalarVariant();
|
||||
assert(!cg.hasScalarVariant());
|
||||
cg.setContext(context);
|
||||
}
|
||||
if (comment) {
|
||||
cg_printf("\n");
|
||||
}
|
||||
}
|
||||
cg.setFileOrClassHeader(inHeader);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ public:
|
||||
|
||||
bool isRef() const { return m_ref;}
|
||||
bool isOptional() const { return m_defaultValue;}
|
||||
bool hasRTTI() const { return m_hasRTTI;}
|
||||
void setHasRTTI() { m_hasRTTI = true;}
|
||||
const std::string &getName() const { return m_name; }
|
||||
int getLocalEffects() const { return NoEffect; }
|
||||
void rename(const std::string &name) { m_name = name;}
|
||||
@@ -65,7 +63,6 @@ private:
|
||||
std::string m_originalType;
|
||||
std::string m_name;
|
||||
bool m_ref;
|
||||
bool m_hasRTTI;
|
||||
ExpressionPtr m_defaultValue;
|
||||
ExpressionPtr m_attributeList;
|
||||
};
|
||||
|
||||
@@ -176,151 +176,3 @@ void QOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_expNo->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
void QOpExpression::wrapBoolean(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
ExpressionPtr exp) {
|
||||
TypePtr t(exp->getType());
|
||||
assert(t);
|
||||
bool wrap = false;
|
||||
if (!t->is(Type::KindOfBoolean)) {
|
||||
wrap = true;
|
||||
cg_printf("toBoolean(");
|
||||
}
|
||||
exp->outputCPP(cg, ar);
|
||||
if (wrap) cg_printf(")");
|
||||
}
|
||||
|
||||
bool QOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (!hasEffect()) {
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
bool fix_condition = m_condition->preOutputCPP(cg, ar, 0);
|
||||
if (!cg.inExpression()) {
|
||||
return fix_condition || (state & FixOrder) ||
|
||||
(!m_expYes || m_expYes->preOutputCPP(cg, ar, 0)) ||
|
||||
m_expNo->preOutputCPP(cg, ar, 0);
|
||||
}
|
||||
|
||||
cg.setInExpression(false);
|
||||
bool fix_yes = (!m_expYes || m_expYes->preOutputCPP(cg, ar, 0));
|
||||
bool fix_no = m_expNo->preOutputCPP(cg, ar, 0);
|
||||
cg.setInExpression(true);
|
||||
|
||||
if (fix_yes || fix_no) {
|
||||
cg.wrapExpressionBegin();
|
||||
if (isUnused()) {
|
||||
cg_printf("if (");
|
||||
wrapBoolean(cg, ar, m_condition);
|
||||
cg_indentBegin(") {\n");
|
||||
if (m_expYes) {
|
||||
m_expYes->preOutputCPP(cg, ar, 0);
|
||||
if (m_expYes->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
|
||||
}
|
||||
cg_indentEnd("\n");
|
||||
cg_indentBegin("} else {\n");
|
||||
m_expNo->preOutputCPP(cg, ar, 0);
|
||||
if (m_expNo->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
|
||||
cg_indentEnd("}\n");
|
||||
m_cppValue = "null_variant";
|
||||
} else {
|
||||
std::string tmp = genCPPTemp(cg, ar);
|
||||
|
||||
if (m_expYes) {
|
||||
TypePtr typeYes = m_expYes->getActualType();
|
||||
TypePtr typeNo = m_expNo->getActualType();
|
||||
TypePtr type =
|
||||
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
|
||||
!typeYes->is(Type::KindOfVariant) &&
|
||||
m_expYes->isLiteralString() == m_expNo->isLiteralString() ?
|
||||
typeYes : Type::Variant;
|
||||
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
cg_printf(" %s;\n", tmp.c_str());
|
||||
cg_printf("if (");
|
||||
wrapBoolean(cg, ar, m_condition);
|
||||
cg_indentBegin(") {\n");
|
||||
m_expYes->preOutputCPP(cg, ar, 0);
|
||||
cg_printf("%s = (", tmp.c_str());
|
||||
m_expYes->outputCPP(cg, ar);
|
||||
cg_indentEnd(");\n");
|
||||
} else {
|
||||
TypePtr typeYes = m_condition->getActualType();
|
||||
TypePtr typeNo = m_expNo->getActualType();
|
||||
TypePtr type =
|
||||
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
|
||||
!typeYes->is(Type::KindOfVariant) &&
|
||||
m_condition->isLiteralString() == m_expNo->isLiteralString() ?
|
||||
typeYes : Type::Variant;
|
||||
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
cg_printf(" %s = ", tmp.c_str());
|
||||
m_condition->outputCPP(cg, ar);
|
||||
cg_printf(";\n");
|
||||
cg_printf("if (toBoolean(%s)) {\n", tmp.c_str());
|
||||
}
|
||||
|
||||
cg_indentBegin("} else {\n");
|
||||
m_expNo->preOutputCPP(cg, ar, 0);
|
||||
cg_printf("%s = (", tmp.c_str());
|
||||
m_expNo->outputCPP(cg, ar);
|
||||
cg_printf(");\n");
|
||||
cg_indentEnd("}\n");
|
||||
m_cppValue = tmp;
|
||||
}
|
||||
} else if (state & FixOrder) {
|
||||
preOutputStash(cg, ar, state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QOpExpression::outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
return m_cppValue.empty() && Expression::outputCPPUnneeded(cg, ar);
|
||||
}
|
||||
|
||||
static void outputUnneededExpr(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
ExpressionPtr exp) {
|
||||
cg_printf("(");
|
||||
if (exp->outputCPPUnneeded(cg, ar)) {
|
||||
cg_printf(",");
|
||||
}
|
||||
cg_printf("false)");
|
||||
}
|
||||
|
||||
void QOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (!m_cppValue.empty()) {
|
||||
cg_printf("%s", m_cppValue.c_str());
|
||||
} else {
|
||||
ExpressionPtr expYes = m_expYes ? m_expYes : m_condition;
|
||||
bool wrapped = !isUnused();
|
||||
if (wrapped) {
|
||||
cg_printf("(");
|
||||
}
|
||||
wrapBoolean(cg, ar, m_condition);
|
||||
if (isUnused()) {
|
||||
cg_printf(" ? ");
|
||||
outputUnneededExpr(cg, ar, expYes);
|
||||
cg_printf(" : ");
|
||||
outputUnneededExpr(cg, ar, m_expNo);
|
||||
} else {
|
||||
TypePtr typeYes = expYes->getActualType();
|
||||
TypePtr typeNo = m_expNo->getActualType();
|
||||
const char *castType =
|
||||
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
|
||||
!typeYes->is(Type::KindOfVariant) &&
|
||||
expYes->isLiteralString() == m_expNo->isLiteralString()
|
||||
? "" : "(Variant)";
|
||||
|
||||
cg_printf(" ? (%s(", castType);
|
||||
expYes->outputCPP(cg, ar);
|
||||
cg_printf(")) : (%s(", castType);
|
||||
m_expNo->outputCPP(cg, ar);
|
||||
cg_printf("))");
|
||||
}
|
||||
if (wrapped) {
|
||||
cg_printf(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,17 +36,10 @@ public:
|
||||
virtual int getLocalEffects() const { return NoEffect; }
|
||||
|
||||
virtual ExpressionPtr unneededHelper();
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
ExpressionPtr getCondition() const { return m_condition; }
|
||||
ExpressionPtr getYes() const { return m_expYes; }
|
||||
ExpressionPtr getNo() const { return m_expNo; }
|
||||
private:
|
||||
void wrapBoolean(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
ExpressionPtr exp);
|
||||
|
||||
ExpressionPtr m_condition;
|
||||
ExpressionPtr m_expYes;
|
||||
ExpressionPtr m_expNo;
|
||||
|
||||
@@ -164,7 +164,7 @@ void ScalarExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
unsigned ScalarExpression::getCanonHash() const {
|
||||
int64 val = getHash();
|
||||
int64_t val = getHash();
|
||||
if (val == -1) {
|
||||
val = hash_string(m_value.c_str(), m_value.size());
|
||||
}
|
||||
@@ -288,7 +288,7 @@ bool ScalarExpression::isLiteralInteger() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64 ScalarExpression::getLiteralInteger() const {
|
||||
int64_t ScalarExpression::getLiteralInteger() const {
|
||||
assert(isLiteralInteger());
|
||||
return strtoll(m_value.c_str(), nullptr, 0);
|
||||
}
|
||||
@@ -405,228 +405,13 @@ void ScalarExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string ScalarExpression::getCPPLiteralString(bool *binary /* = NULL */) {
|
||||
string output;
|
||||
switch (m_type) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
case T_STRING: {
|
||||
output = "\"";
|
||||
output += CodeGenerator::EscapeLabel(m_value, binary);
|
||||
output += "\"";
|
||||
break;
|
||||
}
|
||||
case T_TRAIT_C:
|
||||
case T_CLASS_C:
|
||||
case T_NS_C:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C:
|
||||
output = "\"";
|
||||
output += m_translated;
|
||||
output += "\"";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void ScalarExpression::OutputCPPString(
|
||||
const string &str, CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
BlockScopeRawPtr scope, bool constant) {
|
||||
if (!cg.hasScalarVariant() || !Option::UseScalarVariant) {
|
||||
cg_printString(str, ar, scope, constant);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isBinary = false;
|
||||
string escaped = CodeGenerator::EscapeLabel(str, &isBinary);
|
||||
string fullName = cg.printNamedString(str, escaped, ar, scope, false);
|
||||
assert(!fullName.empty());
|
||||
string prefix(Option::ScalarPrefix);
|
||||
if (Option::SystemGen) prefix += Option::SysPrefix;
|
||||
assert(fullName.find(prefix) == 0);
|
||||
string name =
|
||||
fullName.substr(prefix.size() + strlen(Option::StaticStringPrefix));
|
||||
cg.printf("NAMVAR(%s%s%s, \"%s\")",
|
||||
prefix.c_str(), Option::StaticVarStrPrefix,
|
||||
name.c_str(), escaped.c_str());
|
||||
ar->addNamedLiteralVarString(fullName);
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPString(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
switch (m_type) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
assert(m_quoted); // fall through
|
||||
case T_STRING: {
|
||||
if (m_quoted) {
|
||||
string output = getLiteralString();
|
||||
bool constant =
|
||||
(cg.getContext() == CodeGenerator::CppConstantsDecl) ||
|
||||
(cg.getContext() == CodeGenerator::CppClassConstantsImpl);
|
||||
OutputCPPString(output, cg, ar, getScope(), constant);
|
||||
} else {
|
||||
not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_TRAIT_C:
|
||||
case T_CLASS_C:
|
||||
case T_NS_C:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C:
|
||||
OutputCPPString(m_translated, cg, ar, getScope(), false);
|
||||
break;
|
||||
case T_NUM_STRING: {
|
||||
bool constant =
|
||||
(cg.getContext() == CodeGenerator::CppConstantsDecl) ||
|
||||
(cg.getContext() == CodeGenerator::CppClassConstantsImpl);
|
||||
always_assert(!constant);
|
||||
OutputCPPString(m_value, cg, ar, getScope(), false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPNamedInteger(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
Variant v = getVariant();
|
||||
assert(v.isInteger());
|
||||
int index = -1;
|
||||
int64 val = v.toInt64();
|
||||
int intId = ar->checkScalarVarInteger(val, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarIntegerName(intId, index);
|
||||
cg_printf("NAMVAR(%s, int64_t(%" PRId64 "))", name.c_str(), val);
|
||||
|
||||
getUsedScalarScope(cg)->addUsedScalarVarInteger(val);
|
||||
if (cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedScalarVarIntegerHeader(val);
|
||||
} else {
|
||||
getFileScope()->addUsedScalarVarIntegerHeader(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPInteger(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
Variant v = getVariant();
|
||||
assert(v.isInteger());
|
||||
if (v.toInt64() == std::numeric_limits<int64_t>::min()) {
|
||||
cg_printf("int64_t(0x8000000000000000LL)");
|
||||
} else {
|
||||
cg_printf("%" PRId64 "L", v.toInt64());
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPNamedDouble(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
double dval = getVariant().getDouble();
|
||||
if (finite(dval)) {
|
||||
int index = -1;
|
||||
int dblId = ar->checkScalarVarDouble(dval, index);
|
||||
always_assert(index != -1);
|
||||
string name = ar->getScalarVarDoubleName(dblId, index);
|
||||
cg_printf("NAMVAR(%s, ", name.c_str());
|
||||
ar->outputCPPFiniteDouble(cg, dval);
|
||||
cg_printf(")");
|
||||
getUsedScalarScope(cg)->addUsedScalarVarDouble(dval);
|
||||
if (cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedScalarVarDoubleHeader(dval);
|
||||
} else {
|
||||
getFileScope()->addUsedScalarVarDoubleHeader(dval);
|
||||
}
|
||||
}
|
||||
} else if (std::isnan(dval)) {
|
||||
cg_printf("NAN_varNR");
|
||||
} else if (dval > 0) {
|
||||
cg_printf("INF_varNR");
|
||||
} else {
|
||||
cg_printf("NEGINF_varNR");
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPDouble(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
double dval = getVariant().getDouble();
|
||||
if (finite(dval)) {
|
||||
ar->outputCPPFiniteDouble(cg, dval);
|
||||
} else if (std::isnan(dval)) {
|
||||
cg_printf("%sNAN", Option::ConstantPrefix);
|
||||
} else if (dval > 0) {
|
||||
cg_printf("%sINF", Option::ConstantPrefix);
|
||||
} else {
|
||||
cg_printf("-%sINF", Option::ConstantPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
switch (m_type) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
case T_STRING:
|
||||
case T_TRAIT_C:
|
||||
case T_CLASS_C:
|
||||
case T_NS_C:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C: {
|
||||
outputCPPString(cg, ar);
|
||||
break;
|
||||
}
|
||||
case T_LINE:
|
||||
ar->addInteger(getVariant().toInt64());
|
||||
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
|
||||
outputCPPNamedInteger(cg, ar);
|
||||
} else {
|
||||
cg_printf("%s", m_translated.c_str());
|
||||
}
|
||||
break;
|
||||
case T_NUM_STRING: {
|
||||
always_assert(!cg.hasScalarVariant());
|
||||
const char *s = m_value.c_str();
|
||||
|
||||
if ((*s == '0' && m_value.size() == 1) || ('1' <= *s && *s <= '9')) {
|
||||
// Offset could be treated as a long
|
||||
cg_printf("%sL", m_value.c_str());
|
||||
} else {
|
||||
// Offset must be treated as a string
|
||||
outputCPPString(cg, ar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_LNUMBER:
|
||||
ar->addInteger(getVariant().toInt64());
|
||||
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
|
||||
outputCPPNamedInteger(cg, ar);
|
||||
} else {
|
||||
outputCPPInteger(cg, ar);
|
||||
}
|
||||
break;
|
||||
case T_DNUMBER:
|
||||
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
|
||||
outputCPPNamedDouble(cg, ar);
|
||||
} else {
|
||||
outputCPPDouble(cg, ar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int64 ScalarExpression::getHash() const {
|
||||
int64 hash = -1;
|
||||
int64_t ScalarExpression::getHash() const {
|
||||
int64_t hash = -1;
|
||||
if (isLiteralInteger()) {
|
||||
hash = hash_int64(getLiteralInteger());
|
||||
} else if (isLiteralString()) {
|
||||
string scs = getLiteralString();
|
||||
int64 res;
|
||||
int64_t res;
|
||||
if (is_strictly_integer(scs.c_str(), scs.size(), res)) {
|
||||
hash = hash_int64(res);
|
||||
} else {
|
||||
@@ -690,7 +475,7 @@ bool ScalarExpression::getString(const std::string *&s) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool ScalarExpression::getInt(int64 &i) const {
|
||||
bool ScalarExpression::getInt(int64_t &i) const {
|
||||
if (m_type == T_LNUMBER) {
|
||||
i = strtoll(m_value.c_str(), nullptr, 0);
|
||||
return true;
|
||||
|
||||
@@ -63,26 +63,18 @@ public:
|
||||
void appendEncapString(const std::string &value);
|
||||
bool isLiteralInteger() const;
|
||||
|
||||
int64 getLiteralInteger() const;
|
||||
int64_t getLiteralInteger() const;
|
||||
std::string getIdentifier() const;
|
||||
Variant getVariant() const;
|
||||
int64 getHash() const;
|
||||
int64_t getHash() const;
|
||||
|
||||
void setComment(const std::string &comment) { m_comment = comment;}
|
||||
const std::string getComment() { return m_comment;}
|
||||
|
||||
void outputCPPString(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPInteger(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPDouble(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
std::string getCPPLiteralString(bool *binary = nullptr);
|
||||
|
||||
bool getString(const std::string *&s) const;
|
||||
bool getInt(int64 &i) const;
|
||||
bool getInt(int64_t &i) const;
|
||||
bool getDouble(double &d) const;
|
||||
static void OutputCPPString(const std::string &str, CodeGenerator &cg,
|
||||
AnalysisResultPtr ar, BlockScopeRawPtr scope,
|
||||
bool constant);
|
||||
private:
|
||||
int m_type;
|
||||
std::string m_serializedValue;
|
||||
@@ -92,8 +84,6 @@ private:
|
||||
std::string m_translated;
|
||||
bool m_quoted;
|
||||
std::string m_comment; // for inlined constant name
|
||||
void outputCPPNamedInteger(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
void outputCPPNamedDouble(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -67,7 +67,6 @@ public:
|
||||
static SimpleFunctionCallPtr GetFunctionCallForCallUserFunc(
|
||||
AnalysisResultConstPtr ar, SimpleFunctionCallPtr call, int testOnly,
|
||||
int firstParam, bool &error);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
|
||||
void setupScopes(AnalysisResultConstPtr ar);
|
||||
bool readsLocals() const;
|
||||
bool writesLocals() const;
|
||||
@@ -113,7 +112,6 @@ protected:
|
||||
ExpressionPtr m_safeDef;
|
||||
std::string m_lambda;
|
||||
|
||||
void outputCPPParamOrderControlled(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
ExpressionPtr optimize(AnalysisResultConstPtr ar);
|
||||
private:
|
||||
int checkObjCall(AnalysisResultPtr ar);
|
||||
|
||||
@@ -142,8 +142,8 @@ void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_globals = true;
|
||||
} else {
|
||||
m_sym = variables->addDeclaredSymbol(
|
||||
m_name, hhvm && Option::OutputHHBC ?
|
||||
shared_from_this() : ConstructPtr());
|
||||
m_name,
|
||||
Option::OutputHHBC ? shared_from_this() : ConstructPtr());
|
||||
}
|
||||
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
|
||||
@@ -172,7 +172,7 @@ void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
} else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
|
||||
if (m_sym) {
|
||||
if (m_sym && !m_this) {
|
||||
if (!m_sym->isSystem() &&
|
||||
!(getContext() &
|
||||
(LValue|RefValue|RefParameter|UnsetContext|ExistContext)) &&
|
||||
@@ -324,162 +324,3 @@ TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
|
||||
void SimpleVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("$%s", m_name.c_str());
|
||||
}
|
||||
|
||||
void SimpleVariable::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state)
|
||||
{
|
||||
if (hasCPPTemp()) return;
|
||||
VariableTablePtr vt(getScope()->getVariables());
|
||||
if (hasContext(InvokeArgument) && !hasContext(AccessContext) &&
|
||||
(isLocalExprAltered() || (m_sym && m_sym->isReseated())) &&
|
||||
!m_globals /* $GLOBALS always has reference semantics */ &&
|
||||
hasAssignableCPPVariable()) {
|
||||
const string &cppName = getAssignableCPPVariable(ar);
|
||||
assert(!cppName.empty());
|
||||
if (m_sym && m_sym->isReseated()) {
|
||||
const string &arg_temp = genCPPTemp(cg, ar);
|
||||
cg.wrapExpressionBegin();
|
||||
cg_printf("const Variant %s = cit%d->isRef(%d) ? "
|
||||
"Variant(strongBind(%s)) : %s;\n",
|
||||
arg_temp.c_str(),
|
||||
cg.callInfoTop(),
|
||||
m_argNum,
|
||||
cppName.c_str(),
|
||||
cppName.c_str());
|
||||
|
||||
setCPPTemp(arg_temp);
|
||||
} else {
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
const string &ref_temp = cppTemp();
|
||||
assert(!ref_temp.empty());
|
||||
const string ©_temp = genCPPTemp(cg, ar);
|
||||
const string &arg_temp = genCPPTemp(cg, ar);
|
||||
cg_printf("const Variant %s = %s;\n",
|
||||
copy_temp.c_str(),
|
||||
cppName.c_str());
|
||||
cg_printf("const Variant &%s = cit%d->isRef(%d) ? %s : %s;\n",
|
||||
arg_temp.c_str(),
|
||||
cg.callInfoTop(),
|
||||
m_argNum,
|
||||
ref_temp.c_str(),
|
||||
copy_temp.c_str());
|
||||
setCPPTemp(arg_temp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (hasAnyContext(RefValue|RefParameter)) {
|
||||
if (!hasAnyContext(InvokeArgument|AccessContext|
|
||||
AssignmentRHS|ReturnContext) &&
|
||||
!m_globals && (!m_sym || m_sym->isReseated()) &&
|
||||
hasAssignableCPPVariable()) {
|
||||
cg.wrapExpressionBegin();
|
||||
const string &cppName = getAssignableCPPVariable(ar);
|
||||
assert(!cppName.empty());
|
||||
const string &tmp = genCPPTemp(cg, ar);
|
||||
cg_printf("VRefParamValue %s((ref(%s)));\n",
|
||||
tmp.c_str(), cppName.c_str());
|
||||
setCPPTemp(tmp);
|
||||
setContext(NoRefWrapper);
|
||||
}
|
||||
return;
|
||||
} else if (hasContext(LValue)) {
|
||||
return;
|
||||
}
|
||||
if (!m_alwaysStash && !(state & StashVars)) return;
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
bool SimpleVariable::hasAssignableCPPVariable() const {
|
||||
if (!m_this) return true;
|
||||
if (hasAnyContext(OprLValue | AssignmentLHS)) return false;
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
return variables->getAttribute(VariableTable::ContainsLDynamicVariable);
|
||||
}
|
||||
|
||||
std::string SimpleVariable::getAssignableCPPVariable(AnalysisResultPtr ar)
|
||||
const {
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
if (m_this) {
|
||||
if (!hasAnyContext(OprLValue | AssignmentLHS) &&
|
||||
variables->getAttribute(VariableTable::ContainsLDynamicVariable)) {
|
||||
assert(m_sym);
|
||||
const string &namePrefix = getNamePrefix();
|
||||
return namePrefix + variables->getVariablePrefix(m_sym) + "this";
|
||||
}
|
||||
return "";
|
||||
} else if (m_superGlobal) {
|
||||
const string &name = variables->getGlobalVariableName(ar, m_name);
|
||||
return string("g->") + name.c_str();
|
||||
} else if (m_globals) {
|
||||
return "get_global_array_wrapper()";
|
||||
} else {
|
||||
assert(m_sym);
|
||||
const string &prefix0 = getNamePrefix();
|
||||
const char *prefix1 =
|
||||
getScope()->getVariables()->getVariablePrefix(m_sym);
|
||||
return prefix0 + prefix1 +
|
||||
CodeGenerator::FormatLabel(m_name);
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
if (m_this) {
|
||||
assert((getContext() & ObjectContext) == 0);
|
||||
if (hasContext(OprLValue) || hasContext(AssignmentLHS)) {
|
||||
cg_printf("throw_assign_this()");
|
||||
return;
|
||||
}
|
||||
if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) {
|
||||
assert(m_sym);
|
||||
const string &namePrefix = getNamePrefix();
|
||||
cg_printf("%s%sthis",
|
||||
namePrefix.c_str(),
|
||||
variables->getVariablePrefix(m_sym));
|
||||
} else if (hasContext(DeepOprLValue) ||
|
||||
hasContext(DeepAssignmentLHS) ||
|
||||
hasContext(LValue)) {
|
||||
// $this[] op= ...; or $this[] = ...
|
||||
cg_printf("Variant(GET_THIS())");
|
||||
} else {
|
||||
ClassScopePtr cls = getOriginalClass();
|
||||
if (!cls || cls->derivedByDynamic()) {
|
||||
cg_printf("Object(GET_THIS())");
|
||||
} else {
|
||||
cg_printf("GET_THIS_TYPED(%s)", cls->getId().c_str());
|
||||
}
|
||||
}
|
||||
} else if (m_superGlobal) {
|
||||
const string &name = variables->getGlobalVariableName(ar, m_name);
|
||||
cg_printf("g->%s", name.c_str());
|
||||
} else if (m_globals) {
|
||||
cg_printf("get_global_array_wrapper()");
|
||||
} else {
|
||||
assert(m_sym);
|
||||
bool sw = false;
|
||||
if (m_sym->isShrinkWrapped() &&
|
||||
m_context == Declaration) {
|
||||
assert(!getFunctionScope()->isGenerator());
|
||||
TypePtr type = m_sym->getFinalType();
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
sw = true;
|
||||
cg_printf(" ");
|
||||
}
|
||||
const string &prefix0 = getNamePrefix();
|
||||
const char *prefix1 = variables->getVariablePrefix(m_sym);
|
||||
cg_printf("%s%s%s",
|
||||
prefix0.c_str(),
|
||||
prefix1,
|
||||
CodeGenerator::FormatLabel(m_name).c_str());
|
||||
if (m_originalSym) {
|
||||
cg.printf(" /* %s */", m_originalSym->getName().c_str());
|
||||
}
|
||||
if (sw) {
|
||||
TypePtr type = m_sym->getFinalType();
|
||||
const char *initializer = type->getCPPInitializer();
|
||||
if (initializer) {
|
||||
cg_printf(" = %s", initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,17 +53,11 @@ public:
|
||||
bool couldBeAliased() const;
|
||||
bool canKill(bool unset) const;
|
||||
bool isHidden() const;
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool checkUnused() const;
|
||||
bool getAlwaysStash() const { return m_alwaysStash; }
|
||||
void setAlwaysStash() { m_alwaysStash = true; }
|
||||
void updateSymbol(SimpleVariablePtr src);
|
||||
void coalesce(SimpleVariablePtr other);
|
||||
|
||||
bool hasAssignableCPPVariable() const;
|
||||
std::string getAssignableCPPVariable(AnalysisResultPtr ar) const;
|
||||
|
||||
private:
|
||||
std::string getNamePrefix() const;
|
||||
|
||||
|
||||
@@ -97,11 +97,7 @@ ClassScopePtr StaticClassName::resolveClass() {
|
||||
m_origClassName = self->getOriginalParent();
|
||||
m_present = true;
|
||||
}
|
||||
} else if (!hhvm) {
|
||||
// When generating hhvm bytecodes, the following statement
|
||||
// causes EmitterVisitor::emitFuncCall to not generate a Parent
|
||||
// byte code. It's unclear whether removing it would break hphpc
|
||||
// so this code is left here under a hhvm flag check for now.
|
||||
} else {
|
||||
m_parent = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ TypePtr StaticMemberExpression::inferTypes(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
unsigned StaticMemberExpression::getCanonHash() const {
|
||||
int64 val = Expression::getCanonHash() +
|
||||
int64_t val = Expression::getCanonHash() +
|
||||
hash_string(Util::toLower(m_className).c_str(), m_className.size());
|
||||
return ~unsigned(val) ^ unsigned(val >> 32);
|
||||
}
|
||||
@@ -360,119 +360,3 @@ void StaticMemberExpression::outputPHP(CodeGenerator &cg,
|
||||
cg_printf("}");
|
||||
}
|
||||
}
|
||||
|
||||
void StaticMemberExpression::preOutputStash(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
int state)
|
||||
{
|
||||
if (getContext() & (LValue|RefValue|RefParameter)) return;
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
|
||||
void StaticMemberExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_class) {
|
||||
const char *func_suffix = "";
|
||||
if (m_context & (LValue | RefValue | UnsetContext)) {
|
||||
func_suffix = "_lval";
|
||||
}
|
||||
|
||||
if (!hasContext(UnsetContext) || !hasContext(LValue)) {
|
||||
cg_printf("get_static_property%s(", func_suffix);
|
||||
} else {
|
||||
cg_printf("throw_fatal_unset_static_property(");
|
||||
}
|
||||
|
||||
if (m_class->is(KindOfScalarExpression)) {
|
||||
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
|
||||
getString().c_str(), "static") == 0);
|
||||
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
|
||||
} else {
|
||||
cg_printf("get_static_class_name(");
|
||||
m_class->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
cg_printf(", toString(");
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(").data())");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasContext(UnsetContext) && hasContext(LValue)) {
|
||||
const string &name = CodeGenerator::EscapeLabel(m_origClassName);
|
||||
cg_printf("throw_fatal_unset_static_property(\"%s\"", name.c_str());
|
||||
cg_printf(", toString(");
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(").data())");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_valid) {
|
||||
if (!m_resolvedClass && !isRedeclared()) {
|
||||
const string &name = CodeGenerator::EscapeLabel(m_origClassName);
|
||||
cg_printf("throw_fatal(\"unknown class %s\")", name.c_str());
|
||||
} else {
|
||||
cg_printf("throw_fatal(\"Access to undeclared static property: ");
|
||||
outputPHP(cg, ar);
|
||||
cg_printf("\")");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool volatileCheck = false;
|
||||
if (!isPresent() &&
|
||||
((m_resolvedClass && m_resolvedClass->isVolatile()) ||
|
||||
isRedeclared())) {
|
||||
volatileCheck = true;
|
||||
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(),
|
||||
m_origClassName);
|
||||
}
|
||||
|
||||
if (m_exp->is(Expression::KindOfScalarExpression) && !isRedeclared() &&
|
||||
!m_dynamicClass) {
|
||||
|
||||
assert(m_resolvedClass);
|
||||
ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(m_exp);
|
||||
string clsId = m_resolvedClass->getId();
|
||||
TypePtr type = getCPPType();
|
||||
bool close = type->isSpecificObject();
|
||||
if (close) {
|
||||
cg_printf("((%s&)", type->getCPPDecl(ar, getScope()).c_str());
|
||||
}
|
||||
if (m_resolvedClass->needLazyStaticInitializer()) {
|
||||
cg_printf("%s%s->lazy_initializer(g)->%s%s%s%s",
|
||||
Option::ClassStaticsCallbackPrefix, clsId.c_str(),
|
||||
Option::StaticPropertyPrefix, clsId.c_str(),
|
||||
Option::IdPrefix.c_str(),
|
||||
CodeGenerator::FormatLabel(var->getString()).c_str());
|
||||
} else {
|
||||
cg_printf("g->%s%s%s%s", Option::StaticPropertyPrefix, clsId.c_str(),
|
||||
Option::IdPrefix.c_str(),
|
||||
CodeGenerator::FormatLabel(var->getString()).c_str());
|
||||
}
|
||||
if (close) cg_printf(")");
|
||||
} else {
|
||||
if (m_context & (LValue | RefValue | UnsetContext)) {
|
||||
if (isRedeclared()) cg_printf("g->");
|
||||
cg_printf("%s%s->%slval(", Option::ClassStaticsCallbackPrefix,
|
||||
isRedeclared() ?
|
||||
CodeGenerator::FormatLabel(m_className).c_str() :
|
||||
m_resolvedClass->getId().c_str(),
|
||||
Option::ObjectStaticPrefix);
|
||||
} else {
|
||||
if (isRedeclared()) cg_printf("g->");
|
||||
cg_printf("%s%s->%sget(", Option::ClassStaticsCallbackPrefix,
|
||||
isRedeclared() ?
|
||||
CodeGenerator::FormatLabel(m_className).c_str() :
|
||||
m_resolvedClass->getId().c_str(),
|
||||
Option::ObjectStaticPrefix);
|
||||
}
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(")");
|
||||
}
|
||||
|
||||
if (volatileCheck) {
|
||||
ClassScope::OutputVolatileCheckEnd(cg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@ public:
|
||||
|
||||
virtual unsigned getCanonHash() const;
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
|
||||
ExpressionPtr getExp() { return m_exp; }
|
||||
|
||||
|
||||
@@ -617,351 +617,3 @@ void UnaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnaryOpExpression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
if (hasCPPTemp() || m_op == T_FILE || m_op == T_DIR) return;
|
||||
if (m_op == T_CLASS || m_op == T_FUNCTION) {
|
||||
m_definedScope->outputCPPDef(cg);
|
||||
setCPPTemp("id(0)");
|
||||
return;
|
||||
}
|
||||
if (m_exp && !getLocalEffects() &&
|
||||
m_op != '@' && m_op != T_ISSET && m_op != T_EMPTY &&
|
||||
!m_exp->is(KindOfExpressionList)) {
|
||||
m_exp->preOutputStash(cg, ar, state);
|
||||
} else {
|
||||
Expression::preOutputStash(cg, ar, state);
|
||||
}
|
||||
}
|
||||
|
||||
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state) {
|
||||
|
||||
if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) {
|
||||
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
|
||||
int count = exps->getCount();
|
||||
if (count > 1) {
|
||||
bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0);
|
||||
bool inExpression = cg.inExpression();
|
||||
cg.setInExpression(false);
|
||||
bool fix_en = false;
|
||||
for (int i = 1; i < count; i++) {
|
||||
if ((*exps)[i]->preOutputCPP(cg, ar, 0)) {
|
||||
fix_en = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cg.setInExpression(inExpression);
|
||||
if (inExpression && fix_en) {
|
||||
cg.wrapExpressionBegin();
|
||||
std::string tmp = genCPPTemp(cg, ar);
|
||||
cg_printf("bool %s = (", tmp.c_str());
|
||||
(*exps)[0]->outputCPPExistTest(cg, ar, m_op);
|
||||
cg_printf(");\n");
|
||||
for (int i = 1; i < count; i++) {
|
||||
cg_indentBegin("if (%s) {\n", tmp.c_str());
|
||||
ExpressionPtr e = (*exps)[i];
|
||||
e->preOutputCPP(cg, ar, 0);
|
||||
cg_printf("%s = (", tmp.c_str());
|
||||
e->outputCPPExistTest(cg, ar, m_op);
|
||||
cg_printf(");\n");
|
||||
}
|
||||
for (int i = 1; i < count; i++) {
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
m_cppTemp = tmp;
|
||||
} else if (state & FixOrder) {
|
||||
preOutputStash(cg, ar, state);
|
||||
fix_e1 = true;
|
||||
}
|
||||
return fix_e1 || fix_en;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_op == '@') {
|
||||
if (isUnused()) m_exp->setUnused(true);
|
||||
bool doit = (state & FixOrder) || m_exp->hasEffect();
|
||||
if (doit && cg.inExpression()) {
|
||||
cg.wrapExpressionBegin();
|
||||
std::string tmp = genCPPTemp(cg, ar);
|
||||
cg_printf("Silencer %s(true);\n", tmp.c_str());
|
||||
m_exp->preOutputCPP(cg, ar, 0);
|
||||
this->preOutputStash(cg, ar, state | FixOrder | StashAll);
|
||||
cg_printf("%s.disable();\n", tmp.c_str());
|
||||
}
|
||||
return doit;
|
||||
} else if (m_op == T_PRINT && m_exp && !m_exp->hasEffect()) {
|
||||
ExpressionPtrVec ev;
|
||||
bool hasVoid = false;
|
||||
if (BinaryOpExpression::getConcatList(ev, m_exp, hasVoid) > 1 ||
|
||||
hasVoid ) {
|
||||
|
||||
if (!cg.inExpression()) return true;
|
||||
cg.wrapExpressionBegin();
|
||||
for (int i = 0, s = ev.size(); i < s; i++) {
|
||||
ExpressionPtr e = ev[i];
|
||||
e->preOutputCPP(cg, ar, 0);
|
||||
cg_printf("print(");
|
||||
e->outputCPP(cg, ar);
|
||||
cg_printf(");\n");
|
||||
}
|
||||
m_cppTemp = "id(1)";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_op == T_CLASS || m_op == T_FUNCTION) {
|
||||
if (cg.inExpression()) {
|
||||
cg.wrapExpressionBegin();
|
||||
m_definedScope->outputCPPDef(cg);
|
||||
setCPPTemp("id(0)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return Expression::preOutputCPP(cg, ar, state);
|
||||
}
|
||||
|
||||
bool UnaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if (m_exp->is(Expression::KindOfObjectPropertyExpression)) {
|
||||
ObjectPropertyExpressionPtr var(
|
||||
dynamic_pointer_cast<ObjectPropertyExpression>(m_exp));
|
||||
if (var->isValid()) return false;
|
||||
var->outputCPPObject(cg, ar);
|
||||
cg_printf("o_assign_op<%s,%d>(",
|
||||
isUnused() ? "void" : "Variant", m_op);
|
||||
var->outputCPPProperty(cg, ar);
|
||||
cg_printf(", %s%s)",
|
||||
isUnused() || m_front ? "null_variant" : "Variant(0)",
|
||||
originalClassName(cg, true).c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) {
|
||||
return;
|
||||
}
|
||||
if (m_op == T_ARRAY &&
|
||||
(getContext() & (RefValue|LValue)) == 0 &&
|
||||
!cg.getInsideScalarArray()) {
|
||||
int id = -1;
|
||||
int hash = -1;
|
||||
int index = -1;
|
||||
string text;
|
||||
if (m_exp) {
|
||||
ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
|
||||
Variant v;
|
||||
if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
|
||||
id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
|
||||
m_exp, hash, index, text);
|
||||
}
|
||||
} else {
|
||||
id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
|
||||
m_exp, hash, index, text); // empty array
|
||||
}
|
||||
if (id != -1) {
|
||||
bool scalarVariant =
|
||||
Option::UseScalarVariant && cg.hasScalarVariant();
|
||||
if (scalarVariant) {
|
||||
ar->addNamedScalarVarArray(text);
|
||||
getUsedScalarScope(cg)->addUsedScalarVarArray(text);
|
||||
}
|
||||
if (Option::UseNamedScalarArray && cg.isFileOrClassHeader()) {
|
||||
if (getClassScope()) {
|
||||
getClassScope()->addUsedDefaultValueScalarArray(text);
|
||||
if (scalarVariant) {
|
||||
getClassScope()->addUsedDefaultValueScalarVarArray(text);
|
||||
}
|
||||
} else {
|
||||
getFileScope()->addUsedDefaultValueScalarArray(text);
|
||||
if (scalarVariant) {
|
||||
getFileScope()->addUsedDefaultValueScalarVarArray(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
ar->outputCPPScalarArrayId(cg, id, hash, index, scalarVariant);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) {
|
||||
if (m_exp->is(Expression::KindOfExpressionList)) {
|
||||
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
|
||||
if (exps->getListKind() == ExpressionList::ListKindParam) {
|
||||
int count = exps->getCount();
|
||||
if (count > 1) {
|
||||
cg_printf("(");
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (m_op == T_UNSET) {
|
||||
if (i > 0) cg_printf(", ");
|
||||
(*exps)[i]->outputCPPUnset(cg, ar);
|
||||
} else {
|
||||
if (i > 0) cg_printf(" && ");
|
||||
(*exps)[i]->outputCPPExistTest(cg, ar, m_op);
|
||||
}
|
||||
}
|
||||
if (exps->getCount() > 1) {
|
||||
cg_printf(")");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_op == T_UNSET) {
|
||||
m_exp->outputCPPUnset(cg, ar);
|
||||
} else {
|
||||
m_exp->outputCPPExistTest(cg, ar, m_op);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_op != T_CLASS && m_op != T_FUNCTION);
|
||||
|
||||
const char *cstr = 0;
|
||||
if (m_front) {
|
||||
switch (m_op) {
|
||||
case T_CLONE: cg_printf("f_clone("); break;
|
||||
case T_INC: cg_printf("++"); break;
|
||||
case T_DEC: cg_printf("--"); break;
|
||||
case '+': cg_printf("+"); break;
|
||||
case '-': cg_printf("negate("); break;
|
||||
case '!': cg_printf("!("); break;
|
||||
case '~': cg_printf("~"); break;
|
||||
case T_INT_CAST: cg_printf("("); break;
|
||||
case T_DOUBLE_CAST: cg_printf("("); break;
|
||||
case T_STRING_CAST: cstr = "String"; goto null_cast;
|
||||
case T_ARRAY_CAST: cstr = "Array"; goto null_cast;
|
||||
case T_OBJECT_CAST: cstr = "Object"; goto null_cast;
|
||||
null_cast: {
|
||||
TypePtr at = m_exp->getActualType();
|
||||
TypePtr et = m_exp->getType();
|
||||
TypePtr it = m_exp->getCPPType();
|
||||
if (at && Type::SameType(at, et) && Type::SameType(it, at)) {
|
||||
cg_printf("to%s(", cstr);
|
||||
} else {
|
||||
cg_printf("(");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_BOOL_CAST: cg_printf("("); break;
|
||||
case T_UNSET_CAST:
|
||||
if (m_exp->isScalar()) {
|
||||
cg_printf("(null)");
|
||||
return;
|
||||
}
|
||||
if (m_exp->hasCPPTemp()) {
|
||||
cg_printf("(id(");
|
||||
} else {
|
||||
cg_printf("(");
|
||||
}
|
||||
break;
|
||||
case T_EXIT: cg_printf("f_exit("); break;
|
||||
case T_ARRAY:
|
||||
cg_printf("Array(");
|
||||
break;
|
||||
case T_PRINT: cg_printf("print("); break;
|
||||
case T_EVAL:
|
||||
if (Option::EnableEval > Option::NoEval) {
|
||||
bool instance;
|
||||
if (getClassScope()) {
|
||||
FunctionScopePtr fs = getFunctionScope();
|
||||
instance = fs && !fs->isStatic();
|
||||
} else {
|
||||
instance = false;
|
||||
}
|
||||
cg_printf("eval(%s, Object(%s), ",
|
||||
getScope()->inPseudoMain() ?
|
||||
"get_variable_table()" : "variables",
|
||||
instance ? "this" : "");
|
||||
} else {
|
||||
cg_printf("f_eval(");
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
break;
|
||||
case T_FILE:
|
||||
cg_printf("get_source_filename(\"%s\")", getLocation()->file);
|
||||
break;
|
||||
case T_DIR:
|
||||
cg_printf("get_source_filename(\"%s\", true)", getLocation()->file);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_exp) {
|
||||
switch (m_op) {
|
||||
case '+':
|
||||
case '-':
|
||||
if (!m_exp->outputCPPArithArg(cg, ar, false)) {
|
||||
m_exp->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (isUnused()) {
|
||||
m_exp->outputCPPUnneeded(cg, ar);
|
||||
} else {
|
||||
m_exp->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
m_exp->outputCPP(cg, ar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_front) {
|
||||
switch (m_op) {
|
||||
case T_ARRAY:
|
||||
{
|
||||
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
|
||||
if (!exps) {
|
||||
cg_printf("ArrayData::Create()");
|
||||
}
|
||||
cg_printf(")");
|
||||
}
|
||||
break;
|
||||
case T_UNSET_CAST:
|
||||
if (m_exp->hasCPPTemp()) {
|
||||
cg_printf("),null");
|
||||
} else {
|
||||
cg_printf(",null");
|
||||
}
|
||||
case T_CLONE:
|
||||
case '!':
|
||||
case '-':
|
||||
case T_INT_CAST:
|
||||
case T_DOUBLE_CAST:
|
||||
case T_STRING_CAST:
|
||||
case T_ARRAY_CAST:
|
||||
case T_OBJECT_CAST:
|
||||
case T_BOOL_CAST:
|
||||
case T_EXIT:
|
||||
case T_PRINT:
|
||||
case T_EVAL:
|
||||
case T_INCLUDE:
|
||||
case T_INCLUDE_ONCE:
|
||||
case T_REQUIRE:
|
||||
case T_REQUIRE_ONCE:
|
||||
cg_printf(")");
|
||||
break;
|
||||
case '@':
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (m_op) {
|
||||
case T_INC: cg_printf("++"); break;
|
||||
case T_DEC: cg_printf("--"); break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,6 @@ public:
|
||||
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
virtual ExpressionPtr unneededHelper();
|
||||
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int state);
|
||||
void setDefinedScope(BlockScopeRawPtr scope);
|
||||
protected:
|
||||
ExpressionPtr m_exp;
|
||||
@@ -72,8 +68,6 @@ protected:
|
||||
private:
|
||||
bool preCompute(CVarRef value, Variant &result);
|
||||
void setExistContext();
|
||||
bool outputCPPImplOpEqual(CodeGenerator &cg, AnalysisResultPtr ar);
|
||||
|
||||
static void SetExpTypeForExistsContext(AnalysisResultPtr ar,
|
||||
ExpressionPtr e, bool allowPrimitives);
|
||||
};
|
||||
|
||||
@@ -65,8 +65,4 @@ void UserAttribute::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
|
||||
void UserAttribute::outputCPPImpl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ map<string, int> Option::DynamicFunctionCalls;
|
||||
bool Option::GeneratePickledPHP = false;
|
||||
bool Option::GenerateInlinedPHP = false;
|
||||
bool Option::GenerateTrimmedPHP = false;
|
||||
bool Option::GenerateInlineComments = true;
|
||||
bool Option::GenerateInferredTypes = false;
|
||||
bool Option::ConvertSuperGlobals = false;
|
||||
bool Option::ConvertQOpExpressions = false;
|
||||
@@ -91,119 +90,25 @@ string Option::LabelEscape = "$";
|
||||
string Option::LambdaPrefix = "df_";
|
||||
string Option::Tab = " ";
|
||||
|
||||
/**
|
||||
* They all have to be something different. Otherwise, there is always a chance
|
||||
* of name collision or incorrect code transformation.
|
||||
*/
|
||||
const char *Option::FunctionPrefix = "f_";
|
||||
const char *Option::TypedFunctionPrefix = "ft_";
|
||||
const char *Option::BuiltinFunctionPrefix = "x_";
|
||||
const char *Option::InvokePrefix = "i_";
|
||||
const char *Option::InvokeFewArgsPrefix = "ifa_";
|
||||
const char *Option::InvokeWrapperPrefix = "iw_";
|
||||
const char *Option::InvokeWrapperFewArgsPrefix = "iwfa_";
|
||||
const char *Option::InvokeSinglePrefix = "is_";
|
||||
const char *Option::CreateObjectOnlyPrefix = "coo_";
|
||||
const char *Option::PseudoMainPrefix = "pm_";
|
||||
const char *Option::VariablePrefix = "v_";
|
||||
const char *Option::LabelPrefix = "l_";
|
||||
const char *Option::HiddenVariablePrefix = "h_";
|
||||
const char *Option::GlobalVariablePrefix = "gv_";
|
||||
const char *Option::StaticVariablePrefix = "sv_";
|
||||
const char *Option::ClassPropTablePrefix = "cpt_";
|
||||
const char *Option::ScalarArrayName = "sa_";
|
||||
const char *Option::SystemScalarArrayName = "ssa_";
|
||||
const char *Option::ClassPrefix = "c_";
|
||||
const char *Option::ClassStaticsCallbackPrefix = "cw_";
|
||||
const char *Option::ClassStaticsCallbackNullPrefix = "cwn_";
|
||||
const char *Option::ClassStaticInitializerFlagPrefix = "csf_";
|
||||
const char *Option::ObjectPrefix = "o_";
|
||||
const char *Option::ObjectStaticPrefix = "os_";
|
||||
const char *Option::SmartPtrPrefix = "p_";
|
||||
const char *Option::MethodPrefix = "t_";
|
||||
const char *Option::TypedMethodPrefix = "tt_";
|
||||
const char *Option::MethodWrapperPrefix = "mf_";
|
||||
const char *Option::MethodImplPrefix = "ti_";
|
||||
const char *Option::TypedMethodImplPrefix = "tti_";
|
||||
const char *Option::PropertyPrefix = "m_";
|
||||
const char *Option::StaticPropertyPrefix = "s_";
|
||||
const char *Option::ConstantPrefix = "k_";
|
||||
const char *Option::ClassConstantPrefix = "q_";
|
||||
const char *Option::ExceptionPrefix = "e_";
|
||||
const char *Option::TempVariablePrefix = "r_";
|
||||
const char *Option::CseTempVariablePrefix = "cse_";
|
||||
const char *Option::CseTempStoragePrefix = "cses_";
|
||||
const char *Option::EvalOrderTempPrefix = "eo_";
|
||||
const char *Option::CallInfoPrefix = "ci_";
|
||||
const char *Option::CallInfoWrapperPrefix = "ciw_";
|
||||
const char *Option::SilencerPrefix = "sil_";
|
||||
|
||||
const char *Option::ScalarPrefix = "s_";
|
||||
const char *Option::SysPrefix = "sys_";
|
||||
const char *Option::StaticStringPrefix = "ss";
|
||||
const char *Option::StaticStringProxyPrefix = "ssp";
|
||||
const char *Option::StaticArrayPrefix = "sa";
|
||||
const char *Option::StaticVarIntPrefix = "svi";
|
||||
const char *Option::StaticVarDblPrefix = "svd";
|
||||
const char *Option::StaticVarStrPrefix = "svs";
|
||||
const char *Option::StaticVarStrProxyPrefix = "svsp";
|
||||
const char *Option::StaticVarArrPrefix = "sva";
|
||||
|
||||
const char *Option::FFIFnPrefix = "ffi_";
|
||||
|
||||
const char *Option::TempPrefix = "tmp";
|
||||
const char *Option::MapPrefix = "map";
|
||||
const char *Option::IterPrefix = "iter";
|
||||
const char *Option::InitPrefix = "inited_";
|
||||
const char *Option::SwitchPrefix = "switch";
|
||||
|
||||
const char *Option::SystemFilePrefix = "sys/";
|
||||
const char *Option::UserFilePrefix = "php/";
|
||||
const char *Option::ClassHeaderPrefix = "cls/";
|
||||
const char *Option::ClusterPrefix = "cpp/";
|
||||
const char *Option::FFIFilePrefix = "ffi/";
|
||||
|
||||
bool Option::PreOptimization = false;
|
||||
bool Option::PostOptimization = false;
|
||||
bool Option::ScalarArrayOptimization = true;
|
||||
bool Option::ScalarArrayCompression = true;
|
||||
int Option::ScalarArrayFileCount = 1;
|
||||
int Option::ScalarArrayOverflowLimit = 2000;
|
||||
bool Option::SeparateCompilation = false;
|
||||
bool Option::SeparateCompLib = false;
|
||||
bool Option::UseNamedScalarArray = true;
|
||||
int Option::LiteralStringFileCount = 2;
|
||||
bool Option::AnalyzePerfectVirtuals = true;
|
||||
bool Option::HardTypeHints = true;
|
||||
|
||||
std::string Option::RTTIOutputFile;
|
||||
std::string Option::RTTIDirectory;
|
||||
bool Option::GenRTTIProfileData = false;
|
||||
bool Option::UseRTTIProfileData = false;
|
||||
|
||||
bool Option::GenerateCPPMacros = true;
|
||||
bool Option::GenerateCPPMain = false;
|
||||
bool Option::GenerateCPPComments = true;
|
||||
bool Option::GenerateCPPMetaInfo = true;
|
||||
bool Option::GenerateCPPNameSpace = true;
|
||||
bool Option::GenArrayCreate = true;
|
||||
bool Option::UseScalarVariant = true;
|
||||
bool Option::UseStaticStringProxy = true;
|
||||
bool Option::UseCallUserFuncFewArgs = true;
|
||||
bool Option::GenGlobalState = false;
|
||||
bool Option::KeepStatementsWithNoEffect = false;
|
||||
bool Option::GenerateDummyPseudoMain = true;
|
||||
|
||||
int Option::ConditionalIncludeExpandLevel = 1;
|
||||
|
||||
int Option::DependencyMaxProgram = 1;
|
||||
int Option::CodeErrorMaxProgram = 1;
|
||||
|
||||
bool Option::GenerateFFI = false;
|
||||
Option::EvalLevel Option::EnableEval = NoEval;
|
||||
|
||||
std::string Option::JavaFFIRootPackage;
|
||||
|
||||
std::string Option::ProgramName;
|
||||
std::string Option::PreprocessedPartitionConfig;
|
||||
|
||||
@@ -216,7 +121,6 @@ bool Option::EnableShortTags = true;
|
||||
bool Option::EnableAspTags = false;
|
||||
bool Option::EnableXHP = true;
|
||||
bool Option::EnableFinallyStatement = false;
|
||||
bool Option::NativeXHP = true;
|
||||
int Option::ScannerType = Scanner::AllowShortTags;
|
||||
int Option::ParserThreadCount = 0;
|
||||
|
||||
@@ -248,10 +152,6 @@ bool Option::GenerateSourceInfo = false;
|
||||
bool Option::GenerateDocComments = true;
|
||||
bool Option::FlAnnotate = false;
|
||||
bool Option::SystemGen = false;
|
||||
bool Option::PregenerateCPP = false;
|
||||
bool Option::GenerateFFIStaticBinding = true;
|
||||
|
||||
int Option::GCCOptimization[] = {0, 0, 0};
|
||||
|
||||
void (*Option::m_hookHandler)(Hdf &config);
|
||||
bool (*Option::PersistenceHook)(BlockScopeRawPtr scope, FileScopeRawPtr file);
|
||||
@@ -320,46 +220,6 @@ void Option::Load(Hdf &config) {
|
||||
READ_CG_OPTION(IdPrefix);
|
||||
READ_CG_OPTION(LabelEscape);
|
||||
READ_CG_OPTION(LambdaPrefix);
|
||||
READ_CG_OPTION(FunctionPrefix);
|
||||
READ_CG_OPTION(BuiltinFunctionPrefix);
|
||||
READ_CG_OPTION(InvokePrefix);
|
||||
READ_CG_OPTION(PseudoMainPrefix);
|
||||
READ_CG_OPTION(VariablePrefix);
|
||||
READ_CG_OPTION(LabelPrefix);
|
||||
READ_CG_OPTION(HiddenVariablePrefix);
|
||||
READ_CG_OPTION(GlobalVariablePrefix);
|
||||
READ_CG_OPTION(StaticVariablePrefix);
|
||||
READ_CG_OPTION(ScalarArrayName);
|
||||
READ_CG_OPTION(SystemScalarArrayName);
|
||||
READ_CG_OPTION(ClassPrefix);
|
||||
READ_CG_OPTION(ClassStaticsCallbackPrefix);
|
||||
READ_CG_OPTION(ClassStaticsCallbackNullPrefix);
|
||||
READ_CG_OPTION(ClassStaticInitializerFlagPrefix);
|
||||
READ_CG_OPTION(ObjectPrefix);
|
||||
READ_CG_OPTION(ObjectStaticPrefix);
|
||||
READ_CG_OPTION(SmartPtrPrefix);
|
||||
READ_CG_OPTION(MethodPrefix);
|
||||
READ_CG_OPTION(MethodWrapperPrefix);
|
||||
READ_CG_OPTION(MethodImplPrefix);
|
||||
READ_CG_OPTION(PropertyPrefix);
|
||||
READ_CG_OPTION(StaticPropertyPrefix);
|
||||
READ_CG_OPTION(ConstantPrefix);
|
||||
READ_CG_OPTION(ClassConstantPrefix);
|
||||
READ_CG_OPTION(ExceptionPrefix);
|
||||
READ_CG_OPTION(TempVariablePrefix);
|
||||
READ_CG_OPTION(EvalOrderTempPrefix);
|
||||
READ_CG_OPTION(SilencerPrefix);
|
||||
READ_CG_OPTION(TempPrefix);
|
||||
READ_CG_OPTION(MapPrefix);
|
||||
READ_CG_OPTION(IterPrefix);
|
||||
READ_CG_OPTION(InitPrefix);
|
||||
READ_CG_OPTION(SwitchPrefix);
|
||||
READ_CG_OPTION(FFIFnPrefix);
|
||||
READ_CG_OPTION(SystemFilePrefix);
|
||||
READ_CG_OPTION(UserFilePrefix);
|
||||
READ_CG_OPTION(ClassHeaderPrefix);
|
||||
READ_CG_OPTION(ClusterPrefix);
|
||||
READ_CG_OPTION(FFIFilePrefix);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
@@ -411,18 +271,7 @@ void Option::Load(Hdf &config) {
|
||||
AutoloadRoot = autoloadMap["root"].getString();
|
||||
}
|
||||
|
||||
ScalarArrayFileCount = config["ScalarArrayFileCount"].getByte(1);
|
||||
if (ScalarArrayFileCount <= 0) ScalarArrayFileCount = 1;
|
||||
LiteralStringFileCount = config["LiteralStringFileCount"].getInt32(2);
|
||||
if (LiteralStringFileCount <= 0) LiteralStringFileCount = 2;
|
||||
UseStaticStringProxy = config["UseStaticStringProxy"].getBool(true);
|
||||
HardTypeHints = config["HardTypeHints"].getBool(true);
|
||||
ScalarArrayOverflowLimit = config["ScalarArrayOverflowLimit"].getInt32(2000);
|
||||
if (ScalarArrayOverflowLimit <= 0) ScalarArrayOverflowLimit = 2000;
|
||||
if (UseNamedScalarArray) {
|
||||
ScalarArrayOptimization = true;
|
||||
ScalarArrayCompression = true;
|
||||
}
|
||||
|
||||
EnableHipHopSyntax = config["EnableHipHopSyntax"].getBool();
|
||||
JitEnableRenameFunction = config["JitEnableRenameFunction"].getBool();
|
||||
@@ -437,9 +286,6 @@ void Option::Load(Hdf &config) {
|
||||
else ScannerType &= ~Scanner::AllowAspTags;
|
||||
|
||||
EnableXHP = config["EnableXHP"].getBool(true);
|
||||
NativeXHP = config["NativeXHP"].getBool(true);
|
||||
if (EnableXHP && !NativeXHP) ScannerType |= Scanner::PreprocessXHP;
|
||||
else ScannerType &= ~Scanner::PreprocessXHP;
|
||||
|
||||
ParserThreadCount = config["ParserThreadCount"].getInt32(0);
|
||||
if (ParserThreadCount <= 0) {
|
||||
@@ -448,7 +294,6 @@ void Option::Load(Hdf &config) {
|
||||
|
||||
EnableFinallyStatement = config["EnableFinallyStatement"].getBool();
|
||||
|
||||
RTTIOutputFile = config["RTTIOutputFile"].getString();
|
||||
EnableEval = (EvalLevel)config["EnableEval"].getByte(0);
|
||||
AllDynamic = config["AllDynamic"].getBool(true);
|
||||
AllVolatile = config["AllVolatile"].getBool();
|
||||
@@ -467,30 +312,12 @@ void Option::Load(Hdf &config) {
|
||||
ArrayAccessIdempotent = config["ArrayAccessIdempotent"].getBool(false);
|
||||
DumpAst = config["DumpAst"].getBool(false);
|
||||
WholeProgram = config["WholeProgram"].getBool(true);
|
||||
PregenerateCPP = config["PregenerateCPP"].getBool(false);
|
||||
GenerateFFIStaticBinding = config["GenerateFFIStaticBinding"].getBool(true);
|
||||
|
||||
{
|
||||
Hdf gccOptimization = config["GCCOptimization"];
|
||||
GCCOptimization[0] = gccOptimization["O0"].getInt32(0);
|
||||
GCCOptimization[1] = gccOptimization["O1"].getInt32(GCCOptimization[0]);
|
||||
GCCOptimization[2] = gccOptimization["O2"].getInt32(GCCOptimization[1]);
|
||||
}
|
||||
|
||||
if (m_hookHandler) m_hookHandler(config);
|
||||
|
||||
OnLoad();
|
||||
}
|
||||
|
||||
int Option::GetOptimizationLevel(int length) {
|
||||
if (length <= 0) return 3;
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
int min = GCCOptimization[i];
|
||||
if (length < min || min == 0) return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Option::Load() {
|
||||
OnLoad();
|
||||
}
|
||||
@@ -558,12 +385,6 @@ std::string Option::MangleFilename(const std::string &name, bool id) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Option::FormatClusterFile(int index) {
|
||||
char buf[PATH_MAX];
|
||||
snprintf(buf, sizeof(buf), "%s%03d", ClusterPrefix, index);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool Option::IsFileExcluded(const std::string &file,
|
||||
const std::set<std::string> &patterns) {
|
||||
String sfile(file.c_str(), file.size(), AttachLiteral);
|
||||
|
||||
@@ -117,46 +117,14 @@ public:
|
||||
*/
|
||||
static bool PreOptimization;
|
||||
static bool PostOptimization;
|
||||
static bool ScalarArrayOptimization;
|
||||
static bool ScalarArrayCompression;
|
||||
static int ScalarArrayFileCount;
|
||||
static int ScalarArrayOverflowLimit;
|
||||
static int LiteralStringFileCount;
|
||||
static bool AnalyzePerfectVirtuals;
|
||||
static bool HardTypeHints;
|
||||
|
||||
/**
|
||||
* RTTI profiling metadata output file
|
||||
*/
|
||||
static std::string RTTIOutputFile;
|
||||
|
||||
/**
|
||||
* Directory of RTTI profiling data, used for second pass compilation
|
||||
*/
|
||||
static std::string RTTIDirectory;
|
||||
|
||||
static bool GenRTTIProfileData;
|
||||
static bool UseRTTIProfileData;
|
||||
|
||||
/**
|
||||
* Generate array_createN service routines
|
||||
*/
|
||||
static bool GenArrayCreate;
|
||||
|
||||
static bool UseScalarVariant;
|
||||
|
||||
static bool UseStaticStringProxy;
|
||||
|
||||
static bool UseCallUserFuncFewArgs;
|
||||
|
||||
static bool GenGlobalState;
|
||||
|
||||
/**
|
||||
* Separate compilation
|
||||
*/
|
||||
static bool SeparateCompilation;
|
||||
static bool SeparateCompLib;
|
||||
static bool UseNamedScalarArray;
|
||||
|
||||
/**
|
||||
* CodeGenerator options for PHP.
|
||||
@@ -164,7 +132,6 @@ public:
|
||||
static bool GeneratePickledPHP;
|
||||
static bool GenerateInlinedPHP;
|
||||
static bool GenerateTrimmedPHP;
|
||||
static bool GenerateInlineComments; // comments on inlined file names
|
||||
static bool GenerateInferredTypes; // comments on constant/variable tables
|
||||
static bool ConvertSuperGlobals; // $GLOBALS['var'] => global $var
|
||||
static bool ConvertQOpExpressions; // $var = $exp ? $yes : $no => if-else
|
||||
@@ -207,83 +174,13 @@ public:
|
||||
/**
|
||||
* Name resolution helpers.
|
||||
*/
|
||||
static const char *FunctionPrefix;
|
||||
static const char *TypedFunctionPrefix;
|
||||
static const char *BuiltinFunctionPrefix;
|
||||
static const char *InvokePrefix;
|
||||
static const char *InvokeFewArgsPrefix;
|
||||
static const char *InvokeWrapperPrefix;
|
||||
static const char *InvokeWrapperFewArgsPrefix;
|
||||
static const char *InvokeSinglePrefix;
|
||||
static const char *CreateObjectOnlyPrefix;
|
||||
static const char *PseudoMainPrefix;
|
||||
static const char *VariablePrefix;
|
||||
static const char *LabelPrefix;
|
||||
static const char *HiddenVariablePrefix;
|
||||
static const char *GlobalVariablePrefix;
|
||||
static const char *StaticVariablePrefix;
|
||||
static const char *ScalarArrayName;
|
||||
static const char *SystemScalarArrayName;
|
||||
static const char *ClassPrefix;
|
||||
static const char *ClassStaticsCallbackPrefix;
|
||||
static const char *ClassStaticsCallbackNullPrefix;
|
||||
static const char *ClassStaticInitializerFlagPrefix;
|
||||
static const char *ObjectPrefix;
|
||||
static const char *ObjectStaticPrefix;
|
||||
static const char *SmartPtrPrefix;
|
||||
static const char *MethodPrefix;
|
||||
static const char *TypedMethodPrefix;
|
||||
static const char *MethodWrapperPrefix;
|
||||
static const char *MethodImplPrefix;
|
||||
static const char *TypedMethodImplPrefix;
|
||||
static const char *PropertyPrefix;
|
||||
static const char *StaticPropertyPrefix;
|
||||
static const char *ConstantPrefix;
|
||||
static const char *ClassConstantPrefix;
|
||||
static const char *ExceptionPrefix;
|
||||
static const char *TempVariablePrefix;
|
||||
static const char *CseTempVariablePrefix;
|
||||
static const char *CseTempStoragePrefix;
|
||||
static const char *EvalOrderTempPrefix;
|
||||
static const char *SilencerPrefix;
|
||||
static const char *CallInfoPrefix;
|
||||
static const char *CallInfoWrapperPrefix;
|
||||
static const char *SysPrefix;
|
||||
static const char *ScalarPrefix;
|
||||
static const char *StaticStringPrefix;
|
||||
static const char *StaticStringProxyPrefix;
|
||||
static const char *StaticArrayPrefix;
|
||||
static const char *StaticVarIntPrefix;
|
||||
static const char *StaticVarDblPrefix;
|
||||
static const char *StaticVarStrPrefix;
|
||||
static const char *StaticVarStrProxyPrefix;
|
||||
static const char *StaticVarArrPrefix;
|
||||
static const char *ClassPropTablePrefix;
|
||||
|
||||
static const char *TempPrefix;
|
||||
static const char *MapPrefix;
|
||||
static const char *IterPrefix;
|
||||
static const char *InitPrefix;
|
||||
static const char *SwitchPrefix;
|
||||
|
||||
static const char *FFIFnPrefix;
|
||||
|
||||
static const char *SystemFilePrefix;
|
||||
static const char *UserFilePrefix;
|
||||
static const char *ClassHeaderPrefix;
|
||||
static const char *ClusterPrefix;
|
||||
static const char *FFIFilePrefix;
|
||||
|
||||
/**
|
||||
* Turn it off for cleaner unit tests.
|
||||
*/
|
||||
static bool GenerateCPPMacros; // all macros
|
||||
static bool GenerateCPPMain; // include and main()
|
||||
static bool GenerateCPPComments; // section comments
|
||||
static bool GenerateCPPMetaInfo; // class map
|
||||
static bool GenerateCPPNameSpace; // namespace HPHP
|
||||
static bool KeepStatementsWithNoEffect;
|
||||
static bool GenerateDummyPseudoMain;
|
||||
|
||||
/**
|
||||
* When we have an include inside a function or a method, how many levels
|
||||
@@ -318,13 +215,6 @@ public:
|
||||
*/
|
||||
static std::string MangleFilename(const std::string &name, bool id);
|
||||
|
||||
/**
|
||||
* Returns a name for a clustered .cpp file.
|
||||
*/
|
||||
static std::string FormatClusterFile(int index);
|
||||
|
||||
static bool GenerateFFI;
|
||||
|
||||
enum EvalLevel {
|
||||
NoEval = 0, // calling eval is a fatal
|
||||
LimitedEval = 1, // eval is supported in a limited way with no perf hit
|
||||
@@ -333,11 +223,6 @@ public:
|
||||
|
||||
static EvalLevel EnableEval;
|
||||
|
||||
/**
|
||||
* The root package for Java FFI stubs (dot-separated). The default is php.
|
||||
*/
|
||||
static std::string JavaFFIRootPackage;
|
||||
|
||||
static std::string ProgramName;
|
||||
static std::string PreprocessedPartitionConfig; // generated by ppp.php
|
||||
|
||||
@@ -350,7 +235,6 @@ public:
|
||||
static bool EnableAspTags;
|
||||
static bool EnableXHP;
|
||||
static bool EnableFinallyStatement;
|
||||
static bool NativeXHP;
|
||||
static int ScannerType;
|
||||
static int ParserThreadCount;
|
||||
|
||||
@@ -390,11 +274,6 @@ public:
|
||||
static bool WholeProgram;
|
||||
static bool RecordErrors;
|
||||
static std::string DocJson; // filename to dump doc JSON to
|
||||
static bool PregenerateCPP;
|
||||
static bool GenerateFFIStaticBinding;
|
||||
|
||||
static int GCCOptimization[3];
|
||||
static int GetOptimizationLevel(int length);
|
||||
|
||||
static void setHookHandler(void (*hookHandler)(Hdf &config)) {
|
||||
m_hookHandler = hookHandler;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <util/db_conn.h>
|
||||
#include <util/db_query.h>
|
||||
#include <util/exception.h>
|
||||
#include <util/preprocess.h>
|
||||
#include <util/job_queue.h>
|
||||
#include <runtime/base/execution_context.h>
|
||||
|
||||
@@ -298,7 +297,7 @@ bool Package::parseImpl(const char *fileName) {
|
||||
int lines = 0;
|
||||
try {
|
||||
Logger::Verbose("parsing %s ...", fullPath.c_str());
|
||||
Scanner scanner(fullPath.c_str(), Option::ScannerType, hhvm);
|
||||
Scanner scanner(fullPath.c_str(), Option::ScannerType, true);
|
||||
Compiler::Parser parser(scanner, fileName, m_ar, sb.st_size);
|
||||
parser.parse();
|
||||
lines = parser.line1();
|
||||
|
||||
+20072
-19642
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+3961
-3792
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -83,7 +83,6 @@
|
||||
#include <compiler/analysis/code_error.h>
|
||||
#include <compiler/analysis/analysis_result.h>
|
||||
|
||||
#include <util/preprocess.h>
|
||||
#include <util/lock.h>
|
||||
#include <util/logger.h>
|
||||
|
||||
@@ -146,7 +145,7 @@ StatementListPtr Parser::ParseString(CStrRef input, AnalysisResultPtr ar,
|
||||
if (!fileName || !*fileName) fileName = "string";
|
||||
|
||||
int len = input.size();
|
||||
Scanner scanner(input.data(), len, Option::ScannerType, fileName, hhvm);
|
||||
Scanner scanner(input.data(), len, Option::ScannerType, fileName, true);
|
||||
Parser parser(scanner, fileName, ar, len);
|
||||
parser.m_lambdaMode = lambdaMode;
|
||||
if (parser.parse()) {
|
||||
@@ -163,11 +162,8 @@ Parser::Parser(Scanner &scanner, const char *fileName,
|
||||
AnalysisResultPtr ar, int fileSize /* = 0 */)
|
||||
: ParserBase(scanner, fileName), m_ar(ar), m_lambdaMode(false),
|
||||
m_closureGenerator(false) {
|
||||
MD5 md5;
|
||||
if (hhvm) {
|
||||
string md5str = Eval::FileRepository::unitMd5(scanner.getMd5());
|
||||
md5 = MD5(md5str.c_str());
|
||||
}
|
||||
string md5str = Eval::FileRepository::unitMd5(scanner.getMd5());
|
||||
MD5 md5 = MD5(md5str.c_str());
|
||||
|
||||
m_file = FileScopePtr(new FileScope(m_fileName, fileSize, md5));
|
||||
|
||||
@@ -858,7 +854,7 @@ void Parser::onFunction(Token &out, Token &ret, Token &ref, Token &name,
|
||||
Token origGenFunc;
|
||||
create_generator(this, out, params, name, closureName, nullptr, nullptr,
|
||||
hasCallToGetArgs, origGenFunc,
|
||||
hhvm && Option::OutputHHBC &&
|
||||
Option::OutputHHBC &&
|
||||
(!Option::WholeProgram || !Option::ParseTimeOpts),
|
||||
attr);
|
||||
m_closureGenerator = false;
|
||||
@@ -1154,7 +1150,7 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
||||
Token origGenFunc;
|
||||
create_generator(this, out, params, name, closureName, m_clsName.c_str(),
|
||||
&modifiers, hasCallToGetArgs, origGenFunc,
|
||||
hhvm && Option::OutputHHBC &&
|
||||
Option::OutputHHBC &&
|
||||
(!Option::WholeProgram || !Option::ParseTimeOpts),
|
||||
attr);
|
||||
MethodStatementPtr origStmt =
|
||||
@@ -1571,12 +1567,15 @@ void Parser::onClosureStart(Token &name) {
|
||||
void Parser::onClosure(Token &out, Token &ret, Token &ref, Token ¶ms,
|
||||
Token &cparams, Token &stmts) {
|
||||
Token func, name;
|
||||
onFunction(func, ret, ret, name, params, stmts, 0);
|
||||
onFunction(func, ret, ref, name, params, stmts, 0);
|
||||
|
||||
ClosureExpressionPtr closure = NEW_EXP(
|
||||
ClosureExpression,
|
||||
dynamic_pointer_cast<FunctionStatement>(func->stmt),
|
||||
dynamic_pointer_cast<ExpressionList>(cparams->exp));
|
||||
closure->getClosureFunction()->setContainingClosure(closure);
|
||||
out.reset();
|
||||
out->exp = NEW_EXP(ClosureExpression,
|
||||
dynamic_pointer_cast<FunctionStatement>(func->stmt),
|
||||
dynamic_pointer_cast<ExpressionList>(cparams->exp));
|
||||
out->exp = closure;
|
||||
}
|
||||
|
||||
void Parser::onClosureParam(Token &out, Token *params, Token ¶m,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <runtime/base/util/exceptions.h>
|
||||
#include <util/parser/parser.h>
|
||||
#include <compiler/construct.h>
|
||||
#include <compiler/option.h>
|
||||
|
||||
#ifdef HPHP_PARSER_NS
|
||||
#undef HPHP_PARSER_NS
|
||||
@@ -31,7 +32,7 @@
|
||||
#endif
|
||||
#define HPHP_PARSER_ERROR(fmt, p, args...) \
|
||||
do { \
|
||||
if (!HPHP::hhvm) { \
|
||||
if (HPHP::Option::WholeProgram) { \
|
||||
HPHP::Logger::Error(fmt " %s", ##args, (p)->getMessage(true).c_str()); \
|
||||
} \
|
||||
throw HPHP::ParseTimeFatalException((p)->file(), (p)->line1(), \
|
||||
|
||||
@@ -101,11 +101,3 @@ void BlockStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_stmts) m_stmts->outputPHP(cg, ar);
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
|
||||
void BlockStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_stmts) {
|
||||
cg_indentBegin("{\n");
|
||||
m_stmts->outputCPP(cg, ar);
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,86 +109,13 @@ void BreakStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
|
||||
int64 BreakStatement::getDepth() {
|
||||
int64_t BreakStatement::getDepth() {
|
||||
if (!m_exp) return 1;
|
||||
Variant v;
|
||||
if (m_exp->getScalarValue(v) &&
|
||||
v.isInteger()) {
|
||||
int64 depth = v.toInt64();
|
||||
int64_t depth = v.toInt64();
|
||||
return depth >= 1 ? depth : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BreakStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
const std::vector<int> &labelIds = cg.getBreakScopes();
|
||||
if (labelIds.empty()) {
|
||||
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
|
||||
return;
|
||||
}
|
||||
|
||||
int64 depth = getDepth();
|
||||
|
||||
if (!depth) {
|
||||
unsigned size = labelIds.size();
|
||||
int labelId = 0;
|
||||
|
||||
int varId = cg.createNewLocalId(shared_from_this());
|
||||
cg_printf("int64 %s%d;\n", Option::TempPrefix, varId);
|
||||
|
||||
m_exp->outputCPPBegin(cg, ar);
|
||||
cg_printf("%s%d = (", Option::TempPrefix, varId);
|
||||
m_exp->outputCPP(cg, ar);
|
||||
cg_printf(");\n");
|
||||
m_exp->outputCPPEnd(cg, ar);
|
||||
|
||||
if (size > 1) {
|
||||
cg_printf("switch (");
|
||||
cg_printf("%s%d", Option::TempPrefix, varId);
|
||||
cg_printf(") {\n");
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
labelId = labelIds[i];
|
||||
labelId &= ~CodeGenerator::BreakScopeBitMask;
|
||||
cg_printf("case %d: goto %s%d;\n",
|
||||
int(labelIds.size() - i), m_name, labelId);
|
||||
cg.addLabelId(m_name, labelId);
|
||||
}
|
||||
cg_printf("default:\n");
|
||||
} else {
|
||||
labelId = labelIds.back();
|
||||
labelId &= ~CodeGenerator::BreakScopeBitMask;
|
||||
cg.addLabelId(m_name, labelId);
|
||||
}
|
||||
cg_printf("if (");
|
||||
cg_printf("%s%d", Option::TempPrefix, varId);
|
||||
cg_printf("<2) {\n");
|
||||
cg_printf("goto %s%d;\n", m_name, labelId);
|
||||
cg_printf("} else {\n");
|
||||
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
|
||||
cg_printf("}\n");
|
||||
if (size > 1) {
|
||||
cg_printf("}\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(depth >= 1);
|
||||
|
||||
if (depth > (int64)labelIds.size()) {
|
||||
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
|
||||
return;
|
||||
}
|
||||
|
||||
int labelId = labelIds[labelIds.size() - depth];
|
||||
if (depth > 1 || labelId & CodeGenerator::InsideSwitch) {
|
||||
if (depth == 1 && labelId & CodeGenerator::StaticCases) {
|
||||
cg_printf("break;\n"); // continue will turn into break as well
|
||||
} else {
|
||||
labelId &= ~CodeGenerator::BreakScopeBitMask;
|
||||
cg_printf("goto %s%d;\n", m_name, labelId);
|
||||
cg.addLabelId(m_name, labelId);
|
||||
}
|
||||
} else {
|
||||
cg_printf("%s;\n", m_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
|
||||
DECLARE_STATEMENT_VIRTUAL_FUNCTIONS;
|
||||
StatementPtr preOptimize(AnalysisResultConstPtr ar);
|
||||
int64 getDepth();
|
||||
int64_t getDepth();
|
||||
ExpressionPtr getExp();
|
||||
protected:
|
||||
const char *m_name;
|
||||
|
||||
@@ -58,7 +58,7 @@ bool CaseStatement::isLiteralString() const {
|
||||
return exp->isLiteralString();
|
||||
}
|
||||
|
||||
int64 CaseStatement::getLiteralInteger() const {
|
||||
int64_t CaseStatement::getLiteralInteger() const {
|
||||
assert(m_condition->is(Expression::KindOfScalarExpression));
|
||||
ScalarExpressionPtr exp =
|
||||
dynamic_pointer_cast<ScalarExpression>(m_condition);
|
||||
@@ -134,47 +134,3 @@ void CaseStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
cg_indentEnd();
|
||||
}
|
||||
|
||||
void CaseStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_condition) {
|
||||
cg_printf("case ");
|
||||
m_condition->outputCPPImpl(cg, ar);
|
||||
cg_indentBegin(":\n");
|
||||
} else {
|
||||
cg_indentBegin("default:\n");
|
||||
}
|
||||
cg_indentBegin("{\n");
|
||||
if (m_stmt) {
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
cg_indentEnd();
|
||||
}
|
||||
|
||||
void CaseStatement::outputCPPByNumber(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int varId, int caseNum) {
|
||||
if (caseNum >= 0) {
|
||||
cg_indentBegin("case_%d_%d:\n", varId, caseNum);
|
||||
}
|
||||
cg_indentBegin("{\n");
|
||||
if (m_stmt) {
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
if (caseNum >= 0) {
|
||||
cg_indentEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void CaseStatement::outputCPPAsIf(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int varId, const char *var, int caseNum) {
|
||||
if (m_condition) {
|
||||
m_condition->outputCPPBegin(cg, ar);
|
||||
cg_printf("if (equal(%s, (", var);
|
||||
m_condition->outputCPP(cg, ar);
|
||||
cg_printf("))) goto case_%d_%d;\n", varId, caseNum);
|
||||
m_condition->outputCPPEnd(cg, ar);
|
||||
} else {
|
||||
cg_printf("goto case_%d_%d;\n", varId, caseNum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
*/
|
||||
bool isLiteralInteger() const;
|
||||
bool isLiteralString() const;
|
||||
int64 getLiteralInteger() const;
|
||||
int64_t getLiteralInteger() const;
|
||||
std::string getLiteralString() const;
|
||||
|
||||
bool getScalarConditionValue(Variant &v) const {
|
||||
@@ -55,19 +55,6 @@ public:
|
||||
*/
|
||||
ExpressionPtr getCondition() { return m_condition;}
|
||||
StatementPtr getStatement() { return m_stmt; }
|
||||
/**
|
||||
* Generate an "if" statement that sets caseVar to caseNum if m_condition
|
||||
* evaluates true.
|
||||
*/
|
||||
void outputCPPAsIf(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int varId, const char *var, int caseNum);
|
||||
|
||||
/**
|
||||
* Generate a case statement that cases by caseNum.
|
||||
*/
|
||||
void outputCPPByNumber(CodeGenerator &cg, AnalysisResultPtr ar,
|
||||
int varId, int caseNum);
|
||||
|
||||
private:
|
||||
ExpressionPtr m_condition;
|
||||
StatementPtr m_stmt;
|
||||
|
||||
@@ -144,20 +144,3 @@ void CatchStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_stmt) m_stmt->outputPHP(cg, ar);
|
||||
cg_indentEnd("}");
|
||||
}
|
||||
|
||||
void CatchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (m_valid) {
|
||||
cg_printf("if (e.instanceof(");
|
||||
cg_printString(m_className, ar, shared_from_this());
|
||||
cg_indentBegin(")) {\n");
|
||||
VariableTablePtr variables = getScope()->getVariables();
|
||||
assert(m_variable->hasAssignableCPPVariable());
|
||||
const string &cppName =
|
||||
m_variable->getAssignableCPPVariable(ar);
|
||||
cg_printf("%s = e;\n", cppName.c_str());
|
||||
} else {
|
||||
cg_indentBegin("if (false) {\n");
|
||||
}
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
cg_indentEnd("}");
|
||||
}
|
||||
|
||||
@@ -138,79 +138,3 @@ void ClassConstant::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf(";\n");
|
||||
}
|
||||
|
||||
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (cg.getContext() != CodeGenerator::CppClassConstantsDecl &&
|
||||
cg.getContext() != CodeGenerator::CppClassConstantsImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassScopePtr scope = getClassScope();
|
||||
for (int i = 0; i < m_exp->getCount(); i++) {
|
||||
AssignmentExpressionPtr exp =
|
||||
dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]);
|
||||
ConstantExpressionPtr var =
|
||||
dynamic_pointer_cast<ConstantExpression>(exp->getVariable());
|
||||
TypePtr type = scope->getConstants()->getFinalType(var->getName());
|
||||
ExpressionPtr value = exp->getValue();
|
||||
if (scope->getConstants()->isDynamic(var->getName())) {
|
||||
continue;
|
||||
}
|
||||
switch (cg.getContext()) {
|
||||
case CodeGenerator::CppClassConstantsDecl:
|
||||
cg_printf("extern const ");
|
||||
if (type->is(Type::KindOfString)) {
|
||||
cg_printf("StaticString");
|
||||
} else {
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
}
|
||||
cg_printf(" %s%s%s%s;\n",
|
||||
Option::ClassConstantPrefix, scope->getId().c_str(),
|
||||
Option::IdPrefix.c_str(), var->getName().c_str());
|
||||
break;
|
||||
case CodeGenerator::CppClassConstantsImpl: {
|
||||
bool isString = type->is(Type::KindOfString);
|
||||
bool isVariant = Type::IsMappedToVariant(type);
|
||||
ScalarExpressionPtr scalarExp =
|
||||
dynamic_pointer_cast<ScalarExpression>(value);
|
||||
bool stringForVariant = false;
|
||||
if (isVariant && scalarExp &&
|
||||
scalarExp->getActualType() &&
|
||||
scalarExp->getActualType()->is(Type::KindOfString)) {
|
||||
cg_printf("static const StaticString %s%s%s%s%sv(LITSTR_INIT(%s));\n",
|
||||
Option::ClassConstantPrefix, scope->getId().c_str(),
|
||||
Option::IdPrefix.c_str(), var->getName().c_str(),
|
||||
Option::IdPrefix.c_str(),
|
||||
scalarExp->getCPPLiteralString().c_str());
|
||||
stringForVariant = true;
|
||||
}
|
||||
cg_printf("const ");
|
||||
if (isString) {
|
||||
cg_printf("StaticString");
|
||||
} else {
|
||||
type->outputCPPDecl(cg, ar, getScope());
|
||||
}
|
||||
value->outputCPPBegin(cg, ar);
|
||||
cg_printf(" %s%s%s%s",
|
||||
Option::ClassConstantPrefix, scope->getId().c_str(),
|
||||
Option::IdPrefix.c_str(), var->getName().c_str());
|
||||
cg_printf(isString ? "(" : " = ");
|
||||
if (stringForVariant) {
|
||||
cg_printf("%s%s%s%s%sv",
|
||||
Option::ClassConstantPrefix, scope->getId().c_str(),
|
||||
Option::IdPrefix.c_str(), var->getName().c_str(),
|
||||
Option::IdPrefix.c_str());
|
||||
} else if (isString && scalarExp) {
|
||||
cg_printf("LITSTR_INIT(%s)",
|
||||
scalarExp->getCPPLiteralString().c_str());
|
||||
} else {
|
||||
value->outputCPP(cg, ar);
|
||||
}
|
||||
cg_printf(isString ? ");\n" : ";\n");
|
||||
value->outputCPPEnd(cg, ar);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,6 @@ void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
|
||||
|
||||
if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
|
||||
|
||||
ar->recordClassSource(m_name, m_loc, getFileScope()->getName());
|
||||
for (unsigned int i = 0; i < bases.size(); i++) {
|
||||
ClassScopePtr cls = ar->findClass(bases[i]);
|
||||
if (cls) {
|
||||
@@ -275,594 +274,5 @@ bool ClassStatement::hasImpl() const {
|
||||
ClassScopeRawPtr cls = getClassScope();
|
||||
return cls->isVolatile() ||
|
||||
cls->getVariables()->getAttribute(VariableTable::ContainsDynamicStatic) ||
|
||||
(hhvm && Option::OutputHHBC);
|
||||
}
|
||||
|
||||
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
const char *clsName,
|
||||
const char *originalName,
|
||||
const char *parent) {
|
||||
ClassScopeRawPtr classScope = getClassScope();
|
||||
VariableTablePtr variables = classScope->getVariables();
|
||||
ConstantTablePtr constants = classScope->getConstants();
|
||||
const char *sweep =
|
||||
classScope->isUserClass() && !classScope->isSepExtension() ?
|
||||
"_NO_SWEEP" : "";
|
||||
|
||||
if (variables->hasAllJumpTables() &&
|
||||
classScope->hasAllJumpTables()) {
|
||||
cg_printf("DECLARE_CLASS%s(%s, %s, %s)\n",
|
||||
sweep, clsName,
|
||||
CodeGenerator::EscapeLabel(originalName).c_str(), parent);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we start to break down DECLARE_CLASS into lines of code that could
|
||||
// be generated differently...
|
||||
|
||||
cg_printf("DECLARE_CLASS_COMMON%s(%s, %s)\n", sweep,
|
||||
clsName, CodeGenerator::EscapeLabel(originalName).c_str());
|
||||
}
|
||||
|
||||
void ClassStatement::GetCtorAndInitInfo(
|
||||
StatementPtr s, bool &needsCppCtor, bool &needsInit) {
|
||||
if (!s) return;
|
||||
switch (s->getKindOf()) {
|
||||
case Statement::KindOfStatementList:
|
||||
{
|
||||
StatementListPtr stmts = static_pointer_cast<StatementList>(s);
|
||||
for (int i = 0; i < stmts->getCount(); i++) {
|
||||
GetCtorAndInitInfo((*stmts)[i], needsCppCtor, needsInit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Statement::KindOfClassVariable:
|
||||
{
|
||||
ClassVariablePtr cv = static_pointer_cast<ClassVariable>(s);
|
||||
cv->getCtorAndInitInfo(needsCppCtor, needsInit);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassStatement::getCtorAndInitInfo(bool &needsCppCtor, bool &needsInit) {
|
||||
needsCppCtor = needsInit = false;
|
||||
ClassScopeRawPtr classScope = getClassScope();
|
||||
if (!m_parent.empty()) {
|
||||
if (classScope->derivesFromRedeclaring() ==
|
||||
ClassScope::DirectFromRedeclared) {
|
||||
needsInit = true;
|
||||
}
|
||||
}
|
||||
GetCtorAndInitInfo(m_stmt, needsCppCtor, needsInit);
|
||||
// exception is special
|
||||
if (!needsInit && m_name == "exception") needsInit = true;
|
||||
}
|
||||
|
||||
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (cg.getContext() == CodeGenerator::NoContext) {
|
||||
InterfaceStatement::outputCPPImpl(cg, ar);
|
||||
return;
|
||||
}
|
||||
|
||||
ClassScopeRawPtr classScope = getClassScope();
|
||||
if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
|
||||
printSource(cg);
|
||||
}
|
||||
|
||||
string clsNameStr = classScope->getId();
|
||||
const char *clsName = clsNameStr.c_str();
|
||||
|
||||
switch (cg.getContext()) {
|
||||
case CodeGenerator::CppDeclaration:
|
||||
{
|
||||
if (Option::GenerateCPPMacros) {
|
||||
classScope->outputForwardDeclaration(cg);
|
||||
}
|
||||
classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
|
||||
|
||||
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
|
||||
ClassScopePtr parCls;
|
||||
if (!m_parent.empty()) {
|
||||
parCls = ar->findClass(m_parent);
|
||||
if (parCls && parCls->isRedeclaring()) parCls.reset();
|
||||
}
|
||||
if (Option::GenerateCppLibCode) {
|
||||
cg.printDocComment(classScope->getDocComment());
|
||||
}
|
||||
cg_printf("class %s%s", Option::ClassPrefix, clsName);
|
||||
if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)) {
|
||||
if (!parCls) {
|
||||
cg_printf(" : public DynamicObjectData");
|
||||
} else {
|
||||
cg_printf(" : public %s%s", Option::ClassPrefix,
|
||||
parCls->getId().c_str());
|
||||
}
|
||||
} else {
|
||||
if (classScope->derivesFromRedeclaring()) {
|
||||
cg_printf(" : public DynamicObjectData");
|
||||
} else if (system) {
|
||||
cg_printf(" : public ExtObjectData");
|
||||
} else {
|
||||
cg_printf(" : public ObjectData");
|
||||
}
|
||||
}
|
||||
if (m_base && Option::UseVirtualDispatch) {
|
||||
for (int i = 0; i < m_base->getCount(); i++) {
|
||||
ScalarExpressionPtr exp =
|
||||
dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
|
||||
const char *intf = exp->getString().c_str();
|
||||
ClassScopePtr intfClassScope = ar->findClass(intf);
|
||||
if (intfClassScope && !intfClassScope->isRedeclaring() &&
|
||||
classScope->derivesDirectlyFrom(intf) &&
|
||||
(!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
|
||||
string id = intfClassScope->getId();
|
||||
cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
cg_indentBegin(" {\n");
|
||||
cg_printf("public:\n");
|
||||
|
||||
cg.printSection("Properties");
|
||||
if (classScope->getVariables()->outputCPPPropertyDecl(
|
||||
cg, ar, classScope->derivesFromRedeclaring())) {
|
||||
cg.printSection("Destructor");
|
||||
cg_printf("~%s%s() NEVER_INLINE {}", Option::ClassPrefix, clsName);
|
||||
}
|
||||
|
||||
if (Option::GenerateCppLibCode) {
|
||||
cg.printSection("Methods");
|
||||
classScope->outputMethodWrappers(cg, ar);
|
||||
cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<");
|
||||
cg_printf("// NOTE: Anything below is subject to change. "
|
||||
"Use everything above instead.\n");
|
||||
}
|
||||
|
||||
cg.printSection("Class Map");
|
||||
|
||||
bool hasEmitCppCtor = false;
|
||||
bool needsCppCtor = classScope->needsCppCtor();
|
||||
bool needsInit = classScope->needsInitMethod();
|
||||
|
||||
bool disableDestructor =
|
||||
!classScope->canSkipCreateMethod(ar) ||
|
||||
(!classScope->derivesFromRedeclaring() &&
|
||||
!classScope->hasAttribute(ClassScope::HasDestructor, ar));
|
||||
|
||||
if (Option::GenerateCPPMacros) {
|
||||
bool dyn = classScope->derivesFromRedeclaring() ==
|
||||
ClassScope::DirectFromRedeclared;
|
||||
bool idyn = parCls && classScope->derivesFromRedeclaring() ==
|
||||
ClassScope::IndirectFromRedeclared;
|
||||
bool redec = classScope->isRedeclaring();
|
||||
|
||||
if (!parCls && !m_parent.empty()) {
|
||||
always_assert(dyn);
|
||||
}
|
||||
|
||||
if (!classScope->derivesFromRedeclaring()) {
|
||||
outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
|
||||
parCls ? parCls->getId().c_str()
|
||||
: "ObjectData");
|
||||
} else {
|
||||
cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
|
||||
m_originalName.c_str(),
|
||||
dyn || !parCls ? "DynamicObjectData" :
|
||||
parCls->getId().c_str());
|
||||
}
|
||||
|
||||
if (classScope->checkHasPropTable(ar)) {
|
||||
cg_printf("static const ClassPropTable %sprop_table;\n",
|
||||
Option::ObjectStaticPrefix);
|
||||
}
|
||||
|
||||
bool hasGet = classScope->getAttribute(
|
||||
ClassScope::HasUnknownPropGetter);
|
||||
bool hasSet = classScope->getAttribute(
|
||||
ClassScope::HasUnknownPropSetter);
|
||||
bool hasIsset = classScope->getAttribute(
|
||||
ClassScope::HasUnknownPropTester);
|
||||
bool hasUnset = classScope->getAttribute(
|
||||
ClassScope::HasPropUnsetter);
|
||||
bool hasCall = classScope->getAttribute(
|
||||
ClassScope::HasUnknownMethodHandler);
|
||||
bool hasCallStatic = classScope->getAttribute(
|
||||
ClassScope::HasUnknownStaticMethodHandler);
|
||||
|
||||
bool hasRootParam =
|
||||
classScope->derivedByDynamic() && (redec || dyn || idyn);
|
||||
string lateInit = "";
|
||||
if (redec && classScope->derivedByDynamic()) {
|
||||
if (!dyn && !idyn && (!parCls || parCls->isUserClass())) {
|
||||
cg_printf("private: ObjectData* root;\n");
|
||||
cg_printf("public:\n");
|
||||
cg_printf("virtual ObjectData *getRoot() { return root; }\n");
|
||||
lateInit = "root(r ? r : this)";
|
||||
}
|
||||
}
|
||||
|
||||
string callbacks = Option::ClassStaticsCallbackPrefix + clsNameStr;
|
||||
string conInit = "";
|
||||
if (dyn) {
|
||||
conInit = "DynamicObjectData(cb, \"" +
|
||||
CodeGenerator::EscapeLabel(m_parent) + "\", ";
|
||||
if (hasRootParam) {
|
||||
conInit += "r)";
|
||||
} else {
|
||||
conInit += "this)";
|
||||
}
|
||||
} else if (parCls) {
|
||||
conInit = string(Option::ClassPrefix) + parCls->getId() + "(";
|
||||
if (parCls->derivedByDynamic() &&
|
||||
(parCls->isRedeclaring() ||
|
||||
parCls->derivesFromRedeclaring() != ClassScope::FromNormal)) {
|
||||
if (hasRootParam) {
|
||||
conInit += "r ? r : ";
|
||||
}
|
||||
conInit += "this, ";
|
||||
}
|
||||
conInit += "cb)";
|
||||
} else {
|
||||
if (system) {
|
||||
conInit = "ExtObjectData(cb)";
|
||||
} else {
|
||||
if (hasRootParam) {
|
||||
conInit = "ObjectData(cb, r)";
|
||||
} else {
|
||||
conInit = "ObjectData(cb, false)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cg_printf("%s%s(%sconst ObjectStaticCallbacks *cb = &%s%s) : %s",
|
||||
Option::ClassPrefix,
|
||||
clsName,
|
||||
hasRootParam ? "ObjectData* r = NULL," : "",
|
||||
callbacks.c_str(),
|
||||
redec ? ".oscb" : "",
|
||||
conInit.c_str());
|
||||
|
||||
if (needsCppCtor) {
|
||||
cg_printf(", ");
|
||||
cg.setContext(CodeGenerator::CppConstructor);
|
||||
assert(!cg.hasInitListFirstElem());
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
cg.clearInitListFirstElem();
|
||||
cg.setContext(CodeGenerator::CppDeclaration);
|
||||
}
|
||||
if (!lateInit.empty()) {
|
||||
cg_printf(", %s", lateInit.c_str());
|
||||
}
|
||||
|
||||
cg_indentBegin(" {%s",
|
||||
hasGet || hasSet || hasIsset || hasUnset ||
|
||||
hasCall || hasCallStatic || disableDestructor ||
|
||||
hasRootParam ? "\n" : "");
|
||||
if (hasRootParam) {
|
||||
cg_printf("setId(r);\n");
|
||||
}
|
||||
if (hasGet) cg_printf("setAttribute(UseGet);\n");
|
||||
if (hasSet) cg_printf("setAttribute(UseSet);\n");
|
||||
if (hasIsset) cg_printf("setAttribute(UseIsset);\n");
|
||||
if (hasUnset) cg_printf("setAttribute(UseUnset);\n");
|
||||
if (hasCall) cg_printf("setAttribute(HasCall);\n");
|
||||
if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n");
|
||||
if (disableDestructor) {
|
||||
cg_printf("if (!hhvm) setAttribute(NoDestructor);\n");
|
||||
}
|
||||
cg_indentEnd("}\n");
|
||||
hasEmitCppCtor = true;
|
||||
}
|
||||
|
||||
if (needsCppCtor && !hasEmitCppCtor) {
|
||||
cg_printf("%s%s() : ", Option::ClassPrefix, clsName);
|
||||
cg.setContext(CodeGenerator::CppConstructor);
|
||||
assert(!cg.hasInitListFirstElem());
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
cg.clearInitListFirstElem();
|
||||
cg.setContext(CodeGenerator::CppDeclaration);
|
||||
cg_printf(" {%s}\n",
|
||||
disableDestructor ?
|
||||
" if (!hhvm) setAttribute(NoDestructor); " : "");
|
||||
}
|
||||
|
||||
if (needsInit) {
|
||||
cg_printf("void init();\n");
|
||||
}
|
||||
|
||||
// doCall
|
||||
if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
|
||||
cg_printf("Variant doCall(Variant v_name, Variant v_arguments, "
|
||||
"bool fatal);\n");
|
||||
}
|
||||
|
||||
if (classScope->getAttribute(ClassScope::HasInvokeMethod)) {
|
||||
FunctionScopePtr func =
|
||||
classScope->findFunction(ar, "__invoke", false);
|
||||
assert(func);
|
||||
if (!func->isAbstract()) {
|
||||
cg_printf("const CallInfo *"
|
||||
"t___invokeCallInfoHelper(void *&extra);\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (classScope->isRedeclaring() &&
|
||||
!classScope->derivesFromRedeclaring() &&
|
||||
classScope->derivedByDynamic()) {
|
||||
cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, "
|
||||
"bool fatal);\n");
|
||||
}
|
||||
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
{
|
||||
std::set<string> done;
|
||||
classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
|
||||
}
|
||||
if (Option::GenerateCPPMacros) {
|
||||
classScope->outputCPPJumpTableDecl(cg, ar);
|
||||
}
|
||||
cg_indentEnd("};\n");
|
||||
|
||||
classScope->outputCPPDynamicClassDecl(cg);
|
||||
|
||||
if (m_stmt) {
|
||||
cg.setContext(CodeGenerator::CppClassConstantsDecl);
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
cg.setContext(CodeGenerator::CppDeclaration);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CodeGenerator::CppImplementation:
|
||||
{
|
||||
if (m_stmt) {
|
||||
cg.setContext(CodeGenerator::CppClassConstantsImpl);
|
||||
m_stmt->outputCPP(cg, ar);
|
||||
cg.setContext(CodeGenerator::CppImplementation);
|
||||
}
|
||||
|
||||
classScope->outputCPPSupportMethodsImpl(cg, ar);
|
||||
|
||||
bool needsInit = classScope->needsInitMethod();
|
||||
if (needsInit) {
|
||||
cg_indentBegin("void %s%s::init() {\n",
|
||||
Option::ClassPrefix, clsName);
|
||||
if (!m_parent.empty()) {
|
||||
if (classScope->derivesFromRedeclaring() ==
|
||||
ClassScope::DirectFromRedeclared) {
|
||||
cg_printf("parent->init();\n");
|
||||
} else {
|
||||
ClassScopePtr parCls = ar->findClass(m_parent);
|
||||
cg_printf("%s%s::init();\n", Option::ClassPrefix,
|
||||
parCls->getId().c_str());
|
||||
}
|
||||
}
|
||||
if (classScope->getVariables()->
|
||||
getAttribute(VariableTable::NeedGlobalPointer)) {
|
||||
cg.printDeclareGlobals();
|
||||
}
|
||||
cg.setContext(CodeGenerator::CppInitializer);
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
|
||||
// This is lame. Exception base class needs to prepare stacktrace
|
||||
// outside of its PHP constructor. Every subclass of exception also
|
||||
// needs this stacktrace, so we're adding an artificial __init__ in
|
||||
// exception.php and calling it here.
|
||||
if (m_name == "exception") {
|
||||
cg_printf("{CountableHelper h(this); t___init__();}\n");
|
||||
}
|
||||
|
||||
cg_indentEnd("}\n");
|
||||
}
|
||||
|
||||
cg.setContext(CodeGenerator::CppImplementation);
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
}
|
||||
break;
|
||||
case CodeGenerator::CppFFIDecl:
|
||||
case CodeGenerator::CppFFIImpl:
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
break;
|
||||
case CodeGenerator::JavaFFI:
|
||||
{
|
||||
if (classScope->isRedeclaring()) break;
|
||||
|
||||
// TODO support PHP namespaces, once HPHP supports it
|
||||
string packageName = Option::JavaFFIRootPackage;
|
||||
string packageDir = packageName;
|
||||
Util::replaceAll(packageDir, ".", "/");
|
||||
|
||||
string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
|
||||
packageDir + "/";
|
||||
Util::mkdir(outputDir);
|
||||
|
||||
// uses a different cg to generate a separate file for each PHP class
|
||||
// also, uses the original capitalized class name
|
||||
string clsFile = outputDir + getOriginalName() + ".java";
|
||||
std::ofstream fcls(clsFile.c_str());
|
||||
CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
|
||||
cgCls.setContext(CodeGenerator::JavaFFI);
|
||||
|
||||
cgCls.printf("package %s;\n\n", packageName.c_str());
|
||||
cgCls.printf("import hphp.*;\n\n");
|
||||
|
||||
printSource(cgCls);
|
||||
|
||||
string clsModifier;
|
||||
switch (m_type) {
|
||||
case T_CLASS:
|
||||
break;
|
||||
case T_ABSTRACT:
|
||||
clsModifier = "abstract ";
|
||||
break;
|
||||
case T_FINAL:
|
||||
clsModifier = "final ";
|
||||
break;
|
||||
}
|
||||
cgCls.printf("public %sclass %s ", clsModifier.c_str(),
|
||||
getOriginalName().c_str());
|
||||
|
||||
ClassScopePtr parCls;
|
||||
if (!m_parent.empty()) parCls = ar->findClass(m_parent);
|
||||
if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)
|
||||
&& parCls && parCls->isUserClass() && !parCls->isRedeclaring()) {
|
||||
// system classes are not supported in static FFI translation
|
||||
// they shouldn't appear as superclasses as well
|
||||
cgCls.printf("extends %s", parCls->getOriginalName().c_str());
|
||||
}
|
||||
else {
|
||||
cgCls.printf("extends HphpObject");
|
||||
}
|
||||
if (m_base) {
|
||||
bool first = true;
|
||||
for (int i = 0; i < m_base->getCount(); i++) {
|
||||
ScalarExpressionPtr exp =
|
||||
dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
|
||||
const char *intf = exp->getString().c_str();
|
||||
ClassScopePtr intfClassScope = ar->findClass(intf);
|
||||
if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
|
||||
&& intfClassScope->isUserClass()) {
|
||||
if (first) {
|
||||
cgCls.printf(" implements ");
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
cgCls.printf(", ");
|
||||
}
|
||||
cgCls.print(intfClassScope->getOriginalName().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cgCls.indentBegin(" {\n");
|
||||
|
||||
// constructor for initializing the variant pointer
|
||||
cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n",
|
||||
getOriginalName().c_str());
|
||||
|
||||
FunctionScopePtr cons = classScope->findConstructor(ar, true);
|
||||
if ((cons && !cons->isAbstract()) || m_type != T_ABSTRACT) {
|
||||
// if not an abstract class and not having an explicit constructor,
|
||||
// adds a default constructor
|
||||
outputJavaFFIConstructor(cgCls, ar, cons);
|
||||
}
|
||||
|
||||
if (m_stmt) m_stmt->outputCPP(cgCls, ar);
|
||||
cgCls.indentEnd("}\n");
|
||||
|
||||
fcls.close();
|
||||
}
|
||||
break;
|
||||
case CodeGenerator::JavaFFICppDecl:
|
||||
case CodeGenerator::JavaFFICppImpl:
|
||||
{
|
||||
if (classScope->isRedeclaring()) break;
|
||||
|
||||
if (m_stmt) m_stmt->outputCPP(cg, ar);
|
||||
FunctionScopePtr cons = classScope->findConstructor(ar, true);
|
||||
if ((cons && !cons->isAbstract()) || m_type != T_ABSTRACT) {
|
||||
outputJavaFFICPPCreator(cg, ar, cons);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassStatement::outputJavaFFIConstructor(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
FunctionScopePtr cons) {
|
||||
int ac = cons ? cons->getMaxParamCount() : 0;
|
||||
bool varArgs = cons && cons->isVariableArgument();
|
||||
|
||||
// generates the constructor
|
||||
cg_printf("public %s(", getOriginalName().c_str());
|
||||
std::ostringstream args;
|
||||
std::ostringstream params;
|
||||
bool first = true;
|
||||
for (int i = 0; i < ac; i++) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
cg_printf(", ");
|
||||
args << ", ";
|
||||
params << ", ";
|
||||
}
|
||||
cg_printf("HphpVariant a%d", i);
|
||||
args << "a" << i << ".getVariantPtr()";
|
||||
params << "long a" << i;
|
||||
}
|
||||
if (varArgs) {
|
||||
if (!first) {
|
||||
cg_printf(", ");
|
||||
args << ", ";
|
||||
params << ", ";
|
||||
}
|
||||
cg_printf("HphpVariant va");
|
||||
args << "va.getVariantPtr()";
|
||||
params << "long va";
|
||||
}
|
||||
cg_indentBegin(") {\n");
|
||||
cg_printf("this(create(%s));\n", args.str().c_str());
|
||||
cg_indentEnd("}\n\n");
|
||||
|
||||
// generates the native method stub for creating the object
|
||||
cg_printf("private static native long create(%s);\n\n",
|
||||
params.str().c_str());
|
||||
}
|
||||
|
||||
void ClassStatement::outputJavaFFICPPCreator(CodeGenerator &cg,
|
||||
AnalysisResultPtr ar,
|
||||
FunctionScopePtr cons) {
|
||||
ClassScopeRawPtr cls = getClassScope();
|
||||
string packageName = Option::JavaFFIRootPackage;
|
||||
int ac = cons ? cons->getMaxParamCount() : 0;
|
||||
bool varArgs = cons && cons->isVariableArgument();
|
||||
const char *clsName = getOriginalName().c_str();
|
||||
|
||||
string mangledName = "Java_" + packageName + "_" + clsName + "_create";
|
||||
Util::replaceAll(mangledName, ".", "_");
|
||||
|
||||
cg_printf("JNIEXPORT jlong JNICALL\n");
|
||||
cg_printf("%s(JNIEnv *env, jclass cls", mangledName.c_str());
|
||||
|
||||
std::ostringstream args;
|
||||
bool first = true;
|
||||
if (varArgs) {
|
||||
args << ac << " + (((Variant *)va)->isNull() ? 0"
|
||||
<< " : ((Variant *)va)->getArrayData()->size())";
|
||||
first = false;
|
||||
}
|
||||
for (int i = 0; i < ac; i++) {
|
||||
if (first) first = false;
|
||||
else {
|
||||
args << ", ";
|
||||
}
|
||||
cg_printf(", jlong a%d", i);
|
||||
args << "*(Variant *)a" << i;
|
||||
}
|
||||
if (varArgs) {
|
||||
if (!first) {
|
||||
args << ", ";
|
||||
}
|
||||
cg_printf(", jlong va");
|
||||
args << "((Variant *)va)->toArray()";
|
||||
}
|
||||
|
||||
if (cg.getContext() == CodeGenerator::JavaFFICppDecl) {
|
||||
// java_stubs.h
|
||||
cg_printf(");\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cg_indentBegin(") {\n");
|
||||
cg_printf("ObjectData *obj = (NEWOBJ(%s%s)())->create(%s);\n",
|
||||
Option::ClassPrefix, cls->getId().c_str(), args.str().c_str());
|
||||
cg_printf("return (jlong)(NEW(Variant)(obj));\n");
|
||||
cg_indentEnd("}\n\n");
|
||||
Option::OutputHHBC;
|
||||
}
|
||||
|
||||
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