Skip to content

Commit

Permalink
Cleanup tv-comparisons for func/class types
Browse files Browse the repository at this point in the history
Summary: Forgot that I had planned on doing this cleanup ages ago and spotted it again while auditing the `KindOfFunc` code paths. Behavior should be the same after this change.

Reviewed By: alexeyt

Differential Revision: D16052925

fbshipit-source-id: 500d3df923ef5bebdce29e0422831b5a16d86fc7
  • Loading branch information
paulbiss authored and hhvm-bot committed Jun 28, 2019
1 parent eb1bb5d commit 6a632d1
Showing 1 changed file with 213 additions and 10 deletions.
223 changes: 213 additions & 10 deletions hphp/runtime/base/tv-comparisons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,206 @@ typename Op::RetType cellRelOp(Op op, Cell cell, ClsMethDataRef clsMeth) {
not_reached();
}

template<class Op>
typename Op::RetType cellRelOp(Op op, Cell cell, const Func* val) {
assertx(cellIsPlausible(cell));
assertx(val != nullptr);

switch (cell.m_type) {
case KindOfUninit:
case KindOfNull:
return op(staticEmptyString(), funcToStringHelper(val));

case KindOfInt64: {
auto const num = stringToNumeric(funcToStringHelper(val));
return num.m_type == KindOfInt64 ? op(cell.m_data.num, num.m_data.num) :
num.m_type == KindOfDouble ? op(cell.m_data.num, num.m_data.dbl) :
op(cell.m_data.num, 0);
}
case KindOfBoolean:
return op(!!cell.m_data.num, funcToStringHelper(val)->toBoolean());

case KindOfDouble: {
auto const num = stringToNumeric(funcToStringHelper(val));
return num.m_type == KindOfInt64 ? op(cell.m_data.dbl, num.m_data.num) :
num.m_type == KindOfDouble ? op(cell.m_data.dbl, num.m_data.dbl) :
op(cell.m_data.dbl, 0);
}

case KindOfPersistentString:
case KindOfString:
return op(cell.m_data.pstr, funcToStringHelper(val));

case KindOfPersistentVec:
case KindOfVec:
return op.vecVsNonVec();

case KindOfPersistentDict:
case KindOfDict:
return op.dictVsNonDict();

case KindOfPersistentKeyset:
case KindOfKeyset:
return op.keysetVsNonKeyset();

case KindOfPersistentShape:
case KindOfShape:
if (RuntimeOption::EvalHackArrDVArrs) {
return op.dictVsNonDict();
}
// Fallthrough

case KindOfPersistentArray:
case KindOfArray:
if (UNLIKELY(op.noticeOnArrNonArr())) {
raiseHackArrCompatArrMixedCmp();
}
funcToStringHelper(val); // warn
return op(true, false);

case KindOfObject: {
auto od = cell.m_data.pobj;
if (od->isCollection()) return op.collectionVsNonObj();
if (od->hasToString()) {
String str(od->invokeToString());
return op(str.get(), funcToStringHelper(val));
}
return op(true, false);
}

case KindOfResource: {
auto const rd = cell.m_data.pres;
return op(rd->data()->o_toDouble(), funcToStringHelper(val)->toDouble());
}

case KindOfFunc:
return op(cell.m_data.pfunc, val);

case KindOfClass:
return op(
classToStringHelper(cell.m_data.pclass), funcToStringHelper(val));

case KindOfClsMeth:
raiseClsMethToVecWarningHelper();
if (RuntimeOption::EvalHackArrDVArrs) {
return op.vecVsNonVec();
} else {
if (UNLIKELY(op.noticeOnArrNonArr())) {
raiseHackArrCompatArrMixedCmp();
}
funcToStringHelper(val); // warn
return op(true, false);
}

case KindOfRecord:
return op.recordVsNonRecord();

case KindOfRef:
break;
}
not_reached();
}

template<class Op>
typename Op::RetType cellRelOp(Op op, Cell cell, const Class* val) {
assertx(cellIsPlausible(cell));
assertx(val != nullptr);

switch (cell.m_type) {
case KindOfUninit:
case KindOfNull:
return op(staticEmptyString(), classToStringHelper(val));

case KindOfInt64: {
auto const num = stringToNumeric(classToStringHelper(val));
return num.m_type == KindOfInt64 ? op(cell.m_data.num, num.m_data.num) :
num.m_type == KindOfDouble ? op(cell.m_data.num, num.m_data.dbl) :
op(cell.m_data.num, 0);
}
case KindOfBoolean:
return op(!!cell.m_data.num, classToStringHelper(val)->toBoolean());

case KindOfDouble: {
auto const num = stringToNumeric(classToStringHelper(val));
return num.m_type == KindOfInt64 ? op(cell.m_data.dbl, num.m_data.num) :
num.m_type == KindOfDouble ? op(cell.m_data.dbl, num.m_data.dbl) :
op(cell.m_data.dbl, 0);
}

case KindOfPersistentString:
case KindOfString:
return op(cell.m_data.pstr, classToStringHelper(val));

case KindOfPersistentVec:
case KindOfVec:
return op.vecVsNonVec();

case KindOfPersistentDict:
case KindOfDict:
return op.dictVsNonDict();

case KindOfPersistentKeyset:
case KindOfKeyset:
return op.keysetVsNonKeyset();

case KindOfPersistentShape:
case KindOfShape:
if (RuntimeOption::EvalHackArrDVArrs) {
return op.dictVsNonDict();
}
// Fallthrough

case KindOfPersistentArray:
case KindOfArray:
if (UNLIKELY(op.noticeOnArrNonArr())) {
raiseHackArrCompatArrMixedCmp();
}
classToStringHelper(val); // warn
return op(true, false);

case KindOfObject: {
auto od = cell.m_data.pobj;
if (od->isCollection()) return op.collectionVsNonObj();
if (od->hasToString()) {
String str(od->invokeToString());
return op(str.get(), classToStringHelper(val));
}
return op(true, false);
}

case KindOfResource: {
auto const rd = cell.m_data.pres;
return op(rd->data()->o_toDouble(), classToStringHelper(val)->toDouble());
}

case KindOfFunc:
return op(
funcToStringHelper(cell.m_data.pfunc), classToStringHelper(val));

case KindOfClass:
return op(cell.m_data.pclass, val);

case KindOfClsMeth:
raiseClsMethToVecWarningHelper();
if (RuntimeOption::EvalHackArrDVArrs) {
return op.vecVsNonVec();
} else {
if (UNLIKELY(op.noticeOnArrNonArr())) {
raiseHackArrCompatArrMixedCmp();
}
classToStringHelper(val); // warn
return op(true, false);
}

case KindOfRecord:
return op.recordVsNonRecord();

case KindOfRef:
break;
}
not_reached();
}

template<class Op>
typename Op::RetType cellRelOp(Op op, Cell c1, Cell c2) {
assertx(cellIsPlausible(c1));
Expand Down Expand Up @@ -782,10 +982,8 @@ typename Op::RetType cellRelOp(Op op, Cell c1, Cell c2) {
case KindOfArray: return cellRelOp(op, c1, c2.m_data.parr);
case KindOfObject: return cellRelOp(op, c1, c2.m_data.pobj);
case KindOfResource: return cellRelOp(op, c1, c2.m_data.pres);
case KindOfFunc:
return cellRelOp(op, c1, funcToStringHelper(c2.m_data.pfunc));
case KindOfClass:
return cellRelOp(op, c1, classToStringHelper(c2.m_data.pclass));
case KindOfFunc: return cellRelOp(op, c1, c2.m_data.pfunc);
case KindOfClass: return cellRelOp(op, c1, c2.m_data.pclass);
case KindOfClsMeth: return cellRelOp(op, c1, c2.m_data.pclsmeth);
case KindOfRecord: return cellRelOp(op, c1, c2.m_data.prec);
case KindOfRef:
Expand Down Expand Up @@ -835,6 +1033,9 @@ struct Eq {
return ArrayData::Equal(ad1, ad2);
}

bool operator()(const Func* f1, const Func* f2) const { return f1 == f2; }
bool operator()(const Class* c1, const Class* c2) const { return c1 == c2; }

bool operator()(const ObjectData* od1, const ObjectData* od2) const {
assertx(od1);
assertx(od2);
Expand Down Expand Up @@ -942,6 +1143,14 @@ struct CompareBase {
return checkHACCompare();
}

bool operator()(const Func* f1, const Func* f2) const {
return operator()(funcToStringHelper(f1), funcToStringHelper(f2));
}

bool operator()(const Class* c1, const Class* c2) const {
return operator()(classToStringHelper(c1), classToStringHelper(c2));
}

RetType operator()(ClsMethDataRef c1, ClsMethDataRef c2) const {
auto const cls1 = classToStringHelper(c1->getCls());
auto const cls2 = classToStringHelper(c2->getCls());
Expand Down Expand Up @@ -1291,12 +1500,6 @@ bool cellEqual(Cell cell, ClsMethDataRef val) {
}

bool cellEqual(Cell c1, Cell c2) {
if (UNLIKELY(isFuncType(c1.m_type) && isFuncType(c2.m_type))) {
return c1.m_data.pfunc == c2.m_data.pfunc;
}
if (UNLIKELY(isClassType(c1.m_type) && isClassType(c2.m_type))) {
return c1.m_data.pfunc == c2.m_data.pfunc;
}
return cellRelOp(Eq(), c1, c2);
}

Expand Down

0 comments on commit 6a632d1

Please sign in to comment.