Add support for .hhas files in systemlib
Will be needed for array_filter/array_map etc This sets things up so that if we define a builtin in systemlib, we rename the corresponding c++ builtin with the prefix __builtin_, so its still available (in case the php builtin wants to delegate some edge cases, and to make it easy to run comparisons between the php and c++ implementations). Also did a little reorganization to get rid of Func::isPHPBuiltin, and use an Attr to identify functions as builtins. C++ builtins can still be identified by checking the Func::info() method. This is needed to allow builtin methods defined in php (such as array_map) to lookup their arguments in the correct context.
Esse commit está contido em:
@@ -5238,6 +5238,7 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
PostponedMeth& p = m_postponedMeths.front();
|
||||
FunctionScopePtr funcScope = p.m_meth->getFunctionScope();
|
||||
FuncEmitter* fe = p.m_fe;
|
||||
bool allowOverride = false;
|
||||
if (!fe) {
|
||||
assert(p.m_top);
|
||||
const StringData* methName =
|
||||
@@ -5253,6 +5254,10 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
funcScope->userAttributes();
|
||||
for (FunctionScope::UserAttributeMap::const_iterator it = userAttrs.begin();
|
||||
it != userAttrs.end(); ++it) {
|
||||
if (it->first == "__Overridable") {
|
||||
allowOverride = true;
|
||||
continue;
|
||||
}
|
||||
const StringData* uaName = StringData::GetStaticString(it->first);
|
||||
ExpressionPtr uaValue = it->second;
|
||||
assert(uaValue);
|
||||
@@ -5394,6 +5399,8 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
ModifierExpressionPtr mod(p.m_meth->getModifiers());
|
||||
Attr attrs = buildAttrs(mod, p.m_meth->isRef());
|
||||
|
||||
if (allowOverride) attrs = attrs | AttrAllowOverride;
|
||||
|
||||
if (funcScope->mayUseVV()) {
|
||||
attrs = attrs | AttrMayUseVV;
|
||||
}
|
||||
@@ -5926,6 +5933,10 @@ bool EmitterVisitor::canEmitBuiltinCall(FunctionCallPtr fn,
|
||||
if (func->allowOverride() && !Option::WholeProgram) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Func* f = Unit::lookupFunc(StringData::GetStaticString(name))) {
|
||||
if (!f->info()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -6974,20 +6985,7 @@ static Unit* emitHHBCNativeFuncUnit(const HhbcExtFuncInfo* builtinFuncs,
|
||||
MD5 md5("11111111111111111111111111111111");
|
||||
UnitEmitter* ue = new UnitEmitter(md5);
|
||||
ue->setFilepath(StringData::GetStaticString(""));
|
||||
ue->initMain(0, 0);
|
||||
FuncEmitter* mfe = ue->getMain();
|
||||
ue->emitOp(OpInt);
|
||||
ue->emitInt64(1);
|
||||
ue->emitOp(OpRetC);
|
||||
mfe->setMaxStackCells(1);
|
||||
mfe->finish(ue->bcPos(), false);
|
||||
ue->recordFunction(mfe);
|
||||
|
||||
TypedValue mainReturn;
|
||||
mainReturn.m_data.num = 1;
|
||||
mainReturn.m_type = KindOfInt64;
|
||||
ue->setMainReturn(&mainReturn);
|
||||
ue->setMergeOnly(true);
|
||||
ue->addTrivialPseudoMain();
|
||||
|
||||
/*
|
||||
Special function used by FPushCuf* when its argument
|
||||
@@ -7011,6 +7009,11 @@ static Unit* emitHHBCNativeFuncUnit(const HhbcExtFuncInfo* builtinFuncs,
|
||||
const ClassInfo::MethodInfo* mi = ClassInfo::FindFunction(name);
|
||||
assert(mi &&
|
||||
"MethodInfo not found; may be a problem with the .idl.json files");
|
||||
if (Unit::lookupFunc(name)) {
|
||||
// already provided by systemlib, rename to allow the php
|
||||
// version to delegate if necessary
|
||||
name = StringData::GetStaticString("__builtin_" + name->toCPPString());
|
||||
}
|
||||
FuncEmitter* fe = ue->newFuncEmitter(name, /*top*/ true);
|
||||
Offset base = ue->bcPos();
|
||||
fe->setBuiltinFunc(mi, bif, nif, base);
|
||||
@@ -7097,21 +7100,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
|
||||
MD5 md5("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
|
||||
UnitEmitter* ue = new UnitEmitter(md5);
|
||||
ue->setFilepath(StringData::GetStaticString(""));
|
||||
ue->initMain(0, 0);
|
||||
FuncEmitter* mfe = ue->getMain();
|
||||
ue->emitOp(OpInt);
|
||||
ue->emitInt64(1);
|
||||
ue->emitOp(OpRetC);
|
||||
Offset past = ue->bcPos();
|
||||
mfe->setMaxStackCells(1);
|
||||
mfe->finish(past, false);
|
||||
ue->recordFunction(mfe);
|
||||
|
||||
TypedValue mainReturn;
|
||||
mainReturn.m_data.num = 1;
|
||||
mainReturn.m_type = KindOfInt64;
|
||||
ue->setMainReturn(&mainReturn);
|
||||
ue->setMergeOnly(true);
|
||||
ue->addTrivialPseudoMain();
|
||||
|
||||
MetaInfoBuilder metaInfo;
|
||||
|
||||
@@ -7400,41 +7389,6 @@ static void batchCommit(std::vector<UnitEmitter*>& ues) {
|
||||
ues.clear();
|
||||
}
|
||||
|
||||
static void emitSystemLib() {
|
||||
if (!Option::WholeProgram) return;
|
||||
|
||||
string slib = get_systemlib();
|
||||
if (slib.empty()) return;
|
||||
|
||||
Option::WholeProgram = false;
|
||||
SystemLib::s_inited = false;
|
||||
|
||||
SCOPE_EXIT {
|
||||
SystemLib::s_inited = true;
|
||||
Option::WholeProgram = true;
|
||||
};
|
||||
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
Scanner scanner(slib.c_str(), slib.size(),
|
||||
RuntimeOption::GetScannerType(), "/:systemlib.php");
|
||||
Parser parser(scanner, "/:systemlib.php", ar, slib.size());
|
||||
parser.parse();
|
||||
FileScopePtr fsp = parser.getFileScope();
|
||||
fsp->setOuterScope(ar);
|
||||
|
||||
ar->loadBuiltins();
|
||||
ar->setPhase(AnalysisResult::AnalyzeAll);
|
||||
fsp->analyzeProgram(ar);
|
||||
|
||||
int md5len;
|
||||
char* md5str = string_md5(slib.c_str(), slib.size(), false, md5len);
|
||||
MD5 md5(md5str);
|
||||
free(md5str);
|
||||
|
||||
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
||||
Repo::get().commitUnit(ue, UnitOriginFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the entry point for offline bytecode generation.
|
||||
*/
|
||||
@@ -7489,8 +7443,6 @@ void emitAllHHBC(AnalysisResultPtr ar) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emitSystemLib();
|
||||
} else {
|
||||
dispatcher.waitEmpty();
|
||||
}
|
||||
@@ -7537,6 +7489,7 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
|
||||
}
|
||||
SCOPE_EXIT { SymbolTable::Purge(); };
|
||||
|
||||
UnitEmitter* ue = nullptr;
|
||||
// Check if this file contains raw hip hop bytecode instead of php.
|
||||
// For now this is just dictated by file extension, and doesn't ever
|
||||
// commit to the repo.
|
||||
@@ -7544,23 +7497,25 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
|
||||
if (const char* dot = strrchr(filename, '.')) {
|
||||
const char hhbc_ext[] = "hhas";
|
||||
if (!strcmp(dot + 1, hhbc_ext)) {
|
||||
return assemble_file(filename, md5);
|
||||
ue = assemble_string(code, codeLen, filename, md5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
Scanner scanner(code, codeLen, RuntimeOption::GetScannerType(), filename);
|
||||
Parser parser(scanner, filename, ar, codeLen);
|
||||
parser.parse();
|
||||
FileScopePtr fsp = parser.getFileScope();
|
||||
fsp->setOuterScope(ar);
|
||||
if (!ue) {
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
Scanner scanner(code, codeLen, RuntimeOption::GetScannerType(), filename);
|
||||
Parser parser(scanner, filename, ar, codeLen);
|
||||
parser.parse();
|
||||
FileScopePtr fsp = parser.getFileScope();
|
||||
fsp->setOuterScope(ar);
|
||||
|
||||
ar->loadBuiltins();
|
||||
ar->setPhase(AnalysisResult::AnalyzeAll);
|
||||
fsp->analyzeProgram(ar);
|
||||
ar->loadBuiltins();
|
||||
ar->setPhase(AnalysisResult::AnalyzeAll);
|
||||
fsp->analyzeProgram(ar);
|
||||
|
||||
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
||||
ue = emitHHBCUnitEmitter(ar, fsp, md5);
|
||||
}
|
||||
Repo::get().commitUnit(ue, unitOrigin);
|
||||
Unit* unit = ue->create();
|
||||
delete ue;
|
||||
|
||||
@@ -80,7 +80,7 @@ FunctionScope::FunctionScope(AnalysisResultConstPtr ar, bool method,
|
||||
// Support for systemlib functions implemented in PHP
|
||||
if (!m_method &&
|
||||
m_userAttributes.find("__Overridable") != m_userAttributes.end()) {
|
||||
setAllowOverride();
|
||||
setAllowOverride();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -837,6 +837,9 @@ void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar) {
|
||||
RuntimeOption::RepoJournal = "memory";
|
||||
RuntimeOption::EnableHipHopSyntax = Option::EnableHipHopSyntax;
|
||||
RuntimeOption::EvalJitEnableRenameFunction = Option::JitEnableRenameFunction;
|
||||
|
||||
// Turn off commits, because we don't want systemlib to get included
|
||||
RuntimeOption::RepoCommit = false;
|
||||
}
|
||||
|
||||
int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
@@ -868,7 +871,7 @@ int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
|
||||
/* without this, emitClass allows classes with interfaces to be
|
||||
hoistable */
|
||||
SystemLib::s_inited = true;
|
||||
|
||||
RuntimeOption::RepoCommit = true;
|
||||
Option::AutoInline = -1;
|
||||
|
||||
if (po.optimizeLevel > 0) {
|
||||
|
||||
@@ -105,47 +105,39 @@ void ProcessInit() {
|
||||
int db = RuntimeOption::EvalDumpBytecode;
|
||||
bool rp = RuntimeOption::AlwaysUseRelativePath;
|
||||
bool sf = RuntimeOption::SafeFileAccess;
|
||||
bool ah = RuntimeOption::EvalAllowHhas;
|
||||
RuntimeOption::EvalDumpBytecode &= ~1;
|
||||
RuntimeOption::AlwaysUseRelativePath = false;
|
||||
RuntimeOption::SafeFileAccess = false;
|
||||
RuntimeOption::EvalAllowHhas = true;
|
||||
|
||||
Transl::TargetCache::requestInit();
|
||||
|
||||
Unit* nativeFuncUnit = build_native_func_unit(hhbc_ext_funcs,
|
||||
hhbc_ext_funcs_count);
|
||||
SystemLib::s_nativeFuncUnit = nativeFuncUnit;
|
||||
String currentDir = g_vmContext->getCwd();
|
||||
|
||||
if (RuntimeOption::RepoAuthoritative) {
|
||||
auto file = g_vmContext->lookupPhpFile(String("/:systemlib.php").get(),
|
||||
currentDir.data(), nullptr);
|
||||
if (!file) {
|
||||
// Die a horrible death.
|
||||
Logger::Error("Unable to find/load systemlib.php");
|
||||
_exit(1);
|
||||
}
|
||||
file->incRef();
|
||||
SystemLib::s_unit = file->unit();
|
||||
} else {
|
||||
string slib = get_systemlib();
|
||||
string hhas;
|
||||
string slib = get_systemlib(&hhas);
|
||||
|
||||
if (slib.empty()) {
|
||||
// Die a horrible death.
|
||||
Logger::Error("Unable to find/load systemlib.php");
|
||||
_exit(1);
|
||||
}
|
||||
SystemLib::s_unit = compile_string(slib.c_str(), slib.size());
|
||||
if (slib.empty()) {
|
||||
// Die a horrible death.
|
||||
Logger::Error("Unable to find/load systemlib.php");
|
||||
_exit(1);
|
||||
}
|
||||
SystemLib::s_unit = compile_string(slib.c_str(), slib.size(),
|
||||
"systemlib.php");
|
||||
if (!hhas.empty()) {
|
||||
SystemLib::s_hhas_unit = compile_string(hhas.c_str(), hhas.size(),
|
||||
"systemlib.hhas");
|
||||
}
|
||||
|
||||
// Restore most settings before merging anything,
|
||||
// because of optimizations that depend on them
|
||||
RuntimeOption::AlwaysUseRelativePath = rp;
|
||||
RuntimeOption::SafeFileAccess = sf;
|
||||
|
||||
// Load the systemlib unit to build the Class objects
|
||||
SystemLib::s_unit->merge();
|
||||
if (SystemLib::s_hhas_unit) {
|
||||
SystemLib::s_hhas_unit->merge();
|
||||
}
|
||||
|
||||
// load builtins
|
||||
SystemLib::s_nativeFuncUnit = build_native_func_unit(hhbc_ext_funcs,
|
||||
hhbc_ext_funcs_count);
|
||||
SystemLib::s_nativeFuncUnit->merge();
|
||||
SystemLib::s_nullFunc =
|
||||
Unit::lookupFunc(StringData::GetStaticString("86null"));
|
||||
@@ -188,8 +180,10 @@ void ProcessInit() {
|
||||
Stack::ValidateStackSize();
|
||||
SystemLib::s_inited = true;
|
||||
|
||||
// Restore last to avoid dumping system things
|
||||
RuntimeOption::AlwaysUseRelativePath = rp;
|
||||
RuntimeOption::SafeFileAccess = sf;
|
||||
RuntimeOption::EvalDumpBytecode = db;
|
||||
RuntimeOption::EvalAllowHhas = ah;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1151,16 +1151,26 @@ String canonicalize_path(CStrRef p, const char* root, int rootLen) {
|
||||
return path;
|
||||
}
|
||||
|
||||
static string systemlib_split(string slib, string* hhas) {
|
||||
auto pos = slib.find("\n<?hhas\n");
|
||||
if (pos != string::npos) {
|
||||
if (hhas) *hhas = slib.substr(pos + 8);
|
||||
return slib.substr(0, pos);
|
||||
}
|
||||
return slib;
|
||||
}
|
||||
|
||||
// Search for systemlib.php in the following places:
|
||||
// 1) ${HHVM_SYSTEMLIB}
|
||||
// 2) section "systemlib" in the current executable
|
||||
// and return its contents
|
||||
string get_systemlib() {
|
||||
string get_systemlib(string* hhas) {
|
||||
if (char *file = getenv("HHVM_SYSTEMLIB")) {
|
||||
std::ifstream ifs(file);
|
||||
if (ifs.good()) {
|
||||
return std::string(std::istreambuf_iterator<char>(ifs),
|
||||
std::istreambuf_iterator<char>());
|
||||
return systemlib_split(std::string(
|
||||
std::istreambuf_iterator<char>(ifs),
|
||||
std::istreambuf_iterator<char>()), hhas);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1172,8 +1182,7 @@ string get_systemlib() {
|
||||
ifs.seekg(desc.m_start, std::ios::beg);
|
||||
std::unique_ptr<char[]> data(new char[desc.m_len]);
|
||||
ifs.read(data.get(), desc.m_len);
|
||||
string result(data.get(), desc.m_len);
|
||||
return result;
|
||||
return systemlib_split(string(data.get(), desc.m_len), hhas);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -83,7 +83,7 @@ void hphp_thread_exit();
|
||||
void hphp_session_exit();
|
||||
void hphp_process_exit() ATTRIBUTE_COLD;
|
||||
bool hphp_is_warmup_enabled();
|
||||
std::string get_systemlib();
|
||||
std::string get_systemlib(std::string* hhas = nullptr);
|
||||
|
||||
// Generated by hphp/util/generate_buildinfo.sh.
|
||||
extern const char* const kCompilerId;
|
||||
|
||||
@@ -276,7 +276,7 @@ String f_create_function(CStrRef args, CStrRef code) {
|
||||
|
||||
Variant f_func_get_arg(int arg_num) {
|
||||
CallerFrame cf;
|
||||
ActRec* ar = cf();
|
||||
ActRec* ar = cf.actRecForArgs();
|
||||
|
||||
if (ar == NULL) {
|
||||
return false;
|
||||
@@ -367,7 +367,7 @@ Array hhvm_get_frame_args(const ActRec* ar) {
|
||||
|
||||
Variant f_func_get_args() {
|
||||
EagerCallerFrame cf;
|
||||
ActRec* ar = cf();
|
||||
ActRec* ar = cf.actRecForArgs();
|
||||
if (ar && ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
|
||||
raise_warning(
|
||||
"func_get_args(): Called from the global scope - no function context"
|
||||
@@ -399,7 +399,7 @@ Array func_get_args(int num_args, CArrRef params, CArrRef args) {
|
||||
|
||||
int64_t f_func_num_args() {
|
||||
EagerCallerFrame cf;
|
||||
ActRec* ar = cf();
|
||||
ActRec* ar = cf.actRecForArgs();
|
||||
if (ar == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -330,7 +330,8 @@ static void set_function_info(Array &ret, const Func* func) {
|
||||
}
|
||||
if (func->isBuiltin()) {
|
||||
ret.set(s_internal, true_varNR);
|
||||
if (func->info()->attribute & ClassInfo::HipHopSpecific) {
|
||||
if (func->info() &&
|
||||
func->info()->attribute & ClassInfo::HipHopSpecific) {
|
||||
ret.set(s_hphp, true_varNR);
|
||||
}
|
||||
}
|
||||
|
||||
+38
-13
@@ -75,6 +75,8 @@
|
||||
* @author Jorden DeLong <delong.j@fb.com>
|
||||
*/
|
||||
|
||||
#include "hphp/runtime/vm/as.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -90,6 +92,7 @@
|
||||
#include "hphp/runtime/vm/unit.h"
|
||||
#include "hphp/runtime/vm/hhbc.h"
|
||||
#include "hphp/runtime/base/builtin_functions.h"
|
||||
#include "hphp/system/lib/systemlib.h"
|
||||
|
||||
TRACE_SET_MOD(hhas);
|
||||
|
||||
@@ -944,9 +947,11 @@ OpcodeParserMap opcode_parsers;
|
||||
#define IMM_FOUR(t1, t2, t3, t4) IMM_##t1; IMM_##t2; IMM_##t3; IMM_##t4
|
||||
|
||||
// FCall and NewTuple need to know the the first imm do POP_*MANY.
|
||||
#define IMM_IVA \
|
||||
immIVA = read_opcode_arg<int64_t>(as); \
|
||||
as.ue->emitIVA(immIVA); \
|
||||
#define IMM_IVA do { \
|
||||
int imm = read_opcode_arg<int64_t>(as); \
|
||||
as.ue->emitIVA(imm); \
|
||||
if (immIVA < 0) immIVA = imm; \
|
||||
} while (0)
|
||||
|
||||
#define IMM_SA as.ue->emitInt32(as.ue->mergeLitstr(read_litstr(as)))
|
||||
#define IMM_I64A as.ue->emitInt64(read_opcode_arg<int64_t>(as))
|
||||
@@ -1294,10 +1299,15 @@ enum AttrContext {
|
||||
};
|
||||
Attr parse_attribute_list(AsmState& as, AttrContext ctx) {
|
||||
as.in.skipWhitespace();
|
||||
if (as.in.peek() != '[') return AttrNone;
|
||||
int ret = AttrNone;
|
||||
if (ctx == ClassAttributes || ctx == FuncAttributes) {
|
||||
if (!SystemLib::s_inited) {
|
||||
ret |= AttrUnique | AttrPersistent;
|
||||
}
|
||||
}
|
||||
if (as.in.peek() != '[') return Attr(ret);
|
||||
as.in.getc();
|
||||
|
||||
int ret = AttrNone;
|
||||
std::string word;
|
||||
for (;;) {
|
||||
as.in.skipWhitespace();
|
||||
@@ -1752,6 +1762,13 @@ void parse_class(AsmState& as) {
|
||||
* ;
|
||||
*/
|
||||
void parse_main(AsmState& as) {
|
||||
if (as.emittedPseudoMain) {
|
||||
if (!SystemLib::s_inited) {
|
||||
as.error(".main found in systemlib");
|
||||
} else {
|
||||
as.error("Multiple .main directives found");
|
||||
}
|
||||
}
|
||||
as.in.expectWs('{');
|
||||
|
||||
as.ue->initMain(as.in.getLineNumber(),
|
||||
@@ -1801,6 +1818,17 @@ void parse_adata(AsmState& as) {
|
||||
void parse(AsmState& as) {
|
||||
as.in.skipWhitespace();
|
||||
std::string directive;
|
||||
if (!SystemLib::s_inited) {
|
||||
/*
|
||||
* The SystemLib::s_hhas_unit is required to be merge-only,
|
||||
* and we create the source by concatenating separate .hhas files
|
||||
* Rather than choosing one to have the .main directive, we just
|
||||
* generate a trivial pseudoMain automatically.
|
||||
*/
|
||||
as.ue->addTrivialPseudoMain();
|
||||
as.emittedPseudoMain = true;
|
||||
}
|
||||
|
||||
while (as.in.readword(directive)) {
|
||||
if (directive == ".main") { parse_main(as); continue; }
|
||||
if (directive == ".function") { parse_function(as); continue; }
|
||||
@@ -1819,17 +1847,14 @@ void parse(AsmState& as) {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
Unit* assemble_file(const char* filename, const MD5& md5) {
|
||||
boost::scoped_ptr<UnitEmitter> ue(new UnitEmitter(md5));
|
||||
UnitEmitter* assemble_string(const char*code, int codeLen,
|
||||
const char* filename, const MD5& md5) {
|
||||
std::unique_ptr<UnitEmitter> ue(new UnitEmitter(md5));
|
||||
StringData* sd = StringData::GetStaticString(filename);
|
||||
ue->setFilepath(sd);
|
||||
|
||||
try {
|
||||
std::ifstream instr(filename);
|
||||
if (!instr.is_open()) {
|
||||
throw std::runtime_error(std::string("couldn't open file ") +
|
||||
filename + ": " + strerror(errno));
|
||||
}
|
||||
std::istringstream instr(string(code, codeLen));
|
||||
AsmState as(instr);
|
||||
as.ue = ue.get();
|
||||
parse(as);
|
||||
@@ -1847,7 +1872,7 @@ Unit* assemble_file(const char* filename, const MD5& md5) {
|
||||
ue->recordFunction(fe);
|
||||
}
|
||||
|
||||
return ue->create();
|
||||
return ue.release();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -21,16 +21,17 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
class Unit;
|
||||
class UnitEmitter;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Assemble the contents of `filename' and return a Unit.
|
||||
* Assemble the contents of `filename' and return a UnitEmitter.
|
||||
*
|
||||
* Minimal documentation is available in as.cpp.
|
||||
*/
|
||||
Unit* assemble_file(const char* filename, const MD5&);
|
||||
UnitEmitter* assemble_string(const char* code, int codeLen,
|
||||
const char* filename, const MD5&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ ActRec* ActRec::arGetSfp() const {
|
||||
|
||||
bool
|
||||
ActRec::skipFrame() const {
|
||||
return m_func && m_func->isBuiltin();
|
||||
return m_func && m_func->skipFrame();
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -879,7 +879,7 @@ void Stack::toStringFrame(std::ostream& os, const ActRec* fp,
|
||||
os << ">";
|
||||
}
|
||||
|
||||
assert(!func->isBuiltin() || func->numIterators() == 0);
|
||||
assert(!func->info() || func->numIterators() == 0);
|
||||
if (func->numIterators() > 0) {
|
||||
os << "|";
|
||||
Iter* it = &((Iter*)&tv[1])[-1];
|
||||
@@ -1788,7 +1788,7 @@ bool VMExecutionContext::prepareFuncEntry(ActRec *ar, PC& pc) {
|
||||
// cppext functions/methods have their own logic for raising
|
||||
// warnings for missing arguments, so we only need to do this work
|
||||
// for non-cppext functions/methods
|
||||
if (raiseMissingArgumentWarnings && !func->isBuiltin()) {
|
||||
if (raiseMissingArgumentWarnings && !func->info()) {
|
||||
// need to sync m_pc to pc for backtraces/re-entry
|
||||
SYNC();
|
||||
const Func::ParamInfoVec& paramInfo = func->params();
|
||||
@@ -2282,7 +2282,7 @@ void VMExecutionContext::invokeUnit(TypedValue* retval, Unit* unit) {
|
||||
void VMExecutionContext::unwindBuiltinFrame() {
|
||||
// Unwind the frame for a builtin. Currently only used for
|
||||
// hphpd_break and fb_enable_code_coverage
|
||||
assert(m_fp->m_func->isBuiltin());
|
||||
assert(m_fp->m_func->info());
|
||||
assert(m_fp->m_func->name()->isame(s_hphpd_break.get()) ||
|
||||
m_fp->m_func->name()->isame(s_fb_enable_code_coverage.get()));
|
||||
// Free any values that may be on the eval stack
|
||||
@@ -2839,7 +2839,7 @@ bool VMExecutionContext::evalUnit(Unit* unit, bool local,
|
||||
ar->setThis(nullptr);
|
||||
}
|
||||
Func* func = unit->getMain(cls);
|
||||
assert(!func->isBuiltin());
|
||||
assert(!func->info());
|
||||
assert(!func->isGenerator());
|
||||
ar->m_func = func;
|
||||
ar->initNumArgs(0);
|
||||
@@ -5974,7 +5974,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassCW(PC& pc) {
|
||||
TRACE(1, "FPassCW: function %s(%d) param %d is by reference, "
|
||||
"raising a strict warning (attr:0x%x)\n",
|
||||
func->name()->data(), func->numParams(), paramId,
|
||||
func->isBuiltin() ? func->info()->attribute : 0);
|
||||
func->info() ? func->info()->attribute : 0);
|
||||
raise_strict_warning("Only variables should be passed by reference");
|
||||
}
|
||||
}
|
||||
@@ -5985,7 +5985,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPassCE(PC& pc) {
|
||||
TRACE(1, "FPassCE: function %s(%d) param %d is by reference, "
|
||||
"throwing a fatal error (attr:0x%x)\n",
|
||||
func->name()->data(), func->numParams(), paramId,
|
||||
func->isBuiltin() ? func->info()->attribute : 0);
|
||||
func->info() ? func->info()->attribute : 0);
|
||||
raise_error("Cannot pass parameter %d by reference", paramId+1);
|
||||
}
|
||||
}
|
||||
@@ -6200,8 +6200,8 @@ static int makeNativeRefCall(const Func* f, Ret* ret,
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFCallBuiltin(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IA(numArgs);
|
||||
DECODE_IA(numNonDefault);
|
||||
DECODE_IVA(numArgs);
|
||||
DECODE_IVA(numNonDefault);
|
||||
DECODE(Id, id);
|
||||
const NamedEntity* ne = m_fp->m_func->unit()->lookupNamedEntityId(id);
|
||||
Func* func = Unit::lookupFunc(ne);
|
||||
@@ -7591,12 +7591,14 @@ void VMExecutionContext::requestInit() {
|
||||
|
||||
if (UNLIKELY(RuntimeOption::EvalJitEnableRenameFunction)) {
|
||||
SystemLib::s_unit->merge();
|
||||
if (SystemLib::s_hhas_unit) SystemLib::s_hhas_unit->merge();
|
||||
SystemLib::s_nativeFuncUnit->merge();
|
||||
SystemLib::s_nativeClassUnit->merge();
|
||||
} else {
|
||||
// System units are always merge only, and
|
||||
// everything is persistent.
|
||||
assert(SystemLib::s_unit->isEmpty());
|
||||
assert(!SystemLib::s_hhas_unit || SystemLib::s_hhas_unit->isEmpty());
|
||||
assert(SystemLib::s_nativeFuncUnit->isEmpty());
|
||||
assert(SystemLib::s_nativeClassUnit->isEmpty());
|
||||
}
|
||||
|
||||
@@ -1282,7 +1282,8 @@ void Class::setSpecial() {
|
||||
// Use 86ctor(), since no program-supplied constructor exists
|
||||
m_ctor = findSpecialMethod(this, sd86ctor);
|
||||
assert(m_ctor && "class had no user-defined constructor or 86ctor");
|
||||
assert(m_ctor->attrs() == (AttrPublic|AttrNoInjection|AttrPhpLeafFn));
|
||||
assert((m_ctor->attrs() & ~AttrBuiltin) ==
|
||||
(AttrPublic|AttrNoInjection|AttrPhpLeafFn));
|
||||
}
|
||||
|
||||
void Class::applyTraitPrecRule(const PreClass::TraitPrecRule& rule) {
|
||||
|
||||
@@ -97,6 +97,15 @@ const Slot kInvalidSlot = Slot(-1);
|
||||
* to other php functions. It may still call other user-level
|
||||
* functions via re-entry (e.g. for destructors or autoload), and it
|
||||
* may make calls to builtins using FCallBuiltin.
|
||||
*
|
||||
* AttrBuiltin is set on builtin functions - whether c++ or php
|
||||
*
|
||||
* AttrAllowOverride is set on builtin functions that can be replaced
|
||||
* by user implementations
|
||||
*
|
||||
* AttrSkipFrame is set to indicate that the frame should be ignored
|
||||
* when searching for the context (eg array_map evaluates its
|
||||
* callback in the context of its caller).
|
||||
*/
|
||||
enum Attr {
|
||||
AttrNone = 0, // class property method //
|
||||
@@ -121,6 +130,9 @@ enum Attr {
|
||||
AttrPersistent= (1 << 17), // X X //
|
||||
AttrDeepInit = (1 << 18), // X //
|
||||
AttrHot = (1 << 19), // X //
|
||||
AttrBuiltin = (1 << 20), // X //
|
||||
AttrAllowOverride = (1 << 21), // X //
|
||||
AttrSkipFrame = (1 << 22), // X //
|
||||
};
|
||||
|
||||
static inline Attr operator|(Attr a, Attr b) { return Attr((int)a | (int)b); }
|
||||
|
||||
@@ -93,7 +93,7 @@ void EventHook::RunUserProfiler(const ActRec* ar, int mode) {
|
||||
if (fault.m_faultType == Fault::UserException) {
|
||||
frameinfo.set(s_exception, fault.m_userException);
|
||||
}
|
||||
} else if (!ar->m_func->isBuiltin() &&
|
||||
} else if (!ar->m_func->info() &&
|
||||
!ar->m_func->isGenerator()) {
|
||||
// TODO (#1131400) This is wrong for builtins
|
||||
frameinfo.set(s_return, tvAsCVarRef(g_vmContext->m_stack.topTV()));
|
||||
|
||||
+19
-29
@@ -39,10 +39,6 @@ static const Trace::Module TRACEMOD = Trace::bcinterp;
|
||||
const StringData* Func::s___call = StringData::GetStaticString("__call");
|
||||
const StringData* Func::s___callStatic =
|
||||
StringData::GetStaticString("__callStatic");
|
||||
static const StringData* sd___overridable =
|
||||
StringData::GetStaticString("__Overridable");
|
||||
static const StringData* sd___PHPBuiltin =
|
||||
StringData::GetStaticString("__PHPBuiltin");
|
||||
|
||||
//=============================================================================
|
||||
// Func.
|
||||
@@ -394,7 +390,7 @@ bool Func::isNameBindingImmutable(const Unit* fromUnit) const {
|
||||
bool Func::byRef(int32_t arg) const {
|
||||
// Super special case. A handful of builtins are varargs functions where the
|
||||
// (not formally declared) varargs are pass-by-reference. psychedelic-kitten
|
||||
if (arg >= m_numParams && isBuiltin() &&
|
||||
if (arg >= m_numParams && info() &&
|
||||
(info()->attribute & (ClassInfo::RefVariableArguments |
|
||||
ClassInfo::MixedVariableArguments))) {
|
||||
return true;
|
||||
@@ -408,7 +404,7 @@ bool Func::byRef(int32_t arg) const {
|
||||
bool Func::mustBeRef(int32_t arg) const {
|
||||
// return true if the argument is required to be a reference
|
||||
// (and thus should be an lvalue)
|
||||
if (arg >= m_numParams && isBuiltin() &&
|
||||
if (arg >= m_numParams && info() &&
|
||||
((info()->attribute & (ClassInfo::RefVariableArguments |
|
||||
ClassInfo::MixedVariableArguments)) ==
|
||||
ClassInfo::RefVariableArguments)) {
|
||||
@@ -514,11 +510,6 @@ void Func::prettyPrint(std::ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool Func::isPHPBuiltin() const {
|
||||
return shared()->m_userAttributes.find(sd___PHPBuiltin) !=
|
||||
shared()->m_userAttributes.end();
|
||||
}
|
||||
|
||||
HphpArray* Func::getStaticLocals() const {
|
||||
return g_vmContext->getFuncStaticCtx(this);
|
||||
}
|
||||
@@ -667,13 +658,6 @@ void Func::setCached() {
|
||||
setCachedFunc(this, isDebuggerAttached());
|
||||
}
|
||||
|
||||
bool Func::isAllowOverride() const {
|
||||
return (shared()->m_info &&
|
||||
(shared()->m_info->attribute & ClassInfo::AllowOverride)) ||
|
||||
(shared()->m_userAttributes.find(sd___overridable) !=
|
||||
shared()->m_userAttributes.end());
|
||||
}
|
||||
|
||||
const Func* Func::getGeneratorBody(const StringData* name) const {
|
||||
if (isNonClosureMethod()) {
|
||||
return cls()->lookupMethod(name);
|
||||
@@ -744,6 +728,10 @@ void FuncEmitter::init(int line1, int line2, Offset base, Attr attrs, bool top,
|
||||
m_attrs = attrs;
|
||||
m_top = top;
|
||||
m_docComment = docComment;
|
||||
if (!SystemLib::s_inited) {
|
||||
m_attrs = m_attrs | AttrBuiltin;
|
||||
if (!pce()) m_attrs = m_attrs | AttrSkipFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void FuncEmitter::finish(Offset past, bool load) {
|
||||
@@ -989,37 +977,39 @@ void FuncEmitter::setBuiltinFunc(const ClassInfo::MethodInfo* info,
|
||||
m_docComment = StringData::GetStaticString(info->docComment);
|
||||
m_line1 = 0;
|
||||
m_line2 = 0;
|
||||
m_attrs = AttrNone;
|
||||
m_attrs = AttrBuiltin | AttrSkipFrame;
|
||||
// TODO: Task #1137917: See if we can avoid marking most builtins with
|
||||
// "MayUseVV" and still make things work
|
||||
m_attrs = (Attr)(m_attrs | AttrMayUseVV);
|
||||
m_attrs = m_attrs | AttrMayUseVV;
|
||||
if (info->attribute & (ClassInfo::RefVariableArguments |
|
||||
ClassInfo::MixedVariableArguments)) {
|
||||
m_attrs = Attr(m_attrs | AttrVariadicByRef);
|
||||
m_attrs = m_attrs | AttrVariadicByRef;
|
||||
}
|
||||
if (info->attribute & ClassInfo::IsReference) {
|
||||
m_attrs = (Attr)(m_attrs | AttrReference);
|
||||
m_attrs = m_attrs | AttrReference;
|
||||
}
|
||||
if (info->attribute & ClassInfo::NoInjection) {
|
||||
m_attrs = (Attr)(m_attrs | AttrNoInjection);
|
||||
m_attrs = m_attrs | AttrNoInjection;
|
||||
}
|
||||
if (pce()) {
|
||||
if (info->attribute & ClassInfo::IsStatic) {
|
||||
m_attrs = (Attr)(m_attrs | AttrStatic);
|
||||
m_attrs = m_attrs | AttrStatic;
|
||||
}
|
||||
if (info->attribute & ClassInfo::IsFinal) {
|
||||
m_attrs = (Attr)(m_attrs | AttrFinal);
|
||||
m_attrs = m_attrs | AttrFinal;
|
||||
}
|
||||
if (info->attribute & ClassInfo::IsAbstract) {
|
||||
m_attrs = (Attr)(m_attrs | AttrAbstract);
|
||||
m_attrs = m_attrs | AttrAbstract;
|
||||
}
|
||||
if (info->attribute & ClassInfo::IsPrivate) {
|
||||
m_attrs = (Attr)(m_attrs | AttrPrivate);
|
||||
m_attrs = m_attrs | AttrPrivate;
|
||||
} else if (info->attribute & ClassInfo::IsProtected) {
|
||||
m_attrs = (Attr)(m_attrs | AttrProtected);
|
||||
m_attrs = m_attrs | AttrProtected;
|
||||
} else {
|
||||
m_attrs = (Attr)(m_attrs | AttrPublic);
|
||||
m_attrs = m_attrs | AttrPublic;
|
||||
}
|
||||
} else if (info->attribute & ClassInfo::AllowOverride) {
|
||||
m_attrs = m_attrs | AttrAllowOverride;
|
||||
}
|
||||
|
||||
m_returnType = info->returnType;
|
||||
|
||||
@@ -204,8 +204,8 @@ struct Func {
|
||||
void prettyPrint(std::ostream& out) const;
|
||||
|
||||
bool isPseudoMain() const { return m_name->empty(); }
|
||||
bool isBuiltin() const { return (bool)info(); }
|
||||
bool isPHPBuiltin() const;
|
||||
bool isBuiltin() const { return m_attrs & AttrBuiltin; }
|
||||
bool skipFrame() const { return m_attrs & AttrSkipFrame; }
|
||||
bool isMethod() const {
|
||||
return !isPseudoMain() && (bool)cls();
|
||||
}
|
||||
@@ -352,7 +352,8 @@ struct Func {
|
||||
bool hasStaticLocals() const { return !shared()->m_staticVars.empty(); }
|
||||
int numStaticLocals() const { return shared()->m_staticVars.size(); }
|
||||
const ClassInfo::MethodInfo* info() const { return shared()->m_info; }
|
||||
bool isAllowOverride() const;
|
||||
bool isAllowOverride() const { return m_attrs & AttrAllowOverride; }
|
||||
|
||||
const BuiltinFunction& nativeFuncPtr() const {
|
||||
return shared()->m_nativeFuncPtr;
|
||||
}
|
||||
|
||||
@@ -516,7 +516,7 @@ enum SetOpOp {
|
||||
O(FPassM, TWO(IVA,MA), LMANY(), ONE(FV), FF) \
|
||||
O(FCall, ONE(IVA), FMANY, ONE(RV), CF_FF) \
|
||||
O(FCallArray, NA, ONE(FV), ONE(RV), CF_FF) \
|
||||
O(FCallBuiltin, THREE(IA,IA,SA), FMANY, ONE(RV), CF) \
|
||||
O(FCallBuiltin, THREE(IVA,IVA,SA),FMANY, ONE(RV), CF) \
|
||||
O(CufSafeArray, NA, THREE(RV,CV,CV), ONE(CV), NF) \
|
||||
O(CufSafeReturn, NA, THREE(RV,CV,CV), ONE(RV), NF) \
|
||||
O(IterInit, THREE(IA,BA,HA), ONE(CV), NOV, CF) \
|
||||
|
||||
@@ -328,7 +328,7 @@ Unit* build_native_class_unit(const HhbcExtClassInfo* builtinClasses,
|
||||
return g_hphp_build_native_class_unit(builtinClasses, numBuiltinClasses);
|
||||
}
|
||||
|
||||
Unit* compile_string(const char* s, size_t sz) {
|
||||
Unit* compile_string(const char* s, size_t sz, const char* fname) {
|
||||
MD5 md5;
|
||||
int out_len;
|
||||
md5 = MD5(string_md5(s, sz, false, out_len));
|
||||
@@ -337,7 +337,7 @@ Unit* compile_string(const char* s, size_t sz) {
|
||||
if (u != nullptr) {
|
||||
return u;
|
||||
}
|
||||
return g_hphp_compiler_parse(s, sz, md5, nullptr);
|
||||
return g_hphp_compiler_parse(s, sz, md5, fname);
|
||||
}
|
||||
|
||||
// Returned array has refcount zero! Caller must refcount.
|
||||
|
||||
@@ -174,7 +174,7 @@ frame_free_args(TypedValue* args, int count) {
|
||||
|
||||
Unit*
|
||||
compile_file(const char* s, size_t sz, const MD5& md5, const char* fname);
|
||||
Unit* compile_string(const char* s, size_t sz);
|
||||
Unit* compile_string(const char* s, size_t sz, const char* fname = nullptr);
|
||||
Unit* build_native_func_unit(const HhbcExtFuncInfo* builtinFuncs,
|
||||
ssize_t numBuiltinFuncs);
|
||||
Unit* build_native_class_unit(const HhbcExtClassInfo* builtinClasses,
|
||||
|
||||
@@ -129,26 +129,35 @@ struct EagerVMRegAnchor {
|
||||
}
|
||||
};
|
||||
|
||||
static inline ActRec* regAnchorFP() {
|
||||
inline ActRec* regAnchorFP() {
|
||||
// In builtins, m_fp points to the caller's frame if called
|
||||
// through FCallBuiltin, else it points to the builtin's frame,
|
||||
// in which case, getPrevVMState() gets the caller's frame.
|
||||
// In addition, we need to skip over php-defined builtin functions
|
||||
// in order to find the true context.
|
||||
VMExecutionContext* context = g_vmContext;
|
||||
ActRec* cur = context->getFP();
|
||||
if (!cur) return nullptr;
|
||||
if (cur->skipFrame()) {
|
||||
ActRec* prev = context->getPrevVMState(cur);
|
||||
if (prev == cur) return nullptr;
|
||||
return prev;
|
||||
} else {
|
||||
return cur;
|
||||
while (cur && cur->skipFrame()) {
|
||||
cur = context->getPrevVMState(cur);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
inline ActRec* regAnchorFPForArgs() {
|
||||
// Like regAnchorFP, but only account for FCallBuiltin
|
||||
VMExecutionContext* context = g_vmContext;
|
||||
ActRec* cur = context->getFP();
|
||||
if (cur && cur->m_func->info()) {
|
||||
cur = context->getPrevVMState(cur);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
struct EagerCallerFrame : public EagerVMRegAnchor {
|
||||
ActRec* operator()() {
|
||||
return regAnchorFP();
|
||||
}
|
||||
ActRec* actRecForArgs() { return regAnchorFPForArgs(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -158,6 +167,7 @@ struct CallerFrame : public VMRegAnchor {
|
||||
ActRec* operator()() {
|
||||
return regAnchorFP();
|
||||
}
|
||||
ActRec* actRecForArgs() { return regAnchorFPForArgs(); }
|
||||
};
|
||||
|
||||
#define SYNC_VM_REGS_SCOPED() \
|
||||
|
||||
@@ -2284,7 +2284,7 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
|
||||
Fixup fixup(funcBody.m_offset - func->base(), frameCells);
|
||||
|
||||
// Emit warnings for any missing arguments
|
||||
if (!func->isBuiltin()) {
|
||||
if (!func->info()) {
|
||||
for (int i = nPassed; i < numParams; ++i) {
|
||||
if (paramInfo[i].funcletOff() == InvalidAbsoluteOffset) {
|
||||
emitImmReg(a, (intptr_t)func->name()->data(), argNumToRegName[0]);
|
||||
@@ -2315,7 +2315,7 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
|
||||
|
||||
static bool
|
||||
isNativeImplCall(const Func* funcd, int numArgs) {
|
||||
return funcd && funcd->isBuiltin() && numArgs == funcd->numParams();
|
||||
return funcd && funcd->info() && numArgs == funcd->numParams();
|
||||
}
|
||||
|
||||
int32_t // returns the amount by which rVmSp should be adjusted
|
||||
@@ -6626,17 +6626,19 @@ bool TranslatorX64::eagerRecord(const Func* func) {
|
||||
"func_num_args",
|
||||
"array_filter",
|
||||
"array_map",
|
||||
"WaitHandle::join",
|
||||
};
|
||||
|
||||
assert(func->info());
|
||||
|
||||
const StringData* name = func->isMethod() ?
|
||||
func->fullName() : func->info()->name.get();
|
||||
for (int i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
|
||||
if (!strcmp(func->name()->data(), list[i])) {
|
||||
if (!strcmp(name->data(), list[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (func->cls() && !strcmp(func->cls()->name()->data(), "WaitHandle")
|
||||
&& !strcmp(func->name()->data(), "join")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6680,7 +6682,7 @@ int32_t TranslatorX64::emitNativeImpl(const Func* func,
|
||||
* contains only a single opcode (NativeImpl), and there are no
|
||||
* non-argument locals.
|
||||
*/
|
||||
assert(func->numIterators() == 0 && func->isBuiltin());
|
||||
assert(func->numIterators() == 0 && func->info());
|
||||
assert(func->numLocals() == func->numParams());
|
||||
assert(*func->getEntry() == OpNativeImpl);
|
||||
assert(instrLen(func->getEntry()) == func->past() - func->base());
|
||||
@@ -9681,7 +9683,7 @@ void TranslatorX64::analyzeFCallBuiltin(Tracelet& t,
|
||||
void TranslatorX64::translateFCallBuiltin(const Tracelet& t,
|
||||
const NormalizedInstruction& ni) {
|
||||
int numArgs = ni.imm[0].u_IVA;
|
||||
int numNonDefault = ni.imm[1].u_IA;
|
||||
int numNonDefault = ni.imm[1].u_IVA;
|
||||
Id funcId = ni.imm[2].u_SA;
|
||||
const NamedEntity* ne = curUnit()->lookupNamedEntityId(funcId);
|
||||
const Func* func = Unit::lookupFunc(ne);
|
||||
|
||||
@@ -3125,7 +3125,7 @@ static bool shouldAnalyzeCallee(const NormalizedInstruction* fcall) {
|
||||
FTRACE(1, "analyzeCallee: target func not known\n");
|
||||
return false;
|
||||
}
|
||||
if (target->isBuiltin()) {
|
||||
if (target->info()) {
|
||||
FTRACE(1, "analyzeCallee: target func is a builtin\n");
|
||||
return false;
|
||||
}
|
||||
@@ -3946,6 +3946,7 @@ ActRecState::getCurrentState() {
|
||||
const Func* lookupImmutableMethod(const Class* cls, const StringData* name,
|
||||
bool& magicCall, bool staticLookup) {
|
||||
if (!cls || RuntimeOption::EvalJitEnableRenameFunction) return nullptr;
|
||||
if (cls->attrs() & AttrInterface) return nullptr;
|
||||
bool privateOnly = false;
|
||||
if (!RuntimeOption::RepoAuthoritative ||
|
||||
!(cls->preClass()->attrs() & AttrUnique)) {
|
||||
|
||||
@@ -181,7 +181,7 @@ Array Unit::getUserFunctions() {
|
||||
for (NamedEntityMap::const_iterator it = s_namedDataMap->begin();
|
||||
it != s_namedDataMap->end(); ++it) {
|
||||
Func* func_ = it->second.getCachedFunc();
|
||||
if (!func_ || func_->isBuiltin() || func_->isPHPBuiltin() ||
|
||||
if (!func_ || func_->isBuiltin() ||
|
||||
isdigit(func_->name()->data()[0])) {
|
||||
continue;
|
||||
}
|
||||
@@ -2236,6 +2236,23 @@ UnitEmitter::~UnitEmitter() {
|
||||
}
|
||||
}
|
||||
|
||||
void UnitEmitter::addTrivialPseudoMain() {
|
||||
initMain(0, 0);
|
||||
FuncEmitter* mfe = getMain();
|
||||
emitOp(OpInt);
|
||||
emitInt64(1);
|
||||
emitOp(OpRetC);
|
||||
mfe->setMaxStackCells(1);
|
||||
mfe->finish(bcPos(), false);
|
||||
recordFunction(mfe);
|
||||
|
||||
TypedValue mainReturn;
|
||||
mainReturn.m_data.num = 1;
|
||||
mainReturn.m_type = KindOfInt64;
|
||||
setMainReturn(&mainReturn);
|
||||
setMergeOnly(true);
|
||||
}
|
||||
|
||||
void UnitEmitter::setBc(const uchar* bc, size_t bclen) {
|
||||
m_bc = (uchar*)malloc(bclen);
|
||||
m_bcmax = bclen;
|
||||
@@ -2278,6 +2295,7 @@ Id UnitEmitter::addPreConst(const StringData* name, const TypedValue& value) {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
Id UnitEmitter::mergeLitstr(const StringData* litstr) {
|
||||
LitstrMap::const_iterator it = m_litstr2id.find(litstr);
|
||||
if (it == m_litstr2id.end()) {
|
||||
|
||||
@@ -717,6 +717,7 @@ class UnitEmitter {
|
||||
explicit UnitEmitter(const MD5& md5);
|
||||
~UnitEmitter();
|
||||
|
||||
void addTrivialPseudoMain();
|
||||
int repoId() const { return m_repoId; }
|
||||
void setRepoId(int repoId) { m_repoId = repoId; }
|
||||
int64_t sn() const { return m_sn; }
|
||||
|
||||
@@ -10,12 +10,15 @@ $outputPath = $argv[1];
|
||||
function processPhpFile($phpfile, $systemlib_php) {
|
||||
$firstchar = true;
|
||||
$contents = file_get_contents($phpfile);
|
||||
$i = 0;
|
||||
$k = strpos($contents, "\n") + 1;
|
||||
$header = trim(substr($contents, 0, $k));
|
||||
if ($header !== "<?php") {
|
||||
echo "ERROR: Unexpected header in file $phpfile\n";
|
||||
throw new Exception("Unexpected header in file $phpfile");
|
||||
if (preg_match('/\.hhas$/', $phpfile)) {
|
||||
$k = 0;
|
||||
} else {
|
||||
$k = strpos($contents, "\n") + 1;
|
||||
$header = trim(substr($contents, 0, $k));
|
||||
if ($header !== "<?php") {
|
||||
echo "ERROR: Unexpected header in file $phpfile\n";
|
||||
throw new Exception("Unexpected header in file $phpfile");
|
||||
}
|
||||
}
|
||||
fwrite($systemlib_php, substr($contents, $k));
|
||||
}
|
||||
@@ -24,7 +27,7 @@ function populatePhpFiles($input_files) {
|
||||
$php_files = array();
|
||||
foreach ($input_files as $file) {
|
||||
$key = strtolower(basename($file));
|
||||
if (!preg_match('/\.php$/', $file)) {
|
||||
if (!preg_match('/\.(php|hhas)$/', $file)) {
|
||||
$errMsg = "ERROR: Encountered non-php file ($file)";
|
||||
echo $errMsg . "\n";
|
||||
throw new Exception($errMsg);
|
||||
@@ -66,11 +69,20 @@ function genSystemlib($input_files) {
|
||||
unset($phpfiles[$initialFile]);
|
||||
}
|
||||
}
|
||||
foreach ($phpfiles as $phpfile) {
|
||||
processPhpFile($phpfile, $systemlib_php);
|
||||
foreach ($phpfiles as $key => $phpfile) {
|
||||
if (preg_match('/\.php$/', $phpfile)) {
|
||||
processPhpFile($phpfile, $systemlib_php);
|
||||
unset($phpfiles[$key]);
|
||||
}
|
||||
}
|
||||
fwrite($systemlib_php, "\n");
|
||||
|
||||
if (count($phpfiles)) {
|
||||
fwrite($systemlib_php, "\n\n<?hhas\n\n");
|
||||
foreach ($phpfiles as $key => $phpfile) {
|
||||
processPhpFile($phpfile, $systemlib_php);
|
||||
unset($phpfiles[$key]);
|
||||
}
|
||||
}
|
||||
fclose($systemlib_php);
|
||||
$systemlib_php = null;
|
||||
chmod($systemlib_php_tempnam, 0644);
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace HPHP {
|
||||
|
||||
bool SystemLib::s_inited = false;
|
||||
HPHP::Unit* SystemLib::s_unit = nullptr;
|
||||
HPHP::Unit* SystemLib::s_hhas_unit = nullptr;
|
||||
HPHP::Unit* SystemLib::s_nativeFuncUnit = nullptr;
|
||||
HPHP::Unit* SystemLib::s_nativeClassUnit = nullptr;
|
||||
HPHP::Func* SystemLib::s_nullFunc = nullptr;
|
||||
|
||||
@@ -73,6 +73,7 @@ class SystemLib {
|
||||
public:
|
||||
static bool s_inited;
|
||||
static HPHP::Unit* s_unit;
|
||||
static HPHP::Unit* s_hhas_unit;
|
||||
static HPHP::Unit* s_nativeFuncUnit;
|
||||
static HPHP::Unit* s_nativeClassUnit;
|
||||
|
||||
|
||||
@@ -198,11 +198,7 @@ array(3) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
[0]=>
|
||||
array(6) {
|
||||
["file"]=>
|
||||
string(%d) "%S"
|
||||
["line"]=>
|
||||
int(42)
|
||||
array(4) {
|
||||
["function"]=>
|
||||
string(9) "initTrace"
|
||||
["class"]=>
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário