Rewrite idx in PHP using IR instruction for hot path

- Do the actual work of implementing idx() in PHP
- Remove the old C++ builtin (which needs to be done at the same time)
- Remove OSS test dependencies on idx()
Esse commit está contido em:
Sean Cannella
2013-05-20 19:26:09 -07:00
commit de Sara Golemon
commit 05a8a8d7ca
13 arquivos alterados com 106 adições e 102 exclusões
+6
Ver Arquivo
@@ -76,6 +76,12 @@ FunctionScope::FunctionScope(AnalysisResultConstPtr ar, bool method,
}
m_userAttributes[attrs[i]->getName()] = attrs[i]->getExp();
}
// Support for systemlib functions implemented in PHP
if (!m_method &&
m_userAttributes.find("__Overridable") != m_userAttributes.end()) {
setAllowOverride();
}
}
FunctionScope::FunctionScope(FunctionScopePtr orig,
+10 -8
Ver Arquivo
@@ -1340,14 +1340,16 @@ Variant f_i18n_loc_get_error_code() {
}
Variant f_hphp_array_idx(CVarRef key, CVarRef search, CVarRef def) {
if (UNLIKELY(!search.isArray())) {
raise_error("hphp_array_idx: search must be an array");
} else if (LIKELY(!key.isNull())) {
ArrayData *arr = search.getArrayData();
VarNR index = key.toKey();
if (LIKELY(!index.isNull())) {
CVarRef ret = arr->get(index, false);
return (&ret != &null_variant) ? ret : def;
if (!key.isNull()) {
if (LIKELY(search.isArray())) {
ArrayData *arr = search.getArrayData();
VarNR index = key.toKey();
if (!index.isNull()) {
CVarRef ret = arr->get(index, false);
return (&ret != &null_variant) ? ret : def;
}
} else {
raise_error("hphp_array_idx: search must be an array");
}
}
return def;
+13 -2
Ver Arquivo
@@ -39,6 +39,10 @@ static const Trace::Module TRACEMOD = Trace::bcinterp;
const StringData* Func::s___call = StringData::GetStaticString("__call");
const StringData* Func::s___callStatic =
StringData::GetStaticString("__callStatic");
static const StringData* sd___overridable =
StringData::GetStaticString("__Overridable");
static const StringData* sd___PHPBuiltin =
StringData::GetStaticString("__PHPBuiltin");
//=============================================================================
// Func.
@@ -506,6 +510,11 @@ void Func::prettyPrint(std::ostream& out) const {
}
}
bool Func::isPHPBuiltin() const {
return shared()->m_userAttributes.find(sd___PHPBuiltin) !=
shared()->m_userAttributes.end();
}
HphpArray* Func::getStaticLocals() const {
return g_vmContext->getFuncStaticCtx(this);
}
@@ -655,8 +664,10 @@ void Func::setCached() {
}
bool Func::isAllowOverride() const {
return shared()->m_info &&
(shared()->m_info->attribute & ClassInfo::AllowOverride);
return (shared()->m_info &&
(shared()->m_info->attribute & ClassInfo::AllowOverride)) ||
(shared()->m_userAttributes.find(sd___overridable) !=
shared()->m_userAttributes.end());
}
const Func* Func::getGeneratorBody(const StringData* name) const {
+1
Ver Arquivo
@@ -205,6 +205,7 @@ struct Func {
bool isPseudoMain() const { return m_name->empty(); }
bool isBuiltin() const { return (bool)info(); }
bool isPHPBuiltin() const;
bool isMethod() const {
return !isPseudoMain() && (bool)cls();
}
+21 -11
Ver Arquivo
@@ -1119,37 +1119,47 @@ void HhbcTranslator::emitIncStat(int32_t counter, int32_t value, bool force) {
}
void HhbcTranslator::emitArrayIdx() {
SSATmp* def = popC();
SSATmp* arr = popC();
SSATmp* key = popC();
Type arrType = topC(1)->type();
Type keyType = topC(2)->type();
if (UNLIKELY(!arr->isA(Type::Arr))) {
if (UNLIKELY(!arrType.subtypeOf(Type::Arr))) {
// raise fatal
emitInterpOne(Type::Cell, 3);
return;
}
if (UNLIKELY(key->isA(Type::Null))) {
if (UNLIKELY(keyType.subtypeOf(Type::Null))) {
SSATmp* def = popC();
SSATmp* arr = popC();
SSATmp* key = popC();
// if the key is null it will not be found so just return the default
push(def);
gen(DecRef, arr);
gen(DecRef, key);
return;
}
if (UNLIKELY(!(key->isA(Type::Int) || key->isA(Type::Str)))) {
PUNT(ArrayIdx_unsupportedKey);
if (UNLIKELY(
!(keyType.subtypeOf(Type::Int) || keyType.subtypeOf(Type::Str)))) {
emitInterpOneOrPunt(Type::Cell, 3);
return;
}
KeyType keyType;
SSATmp* def = popC();
SSATmp* arr = popC();
SSATmp* key = popC();
KeyType arrayKeyType;
bool checkForInt;
checkStrictlyInteger(key, keyType, checkForInt);
checkStrictlyInteger(key, arrayKeyType, checkForInt);
TCA opFunc;
if (checkForInt) {
opFunc = (TCA)&arrayIdxSi;
} else if (IntKey == keyType) {
} else if (IntKey == arrayKeyType) {
opFunc = (TCA)&arrayIdxI;
} else {
assert(StrKey == keyType);
assert(StrKey == arrayKeyType);
opFunc = (TCA)&arrayIdxS;
}
+1 -1
Ver Arquivo
@@ -181,7 +181,7 @@ Array Unit::getUserFunctions() {
for (NamedEntityMap::const_iterator it = s_namedDataMap->begin();
it != s_namedDataMap->end(); ++it) {
Func* func_ = it->second.getCachedFunc();
if (!func_ || func_->isBuiltin() ||
if (!func_ || func_->isBuiltin() || func_->isPHPBuiltin() ||
isdigit(func_->name()->data()[0])) {
continue;
}
+3 -1
Ver Arquivo
@@ -65,8 +65,10 @@ function genSystemlib() {
searchDirForPhpFiles($searchPath, $phpfiles);
$searchPath = realpath($scriptPath . '/../../system/classes_hhvm');
searchDirForPhpFiles($searchPath, $phpfiles);
$searchPath = realpath($scriptPath . '/../../facebook/system/classes');
searchDirForPhpFiles($searchPath, $phpfiles);
fwrite($systemlib_php, "<?php\n");
fwrite($systemlib_php, "<?hh\n");
fwrite($systemlib_php, '// @' . 'generated' . "\n\n");
// There are some dependencies between files, so we output
// the classes in a certain order so that all classes can be
+11 -11
Ver Arquivo
@@ -6,20 +6,20 @@ function main() {
$b = null;
var_dump(hphp_array_idx('1', $a, 3));
var_dump(hphp_array_idx('0', $a, 3));
var_dump(hphp_array_idx(1, $a, 3));
var_dump(hphp_array_idx(0, $a, 3));
var_dump(hphp_array_idx(1.01, $a, 3));
var_dump(hphp_array_idx(true, $a, 3));
var_dump(hphp_array_idx(false, $a, 3));
var_dump(hphp_array_idx('0', $a, 4));
var_dump(hphp_array_idx(1, $a, 5));
var_dump(hphp_array_idx(0, $a, 6));
var_dump(hphp_array_idx(1.01, $a, 7));
var_dump(hphp_array_idx(true, $a, 8));
var_dump(hphp_array_idx(false, $a, 9));
var_dump(hphp_array_idx('hello', $a, 3));
var_dump(hphp_array_idx('world', $a, 3));
var_dump(hphp_array_idx('', $a, 3));
var_dump(hphp_array_idx(null, $a, 3));
var_dump(hphp_array_idx('hello', $a, 10));
var_dump(hphp_array_idx('world', $a, 11));
var_dump(hphp_array_idx('', $a, 12));
var_dump(hphp_array_idx(null, $a, 13));
// should fatal
var_dump(hphp_array_idx('not_reached', $b, 3));
var_dump(hphp_array_idx('not_reached', $b, 14));
}
main();
+5 -5
Ver Arquivo
@@ -1,12 +1,12 @@
string(1) "2"
int(3)
int(4)
string(1) "2"
int(3)
int(6)
string(1) "2"
string(1) "2"
int(3)
int(9)
string(5) "world"
int(3)
int(11)
string(5) "empty"
int(3)
int(13)
HipHop Fatal error: hphp_array_idx: search must be an array in %s on line 22
-11
Ver Arquivo
@@ -1,11 +0,0 @@
<?php
function idx($a, $b) {
var_dump("override");
}
function foo($a,$b) {
idx($a, $b);
}
foo("a", "b");
-1
Ver Arquivo
@@ -1 +0,0 @@
string(8) "override"
+34 -50
Ver Arquivo
@@ -1,83 +1,67 @@
<?
<?php
class KarmaMemcache {
private $keyScoreArr;
class KM {
private $kSA;
private $specs;
function getKeyScores() {
return $this->keyScoreArr;
function getKS() {
return $this->kSA;
}
function __construct() {
$this->specs = array(
"login_bruteforce_protection_delta_vetted_datr:3600" =>
// A spec
array('on_block_lockout_time' => 0,
'max_score' => 10000000,
'time_to_decay_max_score' => 100)
"r:3600" =>
array('oblt' => 0,
'ms' => 10000000,
'ttdm' => 100)
);
}
private static function decayScore($a, $b, $c, $d) { return 0; }
/**
* Takes raw data fetched from memcache, applies necessary decay
* function.
*/
private static function decay($a, $b, $c, $d) { return 0; }
private function getFetchedXXX() {
return array(1 /* score */, 0 /*last_occurrence*/, 0
/*last_blocked_time*/);
private function getXXX() {
return array(1, 0, 0);
}
public function getInfo() {
$time = time();
$this->keyScoreArr = array();
$this->kSA = array();
foreach ($this->specs as $key => $spec) {
$fetched = $this->getFetchedXXX();
list($score, $last_occurrence, $last_blocked_time) =
$fetched = $this->getXXX();
list($sc, $l_o, $l_b_t) =
array(
idx($fetched, 0, 0),
idx($fetched, 1, 0),
idx($fetched, 2, 0)
$fetched[0],
$fetched[1],
$fetched[2]
);
// FBLogger('test_remat')->warn("score starts $score\n");
if ($time - $last_blocked_time > $spec['on_block_lockout_time']) {
if ($score > $spec['max_score']) {
// Only possible if thresholds were reduced.
$score = 0.5 * $spec['max_score'];
// FBLogger('test_remat')->warn("score halved max case $score\n");
if ($time - $l_b_t > $spec['oblt']) {
if ($sc > $spec['ms']) {
$sc = 0.5 * $spec['ms'];
} else {
$score = self::decayScore(
$spec['max_score'],
$spec['time_to_decay_max_score'],
$score,
$last_occurrence
$sc = self::decay(
$spec['ms'],
$spec['ttdm'],
$sc,
$l_o
);
// FBLogger('test_remat')->warn("score decayed $score\n");
}
$this->decayedKarmaVectors[$key] = array(
'score' => (double)$score,
'last_occurrence' => (int)$last_occurrence,
'last_blocked_time' => (int)$last_blocked_time
$this->dKV[$key] = array(
'sc' => (double)$sc,
'l_o' => (int)$l_o,
'l_b_t' => (int)$l_b_t
);
// FBLogger('test_remat')->warn("decayed decayed $score: " .
// print_r($this->decayedKarmaVectors[$key], true));
} else {
// In on-block-lockout-interval.
// Don't add to $this->decayedKarmaVectors. That would update the
// timestamp.
}
$this->keyScoreArr[$key] = (double)$score;
$this->kSA[$key] = (double)$sc;
if ($this) {
var_dump((double)$score, $this->keyScoreArr[$key]);
var_dump((double)$sc, $this->kSA[$key]);
}
}
}
}
function main() {
$kc = new KarmaMemcache();
$kc = new KM();
$kc->getInfo();
var_dump($kc->getKeyScores());
var_dump($kc->getKS());
}
main();
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
float(0)
float(0)
array(1) {
["login_bruteforce_protection_delta_vetted_datr:3600"]=>
["r:3600"]=>
float(0)
}