4665b068d4
This diff renames the Tracelet -> RegionDesc conversion mode to "legacy" (since it's going away eventually) and changes "tracelet" to use the new region selection mode. It attempts to select a region that will be the same length as what Translator::analyze would come up with, using HhbcTranslator for all of the type flow logic. It generates longer tracelets in some cases due to more precise type information. Once this new mode is no longer a perf regression it can become the new default, replacing all the code in Translator::analyze and the "legacy" region mode. This version doesn't support inlining or tracking of known Func*s; those will come in later diffs.
112 linhas
3.7 KiB
C++
112 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/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((Op*)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.bcOffset)) 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;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
}}
|