Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: facebook/hhvm
...
head fork: facebook/hhvm
  • 7 commits
  • 19 files changed
  • 0 commit comments
  • 5 contributors
Commits on Sep 28, 2012
alia Fixed code generation bugs in LdThis and in ActRec allocation for mag…
…ic calls

Fixed a code generation bug in LdThis where we did not
consider the case that the LdThis target is dead but LdThis itself is
not because of its checks. This was causing the destination register
to be reg::noreg. Fixed a bug in ActRec allocation where we needed to
mask in a 1 into the lower bit of ActRec::m_invName for magic
calls. Added a check to TranslatorX64::translate to check if we have reached
the translation limit for a SrcRec. Fixed an assert in SrcRec::newTranslation
that was off by one: When newTranslation is called when a SrcRec has reached
its limit it will cause the number of translations to become
kMaxTranslations+1, so the assert must check that we are one less than that.
88b22b9
@paroski paroski Fix crash involving static properties with traits
Some programs that used static properties with traits would cause the VM
to crash while building the Class. Here is an example:

  <?php
  final class Foo {
    use Bar;
    private static $a = array();
  }
  trait Bar {
    private static $a = array();
  }

The crash was happening because was the m_staticProperties map of the
current class was being accessed before it was initialized. This fixes the
logic to directly read m_val from the SProp structure for static properties
declared by the current class to avoid this problem.
018f5cf
@paroski paroski Fix crash involving LateBoundCls instruction
The impl for the LateBoundCls instruction was missing logic to handle the
case where there is no late bound class (ex. inside a regular function).
Fix LateBoundCls to raise a fatal error for such cases instead of crashing.
412af0c
ladipro Add missing error checks to copy()
HipHop Fatal error: Unexpected object type stdClass. when copy() is called
with a bad http:// URL source, for example:

copy('http://does.not.exist';, '/tmp/foo');
2a321c6
@paroski paroski Fix reflection to correctly retrieve doc comments for generators
Calling the getDocComment() method on instances of ReflectionFunction or
ReflectionMethod was always returning 'false' if the function/method was
a generator.

This diff adds the missing plumbing in the parser to make this work
correctly and adds some test coverage.
92cf3eb
@edwinsmith edwinsmith Don't use String/AttachDeprecated just to free a malloc'd buffer.
Remove one use of AttachDeprecated; all its being used for is
to optionally free a buffer; that's not so hard to do.
d7e894b
aravind Use StringData* instead of StringData::m_data for hash lookup
For HphpArray lookups, we compare StringData::m_data for
pointer equality, and if that fails, we do a memcmp for
content equality. This diff changes it a StringData*
comparison for pointer identity, which eliminates the
StrinData::m_data dereference.
d4944f9
View
40 src/compiler/parser/hphp.tab.cpp
@@ -1,19 +1,23 @@
-/*
- +----------------------------------------------------------------------+
- | HipHop for PHP |
- +----------------------------------------------------------------------+
- | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
-*/
-// @generated by HipHop Compiler
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -352,9 +356,9 @@ void create_generator(Parser *_p, Token &out, Token &params,
Token &origGenFunc, bool isHhvm, Token *attr) {
_p->pushFuncLocation();
if (clsname) {
- _p->onMethodStart(name, *modifiers);
+ _p->onMethodStart(name, *modifiers, false);
} else {
- _p->onFunctionStart(name);
+ _p->onFunctionStart(name, false);
}
Token scont;
View
23 src/compiler/parser/parser.cpp
@@ -228,6 +228,10 @@ void Parser::pushComment() {
m_comments.push_back(m_scanner.detachDocComment());
}
+void Parser::pushComment(const std::string& s) {
+ m_comments.push_back(s);
+}
+
std::string Parser::popComment() {
std::string ret = m_comments.back();
m_comments.pop_back();
@@ -713,9 +717,11 @@ void Parser::onClassConst(Token &out, Token &cls, Token &name, bool text) {
///////////////////////////////////////////////////////////////////////////////
// function/method declaration
-void Parser::onFunctionStart(Token &name) {
+void Parser::onFunctionStart(Token &name, bool doPushComment /* = true */) {
m_file->pushAttribute();
- pushComment();
+ if (doPushComment) {
+ pushComment();
+ }
newScope();
m_generators.push_back(0);
m_foreaches.push_back(0);
@@ -725,8 +731,9 @@ void Parser::onFunctionStart(Token &name) {
m_staticVars.push_back(StringToExpressionPtrVecMap());
}
-void Parser::onMethodStart(Token &name, Token &mods) {
- onFunctionStart(name);
+void Parser::onMethodStart(Token &name, Token &mods,
+ bool doPushComment /* = true */) {
+ onFunctionStart(name, doPushComment);
}
void Parser::fixStaticVars() {
@@ -812,6 +819,10 @@ void Parser::onFunction(Token &out, Token &ret, Token &ref, Token &name,
prepending.push_back(func);
if (name->text().empty()) m_closureGenerator = true;
+ // create_generator() expects us to push the docComment back
+ // onto the comment stack so that it can make sure that the
+ // the MethodStatement it's building will get the docComment
+ pushComment(comment);
Token origGenFunc;
create_generator(this, out, params, name, closureName, NULL, NULL,
hasCallToGetArgs, origGenFunc,
@@ -1099,6 +1110,10 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
{
completeScope(mth->onInitialParse(m_ar, m_file));
}
+ // create_generator() expects us to push the docComment back
+ // onto the comment stack so that it can make sure that the
+ // the MethodStatement it's building will get the docComment
+ pushComment(comment);
Token origGenFunc;
create_generator(this, out, params, name, closureName, m_clsName.c_str(),
&modifiers, hasCallToGetArgs, origGenFunc,
View
5 src/compiler/parser/parser.h
@@ -163,7 +163,7 @@ class Parser : public ParserBase {
void onUserAttribute(Token &out, Token *attrList, Token &name, Token &value);
void onClassConst(Token &out, Token &cls, Token &name, bool text);
void fixStaticVars();
- void onFunctionStart(Token &name);
+ void onFunctionStart(Token &name, bool doPushComment = true);
void onFunction(Token &out, Token &ret, Token &ref, Token &name,
Token &params, Token &stmt, Token *attr);
void onParam(Token &out, Token *params, Token &type, Token &var,
@@ -182,7 +182,7 @@ class Parser : public ParserBase {
void onTraitAliasRuleStart(Token &out, Token &className, Token &methodName);
void onTraitAliasRuleModify(Token &out, Token &rule, Token &accessModifiers,
Token &newMethodName);
- void onMethodStart(Token &name, Token &mods);
+ void onMethodStart(Token &name, Token &mods, bool doPushComment = true);
void onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
Token &name, Token &params, Token &stmt, Token *attr,
bool reloc = true);
@@ -257,6 +257,7 @@ class Parser : public ParserBase {
bool m_closureGenerator;
void pushComment();
+ void pushComment(const std::string& s);
std::string popComment();
void newScope();
View
79 src/runtime/base/array/hphp_array.cpp
@@ -455,7 +455,7 @@ Variant HphpArray::each() {
#define STRING_HASH(x) (int32_t(x) | 0x80000000)
-static bool hitStringKey(const HphpArray::Elm* e, const char* k, int len,
+static bool hitStringKey(const HphpArray::Elm* e, const StringData* s,
int32_t hash) {
// hitStringKey() should only be called on an Elm that is referenced by a
// hash table entry. HphpArray guarantees that when it adds a hash table
@@ -464,13 +464,17 @@ static bool hitStringKey(const HphpArray::Elm* e, const char* k, int len,
// Therefore the assertion below must hold.
ASSERT(e->data.m_type != HphpArray::KindOfTombstone);
- if (!e->hasStrKey()) {
+ if (e->hash != hash) {
return false;
}
+ if (e->key == s) {
+ return true;
+ }
const char* data = e->key->data();
- return data == k || ((e->hash == hash)
- && e->key->size() == len
- && (memcmp(data, k, len) == 0));
+ const char* sdata = s->data();
+ int slen = s->size();
+ return data == sdata || ((e->key->size() == slen)
+ && (memcmp(data, sdata, slen) == 0));
}
static bool hitIntKey(const HphpArray::Elm* e, int64 ki) {
@@ -514,9 +518,9 @@ ssize_t /*ElmInd*/ HphpArray::find(int64 ki) const {
FIND_BODY(ki, hitIntKey(&elms[pos], ki));
}
-ssize_t /*ElmInd*/ HphpArray::find(const char* k, int len,
+ssize_t /*ElmInd*/ HphpArray::find(const StringData* s,
strhash_t prehash) const {
- FIND_BODY(prehash, hitStringKey(&elms[pos], k, len, STRING_HASH(prehash)));
+ FIND_BODY(prehash, hitStringKey(&elms[pos], s, STRING_HASH(prehash)));
}
#undef FIND_BODY
@@ -558,9 +562,9 @@ HphpArray::ElmInd* HphpArray::findForInsert(int64 ki) const {
FIND_FOR_INSERT_BODY(ki, hitIntKey(&elms[pos], ki));
}
-HphpArray::ElmInd* HphpArray::findForInsert(const char* k, int len,
+HphpArray::ElmInd* HphpArray::findForInsert(const StringData* s,
strhash_t prehash) const {
- FIND_FOR_INSERT_BODY(prehash, hitStringKey(&elms[pos], k, len,
+ FIND_FOR_INSERT_BODY(prehash, hitStringKey(&elms[pos], s,
STRING_HASH(prehash)));
}
#undef FIND_FOR_INSERT_BODY
@@ -592,12 +596,13 @@ bool HphpArray::exists(int64 k) const {
}
bool HphpArray::exists(litstr k) const {
- ssize_t /*ElmInd*/ pos = find(k, strlen(k), hash_string(k));
+ StringData s(k, strlen(k), AttachLiteral);
+ ssize_t /*ElmInd*/ pos = find(&s, hash_string(k));
return pos != ssize_t(ElmIndEmpty);
}
bool HphpArray::exists(CStrRef k) const {
- ssize_t /*ElmInd*/ pos = find(k.data(), k.size(), k->hash());
+ ssize_t /*ElmInd*/ pos = find(k.get(), k->hash());
return pos != ssize_t(ElmIndEmpty);
}
@@ -606,7 +611,7 @@ bool HphpArray::exists(CVarRef k) const {
return find(k.toInt64()) != (ssize_t)ElmIndEmpty;
}
StringData* key = k.getStringData();
- ssize_t /*ElmInd*/ pos = find(key->data(), key->size(), key->hash());
+ ssize_t /*ElmInd*/ pos = find(key, key->hash());
return pos != ssize_t(ElmIndEmpty);
}
@@ -624,7 +629,8 @@ CVarRef HphpArray::get(int64 k, bool error /* = false */) const {
CVarRef HphpArray::get(litstr k, bool error /* = false */) const {
int len = strlen(k);
- ElmInd pos = find(k, len, hash_string(k, len));
+ StringData s(k, len, AttachLiteral);
+ ElmInd pos = find(&s, hash_string(k, len));
if (pos != ElmIndEmpty) {
Elm* e = &m_data[pos];
return tvAsCVarRef(&e->data);
@@ -638,7 +644,7 @@ CVarRef HphpArray::get(litstr k, bool error /* = false */) const {
CVarRef HphpArray::get(CStrRef k, bool error /* = false */) const {
StringData* key = k.get();
strhash_t prehash = key->hash();
- ElmInd pos = find(key->data(), key->size(), prehash);
+ ElmInd pos = find(key, prehash);
if (pos != ElmIndEmpty) {
Elm* e = &m_data[pos];
return tvAsCVarRef(&e->data);
@@ -660,7 +666,7 @@ CVarRef HphpArray::get(CVarRef k, bool error /* = false */) const {
} else {
StringData* strkey = k.getStringData();
strhash_t prehash = strkey->hash();
- pos = find(strkey->data(), strkey->size(), prehash);
+ pos = find(strkey, prehash);
if (pos != ElmIndEmpty) {
Elm* e = &m_data[pos];
return tvAsCVarRef(&e->data);
@@ -678,11 +684,12 @@ ssize_t HphpArray::getIndex(int64 k) const {
ssize_t HphpArray::getIndex(litstr k) const {
size_t len = strlen(k);
- return ssize_t(find(k, strlen(k), hash_string(k, len)));
+ StringData s(k, len, AttachLiteral);
+ return ssize_t(find(&s, hash_string(k, len)));
}
ssize_t HphpArray::getIndex(CStrRef k) const {
- return ssize_t(find(k.data(), k.size(), k->hash()));
+ return ssize_t(find(k.get(), k->hash()));
}
ssize_t HphpArray::getIndex(CVarRef k) const {
@@ -690,7 +697,7 @@ ssize_t HphpArray::getIndex(CVarRef k) const {
return ssize_t(find(k.toInt64()));
} else {
StringData* key = k.getStringData();
- return ssize_t(find(key->data(), key->size(), key->hash()));
+ return ssize_t(find(key, key->hash()));
}
}
@@ -958,7 +965,7 @@ void HphpArray::compact(bool renumber /* = false */) {
if (m_pos != ArrayData::invalid_index) {
// Update m_pos, now that compaction is complete.
if (mPos.hash) {
- m_pos = ssize_t(find(mPos.key->data(), mPos.key->size(), mPos.hash));
+ m_pos = ssize_t(find(mPos.key, mPos.hash));
} else {
m_pos = ssize_t(find(mPos.ikey));
}
@@ -971,7 +978,7 @@ void HphpArray::compact(bool renumber /* = false */) {
ElmKey &k = siKeys[key];
key++;
if (k.hash) { // string key
- fp->pos = ssize_t(find(k.key->data(), k.key->size(), k.hash));
+ fp->pos = ssize_t(find(k.key, k.hash));
} else { // int key
fp->pos = ssize_t(find(k.ikey));
}
@@ -1071,7 +1078,7 @@ void HphpArray::addLvalImpl(int64 ki, Variant** pDest) {
void HphpArray::addLvalImpl(StringData* key, int64 h, Variant** pDest) {
ASSERT(key != NULL && pDest != NULL);
- ElmInd* ei = findForInsert(key->data(), key->size(), h);
+ ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
TypedValue* tv;
@@ -1117,7 +1124,7 @@ inline void HphpArray::addVal(int64 ki, CVarRef data) {
inline void HphpArray::addVal(StringData* key, CVarRef data) {
strhash_t h = key->hash();
- ElmInd* ei = findForInsert(key->data(), key->size(), h);
+ ElmInd* ei = findForInsert(key, h);
Elm *e = allocElm(ei);
if (UNLIKELY(e == NULL)) {
resize();
@@ -1157,7 +1164,7 @@ inline void HphpArray::addValWithRef(int64 ki, CVarRef data) {
inline void HphpArray::addValWithRef(StringData* key, CVarRef data) {
resizeIfNeeded();
strhash_t h = key->hash();
- ElmInd* ei = findForInsert(key->data(), key->size(), h);
+ ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
return;
}
@@ -1187,7 +1194,7 @@ void HphpArray::update(int64 ki, CVarRef data) {
HOT_FUNC_VM
void HphpArray::update(StringData* key, CVarRef data) {
strhash_t h = key->hash();
- ElmInd* ei = findForInsert(key->data(), key->size(), h);
+ ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
Variant* to;
@@ -1213,7 +1220,7 @@ void HphpArray::updateRef(int64 ki, CVarRef data) {
void HphpArray::updateRef(StringData* key, CVarRef data) {
strhash_t h = key->hash();
- ElmInd* ei = findForInsert(key->data(), key->size(), h);
+ ElmInd* ei = findForInsert(key, h);
if (validElmInd(*ei)) {
Elm* e = &m_data[*ei];
tvAsVariant(&e->data).assignRefHelper(data);
@@ -1266,7 +1273,7 @@ ArrayData* HphpArray::lval(CStrRef k, Variant*& ret, bool copy,
a->addLvalImpl(key, prehash, &ret);
return a;
}
- ssize_t /*ElmInd*/ pos = find(key->data(), key->size(), prehash);
+ ssize_t /*ElmInd*/ pos = find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &m_data[pos];
TypedValue* tv = &e->data;
@@ -1301,7 +1308,7 @@ ArrayData *HphpArray::lvalPtr(CStrRef k, Variant*& ret, bool copy,
if (create) {
t->addLvalImpl(key, prehash, &ret);
} else {
- ssize_t /*ElmInd*/ pos = t->find(key->data(), key->size(), prehash);
+ ssize_t /*ElmInd*/ pos = t->find(key, prehash);
if (pos != (ssize_t)ElmIndEmpty) {
Elm* e = &t->m_data[pos];
ret = &tvAsVariant(&e->data);
@@ -1604,10 +1611,10 @@ ArrayData* HphpArray::remove(CStrRef k, bool copy) {
strhash_t prehash = k->hash();
if (copy) {
HphpArray* a = copyImpl();
- a->erase(a->findForInsert(k.data(), k.size(), prehash));
+ a->erase(a->findForInsert(k.get(), prehash));
return a;
}
- erase(findForInsert(k.data(), k.size(), prehash));
+ erase(findForInsert(k.get(), prehash));
return NULL;
}
@@ -1625,10 +1632,10 @@ ArrayData* HphpArray::remove(CVarRef k, bool copy) {
strhash_t prehash = key->hash();
if (copy) {
HphpArray* a = copyImpl();
- a->erase(a->findForInsert(key->data(), key->size(), prehash));
+ a->erase(a->findForInsert(key, prehash));
return a;
}
- erase(findForInsert(key->data(), key->size(), prehash));
+ erase(findForInsert(key, prehash));
return NULL;
}
}
@@ -1662,7 +1669,7 @@ TypedValue* HphpArray::nvGetCell(int64 ki, bool error /* = false */) const {
inline TypedValue*
HphpArray::nvGetCell(const StringData* k, bool error /* = false */) const {
- ElmInd pos = find(k->data(), k->size(), k->hash());
+ ElmInd pos = find(k, k->hash());
if (LIKELY(pos != ElmIndEmpty)) {
Elm* e = &m_data[pos];
TypedValue* tv = &e->data;
@@ -1690,7 +1697,7 @@ TypedValue* HphpArray::nvGet(int64 ki) const {
TypedValue*
HphpArray::nvGet(const StringData* k) const {
- ElmInd pos = find(k->data(), k->size(), k->hash());
+ ElmInd pos = find(k, k->hash());
if (LIKELY(pos != ElmIndEmpty)) {
Elm* e = &m_data[pos];
return &e->data;
@@ -1837,7 +1844,7 @@ bool HphpArray::nvUpdate(int64 ki, int64 vi) {
*/
bool HphpArray::nvInsert(StringData *k, TypedValue *data) {
strhash_t h = k->hash();
- ElmInd* ei = findForInsert(k->data(), k->size(), h);
+ ElmInd* ei = findForInsert(k, h);
if (validElmInd(*ei)) {
return false;
}
@@ -1990,7 +1997,7 @@ ArrayData* HphpArray::pop(Variant& value) {
ASSERT(e->data.m_type != KindOfTombstone);
value = tvAsCVarRef(&e->data);
ElmInd* ei = e->hasStrKey()
- ? a->findForInsert(e->key->data(), e->key->size(), e->hash)
+ ? a->findForInsert(e->key, e->hash)
: a->findForInsert(e->ikey);
a->erase(ei, true);
} else {
@@ -2017,7 +2024,7 @@ ArrayData* HphpArray::dequeue(Variant& value) {
Elm* e = &elms[pos];
value = tvAsCVarRef(&e->data);
a->erase(e->hasStrKey() ?
- a->findForInsert(e->key->data(), e->key->size(), e->hash) :
+ a->findForInsert(e->key, e->hash) :
a->findForInsert(e->ikey));
a->compact(true);
} else {
View
4 src/runtime/base/array/hphp_array.h
@@ -321,9 +321,9 @@ class HphpArray : public ArrayData {
ssize_t /*ElmInd*/ prevElm(Elm* elms, ssize_t /*ElmInd*/ ei) const;
ssize_t /*ElmInd*/ find(int64 ki) const;
- ssize_t /*ElmInd*/ find(const char* k, int len, strhash_t prehash) const;
+ ssize_t /*ElmInd*/ find(const StringData* s, strhash_t prehash) const;
ElmInd* findForInsert(int64 ki) const;
- ElmInd* findForInsert(const char* k, int len, strhash_t prehash) const;
+ ElmInd* findForInsert(const StringData* k, strhash_t prehash) const;
ssize_t iter_advance_helper(ssize_t prev) const ATTRIBUTE_COLD;
View
5 src/runtime/base/server/http_request_handler.cpp
@@ -173,7 +173,7 @@ void HttpRequestHandler::handleRequest(Transport *transport) {
bool original = compressed;
// check against static content cache
if (StaticContentCache::TheCache.find(path, data, len, compressed)) {
- String str;
+ bool free_data = false;
// (qigao) not calling stat at this point because the timestamp of
// local cache file is not valuable, maybe misleading. This way
// the Last-Modified header will not show in response.
@@ -184,12 +184,13 @@ void HttpRequestHandler::handleRequest(Transport *transport) {
throw FatalErrorException("cannot unzip compressed data");
}
compressed = false;
- str = NEW(StringData)(data, len, AttachDeprecated);
+ free_data = true;
}
sendStaticContent(transport, data, len, 0, compressed, path, ext);
StaticContentCache::TheFileCache->adviseOutMemory();
ServerStats::LogPage(path, 200);
GetAccessLog().log(transport, vhost);
+ if (free_data) free(const_cast<char*>(data));
return;
}
}
View
2  src/runtime/base/strings.h
@@ -37,6 +37,8 @@ const char* const CANT_ACCESS_PARENT_WHEN_NO_CLASS =
"Cannot access parent:: when no class scope is active";
const char* const CANT_ACCESS_PARENT_WHEN_NO_PARENT =
"Cannot access parent:: when current class scope has no parent";
+const char* const CANT_ACCESS_STATIC =
+ "Cannot access static:: when no class scope is active";
const char* const UNDEFINED_INDEX =
"Undefined index: %s";
const char* const CANNOT_USE_SCALAR_AS_ARRAY =
View
7 src/runtime/ext/ext_file.cpp
@@ -993,7 +993,14 @@ bool f_copy(CStrRef source, CStrRef dest,
if (!context.isNull() || !File::IsPlainFilePath(source) ||
!File::IsPlainFilePath(dest)) {
Variant sfile = f_fopen(source, "r", false, context);
+ if (same(sfile, false)) {
+ return false;
+ }
Variant dfile = f_fopen(dest, "w", false, context);
+ if (same(dfile, false)) {
+ return false;
+ }
+
return f_stream_copy_to_stream(sfile, dfile).toBoolean();
} else {
int ret =
View
12 src/runtime/vm/bytecode.cpp
@@ -195,7 +195,7 @@ static inline Class* frameStaticClass(ActRec* fp) {
} else if (fp->hasClass()) {
return fp->getClass();
} else {
- not_reached();
+ return NULL;
}
}
@@ -6281,7 +6281,11 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCatch(PC& pc) {
inline void OPTBLD_INLINE VMExecutionContext::iopLateBoundCls(PC& pc) {
NEXT();
- m_stack.pushClass(frameStaticClass(m_fp));
+ Class* cls = frameStaticClass(m_fp);
+ if (!cls) {
+ raise_error(HPHP::Strings::CANT_ACCESS_STATIC);
+ }
+ m_stack.pushClass(cls);
}
inline void OPTBLD_INLINE VMExecutionContext::iopVerifyParamType(PC& pc) {
@@ -6388,7 +6392,9 @@ VMExecutionContext::createContinuation(ActRec* fp,
cont->incRefCount();
cont->setNoDestruct();
if (isMethod) {
- cont->m_vmCalledClass = (intptr_t)frameStaticClass(fp) | 0x1ll;
+ Class* cls = frameStaticClass(fp);
+ ASSERT(cls);
+ cont->m_vmCalledClass = (intptr_t)cls | 0x1ll;
}
cont->m_nLocals = nLocals;
View
12 src/runtime/vm/class.cpp
@@ -1927,7 +1927,17 @@ void Class::importTraitStaticProp(ClassPtr trait,
} else {
// Redeclared prop, make sure it matches previous declaration
SProp& prevProp = curSPropMap[prevIt->second];
- TypedValue prevPropVal = getStaticPropInitVal(prevProp);
+ TypedValue prevPropVal;
+ if (prevProp.m_class == this) {
+ // If this static property was declared by this class, we can
+ // get the initial value directly from m_val
+ prevPropVal = prevProp.m_val;
+ } else {
+ // If this static property was declared in a parent class, m_val
+ // will be KindOfUninit, and we'll need to consult the appropriate
+ // parent class to get the initial value.
+ prevPropVal = getStaticPropInitVal(prevProp);
+ }
if (prevProp.m_attrs != traitProp.m_attrs ||
!compatibleTraitPropInit(traitProp.m_val, prevPropVal)) {
raise_error("trait declaration of property '%s' is incompatible with "
View
67 src/runtime/vm/translator/hopt/codegen.cpp
@@ -1268,7 +1268,7 @@ Address CodeGenerator::cgLdObjClass(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* obj = inst->getSrc(0);
- // TODO:MP
+ // TODO:MP assert copied from translatorx64. Update and make it work
// ASSERT(obj->getType() == Type::Obj);
register_name_t dstReg = dst->getAssignedLoc();
register_name_t objReg = obj->getAssignedLoc();
@@ -1345,23 +1345,27 @@ Address CodeGenerator::cgLdRetAddr(IRInstruction* inst) {
return start;
}
-void checkFrame(ActRec* fp, Cell* sp) {
+void checkFrame(ActRec* fp, Cell* sp, bool checkLocals) {
const Func* func = fp->m_func;
if (fp->hasVarEnv()) {
ASSERT(fp->getVarEnv()->getCfp() == fp);
}
// TODO: validate this pointer from actrec
-// int numLocals = func->numLocals();
-// Cell* firstSp = ((Cell*)fp) - numLocals;
+ int numLocals = func->numLocals();
DEBUG_ONLY Cell* firstSp = ((Cell*)fp) - func->numSlotsInFrame();
ASSERT(sp <= firstSp);
- int numParams = func->numParams();
- for (int i=0; i < numParams; i++) {
- TypedValue* tv = frame_local(fp, i);
- ASSERT(tvIsPlausible(tv));
- DataType t = tv->m_type;
- if (IS_REFCOUNTED_TYPE(t)) {
- // ASSERT(tv->m_data.ptv->_count > 0); // HHIR:TODO:MERGE access protected field _count
+ if (checkLocals) {
+ int numParams = func->numParams();
+ for (int i=0; i < numLocals; i++) {
+ if (i >= numParams && func->isGenerator() && i < func->numNamedLocals()) {
+ continue;
+ }
+ TypedValue* tv = frame_local(fp, i);
+ ASSERT(tvIsPlausible(tv));
+ DataType t = tv->m_type;
+ if (IS_REFCOUNTED_TYPE(t)) {
+ ASSERT(tv->m_data.pstr->getCount() > 0);
+ }
}
}
// We unfortunately can't do the same kind of check for the stack
@@ -1395,7 +1399,7 @@ void traceRet(ActRec* fp, Cell* sp, void* rip) {
<< " " << rip
<< std::endl;
#endif
- checkFrame(fp, sp);
+ checkFrame(fp, sp, false);
}
void CodeGenerator::emitTraceRet(CodeGenerator::Asm& as,
@@ -2283,8 +2287,10 @@ Address CodeGenerator::cgAllocActRec6(SSATmp* dst,
}
// actRec->m_invName
ASSERT(magicName->isConst());
+ // ActRec::m_invName is encoded as a pointer with bottom bit set to 1
+ // to distinguish it from m_varEnv and m_extrArgs
uintptr_t invName = (magicName->getType() == Type::Null ?
- 0 : uintptr_t(magicName->getConstValAsStr()));
+ 0 : (uintptr_t(magicName->getConstValAsStr()) | 1));
m_as.store_imm64_disp_reg64(invName,
actRecAdjustment + AROFF(m_invName),
spReg);
@@ -2598,21 +2604,43 @@ Address CodeGenerator::cgLdThis(IRInstruction* inst) {
// mov dst, [fp + 0x20]
register_name_t dstReg = dst->getAssignedLoc();
- m_as.load_reg64_disp_reg64(src->getAssignedLoc(),
- AROFF(m_this),
- dstReg);
+ // the destination of LdThis could be dead but
+ // the instruction itself still useful because
+ // of the checks that it does (if it has a label).
+ // So we need to make sure there is a dstReg for this
+ // instruction.
+ if (dstReg != reg::noreg) {
+ // instruction's result is not dead
+ m_as.load_reg64_disp_reg64(src->getAssignedLoc(),
+ AROFF(m_this),
+ dstReg);
+ }
if (label != NULL) {
+ // we need to perform its checks
if (curFunc()->cls() == NULL) {
// test dst, dst
// jz label
+
+ if (dstReg == reg::noreg) {
+ dstReg = reg::rScratch;
+ m_as.load_reg64_disp_reg64(src->getAssignedLoc(),
+ AROFF(m_this),
+ dstReg);
+ }
m_as.test_reg64_reg64(dstReg, dstReg);
emitFwdJcc(CC_Z, label);
}
// test dst, 0x01
// jnz label
- m_as.test_imm32_reg64(1, dstReg);
- emitFwdJcc(CC_NZ, label);
+ if (dstReg == reg::noreg) {
+ // TODO: Could also use a 32-bit test here
+ m_as.test_imm64_disp_reg64(1, AROFF(m_this), src->getAssignedLoc());
+ emitFwdJcc(CC_NZ, label);
+ } else {
+ m_as.test_imm32_reg64(1, dstReg);
+ emitFwdJcc(CC_NZ, label);
+ }
#if 0
// TODO: Move this to be the code generated for a new instruction for
// raising fatal
@@ -3698,8 +3726,7 @@ void traceCallback(ActRec* fp, Cell* sp, int64 pcOff, void* rip) {
<< " " << rip
<< std::endl;
#endif
-//fullN std::cout << "traceCallback: pcOff = " << pcOff << std::endl;
- checkFrame(fp, sp);
+ checkFrame(fp, sp, true);
}
void CodeGenerator::emitTraceCall(CodeGenerator::Asm& as, int64 pcOff) {
View
8 src/runtime/vm/translator/hopt/irtranslator.cpp
@@ -1535,15 +1535,13 @@ TranslatorX64::irTranslateTracelet(const Tracelet& t,
}
if (!hhirSucceeded) {
- hhirTraceFree();
-
// The whole translation failed; give up on this BB. Since it is not
// linked into srcDB yet, it is guaranteed not to be reachable.
- m_regMap.reset();
- // Permanent reset; nothing is reachable yet.
+ // Free IR resources for this trace, rollback the Translation cache
+ // frontiers, and discard any pending fixups.
+ hhirTraceFree();
a.code.frontier = start;
astubs.code.frontier = stubStart;
- // Discard any pending fixups.
m_pendingFixups.clear();
}
View
2  src/runtime/vm/translator/srcdb.cpp
@@ -78,7 +78,7 @@ void SrcRec::emitFallbackJump(Asm &a, IncomingBranch incoming) {
void SrcRec::newTranslation(Asm& a, Asm &astubs, TCA newStart) {
// When translation punts due to hitting limit, will generate one
// more translation that will call the interpreter.
- ASSERT(m_translations.size() <= kMaxTranslations + 1);
+ ASSERT(m_translations.size() <= kMaxTranslations);
TRACE(1, "SrcRec(%p)::newTranslation @%p, ", this, newStart);
View
7 src/runtime/vm/translator/translator-x64.cpp
@@ -1839,6 +1839,13 @@ TCA TranslatorX64::retranslateAndPatchNoIR(SrcKey sk,
LeaseHolder writer(s_writeLease);
if (!writer) return NULL;
SKTRACE(1, sk, "retranslateAndPatchNoIR\n");
+ SrcRec* srcRec = getSrcRec(sk);
+ if (srcRec->translations().size() == SrcRec::kMaxTranslations + 1) {
+ // we've gone over the translation limit and already have an anchor
+ // translation that will interpret, so just return NULL and force
+ // interpretation of this BB.
+ return NULL;
+ }
TCA start = translate(&sk, align, false);
if (start != NULL) {
smash(getAsmFor(toSmash), toSmash, start);
View
43 src/test/test_code_run.cpp
@@ -11838,6 +11838,36 @@ bool TestCodeRun::TestReflection() {
"}"
"test();",
"string(3) \"bar\"\n");
+
+ MVCRO("<?php\n"
+ "\n"
+ "/**\n"
+ " * Doc comment on a function generator\n"
+ " */\n"
+ "function foo() {\n"
+ " yield null;\n"
+ "}\n"
+ "$rf = new ReflectionFunction('foo');\n"
+ "var_dump($rf->getDocComment());\n"
+ "\n"
+ "class C {\n"
+ " /**\n"
+ " * Doc comment on a method generator\n"
+ " */\n"
+ " public function bar() {\n"
+ " yield null;\n"
+ " }\n"
+ "}\n"
+ "$rm = new ReflectionMethod('C','bar');\n"
+ "var_dump($rm->getDocComment());\n"
+ ,
+ "string(46) \"/**\n"
+ " * Doc comment on a function generator\n"
+ " */\"\n"
+ "string(48) \"/**\n"
+ " * Doc comment on a method generator\n"
+ " */\"\n"
+ );
}
MVCR("<?php"
@@ -32222,6 +32252,19 @@ bool TestCodeRun::TestTraits() {
"Foo\n"
);
+ MVCRO("<?php\n"
+ "final class Foo {\n"
+ " use Bar;\n"
+ " private static $a = 3;\n"
+ "}\n"
+ "trait Bar {\n"
+ " private static $a = 3;\n"
+ "}\n"
+ "echo \"Done\\n\";\n"
+ ,
+ "Done\n"
+ );
+
return true;
}
View
2  src/test/vm/static_clsmethod.php
@@ -51,6 +51,8 @@ function main() {
echo "**************\n";
$d->yar();
D::yar();
+ echo "**************\n";
+ static::foo();
}
main();
View
2  src/test/vm/static_clsmethod.php.exp
@@ -26,3 +26,5 @@ bool(false)
string(1) "D"
bool(false)
string(1) "C"
+**************
+HipHop Fatal error: Cannot access static:: when no class scope is active in src/test/vm/static_clsmethod.php on line 55
View
3  src/test/vm/static_clsmethod.php.filter
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+sed -e 's, in [^ ]*src/, in src/,'
View
4 src/util/parser/hphp.y
@@ -277,9 +277,9 @@ void create_generator(Parser *_p, Token &out, Token &params,
Token &origGenFunc, bool isHhvm, Token *attr) {
_p->pushFuncLocation();
if (clsname) {
- _p->onMethodStart(name, *modifiers);
+ _p->onMethodStart(name, *modifiers, false);
} else {
- _p->onFunctionStart(name);
+ _p->onFunctionStart(name, false);
}
Token scont;

No commit comments for this range

Something went wrong with that request. Please try again.