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:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
function idx($a, $b) {
|
||||
var_dump("override");
|
||||
}
|
||||
|
||||
function foo($a,$b) {
|
||||
idx($a, $b);
|
||||
}
|
||||
|
||||
foo("a", "b");
|
||||
@@ -1 +0,0 @@
|
||||
string(8) "override"
|
||||
@@ -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,6 +1,6 @@
|
||||
float(0)
|
||||
float(0)
|
||||
array(1) {
|
||||
["login_bruteforce_protection_delta_vetted_datr:3600"]=>
|
||||
["r:3600"]=>
|
||||
float(0)
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário