@@ -307,6 +307,41 @@ SSATmp* HhbcTranslator::MInstrTranslator::genMisPtr() {
307307 }
308308}
309309
310+
311+ namespace {
312+ bool mightCallMagicPropMethod (MInstrAttr mia, const Class* cls,
313+ PropInfo propInfo) {
314+ auto const objAttr = (mia & Define) ? ObjectData::UseSet : ObjectData::UseGet;
315+ auto const clsHasMagicMethod = !cls || (cls->getODAttrs () & objAttr);
316+
317+ return clsHasMagicMethod &&
318+ convertToType (propInfo.repoAuthType ).maybe (Type::Uninit);
319+ }
320+
321+ bool
322+ mInstrHasUnknownOffsets (const NormalizedInstruction& ni, Class* context) {
323+ const MInstrInfo& mii = getMInstrInfo (ni.mInstrOp ());
324+ unsigned mi = 0 ;
325+ unsigned ii = mii.valCount () + 1 ;
326+ for (; mi < ni.immVecM .size (); ++mi) {
327+ MemberCode mc = ni.immVecM [mi];
328+ if (mcodeIsProp (mc)) {
329+ const Class* cls = nullptr ;
330+ auto propInfo = getPropertyOffset (ni, context, cls, mii, mi, ii);
331+ if (propInfo.offset == -1 ||
332+ mightCallMagicPropMethod (mii.getAttr (mc), cls, propInfo)) {
333+ return true ;
334+ }
335+ ++ii;
336+ } else {
337+ return true ;
338+ }
339+ }
340+
341+ return false ;
342+ }
343+ }
344+
310345// Inspect the instruction we're about to translate and determine if
311346// it can be executed without using an MInstrState struct.
312347void HhbcTranslator::MInstrTranslator::checkMIState () {
@@ -320,60 +355,54 @@ void HhbcTranslator::MInstrTranslator::checkMIState() {
320355 // about the operation, this function doesn't care what the type is.
321356 auto baseVal = getBase (DataTypeGeneric);
322357 Type baseType = baseVal->type ();
358+ const bool baseArr = baseType <= Type::Arr;
323359 const bool isCGetM = m_ni.mInstrOp () == OpCGetM;
324360 const bool isSetM = m_ni.mInstrOp () == OpSetM;
325361 const bool isIssetM = m_ni.mInstrOp () == OpIssetM;
326362 const bool isUnsetM = m_ni.mInstrOp () == OpUnsetM;
327363 const bool isSingle = m_ni.immVecM .size () == 1 ;
364+ const bool unknownOffsets = mInstrHasUnknownOffsets (m_ni, contextClass ());
328365
329366 if (baseType.maybeBoxed () && !baseType.isBoxed ()) {
330367 // We don't need to bother with weird base types.
331368 return ;
332369 }
333370 baseType = baseType.unbox ();
334371
372+
335373 // CGetM or SetM with no unknown property offsets
336- const bool simpleProp = !mInstrHasUnknownOffsets (m_ni, contextClass ()) &&
337- (isCGetM || isSetM);
374+ const bool simpleProp = !unknownOffsets && (isCGetM || isSetM);
338375
339- // SetM with only one element
340- const bool singlePropSet = isSingle && isSetM &&
341- mcodeIsProp (m_ni.immVecM [0 ]);
376+ // SetM with only one vector element, for props and elems
377+ const bool singleSet = isSingle && isSetM;
342378
343- // Array access with one element in the vector
379+ // Element access with one element in the vector
344380 const bool singleElem = isSingle && mcodeIsElem (m_ni.immVecM [0 ]);
345381
346- // SetM with one vector array element
347- const bool simpleArraySet = isSetM && singleElem;
348-
349382 // IssetM with one vector array element and an Arr base
350- const bool simpleArrayIsset = isIssetM && singleElem &&
351- baseType <= Type::Arr;
383+ const bool simpleArrayIsset = isIssetM && singleElem && baseArr;
384+
352385 // IssetM with one vector array element and a collection type
353386 const bool simpleCollectionIsset = isIssetM && singleElem &&
354- baseType.strictSubtypeOf (Type::Obj) &&
355- isOptimizableCollectionClass (baseType.getClass ());
387+ baseType < Type::Obj && isOptimizableCollectionClass (baseType.getClass ());
356388
357389 // UnsetM on an array with one vector element
358- const bool simpleArrayUnset = isUnsetM && singleElem;
359-
360- // UnsetM on a non-standard base. Always a noop or fatal.
361- const bool badUnset = isUnsetM && baseType.not (Type::Arr | Type::Obj);
390+ const bool simpleArrayUnset = isUnsetM && singleElem &&
391+ baseType <= Type::Arr;
362392
363393 // CGetM on an array with a base that won't use MInstrState. Str
364394 // will use tvScratch and Obj will fatal or use tvRef.
365395 const bool simpleArrayGet = isCGetM && singleElem &&
366396 baseType.not (Type::Str | Type::Obj);
367397 const bool simpleCollectionGet = isCGetM && singleElem &&
368- baseType.strictSubtypeOf (Type::Obj) &&
369- isOptimizableCollectionClass (baseType.getClass ());
398+ baseType < Type::Obj && isOptimizableCollectionClass (baseType.getClass ());
370399 const bool simpleStringOp = (isCGetM || isIssetM) && isSingle &&
371400 isSimpleBase () && mcodeMaybeArrayIntKey (m_ni.immVecM [0 ]) &&
372401 baseType <= Type::Str;
373402
374- if (simpleProp || singlePropSet ||
375- simpleArraySet || simpleArrayGet || simpleCollectionGet ||
376- simpleArrayUnset || badUnset || simpleCollectionIsset ||
403+ if (simpleProp || singleSet ||
404+ simpleArrayGet || simpleCollectionGet ||
405+ simpleArrayUnset || simpleCollectionIsset ||
377406 simpleArrayIsset || simpleStringOp) {
378407 setNoMIState ();
379408 if (simpleCollectionGet || simpleCollectionIsset) {
@@ -861,14 +890,14 @@ void HhbcTranslator::MInstrTranslator::emitIntermediateOp() {
861890 }
862891}
863892
864-
865893void HhbcTranslator::MInstrTranslator::emitProp () {
866894 const Class* knownCls = nullptr ;
867895 const auto propInfo = getPropertyOffset (m_ni, contextClass (),
868896 knownCls, m_mii,
869897 m_mInd, m_iInd);
870898 auto mia = m_mii.getAttr (m_ni.immVecM [m_mInd]);
871- if (propInfo.offset == -1 || (mia & Unset)) {
899+ if (propInfo.offset == -1 || (mia & Unset) ||
900+ mightCallMagicPropMethod (mia, knownCls, propInfo)) {
872901 emitPropGeneric ();
873902 } else {
874903 emitPropSpecialized (mia, propInfo);
@@ -1338,7 +1367,9 @@ void HhbcTranslator::MInstrTranslator::emitCGetProp() {
13381367 const Class* knownCls = nullptr ;
13391368 const auto propInfo = getPropertyOffset (m_ni, contextClass (), knownCls,
13401369 m_mii, m_mInd, m_iInd);
1341- if (propInfo.offset != -1 ) {
1370+
1371+ if (propInfo.offset != -1 &&
1372+ !mightCallMagicPropMethod (None, knownCls, propInfo)) {
13421373 emitPropSpecialized (MIA_warn, propInfo);
13431374 SSATmp* cellPtr = gen (UnboxPtr, m_base);
13441375 m_result = gen (LdMem, Type::Cell, cellPtr, cns (0 ));
@@ -1463,7 +1494,8 @@ void HhbcTranslator::MInstrTranslator::emitSetProp() {
14631494 const Class* knownCls = nullptr ;
14641495 const auto propInfo = getPropertyOffset (m_ni, contextClass (), knownCls,
14651496 m_mii, m_mInd, m_iInd);
1466- if (propInfo.offset != -1 ) {
1497+ if (propInfo.offset != -1 &&
1498+ !mightCallMagicPropMethod (Define, knownCls, propInfo)) {
14671499 emitPropSpecialized (MIA_define, propInfo);
14681500 SSATmp* cellPtr = gen (UnboxPtr, m_base);
14691501 SSATmp* oldVal = gen (LdMem, Type::Cell, cellPtr, cns (0 ));
0 commit comments