9 Commits

Autor SHA1 Mensagem Data
ptarjan 3fa32fab6e bump version for release 2013-12-12 15:23:59 -08:00
mwilliams 075cb79c9f Generate a pid.map file when we unmap parts of the text section
The perf tool won't lookup symbols for parts of the binary
that aren't file mapped, so provide a perf-pid.map file when we
do that.

Reviewed By: @bertmaher

Differential Revision: D1091918
2013-12-12 15:11:25 -08:00
bsimmers a1f2c80031 Don't arena allocate IRTrace
It has a std::list member so we need to run its destructor. I also
cleaned up some type stuff I ran into along the way.

Reviewed By: @jdelong
2013-12-12 15:11:24 -08:00
mwilliams 4e791cc4b6 Fix cpu identification
I broke this when cleaning up some -fstrict-alias warnings.

Reviewed By: @jdelong

Differential Revision: D1087374
2013-12-12 15:11:24 -08:00
mwilliams e62e500a84 Revert "Allow generation of hack types in hhvm thrift extension"
: This reverts commit 6792a3a1a02048f866eeb78937b4c6d5e3b29074.

Reviewed By: @ckwalsh
2013-12-12 15:11:23 -08:00
mwilliams bab7343e83 Fix crash trying to inline after a bad method call
In some cases, we can statically prove that an FCall will
go to a particular method. But that might depend on the fact that
the FPush* would fatal. eg we know that an object is of class Foo,
or is null. The FPushObjMethodD will fatal if its null, so the
FCall is known to call Foo::method (or an override).

But if we try to inline the FCall bad things will happen if the
FPush* was interped. So don't do that.

Reviewed By: @swtaarrs

Differential Revision: D1078789
2013-12-12 15:11:23 -08:00
mwilliams ef3d8e9fc5 Fix crash trying to inline after a bad method call
In some cases, we can statically prove that an FCall will
go to a particular method. But that might depend on the fact that
the FPush* would fatal. eg we know that an object is of class Foo,
or is null. The FPushObjMethodD will fatal if its null, so the
FCall is known to call Foo::method (or an override).

But if we try to inline the FCall bad things will happen if the
FPush* was interped. So don't do that.

Reviewed By: @ottoni
2013-12-12 15:11:22 -08:00
mwilliams 9401291363 Don't translate idx when JitEnableRenameFunctions is set
Users are supposed to be able to override idx with
their own version - but that doesn't work if we translate it
during bytecode emission.

We don't really have a good way of knowing whether its been
overridden, however, so use JitEnableRenameFunctions as we
have for other, similar cases.

Reviewed By: @dariorussi

Differential Revision: D1078332
2013-12-12 15:11:22 -08:00
mwilliams f0665f2e92 Fix race in pmethodCacheMissPath
pmethodCacheMissPath smashes code under the write lease,
but there's nothing to prevent two threads going through it in
sequence - resulting in a double free of the pdata.

Check to see if the code has already been smashed, and bail out if
it has.

Reviewed By: @edwinsmith

Differential Revision: D1078180
2013-12-12 15:10:56 -08:00
25 arquivos alterados com 218 adições e 154 exclusões
+3 -1
Ver Arquivo
@@ -4251,7 +4251,9 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
e.AKExists();
return true;
}
} else if (call->isCallToFunction("idx") && call->isOptimizable()) {
} else if (call->isCallToFunction("idx") &&
call->isOptimizable() &&
!Option::JitEnableRenameFunction) {
if (params && (params->getCount() == 2 || params->getCount() == 3)) {
visit((*params)[0]);
emitConvertToCell(e);
+1 -1
Ver Arquivo
@@ -70,7 +70,7 @@ const StaticString
///////////////////////////////////////////////////////////////////////////////
typedef smart::unique_ptr<CufIter>::type SmartCufIterPtr;
typedef smart::unique_ptr<CufIter> SmartCufIterPtr;
bool array_is_valid_callback(CArrRef arr) {
if (arr.size() != 2 || !arr.exists(int64_t(0)) || !arr.exists(int64_t(1))) {
+2 -2
Ver Arquivo
@@ -339,13 +339,13 @@ class AutoloadHandler : public RequestEventHandler {
struct HandlerBundle {
HandlerBundle() = delete;
HandlerBundle(CVarRef handler,
smart::unique_ptr<CufIter>::type& cufIter) :
smart::unique_ptr<CufIter>& cufIter) :
m_handler(handler) {
m_cufIter = std::move(cufIter);
}
Variant m_handler; // used to respond to f_spl_autoload_functions
smart::unique_ptr<CufIter>::type m_cufIter; // used to invoke handlers
smart::unique_ptr<CufIter> m_cufIter; // used to invoke handlers
};
class CompareBundles {
+2
Ver Arquivo
@@ -56,6 +56,7 @@
#include "hphp/runtime/base/simple-counter.h"
#include "hphp/runtime/base/extended-logger.h"
#include "hphp/runtime/base/stream-wrapper-registry.h"
#include "hphp/runtime/vm/debug/debug.h"
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
@@ -624,6 +625,7 @@ hugifyText(char* from, char* to) {
mprotect(from, sz, PROT_READ | PROT_EXEC);
free(mem);
mlock(from, to - from);
Debug::DebugInfo::setPidMapOverlay(from, to);
#endif
}
+5 -11
Ver Arquivo
@@ -110,24 +110,18 @@ struct Allocator {
};
/*
* Shorthand to create a std::unique_ptr to a smart-allocated object.
* Shorthand to create a smart::unique_ptr to a smart-allocated object.
*
* Usage:
*
* auto ptr = smart::make_unique<Foo>(arg1, arg2);
*
* If you need to make a typedef to one, since we don't have type
* aliases yet in our version of gcc you have to do:
*
* typedef smart::unique_ptr<T>::type type;
*/
template<class T> struct unique_ptr
: folly::AllocatorUniquePtr<T,Allocator<T>>
{};
template<class T>
using unique_ptr = typename folly::AllocatorUniquePtr<T,Allocator<T>>::type;
template<class T, class... Args>
typename unique_ptr<T>::type make_unique(Args&&... args) {
unique_ptr<T> make_unique(Args&&... args) {
return folly::allocate_unique<T>(
Allocator<T>(),
std::forward<Args>(args)...
@@ -136,7 +130,7 @@ typename unique_ptr<T>::type make_unique(Args&&... args) {
#ifndef __APPLE__ // XXX: this affects codegen quality but not correctness
static_assert(
sizeof(unique_ptr<int>::type) == sizeof(std::unique_ptr<int>),
sizeof(unique_ptr<int>) == sizeof(std::unique_ptr<int>),
"smart::unique_ptr pointer should not be larger than std::unique_ptr"
);
#endif
+9 -42
Ver Arquivo
@@ -18,7 +18,6 @@
#include "hphp/runtime/ext/thrift/transport.h"
#include "hphp/runtime/ext/ext_thrift.h"
#include "hphp/runtime/ext/ext_class.h"
#include "hphp/runtime/ext/ext_collections.h"
#include "hphp/runtime/ext/ext_reflection.h"
#include "hphp/runtime/base/base-includes.h"
#include "hphp/util/logger.h"
@@ -44,8 +43,6 @@ StaticString PHPTransport::s_type("type");
StaticString PHPTransport::s_ktype("ktype");
StaticString PHPTransport::s_vtype("vtype");
StaticString PHPTransport::s_etype("etype");
StaticString PHPTransport::s_format("format");
StaticString PHPTransport::s_collection("collection");
IMPLEMENT_DEFAULT_EXTENSION(thrift_protocol);
@@ -189,13 +186,7 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
AccessFlags::Error_Key).toArray();
Array valspec = fieldspec.rvalAt(PHPTransport::s_val,
AccessFlags::Error_Key).toArray();
String format = fieldspec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
if (format.equal(PHPTransport::s_collection)) {
ret = NEWOBJ(c_Map)();
} else {
ret = Array::Create();
}
ret = Array::Create();
for (uint32_t s = 0; s < size; ++s) {
Variant key = binary_deserialize(types[0], transport, keyspec);
@@ -210,13 +201,7 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem,
AccessFlags::Error_Key);
Array elemspec = elemvar.toArray();
String format = fieldspec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
if (format.equal(PHPTransport::s_collection)) {
ret = NEWOBJ(c_Vector)();
} else {
ret = Array::Create();
}
ret = Array::Create();
for (uint32_t s = 0; s < size; ++s) {
Variant value = binary_deserialize(type, transport, elemspec);
@@ -233,33 +218,15 @@ Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport,
Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem,
AccessFlags::Error_Key);
Array elemspec = elemvar.toArray();
String format = fieldspec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
if (format.equal(PHPTransport::s_collection)) {
p_Set set_ret = NEWOBJ(c_Set)();
ret = Array::Create();
for (uint32_t s = 0; s < size; ++s) {
Variant key = binary_deserialize(type, transport, elemspec);
for (uint32_t s = 0; s < size; ++s) {
Variant key = binary_deserialize(type, transport, elemspec);
if (key.isInteger()) {
set_ret->t_add(key);
} else {
set_ret->t_add(key.toString());
}
}
ret = Variant(set_ret);
} else {
ret = Array::Create();
for (uint32_t s = 0; s < size; ++s) {
Variant key = binary_deserialize(type, transport, elemspec);
if (key.isInteger()) {
ret.set(key, true);
} else {
ret.set(key.toString(), true);
}
if (key.isInteger()) {
ret.set(key, true);
} else {
ret.set(key.toString(), true);
}
}
return ret;
+8 -52
Ver Arquivo
@@ -17,7 +17,6 @@
#include "hphp/runtime/base/request-local.h"
#include "hphp/runtime/ext/thrift/transport.h"
#include "hphp/runtime/ext/ext_collections.h"
#include "hphp/runtime/ext/ext_reflection.h"
#include "hphp/runtime/ext/ext_thrift.h"
@@ -710,10 +709,10 @@ class CompactReader {
return readMap(spec);
case T_LIST:
return readList(spec);
return readList(spec, C_LIST_LIST);
case T_SET:
return readSet(spec);
return readList(spec, C_LIST_SET);
default:
throw InvalidArgumentException("unknown TType", type);
@@ -824,14 +823,7 @@ class CompactReader {
AccessFlags::Error).toArray();
Array valueSpec = spec.rvalAt(PHPTransport::s_val,
AccessFlags::Error).toArray();
String format = spec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
Variant ret;
if (format.equal(PHPTransport::s_collection)) {
ret = NEWOBJ(c_Map)();
} else {
ret = Array::Create();
}
Variant ret = Array::Create();
for (uint32_t i = 0; i < size; i++) {
Variant key = readField(keySpec, keyType);
@@ -843,60 +835,24 @@ class CompactReader {
return ret;
}
Variant readList(CArrRef spec) {
Variant readList(CArrRef spec, CListType listType) {
TType valueType;
uint32_t size;
readListBegin(valueType, size);
Array valueSpec = spec.rvalAt(PHPTransport::s_elem,
AccessFlags::Error_Key).toArray();
String format = spec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
Variant ret;
if (format.equal(PHPTransport::s_collection)) {
ret = NEWOBJ(c_Vector)();
} else {
ret = Array::Create();
}
Variant ret = Array::Create();
for (uint32_t i = 0; i < size; i++) {
Variant value = readField(valueSpec, valueType);
ret.append(value);
}
readCollectionEnd();
return ret;
}
Variant readSet(CArrRef spec) {
TType valueType;
uint32_t size;
readListBegin(valueType, size);
Array valueSpec = spec.rvalAt(PHPTransport::s_elem,
AccessFlags::Error_Key).toArray();
String format = spec.rvalAt(PHPTransport::s_format,
AccessFlags::None).toString();
Variant ret;
if (format.equal(PHPTransport::s_collection)) {
p_Set set_ret = NEWOBJ(c_Set)();
for (uint32_t i = 0; i < size; i++) {
Variant value = readField(valueSpec, valueType);
set_ret->t_add(value);
}
ret = Variant(set_ret);
} else {
ret = Array::Create();
for (uint32_t i = 0; i < size; i++) {
Variant value = readField(valueSpec, valueType);
if (listType == C_LIST_LIST) {
ret.append(value);
} else {
ret.set(value, true);
}
}
readCollectionEnd();
return ret;
}
-2
Ver Arquivo
@@ -105,8 +105,6 @@ public:
static StaticString s_ktype;
static StaticString s_vtype;
static StaticString s_etype;
static StaticString s_format;
static StaticString s_collection;
public:
Object protocol() { return p; }
+76 -1
Ver Arquivo
@@ -16,22 +16,28 @@
#include "hphp/runtime/vm/debug/debug.h"
#include "hphp/runtime/vm/debug/gdb-jit.h"
#include "hphp/runtime/vm/jit/translator-x64.h"
#include "hphp/runtime/base/execution-context.h"
#include "hphp/util/current-executable.h"
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "hphp/runtime/vm/jit/translator-x64.h"
#include <bfd.h>
using namespace HPHP::Transl;
namespace HPHP {
namespace Debug {
void* DebugInfo::pidMapOverlayStart;
void* DebugInfo::pidMapOverlayEnd;
DebugInfo* DebugInfo::Get() {
return tx64->getDebugInfo();
}
@@ -41,6 +47,7 @@ DebugInfo::DebugInfo() {
sizeof m_perfMapName,
"/tmp/perf-%d.map", getpid());
m_perfMap = fopen(m_perfMapName, "w");
generatePidMapOverlay();
}
DebugInfo::~DebugInfo() {
@@ -50,6 +57,74 @@ DebugInfo::~DebugInfo() {
}
}
void DebugInfo::generatePidMapOverlay() {
if (!m_perfMap || !pidMapOverlayStart) return;
std::string self = current_executable_path();
bfd* abfd = bfd_openr(self.c_str(), nullptr);
#ifdef BFD_DECOMPRESS
abfd->flags |= BFD_DECOMPRESS;
#endif
char **match = nullptr;
if (!bfd_check_format(abfd, bfd_archive) &&
bfd_check_format_matches(abfd, bfd_object, &match)) {
std::vector<asymbol*> sorted;
long storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed <= 0) return;
auto symbol_table = (asymbol**)malloc(storage_needed);
long number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
for (long i = 0; i < number_of_symbols; i++) {
auto sym = symbol_table[i];
if (!(sym->flags & (BSF_LOCAL|BSF_GLOBAL))) continue;
if (sym->flags &
(BSF_INDIRECT|BSF_SECTION_SYM|BSF_WEAK|BSF_FILE|BSF_OBJECT)) {
continue;
}
auto sec = sym->section;
if (!(sec->flags & (SEC_ALLOC|SEC_LOAD|SEC_CODE))) continue;
auto addr = sec->vma + sym->value;
if (addr < uintptr_t(pidMapOverlayStart) ||
addr >= uintptr_t(pidMapOverlayEnd)) {
continue;
}
sorted.push_back(sym);
}
std::sort(sorted.begin(), sorted.end(), [](asymbol* a, asymbol* b) {
auto addra = a->section->vma + a->value;
auto addrb = b->section->vma + b->value;
if (addra != addrb) return addra < addrb;
return strncmp("_ZN4HPHP", a->name, 8) &&
!strncmp("_ZN4HPHP", b->name, 8);
});
for (size_t i = 0; i < sorted.size(); i++) {
auto sym = sorted[i];
auto addr = sym->section->vma + sym->value;
unsigned size;
if (i + 1 < sorted.size()) {
auto s2 = sorted[i + 1];
size = s2->section->vma + s2->value - addr;
} else {
size = uintptr_t(pidMapOverlayEnd) - addr;
}
if (!size) continue;
fprintf(m_perfMap, "%lx %x %s\n",
long(addr), size, sym->name);
}
free(symbol_table);
free(match);
}
bfd_close(abfd);
return;
}
void DebugInfo::recordStub(TCRange range, const char* name) {
if (range.isAstubs()) {
m_astubsDwarfInfo.addTracelet(range, name, nullptr, nullptr, false, false);
+9 -1
Ver Arquivo
@@ -41,8 +41,13 @@ class DebugInfo {
void debugSync();
static DebugInfo* Get();
static void setPidMapOverlay(void* from, void* to) {
pidMapOverlayStart = from;
pidMapOverlayEnd = to;
}
private:
void generatePidMapOverlay();
/* maintain separate dwarf info for a and astubs, so that we
* don't emit dwarf info for the two in the same ELF file.
* gdb tends to get confused when it sees dwarf info for
@@ -56,6 +61,9 @@ class DebugInfo {
*/
FILE* m_perfMap;
char m_perfMapName[64];
static void* pidMapOverlayStart;
static void* pidMapOverlayEnd;
};
/*
+12 -4
Ver Arquivo
@@ -178,11 +178,19 @@ void forPreorderDoms(Block* block, const DomChildren& children,
}
}
template <class Body>
void forEachTrace(IRUnit& unit, Body body) {
body(unit.main());
for (auto& exit : unit.exits()) {
body(exit.get());
}
}
template <class Body>
void forEachTrace(const IRUnit& unit, Body body) {
body(unit.main());
for (auto exit : unit.exits()) {
body(exit);
for (auto& exit : unit.exits()) {
body(exit.get());
}
}
@@ -191,7 +199,7 @@ void forEachTraceBlock(const IRUnit& unit, Body body) {
for (auto block : unit.main()->blocks()) {
body(block);
}
for (auto exit : unit.exits()) {
for (auto& exit : unit.exits()) {
for (auto block : exit->blocks()) {
body(block);
}
@@ -208,7 +216,7 @@ void forEachInst(const BlockList& blocks, Body body) {
}
template <class Body>
void forEachTraceInst(const IRUnit& unit, Body body) {
void forEachTraceInst(IRUnit& unit, Body body) {
forEachTrace(unit, [=](IRTrace* t) {
forEachInst(t->blocks(), body);
});
+5 -2
Ver Arquivo
@@ -438,9 +438,12 @@ void optimizeActRecs(BlockList& blocks, DceState& state, IRUnit& unit,
void eliminateDeadCode(IRUnit& unit) {
auto removeEmptyExitTraces = [&] {
unit.exits().remove_if([](IRTrace* exit) {
auto& exits = unit.exits();
auto isEmpty = [](smart::unique_ptr<IRTrace>& exit) {
return exit->blocks().empty();
});
};
exits.erase(std::remove_if(exits.begin(), exits.end(), isEmpty),
exits.end());
};
// kill unreachable code and remove any traces that are now empty
+2 -1
Ver Arquivo
@@ -69,7 +69,8 @@ bool classIsUniqueInterface(const Class* cls) {
HhbcTranslator::HhbcTranslator(Offset startOffset,
uint32_t initialSpOffsetFromFp,
const Func* func)
: m_tb(new TraceBuilder(startOffset,
: m_unit(startOffset)
, m_tb(new TraceBuilder(startOffset,
initialSpOffsetFromFp,
m_unit,
func))
+10 -9
Ver Arquivo
@@ -22,6 +22,15 @@ namespace HPHP { namespace JIT {
TRACE_SET_MOD(hhir);
IRUnit::IRUnit(Offset initialBcOffset)
: m_nextBlockId(0)
, m_nextOpndId(0)
, m_nextInstId(0)
, m_bcOff(initialBcOffset)
, m_main(smart::make_unique<IRTrace>(*this, defBlock()))
{
}
IRInstruction* IRUnit::defLabel(unsigned numDst, BCMarker marker) {
IRInstruction inst(DefLabel, marker);
IRInstruction* label = cloneInstruction(&inst);
@@ -58,18 +67,10 @@ SSATmp* IRUnit::findConst(ConstData& cdata, Type ctype) {
return m_constTable.insert(cloneInstruction(&inst)->dst());
}
Block* IRUnit::makeMain(uint32_t bcOff) {
assert(!m_main);
auto entry = defBlock();
m_bcOff = bcOff;
m_main = new (m_arena) IRTrace(*this, entry);
return entry;
}
Block* IRUnit::addExit() {
auto exit = defBlock();
exit->setHint(Block::Hint::Unlikely);
m_exits.push_back(new (m_arena) IRTrace(*this, exit));
m_exits.push_back(smart::make_unique<IRTrace>(*this, exit));
return exit;
}
+9 -13
Ver Arquivo
@@ -23,6 +23,7 @@
#include "folly/ScopeGuard.h"
#include "hphp/util/arena.h"
#include "hphp/runtime/vm/jit/ir.h"
#include "hphp/runtime/vm/jit/ir-trace.h"
#include "hphp/runtime/vm/jit/cse.h"
#include "hphp/runtime/base/memory-manager.h"
@@ -168,12 +169,7 @@ class IRUnit {
TRACE_SET_MOD(hhir);
public:
IRUnit()
: m_nextBlockId(0)
, m_nextOpndId(0)
, m_nextInstId(0)
, m_main(nullptr)
{}
explicit IRUnit(Offset initialBcOffset);
/*
* Create an IRInstruction with lifetime equivalent to this IRUnit.
@@ -263,9 +259,8 @@ public:
IRInstruction* mov(SSATmp* dst, SSATmp* src, BCMarker marker);
/*
* Create a new trace
* Create a new exit trace.
*/
Block* makeMain(uint32_t bcOff);
Block* addExit();
Arena& arena() { return m_arena; }
@@ -273,7 +268,8 @@ public:
uint32_t numBlocks() const { return m_nextBlockId; }
uint32_t numInsts() const { return m_nextInstId; }
CSEHash& constTable() { return m_constTable; }
IRTrace* main() const { return m_main; }
IRTrace* main() { return m_main.get(); }
const IRTrace* main() const { return m_main.get(); }
uint32_t bcOff() const { return m_bcOff; }
// Overloads useful for StateVector and IdSet
@@ -281,8 +277,8 @@ public:
uint32_t numIds(const Block*) const { return numBlocks(); }
uint32_t numIds(const IRInstruction*) const { return numInsts(); }
typedef std::list<IRTrace*> ExitList;
ExitList& exits() { return m_exits; }
typedef smart::vector<smart::unique_ptr<IRTrace>> ExitList;
ExitList& exits() { return m_exits; }
const ExitList& exits() const { return m_exits; }
Block* entry() const;
std::string toString() const;
@@ -296,13 +292,13 @@ private:
}
private:
Arena m_arena; // contains IRTrace, Block, IRInstruction, and SSATmp objects
Arena m_arena; // contains Block, IRInstruction, and SSATmp objects
CSEHash m_constTable; // DefConst's for each unique constant in this IR
uint32_t m_nextBlockId;
uint32_t m_nextOpndId;
uint32_t m_nextInstId;
uint32_t m_bcOff; // bytecode offset where this unit starts
IRTrace* m_main; // main entry point trace
smart::unique_ptr<IRTrace> m_main; // main entry point trace
ExitList m_exits; // exit traces
};
+1 -1
Ver Arquivo
@@ -184,7 +184,7 @@ class NormalizedInstruction {
}
private:
smart::vector<smart::unique_ptr<DynLocation>::type> m_dynLocs;
smart::vector<smart::unique_ptr<DynLocation>> m_dynLocs;
};
} } // HPHP::Transl
+1 -1
Ver Arquivo
@@ -353,7 +353,7 @@ static BlockList blocks(const IRUnit& unit,
smart::vector<Block*> blocks;
blocks.assign(trace->blocks().begin(), trace->blocks().end());
if (trace->isMain()) {
for (auto exit : unit.exits()) {
for (auto& exit : unit.exits()) {
blocks.insert(blocks.end(), exit->blocks().begin(), exit->blocks().end());
}
}
+11 -5
Ver Arquivo
@@ -454,11 +454,15 @@ void pmethodCacheMissPath(MethodCache* mce,
LeaseHolder writer(Translator::WriteLease());
if (!writer) return;
auto smashMov = [&] (TCA addr, uintptr_t value) {
auto smashMov = [&] (TCA addr, uintptr_t value) -> bool {
always_assert(isSmashable(addr + 2, 8));
assert(addr[0] == 0x49 && addr[1] == 0xba);
auto const ptr = reinterpret_cast<uintptr_t*>(addr + 2);
if (!(*ptr & 1)) {
return false;
}
*ptr = value;
return true;
};
/*
@@ -495,12 +499,14 @@ void pmethodCacheMissPath(MethodCache* mce,
fval < std::numeric_limits<uint32_t>::max() &&
cval < std::numeric_limits<uint32_t>::max();
uintptr_t imm = 0x2; /* not a Class, but clear low bit */
if (cacheable) {
assert(!(mce->m_value->attrs() & AttrStatic));
auto const imm = fval << 32 | mce->m_key;
smashMov(pdata->smashImmAddr, imm);
} else {
smashMov(pdata->smashImmAddr, 0x2 /* not a Class, but clear low bit */);
imm = fval << 32 | cval;
}
if (!smashMov(pdata->smashImmAddr, imm)) {
// someone beat us to it
return methodCacheSlowerPath<Fatal>(mce, ar, name, cls);
}
// Regardless of whether the inline cache was populated, smash the
+1 -1
Ver Arquivo
@@ -35,7 +35,7 @@ TraceBuilder::TraceBuilder(Offset initialBcOffset,
: m_unit(unit)
, m_simplifier(*this)
, m_state(unit, initialSpOffsetFromFp, func)
, m_curTrace(m_unit.makeMain(initialBcOffset)->trace())
, m_curTrace(m_unit.main())
, m_curBlock(nullptr)
, m_enableSimplification(false)
, m_inReoptimize(false)
+14
Ver Arquivo
@@ -3170,6 +3170,20 @@ bool shouldAnalyzeCallee(const NormalizedInstruction* fcall,
// inline if there are any calls in order to prepare arguments.
for (auto* ni = fcall->prev; ni; ni = ni->prev) {
if (ni->source.offset() == fpi->m_fpushOff) {
if (ni->op() == OpFPushObjMethodD ||
ni->op() == OpFPushObjMethod) {
if (!ni->inputs[ni->op() == OpFPushObjMethod]->isObject()) {
/*
* In this case, we're going to throw or fatal when we
* execute the FPush*. But we have statically proven that
* if we get to the FCall, then target is the Func that will
* be called. So the FCall is unreachable - but unfortunately,
* various assumptions by the jit will be violated if we try
* to inline it. So just don't inline in that case.
*/
return false;
}
}
return true;
}
if (isFCallStar(ni->op()) || ni->op() == OpFCallBuiltin) {
+2 -2
Ver Arquivo
@@ -1817,11 +1817,11 @@
},
{
"name": "HPHP_VERSION",
"value": "2.3.0-dev"
"value": "2.3.0"
},
{
"name": "HHVM_VERSION",
"value": "2.3.0-dev"
"value": "2.3.0"
},
{
"name": "HTML_ENTITIES",
@@ -0,0 +1,27 @@
<?hh ;
class X {
private $foo;
function __construct($a) {
$this->foo = $a;
}
function foo() { return $this->foo; }
}
function foo($q, $a) {
$x = getX($q, $a);
fiz($x->foo());
}
foo(true, 1);
foo(false, "a");
function fiz($a) {
var_dump($a);
}
function getX($q, $a) {
if ($q) $x = new X($a);
return $x;
}
@@ -0,0 +1,6 @@
int(1)
HipHop Notice: Undefined variable: x in %s/slow/object_method/bad-inlining.php on line 26
HipHop Fatal error: Uncaught exception 'BadMethodCallException' with message 'Call to a member function foo() on a non-object' in %s/slow/object_method/bad-inlining.php:15
Stack trace:
#0 %s/slow/object_method/bad-inlining.php(19): foo()
#1 {main}
+1 -1
Ver Arquivo
@@ -491,7 +491,7 @@ std::string Process::GetCPUModel() {
do_cpuid(0, regs);
const int vendor_size = sizeof(regs[1])*3;
std::swap(regs[2], regs[3]);
uint32_t cpu_exthigh = 0;
if (memcmp(regs + 1, "GenuineIntel", vendor_size) == 0 ||
memcmp(regs + 1, "AuthenticAMD", vendor_size) == 0) {
+1 -1
Ver Arquivo
@@ -1 +1 @@
HHVM_VERSION(2.3.0-dev)
HHVM_VERSION(2.3.0)