Changeset 256411 in webkit


Ignore:
Timestamp:
Feb 11, 2020 5:00:10 PM (4 years ago)
Author:
Alan Coon
Message:

Apply patch. rdar://problem/59299139

Location:
branches/safari-609-branch/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/safari-609-branch/Source/JavaScriptCore/ChangeLog

    r256248 r256411  
     12020-02-11  Alan Coon  <alancoon@apple.com>
     2
     3        Apply patch. rdar://problem/59299139
     4
     5    2020-02-11  Saam Barati  <sbarati@apple.com>
     6
     7            safe to execute should return false when we know code won't be moved
     8            https://bugs.webkit.org/show_bug.cgi?id=207074
     9
     10            Reviewed by Yusuke Suzuki.
     11
     12            We use safeToExecute to determine inside LICM whether it's safe to execute
     13            a node somewhere else in the program. We were returning true for nodes
     14            we knew would never be moved, because they were effectful. Things like Call
     15            and GetById. This patch makes those nodes return false now, since we want
     16            to make it easier to audit the nodes that return true. This makes that audit
     17            easier, since it gets rid of the obvious things that will never be hoisted.
     18
     19            * dfg/DFGSafeToExecute.h:
     20            (JSC::DFG::safeToExecute):
     21
    1222020-02-10  Kocsen Chung  <kocsen_chung@apple.com>
    223
  • branches/safari-609-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r256248 r256411  
    174174    }
    175175
    176     // NOTE: This tends to lie when it comes to effectful nodes, because it knows that they aren't going to
    177     // get hoisted anyway.
     176    // NOTE: This can lie when it comes to effectful nodes, because it knows that they aren't going to
     177    // get hoisted anyway. Sometimes this is convenient so we can avoid branching on some internal
     178    // state of the node (like what some child's UseKind might be). However, nodes that are obviously
     179    // always effectful, we return false for, to make auditing the "return true" cases easier.
    178180
    179181    switch (node->op()) {
     182    // FIXME: Audit these:
     183    // https://bugs.webkit.org/show_bug.cgi?id=207075
    180184    case JSConstant:
    181185    case DoubleConstant:
     
    184188    case Identity:
    185189    case IdentityWithProfile:
    186     case ToThis:
    187     case CreateThis:
    188     case CreatePromise:
    189     case CreateGenerator:
    190     case CreateAsyncGenerator:
    191     case ObjectCreate:
    192     case ObjectKeys:
    193190    case GetCallee:
    194     case SetCallee:
    195191    case GetArgumentCountIncludingThis:
    196     case SetArgumentCountIncludingThis:
    197192    case GetRestLength:
    198193    case GetLocal:
    199     case SetLocal:
    200     case PutStack:
    201     case KillStack:
    202194    case GetStack:
    203     case MovHint:
    204     case ZombieHint:
    205195    case ExitOK:
    206196    case Phantom:
    207     case Upsilon:
    208     case Phi:
    209     case Flush:
    210     case PhantomLocal:
    211     case SetArgumentDefinitely:
    212     case SetArgumentMaybe:
    213197    case ArithBitNot:
    214198    case ArithBitAnd:
     
    241225    case ArithTrunc:
    242226    case ArithUnary:
    243     case ValueBitAnd:
    244     case ValueBitXor:
    245     case ValueBitOr:
    246     case ValueBitNot:
    247     case ValueBitLShift:
    248     case ValueBitRShift:
    249     case Inc:
    250     case Dec:
    251     case ValueNegate:
    252     case ValueAdd:
    253     case ValueSub:
    254     case ValueMul:
    255     case ValueDiv:
    256     case ValueMod:
    257     case ValuePow:
    258     case TryGetById:
     227    case TryGetById: // FIXME: Audit this: https://bugs.webkit.org/show_bug.cgi?id=163834
     228    case CheckStructure:
     229    case CheckStructureOrEmpty:
     230    case GetExecutable:
     231    case CallDOMGetter:
     232    case CallDOM:
     233    case CheckSubClass:
     234    case CheckArray:
     235    case GetScope:
     236    case SkipScope:
     237    case GetGlobalObject:
     238    case GetGlobalThis:
     239    case GetClosureVar:
     240    case GetGlobalVar:
     241    case GetGlobalLexicalVariable:
     242    case CheckCell:
     243    case CheckNotEmpty:
     244    case AssertNotEmpty:
     245    case CheckIdent:
     246    case CompareLess:
     247    case CompareLessEq:
     248    case CompareGreater:
     249    case CompareGreaterEq:
     250    case CompareBelow:
     251    case CompareBelowEq:
     252    case CompareEq:
     253    case CompareStrictEq:
     254    case CompareEqPtr:
     255    case SameValue:
     256    case CheckTypeInfoFlags:
     257    case ParseInt:
     258    case OverridesHasInstance:
     259    case IsEmpty:
     260    case IsUndefined:
     261    case IsUndefinedOrNull:
     262    case IsBoolean:
     263    case IsNumber:
     264    case NumberIsInteger:
     265    case IsObject:
     266    case IsObjectOrNull:
     267    case IsFunction:
     268    case IsCellWithType:
     269    case IsTypedArrayView:
     270    case TypeOf:
     271    case LogicalNot:
     272    case ToString:
     273    case NumberToStringWithValidRadixConstant:
     274    case StrCat:
     275    case CallStringConstructor:
     276    case MakeRope:
     277    case GetFromArguments:
     278    case GetArgument:
     279    case StringFromCharCode:
     280    case ExtractOSREntryLocal:
     281    case ExtractCatchLocal:
     282    case CheckInBounds:
     283    case ConstantStoragePointer:
     284    case Check:
     285    case CheckVarargs:
     286    case ValueRep:
     287    case DoubleRep:
     288    case Int52Rep:
     289    case BooleanToNumber:
     290    case FiatInt52:
     291    case HasIndexedProperty:
     292    case GetEnumeratorStructurePname:
     293    case GetEnumeratorGenericPname:
     294    case ToIndexString:
     295    case CheckStructureImmediate:
     296    case GetMyArgumentByVal:
     297    case GetMyArgumentByValOutOfBounds:
     298    case GetPrototypeOf:
     299    case StringReplace:
     300    case StringReplaceRegExp:
     301    case GetRegExpObjectLastIndex:
     302    case MapHash:
     303    case NormalizeMapKey:
     304    case StringSlice:
     305    case ToLowerCase:
     306    case GetMapBucket:
     307    case GetMapBucketHead:
     308    case GetMapBucketNext:
     309    case LoadKeyFromMapBucket:
     310    case LoadValueFromMapBucket:
     311    case ExtractValueFromWeakMapGet:
     312    case WeakMapGet:
     313    case AtomicsIsLockFree:
     314    case MatchStructure:
     315    case DateGetInt32OrNaN:
     316    case DateGetTime:
     317    case DataViewGetInt:
     318    case DataViewGetFloat:
     319        return true;
     320
     321    case GetButterfly:
     322        return state.forNode(node->child1()).isType(SpecObject);
     323
     324    case ArraySlice:
     325    case ArrayIndexOf: {
     326        // You could plausibly move this code around as long as you proved the
     327        // incoming array base structure is an original array at the hoisted location.
     328        // Instead of doing that extra work, we just conservatively return false.
     329        return false;
     330    }
     331
     332    case GetGetter:
     333    case GetSetter: {
     334        if (!state.forNode(node->child1()).isType(SpecCell))
     335            return false;
     336        StructureAbstractValue& value = state.forNode(node->child1()).m_structure;
     337        if (value.isInfinite() || value.size() != 1)
     338            return false;
     339
     340        return value[0].get() == graph.m_vm.getterSetterStructure;
     341    }
     342
     343    case BottomValue:
     344        // If in doubt, assume that this isn't safe to execute, just because we have no way of
     345        // compiling this node.
     346        return false;
     347
     348    case StoreBarrier:
     349    case FencedStoreBarrier:
     350    case PutStructure:
     351    case NukeStructureAndSetButterfly:
     352        // We conservatively assume that these cannot be put anywhere, which forces the compiler to
     353        // keep them exactly where they were. This is sort of overkill since the clobberize effects
     354        // already force these things to be ordered precisely. I'm just not confident enough in my
     355        // effect based memory model to rely solely on that right now.
     356        return false;
     357       
     358    case FilterCallLinkStatus:
     359    case FilterGetByStatus:
     360    case FilterPutByIdStatus:
     361    case FilterInByIdStatus:
     362        // We don't want these to be moved anywhere other than where we put them, since we want them
     363        // to capture "profiling" at the point in control flow here the user put them.
     364        return false;
     365
     366    case GetByVal:
     367    case GetIndexedPropertyStorage:
     368    case GetArrayLength:
     369    case GetVectorLength:
     370    case ArrayPop:
     371    case StringCharAt:
     372    case StringCharCodeAt:
     373    case StringCodePointAt:
     374        return node->arrayMode().alreadyChecked(graph, node, state.forNode(graph.child(node, 0)));
     375
     376    case ArrayPush:
     377        return node->arrayMode().alreadyChecked(graph, node, state.forNode(graph.varArgChild(node, 1)));
     378
     379    case GetTypedArrayByteOffset:
     380        return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
     381           
     382    case PutByValDirect:
     383    case PutByVal:
     384    case PutByValAlias:
     385        return node->arrayMode().modeForPut().alreadyChecked(
     386            graph, node, state.forNode(graph.varArgChild(node, 0)));
     387
     388    case AllocatePropertyStorage:
     389    case ReallocatePropertyStorage:
     390        return state.forNode(node->child1()).m_structure.isSubsetOf(
     391            RegisteredStructureSet(node->transition()->previous));
     392       
     393    case GetGetterSetterByOffset: {
     394        // If it's an inline property, we need to make sure it's a cell before trusting what the structure set tells us.
     395        if (node->child1().node() == node->child2().node() && !state.forNode(node->child2()).isType(SpecCell))
     396            return false;
     397
     398        StorageAccessData& data = node->storageAccessData();
     399        auto* uid = graph.identifiers()[data.identifierNumber];
     400        PropertyOffset desiredOffset = data.offset;
     401        StructureAbstractValue& value = state.forNode(node->child2()).m_structure;
     402        if (value.isInfinite())
     403            return false;
     404        for (unsigned i = value.size(); i--;) {
     405            Structure* thisStructure = value[i].get();
     406            if (thisStructure->isUncacheableDictionary())
     407                return false;
     408            unsigned attributes = 0;
     409            PropertyOffset checkOffset = thisStructure->getConcurrently(uid, attributes);
     410            if (checkOffset != desiredOffset || !(attributes & PropertyAttribute::Accessor))
     411                return false;
     412        }
     413        return true;
     414    }
     415
     416    case GetByOffset:
     417    case PutByOffset: {
     418        // If it's an inline property, we need to make sure it's a cell before trusting what the structure set tells us.
     419        if (node->child1().node() == node->child2().node() && !state.forNode(node->child2()).isType(SpecCell))
     420            return false;
     421
     422        StorageAccessData& data = node->storageAccessData();
     423        PropertyOffset offset = data.offset;
     424        // Graph::isSafeToLoad() is all about proofs derived from PropertyConditions. Those don't
     425        // know anything about inferred types. But if we have a proof derived from watching a
     426        // structure that has a type proof, then the next case below will deal with it.
     427        if (state.structureClobberState() == StructuresAreWatched) {
     428            if (JSObject* knownBase = node->child2()->dynamicCastConstant<JSObject*>(graph.m_vm)) {
     429                if (graph.isSafeToLoad(knownBase, offset))
     430                    return true;
     431            }
     432        }
     433       
     434        StructureAbstractValue& value = state.forNode(node->child2()).m_structure;
     435        if (value.isInfinite())
     436            return false;
     437        for (unsigned i = value.size(); i--;) {
     438            Structure* thisStructure = value[i].get();
     439            if (thisStructure->isUncacheableDictionary())
     440                return false;
     441            if (!thisStructure->isValidOffset(offset))
     442                return false;
     443        }
     444        return true;
     445    }
     446       
     447    case MultiGetByOffset: {
     448        // We can't always guarantee that the MultiGetByOffset is safe to execute if it
     449        // contains loads from prototypes. If the load requires a check in IR, which is rare, then
     450        // we currently claim that we don't know if it's safe to execute because finding that
     451        // check in the abstract state would be hard. If the load requires watchpoints, we just
     452        // check if we're not in a clobbered state (i.e. in between a side effect and an
     453        // invalidation point).
     454        for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
     455            GetByOffsetMethod method = getCase.method();
     456            switch (method.kind()) {
     457            case GetByOffsetMethod::Invalid:
     458                RELEASE_ASSERT_NOT_REACHED();
     459                break;
     460            case GetByOffsetMethod::Constant: // OK because constants are always safe to execute.
     461            case GetByOffsetMethod::Load: // OK because the MultiGetByOffset has its own checks for loading from self.
     462                break;
     463            case GetByOffsetMethod::LoadFromPrototype:
     464                // Only OK if the state isn't clobbered. That's almost always the case.
     465                if (state.structureClobberState() != StructuresAreWatched)
     466                    return false;
     467                if (!graph.isSafeToLoad(method.prototype()->cast<JSObject*>(), method.offset()))
     468                    return false;
     469                break;
     470            }
     471        }
     472        return true;
     473    }
     474
     475    case ToThis:
     476    case CreateThis:
     477    case CreatePromise:
     478    case CreateGenerator:
     479    case CreateAsyncGenerator:
     480    case ObjectCreate:
     481    case ObjectKeys:
     482    case SetLocal:
     483    case SetCallee:
     484    case PutStack:
     485    case KillStack:
     486    case MovHint:
     487    case ZombieHint:
     488    case Upsilon:
     489    case Phi:
     490    case Flush:
     491    case SetArgumentDefinitely:
     492    case SetArgumentMaybe:
     493    case SetArgumentCountIncludingThis:
     494    case PhantomLocal:
    259495    case DeleteById:
    260496    case DeleteByVal:
     
    277513    case DefineDataProperty:
    278514    case DefineAccessorProperty:
    279     case CheckStructure:
    280     case CheckStructureOrEmpty:
    281     case GetExecutable:
    282     case CallDOMGetter:
    283     case CallDOM:
    284     case CheckSubClass:
    285     case CheckArray:
    286515    case Arrayify:
    287516    case ArrayifyToStructure:
    288     case GetScope:
    289     case SkipScope:
    290     case GetGlobalObject:
    291     case GetGlobalThis:
    292     case GetClosureVar:
    293517    case PutClosureVar:
    294     case GetGlobalVar:
    295     case GetGlobalLexicalVariable:
    296518    case PutGlobalVariable:
    297     case CheckCell:
    298519    case CheckBadCell:
    299     case CheckNotEmpty:
    300     case AssertNotEmpty:
    301     case CheckIdent:
    302520    case RegExpExec:
    303521    case RegExpExecNonGlobalOrSticky:
     
    305523    case RegExpMatchFast:
    306524    case RegExpMatchFastGlobal:
    307     case CompareLess:
    308     case CompareLessEq:
    309     case CompareGreater:
    310     case CompareGreaterEq:
    311     case CompareBelow:
    312     case CompareBelowEq:
    313     case CompareEq:
    314     case CompareStrictEq:
    315     case CompareEqPtr:
    316     case SameValue:
    317525    case Call:
    318526    case DirectCall:
     
    342550    case ProfileType:
    343551    case ProfileControlFlow:
    344     case CheckTypeInfoFlags:
    345     case ParseInt:
    346     case OverridesHasInstance:
    347552    case InstanceOf:
    348553    case InstanceOfCustom:
    349     case IsEmpty:
    350     case IsUndefined:
    351     case IsUndefinedOrNull:
    352     case IsBoolean:
    353     case IsNumber:
    354     case NumberIsInteger:
    355     case IsObject:
    356     case IsObjectOrNull:
    357     case IsFunction:
    358     case IsCellWithType:
    359     case IsTypedArrayView:
    360     case TypeOf:
    361     case LogicalNot:
    362554    case CallObjectConstructor:
    363555    case ToPrimitive:
    364     case ToString:
    365556    case ToNumber:
    366557    case ToNumeric:
    367558    case ToObject:
    368559    case NumberToStringWithRadix:
    369     case NumberToStringWithValidRadixConstant:
    370560    case SetFunctionName:
    371     case StrCat:
    372     case CallStringConstructor:
    373561    case NewStringObject:
    374     case MakeRope:
    375562    case InByVal:
    376563    case InById:
     
    382569    case CreateClonedArguments:
    383570    case CreateArgumentsButterfly:
    384     case GetFromArguments:
    385     case GetArgument:
    386571    case PutToArguments:
    387572    case NewFunction:
     
    408593    case LogShadowChickenPrologue:
    409594    case LogShadowChickenTail:
    410     case StringFromCharCode:
    411595    case NewTypedArray:
    412596    case Unreachable:
    413     case ExtractOSREntryLocal:
    414     case ExtractCatchLocal:
    415597    case ClearCatchLocals:
    416598    case CheckTierUpInLoop:
     
    420602    case InvalidationPoint:
    421603    case NotifyWrite:
    422     case CheckInBounds:
    423     case ConstantStoragePointer:
    424     case Check:
    425     case CheckVarargs:
    426604    case MultiPutByOffset:
    427     case ValueRep:
    428     case DoubleRep:
    429     case Int52Rep:
    430     case BooleanToNumber:
    431     case FiatInt52:
    432605    case GetEnumerableLength:
    433606    case HasGenericProperty:
    434607    case HasStructureProperty:
    435     case HasIndexedProperty:
    436608    case GetDirectPname:
    437609    case GetPropertyEnumerator:
    438     case GetEnumeratorStructurePname:
    439     case GetEnumeratorGenericPname:
    440     case ToIndexString:
    441610    case PhantomNewObject:
    442611    case PhantomNewFunction:
     
    447616    case PhantomNewRegexp:
    448617    case PutHint:
    449     case CheckStructureImmediate:
    450618    case MaterializeNewObject:
    451619    case MaterializeCreateActivation:
     
    456624    case PhantomNewArrayBuffer:
    457625    case PhantomClonedArguments:
    458     case GetMyArgumentByVal:
    459     case GetMyArgumentByValOutOfBounds:
    460626    case ForwardVarargs:
    461627    case CreateRest:
    462     case GetPrototypeOf:
    463     case StringReplace:
    464     case StringReplaceRegExp:
    465     case GetRegExpObjectLastIndex:
    466628    case SetRegExpObjectLastIndex:
    467629    case RecordRegExpCachedResult:
     
    470632    case ResolveScopeForHoistingFuncDeclInEval:
    471633    case ResolveScope:
    472     case MapHash:
    473     case NormalizeMapKey:
    474634    case StringValueOf:
    475     case StringSlice:
    476     case ToLowerCase:
    477     case GetMapBucket:
    478     case GetMapBucketHead:
    479     case GetMapBucketNext:
    480     case LoadKeyFromMapBucket:
    481     case LoadValueFromMapBucket:
    482     case ExtractValueFromWeakMapGet:
    483     case WeakMapGet:
    484635    case WeakSetAdd:
    485636    case WeakMapSet:
     
    493644    case AtomicsSub:
    494645    case AtomicsXor:
    495     case AtomicsIsLockFree:
    496646    case InitializeEntrypointArguments:
    497     case MatchStructure:
    498     case DateGetInt32OrNaN:
    499     case DateGetTime:
    500     case DataViewGetInt:
    501     case DataViewGetFloat:
    502         return true;
    503 
    504     case GetButterfly:
    505         return state.forNode(node->child1()).isType(SpecObject);
    506 
    507     case ArraySlice:
    508     case ArrayIndexOf: {
    509         // You could plausibly move this code around as long as you proved the
    510         // incoming array base structure is an original array at the hoisted location.
    511         // Instead of doing that extra work, we just conservatively return false.
    512         return false;
    513     }
    514 
    515     case GetGetter:
    516     case GetSetter: {
    517         if (!state.forNode(node->child1()).isType(SpecCell))
    518             return false;
    519         StructureAbstractValue& value = state.forNode(node->child1()).m_structure;
    520         if (value.isInfinite() || value.size() != 1)
    521             return false;
    522 
    523         return value[0].get() == graph.m_vm.getterSetterStructure;
    524     }
    525 
    526     case BottomValue:
    527         // If in doubt, assume that this isn't safe to execute, just because we have no way of
    528         // compiling this node.
    529         return false;
    530 
    531     case StoreBarrier:
    532     case FencedStoreBarrier:
    533     case PutStructure:
    534     case NukeStructureAndSetButterfly:
    535         // We conservatively assume that these cannot be put anywhere, which forces the compiler to
    536         // keep them exactly where they were. This is sort of overkill since the clobberize effects
    537         // already force these things to be ordered precisely. I'm just not confident enough in my
    538         // effect based memory model to rely solely on that right now.
    539         return false;
    540        
    541     case FilterCallLinkStatus:
    542     case FilterGetByStatus:
    543     case FilterPutByIdStatus:
    544     case FilterInByIdStatus:
    545         // We don't want these to be moved anywhere other than where we put them, since we want them
    546         // to capture "profiling" at the point in control flow here the user put them.
    547         return false;
    548 
    549     case GetByVal:
    550     case GetIndexedPropertyStorage:
    551     case GetArrayLength:
    552     case GetVectorLength:
    553     case ArrayPop:
    554     case StringCharAt:
    555     case StringCharCodeAt:
    556     case StringCodePointAt:
    557         return node->arrayMode().alreadyChecked(graph, node, state.forNode(graph.child(node, 0)));
    558 
    559     case ArrayPush:
    560         return node->arrayMode().alreadyChecked(graph, node, state.forNode(graph.varArgChild(node, 1)));
    561 
    562     case GetTypedArrayByteOffset:
    563         return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
    564            
    565     case PutByValDirect:
    566     case PutByVal:
    567     case PutByValAlias:
    568         return node->arrayMode().modeForPut().alreadyChecked(
    569             graph, node, state.forNode(graph.varArgChild(node, 0)));
    570 
    571     case AllocatePropertyStorage:
    572     case ReallocatePropertyStorage:
    573         return state.forNode(node->child1()).m_structure.isSubsetOf(
    574             RegisteredStructureSet(node->transition()->previous));
    575        
    576     case GetGetterSetterByOffset: {
    577         // If it's an inline property, we need to make sure it's a cell before trusting what the structure set tells us.
    578         if (node->child1().node() == node->child2().node() && !state.forNode(node->child2()).isType(SpecCell))
    579             return false;
    580 
    581         StorageAccessData& data = node->storageAccessData();
    582         auto* uid = graph.identifiers()[data.identifierNumber];
    583         PropertyOffset desiredOffset = data.offset;
    584         StructureAbstractValue& value = state.forNode(node->child2()).m_structure;
    585         if (value.isInfinite())
    586             return false;
    587         for (unsigned i = value.size(); i--;) {
    588             Structure* thisStructure = value[i].get();
    589             if (thisStructure->isUncacheableDictionary())
    590                 return false;
    591             unsigned attributes = 0;
    592             PropertyOffset checkOffset = thisStructure->getConcurrently(uid, attributes);
    593             if (checkOffset != desiredOffset || !(attributes & PropertyAttribute::Accessor))
    594                 return false;
    595         }
    596         return true;
    597     }
    598 
    599     case GetByOffset:
    600     case PutByOffset: {
    601         // If it's an inline property, we need to make sure it's a cell before trusting what the structure set tells us.
    602         if (node->child1().node() == node->child2().node() && !state.forNode(node->child2()).isType(SpecCell))
    603             return false;
    604 
    605         StorageAccessData& data = node->storageAccessData();
    606         PropertyOffset offset = data.offset;
    607         // Graph::isSafeToLoad() is all about proofs derived from PropertyConditions. Those don't
    608         // know anything about inferred types. But if we have a proof derived from watching a
    609         // structure that has a type proof, then the next case below will deal with it.
    610         if (state.structureClobberState() == StructuresAreWatched) {
    611             if (JSObject* knownBase = node->child2()->dynamicCastConstant<JSObject*>(graph.m_vm)) {
    612                 if (graph.isSafeToLoad(knownBase, offset))
    613                     return true;
    614             }
    615         }
    616        
    617         StructureAbstractValue& value = state.forNode(node->child2()).m_structure;
    618         if (value.isInfinite())
    619             return false;
    620         for (unsigned i = value.size(); i--;) {
    621             Structure* thisStructure = value[i].get();
    622             if (thisStructure->isUncacheableDictionary())
    623                 return false;
    624             if (!thisStructure->isValidOffset(offset))
    625                 return false;
    626         }
    627         return true;
    628     }
    629        
    630     case MultiGetByOffset: {
    631         // We can't always guarantee that the MultiGetByOffset is safe to execute if it
    632         // contains loads from prototypes. If the load requires a check in IR, which is rare, then
    633         // we currently claim that we don't know if it's safe to execute because finding that
    634         // check in the abstract state would be hard. If the load requires watchpoints, we just
    635         // check if we're not in a clobbered state (i.e. in between a side effect and an
    636         // invalidation point).
    637         for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
    638             GetByOffsetMethod method = getCase.method();
    639             switch (method.kind()) {
    640             case GetByOffsetMethod::Invalid:
    641                 RELEASE_ASSERT_NOT_REACHED();
    642                 break;
    643             case GetByOffsetMethod::Constant: // OK because constants are always safe to execute.
    644             case GetByOffsetMethod::Load: // OK because the MultiGetByOffset has its own checks for loading from self.
    645                 break;
    646             case GetByOffsetMethod::LoadFromPrototype:
    647                 // Only OK if the state isn't clobbered. That's almost always the case.
    648                 if (state.structureClobberState() != StructuresAreWatched)
    649                     return false;
    650                 if (!graph.isSafeToLoad(method.prototype()->cast<JSObject*>(), method.offset()))
    651                     return false;
    652                 break;
    653             }
    654         }
    655         return true;
    656     }
    657 
     647    case ValueNegate:
    658648    case GetInternalField:
    659649    case PutInternalField:
    660         return false;
    661 
    662650    case DataViewSet:
    663         return false;
    664 
    665651    case SetAdd:
    666652    case MapSet:
    667653        return false;
     654
     655    case Inc:
     656    case Dec:
     657        return node->child1().useKind() != UntypedUse;
     658
     659    case ValueBitAnd:
     660    case ValueBitXor:
     661    case ValueBitOr:
     662    case ValueBitLShift:
     663    case ValueBitRShift:
     664    case ValueAdd:
     665    case ValueSub:
     666    case ValueMul:
     667    case ValueDiv:
     668    case ValueMod:
     669    case ValuePow:
     670        return node->isBinaryUseKind(BigIntUse);
     671
     672    case ValueBitNot:
     673        return node->child1().useKind() == BigIntUse;
    668674
    669675    case LastNodeType:
Note: See TracChangeset for help on using the changeset viewer.