543927cc35
It isn't really a constant anyways. Closes #757
113 linhas
3.7 KiB
C++
113 linhas
3.7 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 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. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
#include "hphp/util/arena.h"
|
|
#include "hphp/runtime/base/memory/smart_containers.h"
|
|
#include "hphp/runtime/vm/jit/region_selection.h"
|
|
#include "hphp/runtime/vm/verifier/cfg.h"
|
|
|
|
namespace HPHP { namespace JIT {
|
|
|
|
TRACE_SET_MOD(region);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
namespace {
|
|
|
|
bool isFuncEntry(const Func* func, Offset off) {
|
|
return off == func->base();
|
|
}
|
|
|
|
int numInstrs(PC start, PC end) {
|
|
int ret{};
|
|
for (; start != end; ++ret) {
|
|
start += instrLen(start);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Region-selector that unintelligently takes a whole method at a
|
|
* time. This is primarily intended for use for debugging and
|
|
* development on the JIT.
|
|
*
|
|
* Adds no type annotations to the region beyond those known from the
|
|
* context. It will list only the parameter types as guards.
|
|
*
|
|
* If the context is not a method entry point, returns nullptr to fall
|
|
* back to the tracelet compiler. (This will happen for side-exits
|
|
* from method regions, for example.)
|
|
*/
|
|
RegionDescPtr regionMethod(const RegionContext& context) {
|
|
using namespace HPHP::Verifier;
|
|
|
|
if (!isFuncEntry(context.func, context.offset)) return nullptr;
|
|
FTRACE(1, "function entry for {}: using regionMethod\n",
|
|
context.func->fullName()->data());
|
|
|
|
auto ret = smart::make_unique<RegionDesc>();
|
|
|
|
Arena arena;
|
|
GraphBuilder gb(arena, context.func);
|
|
auto const graph = gb.build();
|
|
auto const unit = context.func->unit();
|
|
|
|
/*
|
|
* Spit out the blocks in a RPO, but skip DV-initializer blocks
|
|
* (i.e. start with graph->first_linear. We don't handle those in
|
|
* our method regions for now---they'll get handled by the tracelet
|
|
* compiler and then may branch to the main entry point.
|
|
*/
|
|
sortRpo(graph);
|
|
for (Block* b = graph->first_linear; b != nullptr; b = b->next_rpo) {
|
|
auto const start = unit->offsetOf(b->start);
|
|
auto const length = numInstrs(b->start, b->end);
|
|
ret->blocks.emplace_back(
|
|
smart::make_unique<RegionDesc::Block>(context.func, start, length)
|
|
);
|
|
}
|
|
|
|
assert(!ret->blocks.empty());
|
|
auto const startSK = ret->blocks.front()->start();
|
|
for (auto& lt : context.liveTypes) {
|
|
typedef RegionDesc::Location::Tag LTag;
|
|
|
|
switch (lt.location.tag()) {
|
|
case LTag::Stack:
|
|
break;
|
|
case LTag::Local:
|
|
if (lt.location.localId() < context.func->numParams()) {
|
|
// Only predict objectness, not the specific class type.
|
|
auto const type = lt.type.strictSubtypeOf(Type::Obj)
|
|
? Type::Obj
|
|
: lt.type;
|
|
ret->blocks.front()->addPredicted(startSK, {lt.location, type});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
}}
|
|
|