Comparar commits
23 Commits
HHVM-2.2
...
HPHP-2.0.1
| 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 |
@@ -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)) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <compiler/analysis/variable_table.h>
|
||||
#include <compiler/construct.h>
|
||||
#include <compiler/expression/class_constant_expression.h>
|
||||
#include <compiler/expression/closure_expression.h>
|
||||
#include <compiler/expression/constant_expression.h>
|
||||
#include <compiler/expression/scalar_expression.h>
|
||||
#include <compiler/expression/unary_op_expression.h>
|
||||
@@ -32,6 +33,7 @@
|
||||
#include <compiler/option.h>
|
||||
#include <compiler/parser/parser.h>
|
||||
#include <compiler/statement/interface_statement.h>
|
||||
#include <compiler/statement/function_statement.h>
|
||||
#include <compiler/statement/method_statement.h>
|
||||
#include <compiler/statement/statement_list.h>
|
||||
#include <runtime/base/builtin_functions.h>
|
||||
@@ -445,6 +447,7 @@ ClassScope::importTraitMethod(const TraitMethod& traitMethod,
|
||||
cloneMeth->getModifiers()));
|
||||
cloneMeth->resetScope(cloneFuncScope, true);
|
||||
cloneFuncScope->setOuterScope(shared_from_this());
|
||||
informClosuresAboutScopeClone(cloneMeth, cloneFuncScope, ar);
|
||||
|
||||
cloneMeth->addTraitMethodToScope(ar,
|
||||
dynamic_pointer_cast<ClassScope>(shared_from_this()));
|
||||
@@ -452,6 +455,34 @@ ClassScope::importTraitMethod(const TraitMethod& traitMethod,
|
||||
return cloneMeth;
|
||||
}
|
||||
|
||||
void ClassScope::informClosuresAboutScopeClone(
|
||||
ConstructPtr root,
|
||||
FunctionScopePtr outerScope,
|
||||
AnalysisResultPtr ar) {
|
||||
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < root->getKidCount(); i++) {
|
||||
ConstructPtr cons = root->getNthKid(i);
|
||||
ClosureExpressionPtr closure =
|
||||
dynamic_pointer_cast<ClosureExpression>(cons);
|
||||
|
||||
if (!closure) {
|
||||
informClosuresAboutScopeClone(cons, outerScope, ar);
|
||||
continue;
|
||||
}
|
||||
|
||||
FunctionStatementPtr func = closure->getClosureFunction();
|
||||
HPHP::FunctionScopePtr funcScope = func->getFunctionScope();
|
||||
assert(funcScope->isClosure());
|
||||
funcScope->addClonedTraitOuterScope(outerScope);
|
||||
// Don't need to recurse
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClassScope::addImportTraitMethod(const TraitMethod &traitMethod,
|
||||
const string &methName) {
|
||||
m_importMethToTraitMap[methName].push_back(traitMethod);
|
||||
|
||||
@@ -437,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,
|
||||
|
||||
@@ -410,6 +410,46 @@ bool FunctionScope::containsReference() const {
|
||||
return m_attribute & FileScope::ContainsReference;
|
||||
}
|
||||
|
||||
void FunctionScope::setContainsThis(bool f /* = true */) {
|
||||
m_containsThis = f;
|
||||
|
||||
BlockScopePtr bs(this->getOuterScope());
|
||||
while (bs && bs->is(BlockScope::FunctionScope)) {
|
||||
FunctionScopePtr fs = static_pointer_cast<FunctionScope>(bs);
|
||||
if (!fs->isClosure()) {
|
||||
break;
|
||||
}
|
||||
fs->setContainsThis(f);
|
||||
bs = bs->getOuterScope();
|
||||
}
|
||||
|
||||
for (auto it = m_clonedTraitOuterScope.begin(); it != m_clonedTraitOuterScope.end(); it++) {
|
||||
(*it)->setContainsThis(f);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionScope::setContainsBareThis(bool f, bool ref /* = false */) {
|
||||
if (f) {
|
||||
m_containsBareThis |= ref ? 2 : 1;
|
||||
} else {
|
||||
m_containsBareThis = 0;
|
||||
}
|
||||
|
||||
BlockScopePtr bs(this->getOuterScope());
|
||||
while (bs && bs->is(BlockScope::FunctionScope)) {
|
||||
FunctionScopePtr fs = static_pointer_cast<FunctionScope>(bs);
|
||||
if (!fs->isClosure()) {
|
||||
break;
|
||||
}
|
||||
fs->setContainsBareThis(f, ref);
|
||||
bs = bs->getOuterScope();
|
||||
}
|
||||
|
||||
for (auto it = m_clonedTraitOuterScope.begin(); it != m_clonedTraitOuterScope.end(); it++) {
|
||||
(*it)->setContainsBareThis(f, ref);
|
||||
}
|
||||
}
|
||||
|
||||
bool FunctionScope::hasImpl() const {
|
||||
if (!isUserFunction()) {
|
||||
return !isAbstract();
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -492,6 +493,7 @@ private:
|
||||
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;
|
||||
|
||||
@@ -567,6 +567,10 @@ void VariableTable::clearUsed() {
|
||||
} else {
|
||||
sym.second.setReferenced();
|
||||
}
|
||||
|
||||
if (sym.second.isRefGeneratorParameter()) {
|
||||
sym.second.setReferenced();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -473,8 +473,8 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
(Util::format_pattern(po.excludeStaticPatterns[i], true));
|
||||
}
|
||||
|
||||
Option::OutputHHBC = true;
|
||||
if (po.target == "hhbc" || po.target == "run") {
|
||||
Option::OutputHHBC = true;
|
||||
Option::AnalyzePerfectVirtuals = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) &&
|
||||
|
||||
@@ -1569,10 +1569,13 @@ void Parser::onClosure(Token &out, Token &ret, Token &ref, Token ¶ms,
|
||||
Token func, name;
|
||||
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,
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <compiler/expression/parameter_expression.h>
|
||||
#include <compiler/expression/assignment_expression.h>
|
||||
#include <compiler/expression/simple_variable.h>
|
||||
#include <compiler/expression/closure_expression.h>
|
||||
|
||||
#include <compiler/analysis/ast_walker.h>
|
||||
#include <compiler/analysis/analysis_result.h>
|
||||
@@ -372,15 +373,44 @@ void MethodStatement::analyzeProgram(AnalysisResultPtr ar) {
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
|
||||
funcScope->setParamSpecs(ar);
|
||||
if (funcScope->isGenerator()) {
|
||||
MethodStatementRawPtr orig = getOrigGeneratorFunc();
|
||||
VariableTablePtr variables = funcScope->getVariables();
|
||||
|
||||
Symbol *cont = variables->getSymbol(CONTINUATION_OBJECT_NAME);
|
||||
cont->setHidden();
|
||||
getOrigGeneratorFunc()->getFunctionScope()->addUse(
|
||||
funcScope, BlockScope::UseKindClosure);
|
||||
getOrigGeneratorFunc()->getFunctionScope()->setContainsBareThis(
|
||||
|
||||
orig->getFunctionScope()->addUse(funcScope, BlockScope::UseKindClosure);
|
||||
orig->getFunctionScope()->setContainsBareThis(
|
||||
funcScope->containsBareThis(), funcScope->containsRefThis());
|
||||
getOrigGeneratorFunc()->getFunctionScope()->setContainsThis(
|
||||
funcScope->containsThis());
|
||||
orig->getFunctionScope()->setContainsThis(funcScope->containsThis());
|
||||
|
||||
if (ExpressionListPtr params = orig->getParams()) {
|
||||
for (int i = 0; i < params->getCount(); ++i) {
|
||||
auto param = dynamic_pointer_cast<ParameterExpression>((*params)[i]);
|
||||
Symbol *gp = variables->addDeclaredSymbol(
|
||||
param->getName(), ConstructPtr());
|
||||
gp->setGeneratorParameter();
|
||||
if (param->isRef()) {
|
||||
gp->setRefGeneratorParameter();
|
||||
gp->setReferenced();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ClosureExpressionRawPtr closure = orig->getContainingClosure()) {
|
||||
if (ExpressionListPtr cvars = closure->getClosureVariables()) {
|
||||
for (int i = 0; i < cvars->getCount(); ++i) {
|
||||
auto param = dynamic_pointer_cast<ParameterExpression>((*cvars)[i]);
|
||||
Symbol *gp = variables->addDeclaredSymbol(
|
||||
param->getName(), ConstructPtr());
|
||||
gp->setGeneratorParameter();
|
||||
if (param->isRef()) {
|
||||
gp->setRefGeneratorParameter();
|
||||
gp->setReferenced();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (funcScope->isSepExtension() ||
|
||||
Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_BOOST_TYPES(ClosureExpression);
|
||||
DECLARE_BOOST_TYPES(ModifierExpression);
|
||||
DECLARE_BOOST_TYPES(ExpressionList);
|
||||
DECLARE_BOOST_TYPES(StatementList);
|
||||
@@ -104,6 +105,13 @@ public:
|
||||
return m_generatorFunc;
|
||||
}
|
||||
|
||||
void setContainingClosure(ClosureExpressionRawPtr exp) {
|
||||
m_containingClosure = exp;
|
||||
}
|
||||
ClosureExpressionRawPtr getContainingClosure() const {
|
||||
return m_containingClosure;
|
||||
}
|
||||
|
||||
void setClassName(const std::string &name) { m_className = name; }
|
||||
void setOriginalClassName(const std::string &name) {
|
||||
m_originalClassName = name;
|
||||
@@ -127,6 +135,7 @@ protected:
|
||||
std::string m_docComment;
|
||||
MethodStatementRawPtr m_origGeneratorFunc;
|
||||
MethodStatementRawPtr m_generatorFunc;
|
||||
ClosureExpressionRawPtr m_containingClosure;
|
||||
ExpressionListPtr m_attrList;
|
||||
|
||||
void setSpecialMethod(ClassScopePtr classScope);
|
||||
|
||||
@@ -31,10 +31,13 @@ int main(int argc, char** argv) {
|
||||
return HPHP::execute_program(argc, argv);
|
||||
}
|
||||
std::vector<char*> args;
|
||||
args.insert(args.begin(), argv, argv + argc);
|
||||
args.push_back(argv[0]);
|
||||
args.push_back("-vRepo.Authoritative=true");
|
||||
args.push_back("-vRepo.Local.Mode=r-");
|
||||
repo = "-vRepo.Local.Path=" + repo;
|
||||
args.push_back(const_cast<char*>(repo.c_str()));
|
||||
if (argc > 1) {
|
||||
args.insert(args.end(), argv + 1, argv + argc);
|
||||
}
|
||||
return HPHP::execute_program(args.size(), &args[0]);
|
||||
}
|
||||
|
||||
@@ -345,7 +345,8 @@ vm_decode_function(CVarRef function,
|
||||
this_ = function.asCObjRef().get();
|
||||
cls = nullptr;
|
||||
const HPHP::VM::Func *f = this_->getVMClass()->lookupMethod(invokeStr);
|
||||
if (f != nullptr && (f->attrs() & HPHP::VM::AttrStatic)) {
|
||||
if (f != nullptr &&
|
||||
((f->attrs() & HPHP::VM::AttrStatic) && !f->isClosureBody())) {
|
||||
// If __invoke is static, invoke it as such
|
||||
cls = this_->getVMClass();
|
||||
this_ = nullptr;
|
||||
|
||||
@@ -594,11 +594,11 @@ bool ClassInfo::HasAccess(CStrRef className, CStrRef methodName,
|
||||
clsInfo->hasMethod(methodName, defClass);
|
||||
if (!methodInfo) return false;
|
||||
if (methodInfo->attribute & ClassInfo::IsPublic) return true;
|
||||
CStrRef ctxName = g_vmContext->getContextClassName();
|
||||
if (ctxName->size() == 0) {
|
||||
VM::Class* ctx = g_vmContext->getContextClass();
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
const ClassInfo *ctxClass = ClassInfo::FindClass(ctxName);
|
||||
const ClassInfo *ctxClass = ClassInfo::FindClass(ctx->nameRef());
|
||||
bool hasObject = hasCallObject || g_vmContext->getThis();
|
||||
if (ctxClass) {
|
||||
return ctxClass->checkAccess(defClass, methodInfo, staticCall, hasObject);
|
||||
|
||||
@@ -591,8 +591,8 @@ public:
|
||||
|
||||
HPHP::VM::ActRec* getStackFrame();
|
||||
ObjectData* getThis();
|
||||
CStrRef getContextClassName();
|
||||
CStrRef getParentContextClassName();
|
||||
VM::Class* getContextClass();
|
||||
VM::Class* getParentContextClass();
|
||||
CStrRef getContainingFileName();
|
||||
int getLine();
|
||||
Array getCallerInfo();
|
||||
|
||||
@@ -72,7 +72,13 @@ void raise_recoverable_error(const char *fmt, ...) {
|
||||
raise_recoverable_error(msg);
|
||||
}
|
||||
|
||||
static int64_t g_notice_counter = 0;
|
||||
|
||||
void raise_strict_warning(const std::string &msg) {
|
||||
if (RuntimeOption::NoticeFrequency <= 0 ||
|
||||
(g_notice_counter++) % RuntimeOption::NoticeFrequency != 0) {
|
||||
return;
|
||||
}
|
||||
int errnum = ErrorConstants::STRICT;
|
||||
if (!g_context->errorNeedsHandling(errnum, true,
|
||||
ExecutionContext::NeverThrow)) {
|
||||
@@ -84,6 +90,10 @@ void raise_strict_warning(const std::string &msg) {
|
||||
}
|
||||
|
||||
void raise_strict_warning(const char *fmt, ...) {
|
||||
if (RuntimeOption::NoticeFrequency <= 0 ||
|
||||
(g_notice_counter++) % RuntimeOption::NoticeFrequency != 0) {
|
||||
return;
|
||||
}
|
||||
std::string msg;
|
||||
int errnum = ErrorConstants::STRICT;
|
||||
if (!g_context->errorNeedsHandling(errnum, true,
|
||||
@@ -117,11 +127,11 @@ void raise_warning(const std::string &msg) {
|
||||
}
|
||||
|
||||
void raise_warning(const char *fmt, ...) {
|
||||
std::string msg;
|
||||
if (RuntimeOption::WarningFrequency <= 0 ||
|
||||
(g_warning_counter++) % RuntimeOption::WarningFrequency != 0) {
|
||||
return;
|
||||
}
|
||||
std::string msg;
|
||||
int errnum = ErrorConstants::WARNING;
|
||||
if (!g_context->errorNeedsHandling(errnum, true,
|
||||
ExecutionContext::NeverThrow)) {
|
||||
@@ -151,8 +161,6 @@ void raise_debugging(const char *fmt, ...) {
|
||||
raise_debugging(msg);
|
||||
}
|
||||
|
||||
static int64_t g_notice_counter = 0;
|
||||
|
||||
void raise_notice(const std::string &msg) {
|
||||
if (RuntimeOption::NoticeFrequency <= 0 ||
|
||||
(g_notice_counter++) % RuntimeOption::NoticeFrequency != 0) {
|
||||
@@ -169,11 +177,11 @@ void raise_notice(const std::string &msg) {
|
||||
}
|
||||
|
||||
void raise_notice(const char *fmt, ...) {
|
||||
std::string msg;
|
||||
if (RuntimeOption::NoticeFrequency <= 0 ||
|
||||
(g_notice_counter++) % RuntimeOption::NoticeFrequency != 0) {
|
||||
return;
|
||||
}
|
||||
std::string msg;
|
||||
int errnum = ErrorConstants::NOTICE;
|
||||
if (!g_context->errorNeedsHandling(errnum, true,
|
||||
ExecutionContext::NeverThrow)) {
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
#ifndef __HPHP_RUNTIME_ERROR_H__
|
||||
#define __HPHP_RUNTIME_ERROR_H__
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
|
||||
#include "util/base.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
F(bool, HHIREnableCalleeSavedOpt, true) \
|
||||
F(bool, HHIREnablePreColoring, true) \
|
||||
F(bool, HHIREnableCoalescing, true) \
|
||||
F(bool, HHIREnableMmx, true) \
|
||||
F(bool, HHIREnableMmx, false) \
|
||||
F(bool, HHIREnableRefCountOpt, true) \
|
||||
F(bool, HHIREnableSinking, true) \
|
||||
F(bool, HHIRGenerateAsserts, debug) \
|
||||
|
||||
@@ -14,19 +14,26 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <runtime/base/util/curl_tls_workarounds.h>
|
||||
#include <runtime/base/runtime_option.h>
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "runtime/base/util/curl_tls_workarounds.h"
|
||||
#include "runtime/base/runtime_error.h"
|
||||
#include "runtime/base/runtime_option.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
CURLcode curl_tls_workarounds_cb(CURL *curl, void *sslctx, void *parm) {
|
||||
// Check to see if workarounds are enabled.
|
||||
if (RuntimeOption::TLSDisableTLS1_2) {
|
||||
#ifdef SSL_OP_NO_TLSv1_2
|
||||
SSL_CTX* ctx = (SSL_CTX*)sslctx;
|
||||
SSL_CTX_set_options(ctx, SSL_CTX_get_options (ctx) | SSL_OP_NO_TLSv1_2);
|
||||
#else
|
||||
raise_notice("TLSDisableTLS1_2 enabled, but this version of "
|
||||
"SSL does not support that option");
|
||||
#endif
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ void StringBuffer::release() {
|
||||
}
|
||||
|
||||
void StringBuffer::resize(int size) {
|
||||
assert(size >= 0 && size < m_cap);
|
||||
if (size >= 0 && size < m_cap) {
|
||||
assert(size >= 0 && size <= m_cap);
|
||||
if (size >= 0 && size <= m_cap) {
|
||||
m_len = size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,8 +623,6 @@ static Variant f_hphp_get_iterator(VRefParam iterable, bool isMutable) {
|
||||
CREATE_VECTOR1(iterable));
|
||||
}
|
||||
if (iterable.isObject()) {
|
||||
CStrRef context = g_vmContext->getContextClassName();
|
||||
|
||||
ObjectData *obj = iterable.getObjectData();
|
||||
Variant iterator;
|
||||
while (obj->instanceof(SystemLib::s_IteratorAggregateClass)) {
|
||||
@@ -632,6 +630,8 @@ static Variant f_hphp_get_iterator(VRefParam iterable, bool isMutable) {
|
||||
if (!iterator.isObject()) break;
|
||||
obj = iterator.getObjectData();
|
||||
}
|
||||
VM::Class*ctx = g_vmContext->getContextClass();
|
||||
CStrRef context = ctx ? ctx->nameRef() : empty_string;
|
||||
if (isMutable) {
|
||||
if (obj->instanceof(SystemLib::s_IteratorClass)) {
|
||||
throw FatalErrorException("An iterator cannot be used for "
|
||||
|
||||
@@ -113,7 +113,7 @@ Variant f_bzdecompress(CStrRef source, int small /* = 0 */) {
|
||||
/* compression is better then 2:1, need to allocate more memory */
|
||||
bzs.avail_out = source_len;
|
||||
size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
|
||||
dest = (char *) Util::safe_realloc(dest, bzs.avail_out + 1);
|
||||
dest = (char *) Util::safe_realloc(dest, size + bzs.avail_out + 1);
|
||||
bzs.next_out = dest + size;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ static String get_classname(CVarRef class_or_object) {
|
||||
}
|
||||
|
||||
static inline CStrRef ctxClassName() {
|
||||
return g_vmContext->getContextClassName();
|
||||
VM::Class* ctx = g_vmContext->getContextClass();
|
||||
return ctx ? ctx->nameRef() : empty_string;
|
||||
}
|
||||
|
||||
static const VM::Class* get_cls(CVarRef class_or_object) {
|
||||
|
||||
@@ -480,7 +480,6 @@ void c_MutableArrayIterator::t___construct(VRefParam array) {
|
||||
m_valid = mi.advance();
|
||||
if (!m_valid) mi.~MArrayIter();
|
||||
} else if (rtv->m_type == KindOfObject) {
|
||||
CStrRef ctxStr = g_vmContext->getContextClassName();
|
||||
if (rtv->m_data.pobj->isCollection()) {
|
||||
raise_error("Collection elements cannot be taken by reference");
|
||||
}
|
||||
@@ -489,7 +488,9 @@ void c_MutableArrayIterator::t___construct(VRefParam array) {
|
||||
if (isIterator) {
|
||||
raise_error("An iterator cannot be used with foreach by reference");
|
||||
}
|
||||
Array iterArray = obj->o_toIterArray(ctxStr, true);
|
||||
VM::Class* ctx = g_vmContext->getContextClass();
|
||||
Array iterArray = obj->o_toIterArray(ctx ? ctx->nameRef() : empty_string,
|
||||
true);
|
||||
ArrayData* ad = iterArray.detach();
|
||||
MArrayIter& mi = marr();
|
||||
(void) new (&mi) MArrayIter(ad);
|
||||
|
||||
@@ -54,6 +54,41 @@ int64_t f_connection_timeout() {
|
||||
return f_connection_status() == k_CONNECTION_TIMEOUT;
|
||||
}
|
||||
|
||||
static VM::Class* getClassByName(const char* name, int len) {
|
||||
VM::Class* cls = nullptr;
|
||||
// translate "self" or "parent"
|
||||
if (len == 4 && !memcmp(name, "self", 4)) {
|
||||
cls = g_vmContext->getContextClass();
|
||||
if (!cls) {
|
||||
throw FatalErrorException("Cannot access self:: "
|
||||
"when no class scope is active");
|
||||
}
|
||||
} else if (len == 6 && !memcmp(name, "parent", 6)) {
|
||||
cls = g_vmContext->getParentContextClass();
|
||||
if (!cls) {
|
||||
throw FatalErrorException("Cannot access parent");
|
||||
}
|
||||
} else if (len == 6 && !memcmp(name, "static", 6)) {
|
||||
CallerFrame cf;
|
||||
auto ar = cf();
|
||||
if (ar) {
|
||||
if (ar->hasThis()) {
|
||||
cls = ar->getThis()->getVMClass();
|
||||
} else if (ar->hasClass()) {
|
||||
cls = ar->getClass();
|
||||
}
|
||||
}
|
||||
if (!cls) {
|
||||
throw FatalErrorException("Cannot access static:: "
|
||||
"when no class scope is active");
|
||||
}
|
||||
} else {
|
||||
String className(name, len, CopyString);
|
||||
cls = VM::Unit::loadClass(className.get());
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
|
||||
Variant f_constant(CStrRef name) {
|
||||
if (!name.get()) return null;
|
||||
const char *data = name.data();
|
||||
@@ -63,26 +98,7 @@ Variant f_constant(CStrRef name) {
|
||||
// class constant
|
||||
int classNameLen = colon - data;
|
||||
char *constantName = colon + 2;
|
||||
String className(data, classNameLen, CopyString);
|
||||
|
||||
// translate "self" or "parent"
|
||||
if (className == "self") {
|
||||
String this_class = g_vmContext->getContextClassName();
|
||||
if (this_class.empty()) {
|
||||
throw FatalErrorException("Cannot access self:: "
|
||||
"when no class scope is active");
|
||||
} else {
|
||||
className = this_class;
|
||||
}
|
||||
} else if (className == "parent") {
|
||||
String parent_class =g_vmContext->getParentContextClassName();
|
||||
if (parent_class.empty()) {
|
||||
throw FatalErrorException("Cannot access parent");
|
||||
} else {
|
||||
className = parent_class;
|
||||
}
|
||||
}
|
||||
VM::Class* cls = VM::Unit::loadClass(className.get());
|
||||
VM::Class* cls = getClassByName(data, classNameLen);
|
||||
if (cls) {
|
||||
String cnsName(constantName, data + len - constantName, CopyString);
|
||||
TypedValue* tv = cls->clsCnsGet(cnsName.get());
|
||||
@@ -123,59 +139,12 @@ bool f_defined(CStrRef name, bool autoload /* = true */) {
|
||||
// class constant
|
||||
int classNameLen = colon - data;
|
||||
char *constantName = colon + 2;
|
||||
String className(data, classNameLen, CopyString);
|
||||
|
||||
// translate "self" or "parent" or "static"
|
||||
if (className == "self") {
|
||||
String this_class = g_vmContext->getContextClassName();
|
||||
if (this_class.empty()) {
|
||||
throw FatalErrorException("Cannot access self:: "
|
||||
"when no class scope is active");
|
||||
} else {
|
||||
className = this_class;
|
||||
}
|
||||
} else if (className == "parent") {
|
||||
String parent_class = g_vmContext->getParentContextClassName();
|
||||
if (parent_class.empty()) {
|
||||
throw FatalErrorException("Cannot access parent");
|
||||
} else {
|
||||
className = parent_class;
|
||||
}
|
||||
} else if (className == "static") {
|
||||
CallerFrame cf;
|
||||
auto ar = cf();
|
||||
if (ar) {
|
||||
HPHP::VM::Class* cls;
|
||||
if (ar->hasThis()) {
|
||||
cls = ar->getThis()->getVMClass();
|
||||
} else if (ar->hasClass()) {
|
||||
cls = ar->getClass();
|
||||
} else {
|
||||
cls = NULL;
|
||||
}
|
||||
if (cls) {
|
||||
className = cls->nameRef();
|
||||
} else {
|
||||
throw FatalErrorException("Cannot access static:: "
|
||||
"when no class scope is active");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (class_exists(className)) { // taking care of volatile class
|
||||
const ClassInfo *info;
|
||||
for (String parentClass = className;
|
||||
!parentClass.empty();
|
||||
parentClass = info->getParentClass()) {
|
||||
info = ClassInfo::FindClass(parentClass);
|
||||
if (!info) {
|
||||
assert(false);
|
||||
}
|
||||
if (info->hasConstant(constantName)) return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
VM::Class* cls = getClassByName(data, classNameLen);
|
||||
if (cls) {
|
||||
String cnsName(constantName, data + len - constantName, CopyString);
|
||||
return cls->clsCnsGet(cnsName.get());
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// system/uniquely defined scalar constant
|
||||
if (ClassInfo::FindConstant(name)) return true;
|
||||
|
||||
@@ -16,7 +16,7 @@ if (!defined('GLOBAL_SYMBOL_REDECLARED_CLASS')) {define('GLOBAL_SYMBOL_REDECLARE
|
||||
if (!defined('GLOBAL_SYMBOL_REDECLARED_FUNCTION')) {define('GLOBAL_SYMBOL_REDECLARED_FUNCTION', 5);}
|
||||
if (!defined('GLOBAL_SYMBOL_STATIC_VARIABLE')) {define('GLOBAL_SYMBOL_STATIC_VARIABLE', 1);}
|
||||
if (!defined('HPHP_TRIM_CHARLIST')) {define('HPHP_TRIM_CHARLIST', ' \n\r\t\v' . "\0" . '');}
|
||||
if (!defined('HPHP_VERSION')) {define('HPHP_VERSION', '1.0.0');}
|
||||
if (!defined('HPHP_VERSION')) {define('HPHP_VERSION', '2.0.1');}
|
||||
if (!defined('INI_SCANNER_NORMAL')) {define('INI_SCANNER_NORMAL', 0);}
|
||||
if (!defined('INI_SCANNER_RAW')) {define('INI_SCANNER_RAW', 1);}
|
||||
if (!defined('PHP_VERSION')) {define('PHP_VERSION', '5.3.3.hiphop');}
|
||||
|
||||
@@ -1425,46 +1425,22 @@ ObjectData* VMExecutionContext::getThis() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CStrRef VMExecutionContext::getContextClassName() {
|
||||
Class* VMExecutionContext::getContextClass() {
|
||||
VMRegAnchor _;
|
||||
ActRec* ar = getFP();
|
||||
assert(ar != nullptr);
|
||||
if (ar->skipFrame()) {
|
||||
ar = getPrevVMState(ar);
|
||||
if (!ar) return empty_string;
|
||||
}
|
||||
if (ar->hasThis()) {
|
||||
return ar->getThis()->o_getClassName();
|
||||
} else if (ar->hasClass()) {
|
||||
return ar->getClass()->nameRef();
|
||||
} else {
|
||||
return empty_string;
|
||||
if (!ar) return nullptr;
|
||||
}
|
||||
return ar->m_func->cls();
|
||||
}
|
||||
|
||||
CStrRef VMExecutionContext::getParentContextClassName() {
|
||||
VMRegAnchor _;
|
||||
ActRec* ar = getFP();
|
||||
assert(ar != nullptr);
|
||||
if (ar->skipFrame()) {
|
||||
ar = getPrevVMState(ar);
|
||||
if (!ar) return empty_string;
|
||||
}
|
||||
if (ar->hasThis()) {
|
||||
const Class* cls = ar->getThis()->getVMClass();
|
||||
if (cls->parent() == nullptr) {
|
||||
return empty_string;
|
||||
}
|
||||
return cls->parent()->nameRef();
|
||||
} else if (ar->hasClass()) {
|
||||
const Class* cls = ar->getClass();
|
||||
if (cls->parent() == nullptr) {
|
||||
return empty_string;
|
||||
}
|
||||
return cls->parent()->nameRef();
|
||||
} else {
|
||||
return empty_string;
|
||||
Class* VMExecutionContext::getParentContextClass() {
|
||||
if (Class* ctx = getContextClass()) {
|
||||
return ctx->parent();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CStrRef VMExecutionContext::getContainingFileName() {
|
||||
@@ -2056,7 +2032,8 @@ void VMExecutionContext::invokeFunc(TypedValue* retval,
|
||||
// If this is a method, either this_ or cls must be non-NULL
|
||||
assert(!f->preClass() || (this_ || cls));
|
||||
// If this is a static method, this_ must be NULL
|
||||
assert(!(f->attrs() & HPHP::VM::AttrStatic) || (!this_));
|
||||
assert(!(f->attrs() & HPHP::VM::AttrStatic && !f->isClosureBody()) ||
|
||||
(!this_));
|
||||
// invName should only be non-NULL if we are calling __call or
|
||||
// __callStatic
|
||||
assert(!invName || f->name()->isame(s___call.get()) ||
|
||||
|
||||
@@ -222,26 +222,6 @@ pathloop:
|
||||
}
|
||||
}
|
||||
|
||||
ConditionCode cmpOpToCC(Opcode opc) {
|
||||
switch (opc) {
|
||||
case OpGt: return CC_G;
|
||||
case OpGte: return CC_GE;
|
||||
case OpLt: return CC_L;
|
||||
case OpLte: return CC_LE;
|
||||
case OpEq: return CC_E;
|
||||
case OpNeq: return CC_NE;
|
||||
case OpSame: return CC_E;
|
||||
case OpNSame: return CC_NE;
|
||||
case InstanceOf: return CC_NZ;
|
||||
case NInstanceOf: return CC_Z;
|
||||
case InstanceOfBitmask: return CC_NZ;
|
||||
case NInstanceOfBitmask: return CC_Z;
|
||||
case IsType: return CC_NZ;
|
||||
case IsNType: return CC_Z;
|
||||
default: always_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char* getContextName(Class* ctx) {
|
||||
return ctx ? ctx->name()->data() : ":anonymous:";
|
||||
}
|
||||
@@ -534,7 +514,7 @@ void CodeGenerator::cgJcc(IRInstruction* inst) {
|
||||
SSATmp* src1 = inst->getSrc(0);
|
||||
SSATmp* src2 = inst->getSrc(1);
|
||||
Opcode opc = inst->getOpcode();
|
||||
ConditionCode cc = cmpOpToCC(queryJmpToQueryOp(opc));
|
||||
ConditionCode cc = queryJmpToCC(opc);
|
||||
Type src1Type = src1->getType();
|
||||
Type src2Type = src2->getType();
|
||||
|
||||
@@ -1467,10 +1447,12 @@ void CodeGenerator::cgInstanceOf(IRInstruction* inst) {
|
||||
void CodeGenerator::cgNInstanceOf(IRInstruction* inst) {
|
||||
// TODO(#2058865): having NInstanceOf is no better than InstanceOf
|
||||
// followed by boolean Not opcode.
|
||||
emitInstanceCheck(inst, inst->getDst()->getReg());
|
||||
PhysReg dstReg = inst->getDst()->getReg();
|
||||
emitInstanceCheck(inst, dstReg);
|
||||
Reg8 dr((int(dstReg)));
|
||||
auto& a = m_as;
|
||||
a. testb (al, al);
|
||||
a. setz (al);
|
||||
a. testb (dr, dr);
|
||||
a. setz (dr);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgJmpInstanceOf(IRInstruction* inst) {
|
||||
@@ -2251,7 +2233,7 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
|
||||
// Patch the original jcc;jmp, don't emit another
|
||||
IRInstruction* jcc = toSmash->getInstruction();
|
||||
Opcode opc = jcc->getOpcode();
|
||||
ConditionCode cc = cmpOpToCC(queryJmpToQueryOp(opc));
|
||||
ConditionCode cc = queryJmpToCC(opc);
|
||||
uint64_t taken = pc->getValInt();
|
||||
uint64_t notTaken = notTakenPC->getValInt();
|
||||
|
||||
|
||||
@@ -772,14 +772,10 @@ void HhbcTranslator::emitContDone() {
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitContNext() {
|
||||
emitInterpOneOrPunt(Type::None);
|
||||
return;
|
||||
// Task #2140912: Fix and re-enable this
|
||||
|
||||
assert(getCurClass());
|
||||
SSATmp* cont = m_tb->genLdThis(nullptr);
|
||||
m_tb->genContPreNext(cont, getExitSlowTrace());
|
||||
m_tb->genSetPropCell(cont, CONTOFF(m_received), m_tb->genDefUninit());
|
||||
m_tb->genSetPropCell(cont, CONTOFF(m_received), m_tb->genDefInitNull());
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitContSendImpl(bool raise) {
|
||||
|
||||
@@ -629,14 +629,60 @@ inline Opcode queryToJmpOp(Opcode opc) {
|
||||
}
|
||||
|
||||
inline bool isQueryJmpOp(Opcode opc) {
|
||||
return opc >= JmpGt && opc <= JmpIsNType;
|
||||
switch (opc) {
|
||||
case JmpGt:
|
||||
case JmpGte:
|
||||
case JmpLt:
|
||||
case JmpLte:
|
||||
case JmpEq:
|
||||
case JmpNeq:
|
||||
case JmpSame:
|
||||
case JmpNSame:
|
||||
case JmpInstanceOf:
|
||||
case JmpNInstanceOf:
|
||||
case JmpInstanceOfBitmask:
|
||||
case JmpNInstanceOfBitmask:
|
||||
case JmpIsType:
|
||||
case JmpIsNType:
|
||||
case JmpZero:
|
||||
case JmpNZero:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline Opcode queryJmpToQueryOp(Opcode opc) {
|
||||
assert(isQueryJmpOp(opc));
|
||||
assert(opc != JmpZero && opc != JmpNZero);
|
||||
return Opcode(OpGt + (opc - JmpGt));
|
||||
}
|
||||
|
||||
inline ConditionCode queryJmpToCC(Opcode opc) {
|
||||
assert(isQueryJmpOp(opc));
|
||||
|
||||
switch (opc) {
|
||||
case JmpGt: return CC_G;
|
||||
case JmpGte: return CC_GE;
|
||||
case JmpLt: return CC_L;
|
||||
case JmpLte: return CC_LE;
|
||||
case JmpEq: return CC_E;
|
||||
case JmpNeq: return CC_NE;
|
||||
case JmpSame: return CC_E;
|
||||
case JmpNSame: return CC_NE;
|
||||
case JmpInstanceOf: return CC_NZ;
|
||||
case JmpNInstanceOf: return CC_Z;
|
||||
case JmpInstanceOfBitmask: return CC_NZ;
|
||||
case JmpNInstanceOfBitmask: return CC_Z;
|
||||
case JmpIsType: return CC_NZ;
|
||||
case JmpIsNType: return CC_Z;
|
||||
case JmpZero: return CC_Z;
|
||||
case JmpNZero: return CC_NZ;
|
||||
default:
|
||||
not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Right now branch fusion is too indiscriminate to handle fusing
|
||||
* with potentially expensive-to-repeat operations. TODO(#2053369)
|
||||
|
||||
@@ -23,10 +23,7 @@ namespace HPHP { namespace VM { namespace JIT {
|
||||
// These are the conditional branches supported for direct branch
|
||||
// to their target trace at TraceExit, TraceExitType::NormalCc
|
||||
static bool jccCanBeDirectExit(Opcode opc) {
|
||||
// JmpGt .. JmpNSame are contiguous and all use cgJcc
|
||||
return (JmpGt <= opc && opc <= JmpNSame) ||
|
||||
opc == JmpInstanceOf || opc == JmpNInstanceOf ||
|
||||
opc == JmpInstanceOfBitmask || opc == JmpNInstanceOfBitmask;
|
||||
return isQueryJmpOp(opc) && (opc != JmpIsType) && (opc != JmpIsNType);
|
||||
// TODO(#2053369): JmpIsType, etc
|
||||
}
|
||||
|
||||
|
||||
@@ -505,28 +505,30 @@ SSATmp* Simplifier::simplifyNot(SSATmp* src) {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLIFY_COMMUTATIVE(OP, NAME) do { \
|
||||
SIMPLIFY_CONST(OP); \
|
||||
if (src1->isConst() && !src2->isConst()) { \
|
||||
return m_tb->gen##NAME(src2, src1); \
|
||||
} \
|
||||
IRInstruction* inst1 = src1->getInstruction(); \
|
||||
IRInstruction* inst2 = src2->getInstruction(); \
|
||||
if (inst1->getOpcode() == Op##NAME && inst1->getSrc(1)->isConst()) { \
|
||||
/* (X + C1) + C2 --> X + C3 */ \
|
||||
if (src2->isConst()) { \
|
||||
int64_t right = inst1->getSrc(1)->getValInt(); \
|
||||
right OP##= src2->getValInt(); \
|
||||
return m_tb->gen##NAME(inst1->getSrc(0), genDefInt(right)); \
|
||||
} \
|
||||
/* (X + C1) + (Y + C2) --> X + Y + C3 */ \
|
||||
if (inst2->getOpcode() == Op##NAME && inst2->getSrc(1)->isConst()) { \
|
||||
int64_t right = inst1->getSrc(1)->getValInt(); \
|
||||
right OP##= inst2->getSrc(1)->getValInt(); \
|
||||
SSATmp* left = m_tb->gen##NAME(inst1->getSrc(0), inst2->getSrc(0)); \
|
||||
return m_tb->gen##NAME(left, genDefInt(right)); \
|
||||
} \
|
||||
} \
|
||||
#define SIMPLIFY_COMMUTATIVE(OP, NAME) do { \
|
||||
SIMPLIFY_CONST(OP); \
|
||||
if (src1->isConst() && !src2->isConst()) { \
|
||||
return m_tb->gen##NAME(src2, src1); \
|
||||
} \
|
||||
if (src1->isA(Type::Int) && src2->isA(Type::Int)) { \
|
||||
IRInstruction* inst1 = src1->getInstruction(); \
|
||||
IRInstruction* inst2 = src2->getInstruction(); \
|
||||
if (inst1->getOpcode() == Op##NAME && inst1->getSrc(1)->isConst()) { \
|
||||
/* (X + C1) + C2 --> X + C3 */ \
|
||||
if (src2->isConst()) { \
|
||||
int64_t right = inst1->getSrc(1)->getValInt(); \
|
||||
right OP##= src2->getValInt(); \
|
||||
return m_tb->gen##NAME(inst1->getSrc(0), genDefInt(right)); \
|
||||
} \
|
||||
/* (X + C1) + (Y + C2) --> X + Y + C3 */ \
|
||||
if (inst2->getOpcode() == Op##NAME && inst2->getSrc(1)->isConst()) { \
|
||||
int64_t right = inst1->getSrc(1)->getValInt(); \
|
||||
right OP##= inst2->getSrc(1)->getValInt(); \
|
||||
SSATmp* left = m_tb->gen##NAME(inst1->getSrc(0), inst2->getSrc(0)); \
|
||||
return m_tb->gen##NAME(left, genDefInt(right)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLIFY_DISTRIBUTIVE(OUTOP, INOP, OUTNAME, INNAME) do { \
|
||||
@@ -766,6 +768,10 @@ SSATmp* Simplifier::simplifyCmp(Opcode opName, SSATmp* src1, SSATmp* src2) {
|
||||
if (src1->getType() == Type::Obj && src2->getType() == Type::Obj) {
|
||||
return nullptr;
|
||||
}
|
||||
// for arrays, don't simplify Same to Eq
|
||||
if (src1->getType() == Type::Arr && src2->getType() == Type::Arr) {
|
||||
return nullptr;
|
||||
}
|
||||
// Type is neither a string nor an object - simplify to OpEq/OpNeq
|
||||
if (opName == OpSame) {
|
||||
return m_tb->genCmp(OpEq, src1, src2);
|
||||
|
||||
@@ -341,7 +341,7 @@ SSATmp* HhbcTranslator::VectorTranslator::getInput(unsigned i) {
|
||||
// as what Transl::Translator came up with.
|
||||
auto t = Type::fromRuntimeType(dl.rtt);
|
||||
if (!val->isA(t)) {
|
||||
FTRACE(0, "{}: hhir stack has a {} where Translator had a {}\n",
|
||||
FTRACE(1, "{}: hhir stack has a {} where Translator had a {}\n",
|
||||
__func__, val->getType().toString(), t.toString());
|
||||
// They'd better not be completely unrelated types...
|
||||
assert(t.subtypeOf(val->getType()));
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
typedef __sighandler_t *sighandler_t;
|
||||
# define RIP_REGISTER(v) (v).mc_rip
|
||||
#else
|
||||
# define RIP_REGISTER(v) (v).gregs[REG_RIP]
|
||||
# if defined(__x86_64__)
|
||||
# define RIP_REGISTER(v) (v).gregs[REG_RIP]
|
||||
# elif defined(__AARCH64EL__)
|
||||
# define RIP_REGISTER(v) (v).pc
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
@@ -3059,6 +3063,22 @@ struct DepthGuard { bool depthOne() const { return false; } };
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* enterTCHelper does not save callee-saved registers except %rbp. This means
|
||||
* when we call it from C++, we have to tell gcc to clobber all the other
|
||||
* callee-saved registers.
|
||||
*/
|
||||
#if defined(__x86_64__)
|
||||
# define CALLEE_SAVED_BARRIER() \
|
||||
asm volatile("" : : : "rbx", "r12", "r13", "r14", "r15")
|
||||
#elif defined(__AARCH64EL__)
|
||||
# define CALLEE_SAVED_BARRIER() \
|
||||
asm volatile("" : : : "x19", "x20", "x21", "x22", "x23", "x24", "x25", \
|
||||
"x26", "x27", "x28")
|
||||
#else
|
||||
# error What are the callee-saved registers on your system?
|
||||
#endif
|
||||
|
||||
/*
|
||||
* enterTCHelper
|
||||
*
|
||||
@@ -9067,7 +9087,7 @@ TranslatorX64::translateFPushObjMethodD(const Tracelet &t,
|
||||
}
|
||||
|
||||
if (func) {
|
||||
if (func->attrs() & AttrStatic) {
|
||||
if (func->attrs() & AttrStatic && !func->isClosureBody()) {
|
||||
if (func->attrs() & AttrPrivate) {
|
||||
emitVStackStoreImm(a, i, uintptr_t(curFunc()->cls()) | 1,
|
||||
thisOff, sz::qword);
|
||||
|
||||
@@ -457,7 +457,7 @@ const int64_t k_GRAPHEME_EXTR_MAXBYTES = 1;
|
||||
const int64_t k_GRAPHEME_EXTR_MAXCHARS = 2;
|
||||
const int64_t k_HASH_HMAC = 1;
|
||||
extern const StaticString k_HPHP_TRIM_CHARLIST("\n\r\t\v\000 ",6);
|
||||
extern const StaticString k_HPHP_VERSION("1.0.0",5);
|
||||
extern const StaticString k_HPHP_VERSION("2.0.1",5);
|
||||
const int64_t k_HTML_ENTITIES = 1;
|
||||
const int64_t k_HTML_SPECIALCHARS = 0;
|
||||
extern const StaticString k_ICONV_IMPL("glibc",5);
|
||||
@@ -17963,7 +17963,7 @@ const char *g_class_map[] = {
|
||||
"GRAPHEME_EXTR_MAXCHARS", (const char*)4, "i:2;",
|
||||
"HASH_HMAC", (const char*)4, "i:1;",
|
||||
"HPHP_TRIM_CHARLIST", (const char*)13, "s:6:\"\n\r\t\v\000 \";",
|
||||
"HPHP_VERSION", (const char*)12, "s:5:\"1.0.0\";",
|
||||
"HPHP_VERSION", (const char*)12, "s:5:\"2.0.1\";",
|
||||
"HTML_ENTITIES", (const char*)4, "i:1;",
|
||||
"HTML_SPECIALCHARS", (const char*)4, "i:0;",
|
||||
"ICONV_IMPL", (const char*)12, "s:5:\"glibc\";",
|
||||
|
||||
@@ -445,7 +445,7 @@ define('GRAPHEME_EXTR_MAXBYTES', 1);
|
||||
define('GRAPHEME_EXTR_MAXCHARS', 2);
|
||||
define('HASH_HMAC', 1);
|
||||
define('HPHP_TRIM_CHARLIST', "\n\r\t\v\000 ");
|
||||
define('HPHP_VERSION', "1.0.0");
|
||||
define('HPHP_VERSION', "2.0.1");
|
||||
define('HTML_ENTITIES', 1);
|
||||
define('HTML_SPECIALCHARS', 0);
|
||||
define('ICONV_IMPL', "glibc");
|
||||
|
||||
@@ -2670,7 +2670,7 @@ DefineConstant(
|
||||
DefineConstant(
|
||||
array(
|
||||
'name' => "HPHP_VERSION",
|
||||
'value' => "1.0.0",
|
||||
'value' => "2.0.1",
|
||||
));
|
||||
|
||||
DefineConstant(
|
||||
|
||||
@@ -9659,6 +9659,236 @@ bool TestCodeRun::TestCollectionClasses() {
|
||||
"bool(false)\n"
|
||||
);
|
||||
|
||||
{
|
||||
HipHopSyntax w1(this);
|
||||
MVCRO("<?php\n"
|
||||
"function f() {\n"
|
||||
" $v = Vector {'a', 'b', 'c'};\n"
|
||||
" $m = new Map($v);\n"
|
||||
" var_dump($m);\n"
|
||||
" $sm = new StableMap($m);\n"
|
||||
" var_dump($sm);\n"
|
||||
"}\n"
|
||||
"function g() {\n"
|
||||
" $m = Map {'a' => 1, 2 => 'b'};\n"
|
||||
" $v = new Vector($m);\n"
|
||||
" var_dump($v);\n"
|
||||
"}\n"
|
||||
"function h() {\n"
|
||||
" $arr1 = array(11, 22, 33);\n"
|
||||
" var_dump(new Vector($arr1));\n"
|
||||
" var_dump(new Map($arr1));\n"
|
||||
" $arr2 = array('a' => 1, 2 => 'b');\n"
|
||||
" var_dump(new Vector($arr2));\n"
|
||||
" var_dump(new StableMap($arr2));\n"
|
||||
"}\n"
|
||||
"function gen() {\n"
|
||||
" yield 42;\n"
|
||||
" yield 72;\n"
|
||||
"}\n"
|
||||
"function j() {\n"
|
||||
" $v = new Vector(gen());\n"
|
||||
" var_dump($v);\n"
|
||||
"}\n"
|
||||
"f();\n"
|
||||
"g();\n"
|
||||
"h();\n"
|
||||
"j();\n"
|
||||
,
|
||||
"object(Map)#2 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(1) \"a\"\n"
|
||||
" [1]=>\n"
|
||||
" string(1) \"b\"\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"c\"\n"
|
||||
"}\n"
|
||||
"object(StableMap)#3 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(1) \"a\"\n"
|
||||
" [1]=>\n"
|
||||
" string(1) \"b\"\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"c\"\n"
|
||||
"}\n"
|
||||
"object(Vector)#2 (2) {\n"
|
||||
" [0]=>\n"
|
||||
" int(1)\n"
|
||||
" [1]=>\n"
|
||||
" string(1) \"b\"\n"
|
||||
"}\n"
|
||||
"object(Vector)#1 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" int(11)\n"
|
||||
" [1]=>\n"
|
||||
" int(22)\n"
|
||||
" [2]=>\n"
|
||||
" int(33)\n"
|
||||
"}\n"
|
||||
"object(Map)#1 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" int(11)\n"
|
||||
" [1]=>\n"
|
||||
" int(22)\n"
|
||||
" [2]=>\n"
|
||||
" int(33)\n"
|
||||
"}\n"
|
||||
"object(Vector)#1 (2) {\n"
|
||||
" [0]=>\n"
|
||||
" int(1)\n"
|
||||
" [1]=>\n"
|
||||
" string(1) \"b\"\n"
|
||||
"}\n"
|
||||
"object(StableMap)#1 (2) {\n"
|
||||
" [\"a\"]=>\n"
|
||||
" int(1)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"b\"\n"
|
||||
"}\n"
|
||||
"object(Vector)#1 (2) {\n"
|
||||
" [0]=>\n"
|
||||
" int(42)\n"
|
||||
" [1]=>\n"
|
||||
" int(72)\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
MVCRO("<?hh\n"
|
||||
"function g((string,int,string) $t) {}\n"
|
||||
"class C {\n"
|
||||
" public $t = Tuple {'foo', 42, '!'};\n"
|
||||
"}\n"
|
||||
"function f() {\n"
|
||||
" $t = Tuple {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\n"
|
||||
" 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,\n"
|
||||
" 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};\n"
|
||||
" var_dump(count($t));\n"
|
||||
" var_dump($t->count());\n"
|
||||
" var_dump($t->isEmpty());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" $c = new C;\n"
|
||||
" $t = $c->t;\n"
|
||||
" var_dump(count($t));\n"
|
||||
" var_dump($t->count());\n"
|
||||
" var_dump($t->isEmpty());\n"
|
||||
" g($t);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" foreach ($t as $k => $v) {\n"
|
||||
" var_dump($k, $v);\n"
|
||||
" }\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t[0], $t[1], $t[2]);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->at(0), $t->at(1), $t->at(2));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->get(0), $t->get(1), $t->get(2), $t->get(3));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump((array)$t);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump(serialize($t));\n"
|
||||
" var_dump(unserialize(serialize($t)));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->count());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->getIterator() instanceof Iterator);\n"
|
||||
" var_dump($t->getIterator() instanceof KeyedIterator);\n"
|
||||
" foreach ($t->getIterator() as $k => $v) {\n"
|
||||
" var_dump($k, $v);\n"
|
||||
" }\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump((array)$t);\n"
|
||||
" var_dump($t->toArray());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump(clone $t);\n"
|
||||
"}\n"
|
||||
"f();\n"
|
||||
,
|
||||
"int(32)\n"
|
||||
"int(32)\n"
|
||||
"bool(false)\n"
|
||||
"==========\n"
|
||||
"int(3)\n"
|
||||
"int(3)\n"
|
||||
"bool(false)\n"
|
||||
"==========\n"
|
||||
"int(0)\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(1)\n"
|
||||
"int(42)\n"
|
||||
"int(2)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"NULL\n"
|
||||
"==========\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"string(39) \"V:5:\"Tuple\":3:{s:3:\"foo\";i:42;s:1:\"!\";}\"\n"
|
||||
"object(Tuple)#6 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"int(3)\n"
|
||||
"==========\n"
|
||||
"bool(true)\n"
|
||||
"bool(true)\n"
|
||||
"int(0)\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(1)\n"
|
||||
"int(42)\n"
|
||||
"int(2)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"object(Tuple)#6 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18832,6 +19062,31 @@ bool TestCodeRun::TestClassConstant() {
|
||||
" var_dump($param->getDefaultValue());"
|
||||
"}");
|
||||
|
||||
MVCR("<?php "
|
||||
"class W {"
|
||||
" const FOO = 0;"
|
||||
"}"
|
||||
"class X extends W {"
|
||||
" const FOO = 1;"
|
||||
" static function foo() {"
|
||||
" var_dump(constant('self::FOO'));"
|
||||
" var_dump(constant('parent::FOO'));"
|
||||
" var_dump(constant('static::FOO'));"
|
||||
" var_dump(defined('self::FOO'));"
|
||||
" var_dump(defined('parent::FOO'));"
|
||||
" var_dump(defined('static::FOO'));"
|
||||
" var_dump(defined('self::BAR'));"
|
||||
" var_dump(defined('parent::BAR'));"
|
||||
" var_dump(defined('static::BAR'));"
|
||||
" }"
|
||||
"}"
|
||||
"class Y extends X {"
|
||||
" const FOO = 2;"
|
||||
" const BAR = 1;"
|
||||
"}"
|
||||
"X::foo();"
|
||||
"Y::foo();");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,5 +125,9 @@ bool TestExtBzip2::test_bzdecompress() {
|
||||
ret = f_bzdecompress(ret);
|
||||
ret = f_bzdecompress(ret);
|
||||
VS(ret, str);
|
||||
str = StringUtil::Repeat("x", 1000);
|
||||
ret = f_bzcompress(str);
|
||||
ret = f_bzdecompress(ret);
|
||||
VS(ret, str);
|
||||
return Count(true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
class A {
|
||||
private $c = 1;
|
||||
|
||||
function b() {
|
||||
$a = function () {
|
||||
var_dump($this);
|
||||
};
|
||||
$a();
|
||||
|
||||
$a = static function () {
|
||||
var_dump($this);
|
||||
};
|
||||
$a();
|
||||
}
|
||||
|
||||
static function c() {
|
||||
$a = function () {
|
||||
var_dump($this);
|
||||
};
|
||||
$a();
|
||||
|
||||
$a = static function () {
|
||||
var_dump($this);
|
||||
};
|
||||
$a();
|
||||
}
|
||||
|
||||
static function d() {
|
||||
var_dump(array_map(function($a) { return $a; }, array(1,2,3)));
|
||||
}
|
||||
}
|
||||
|
||||
(new A)->b();
|
||||
A::b();
|
||||
(new A)->c();
|
||||
A::c();
|
||||
(new A)->d();
|
||||
A::d();
|
||||
@@ -0,0 +1,34 @@
|
||||
object(A)#1 (1) {
|
||||
["c":"A":private]=>
|
||||
int(1)
|
||||
}
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 13
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 8
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 13
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 20
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 25
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 20
|
||||
NULL
|
||||
HipHop Notice: Undefined variable: this in hphp/test/vm/closure_static.php on line 25
|
||||
NULL
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
var_dump(iconv_mime_decode(
|
||||
'=?utf-8?Q?...=20.....=3A=20...=20.....=20....=20'.
|
||||
'.......=20...=20.....=2C=20....=20.......=E2=80=99s'.
|
||||
'=20....=20......=20..=20...=E2=80=99s=20....=20.....'.
|
||||
'=3F=2C=20...=20.......=20..=20.......=20...'.
|
||||
'=20........?=', 2, 'UTF-8'));
|
||||
@@ -0,0 +1 @@
|
||||
string(133) "... .....: ... ..... .... ....... ... ....., .... .......’s .... ...... .. ...’s .... .....?, ... ....... .. ....... ... ........"
|
||||
+1
-1
@@ -1 +1 @@
|
||||
HPHP_VERSION(1.000)
|
||||
HPHP_VERSION(2.0.1)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário