Changeset 256411 in webkit
- Timestamp:
- Feb 11, 2020 5:00:10 PM (4 years ago)
- Location:
- branches/safari-609-branch/Source/JavaScriptCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/safari-609-branch/Source/JavaScriptCore/ChangeLog
r256248 r256411 1 2020-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 1 22 2020-02-10 Kocsen Chung <kocsen_chung@apple.com> 2 23 -
branches/safari-609-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r256248 r256411 174 174 } 175 175 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. 178 180 179 181 switch (node->op()) { 182 // FIXME: Audit these: 183 // https://bugs.webkit.org/show_bug.cgi?id=207075 180 184 case JSConstant: 181 185 case DoubleConstant: … … 184 188 case Identity: 185 189 case IdentityWithProfile: 186 case ToThis:187 case CreateThis:188 case CreatePromise:189 case CreateGenerator:190 case CreateAsyncGenerator:191 case ObjectCreate:192 case ObjectKeys:193 190 case GetCallee: 194 case SetCallee:195 191 case GetArgumentCountIncludingThis: 196 case SetArgumentCountIncludingThis:197 192 case GetRestLength: 198 193 case GetLocal: 199 case SetLocal:200 case PutStack:201 case KillStack:202 194 case GetStack: 203 case MovHint:204 case ZombieHint:205 195 case ExitOK: 206 196 case Phantom: 207 case Upsilon:208 case Phi:209 case Flush:210 case PhantomLocal:211 case SetArgumentDefinitely:212 case SetArgumentMaybe:213 197 case ArithBitNot: 214 198 case ArithBitAnd: … … 241 225 case ArithTrunc: 242 226 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: 259 495 case DeleteById: 260 496 case DeleteByVal: … … 277 513 case DefineDataProperty: 278 514 case DefineAccessorProperty: 279 case CheckStructure:280 case CheckStructureOrEmpty:281 case GetExecutable:282 case CallDOMGetter:283 case CallDOM:284 case CheckSubClass:285 case CheckArray:286 515 case Arrayify: 287 516 case ArrayifyToStructure: 288 case GetScope:289 case SkipScope:290 case GetGlobalObject:291 case GetGlobalThis:292 case GetClosureVar:293 517 case PutClosureVar: 294 case GetGlobalVar:295 case GetGlobalLexicalVariable:296 518 case PutGlobalVariable: 297 case CheckCell:298 519 case CheckBadCell: 299 case CheckNotEmpty:300 case AssertNotEmpty:301 case CheckIdent:302 520 case RegExpExec: 303 521 case RegExpExecNonGlobalOrSticky: … … 305 523 case RegExpMatchFast: 306 524 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:317 525 case Call: 318 526 case DirectCall: … … 342 550 case ProfileType: 343 551 case ProfileControlFlow: 344 case CheckTypeInfoFlags:345 case ParseInt:346 case OverridesHasInstance:347 552 case InstanceOf: 348 553 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:362 554 case CallObjectConstructor: 363 555 case ToPrimitive: 364 case ToString:365 556 case ToNumber: 366 557 case ToNumeric: 367 558 case ToObject: 368 559 case NumberToStringWithRadix: 369 case NumberToStringWithValidRadixConstant:370 560 case SetFunctionName: 371 case StrCat:372 case CallStringConstructor:373 561 case NewStringObject: 374 case MakeRope:375 562 case InByVal: 376 563 case InById: … … 382 569 case CreateClonedArguments: 383 570 case CreateArgumentsButterfly: 384 case GetFromArguments:385 case GetArgument:386 571 case PutToArguments: 387 572 case NewFunction: … … 408 593 case LogShadowChickenPrologue: 409 594 case LogShadowChickenTail: 410 case StringFromCharCode:411 595 case NewTypedArray: 412 596 case Unreachable: 413 case ExtractOSREntryLocal:414 case ExtractCatchLocal:415 597 case ClearCatchLocals: 416 598 case CheckTierUpInLoop: … … 420 602 case InvalidationPoint: 421 603 case NotifyWrite: 422 case CheckInBounds:423 case ConstantStoragePointer:424 case Check:425 case CheckVarargs:426 604 case MultiPutByOffset: 427 case ValueRep:428 case DoubleRep:429 case Int52Rep:430 case BooleanToNumber:431 case FiatInt52:432 605 case GetEnumerableLength: 433 606 case HasGenericProperty: 434 607 case HasStructureProperty: 435 case HasIndexedProperty:436 608 case GetDirectPname: 437 609 case GetPropertyEnumerator: 438 case GetEnumeratorStructurePname:439 case GetEnumeratorGenericPname:440 case ToIndexString:441 610 case PhantomNewObject: 442 611 case PhantomNewFunction: … … 447 616 case PhantomNewRegexp: 448 617 case PutHint: 449 case CheckStructureImmediate:450 618 case MaterializeNewObject: 451 619 case MaterializeCreateActivation: … … 456 624 case PhantomNewArrayBuffer: 457 625 case PhantomClonedArguments: 458 case GetMyArgumentByVal:459 case GetMyArgumentByValOutOfBounds:460 626 case ForwardVarargs: 461 627 case CreateRest: 462 case GetPrototypeOf:463 case StringReplace:464 case StringReplaceRegExp:465 case GetRegExpObjectLastIndex:466 628 case SetRegExpObjectLastIndex: 467 629 case RecordRegExpCachedResult: … … 470 632 case ResolveScopeForHoistingFuncDeclInEval: 471 633 case ResolveScope: 472 case MapHash:473 case NormalizeMapKey:474 634 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:484 635 case WeakSetAdd: 485 636 case WeakMapSet: … … 493 644 case AtomicsSub: 494 645 case AtomicsXor: 495 case AtomicsIsLockFree:496 646 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: 658 648 case GetInternalField: 659 649 case PutInternalField: 660 return false;661 662 650 case DataViewSet: 663 return false;664 665 651 case SetAdd: 666 652 case MapSet: 667 653 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; 668 674 669 675 case LastNodeType:
Note: See TracChangeset
for help on using the changeset viewer.