|
25 | 25 | package com.oracle.graal.pointsto.flow.context.bytecode;
|
26 | 26 |
|
27 | 27 | import static com.oracle.graal.pointsto.util.ListUtils.getTLArrayList;
|
28 |
| -import static jdk.vm.ci.common.JVMCIError.guarantee; |
29 | 28 |
|
30 | 29 | import java.lang.reflect.Modifier;
|
31 |
| -import java.util.ArrayList; |
32 | 30 | import java.util.Arrays;
|
33 | 31 | import java.util.BitSet;
|
34 |
| -import java.util.Collection; |
35 |
| -import java.util.Collections; |
36 |
| -import java.util.concurrent.ConcurrentHashMap; |
37 |
| -import java.util.concurrent.ConcurrentMap; |
38 | 32 |
|
39 | 33 | import org.graalvm.compiler.options.OptionValues;
|
40 | 34 |
|
|
50 | 44 | import com.oracle.graal.pointsto.flow.CallSiteSensitiveMethodTypeFlow;
|
51 | 45 | import com.oracle.graal.pointsto.flow.CloneTypeFlow;
|
52 | 46 | import com.oracle.graal.pointsto.flow.ContextInsensitiveFieldTypeFlow;
|
53 |
| -import com.oracle.graal.pointsto.flow.DirectInvokeTypeFlow; |
54 | 47 | import com.oracle.graal.pointsto.flow.FieldTypeFlow;
|
55 | 48 | import com.oracle.graal.pointsto.flow.InvokeTypeFlow;
|
56 | 49 | import com.oracle.graal.pointsto.flow.MethodFlowsGraph;
|
|
78 | 71 | import com.oracle.graal.pointsto.typestore.SplitFieldTypeStore;
|
79 | 72 | import com.oracle.graal.pointsto.typestore.UnifiedArrayElementsTypeStore;
|
80 | 73 | import com.oracle.graal.pointsto.typestore.UnifiedFieldTypeStore;
|
81 |
| -import com.oracle.graal.pointsto.util.AnalysisError; |
82 | 74 | import com.oracle.graal.pointsto.util.ListUtils;
|
83 | 75 | import com.oracle.graal.pointsto.util.ListUtils.UnsafeArrayList;
|
84 | 76 | import com.oracle.graal.pointsto.util.ListUtils.UnsafeArrayListClosable;
|
@@ -385,305 +377,10 @@ public void registerAsImplementationInvoked(InvokeTypeFlow invoke, MethodFlowsGr
|
385 | 377 | }
|
386 | 378 | }
|
387 | 379 |
|
388 |
| - private static BytecodeAnalysisContextPolicy contextPolicy(BigBang bb) { |
| 380 | + static BytecodeAnalysisContextPolicy contextPolicy(BigBang bb) { |
389 | 381 | return ((BytecodeSensitiveAnalysisPolicy) bb.analysisPolicy()).getContextPolicy();
|
390 | 382 | }
|
391 | 383 |
|
392 |
| - /** |
393 |
| - * Bytecode context sensitive implementation of the invoke virtual type flow update. |
394 |
| - * |
395 |
| - * TODO Can we merge the slow path (i.e., this class) and fast path (i.e., the default, context |
396 |
| - * insensitive virtual invoke implementation) to be able to fall back to fast path when context |
397 |
| - * sensitivity is disabled or reaches budget threshold? |
398 |
| - */ |
399 |
| - private static class BytecodeSensitiveVirtualInvokeTypeFlow extends AbstractVirtualInvokeTypeFlow { |
400 |
| - |
401 |
| - /* |
402 |
| - * Remember all the callee clones that were already linked in each context at this |
403 |
| - * invocation site to avoid redundant relinking. MethodFlows is unique for each method type |
404 |
| - * flow and context combination. |
405 |
| - */ |
406 |
| - private final ConcurrentMap<MethodFlowsGraph, Object> calleesFlows = new ConcurrentHashMap<>(4, 0.75f, 1); |
407 |
| - private final AnalysisContext callerContext; |
408 |
| - |
409 |
| - protected BytecodeSensitiveVirtualInvokeTypeFlow(BytecodePosition invokeLocation, AnalysisType receiverType, PointsToAnalysisMethod targetMethod, |
410 |
| - TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, BytecodeLocation location) { |
411 |
| - super(invokeLocation, receiverType, targetMethod, actualParameters, actualReturn, location); |
412 |
| - callerContext = null; |
413 |
| - } |
414 |
| - |
415 |
| - protected BytecodeSensitiveVirtualInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph methodFlows, BytecodeSensitiveVirtualInvokeTypeFlow original) { |
416 |
| - super(bb, methodFlows, original); |
417 |
| - callerContext = ((MethodFlowsGraphClone) methodFlows).context(); |
418 |
| - } |
419 |
| - |
420 |
| - @Override |
421 |
| - public TypeFlow<BytecodePosition> copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) { |
422 |
| - return new BytecodeSensitiveVirtualInvokeTypeFlow(bb, methodFlows, this); |
423 |
| - } |
424 |
| - |
425 |
| - @Override |
426 |
| - public void onObservedUpdate(PointsToAnalysis bb) { |
427 |
| - assert this.isClone() || this.isContextInsensitive(); |
428 |
| - |
429 |
| - /* |
430 |
| - * Capture the current receiver state before the update. The type state objects are |
431 |
| - * immutable and a later call to getState() can yield a different value. |
432 |
| - */ |
433 |
| - TypeState receiverState = getReceiver().getState(); |
434 |
| - receiverState = filterReceiverState(bb, receiverState); |
435 |
| - |
436 |
| - if (receiverState.isEmpty() || receiverState.isNull()) { |
437 |
| - return; |
438 |
| - } |
439 |
| - |
440 |
| - /* Use the tandem types - objects iterator. */ |
441 |
| - TypesObjectsIterator toi = new TypesObjectsIterator(receiverState); |
442 |
| - while (toi.hasNextType()) { |
443 |
| - AnalysisType type = toi.nextType(); |
444 |
| - |
445 |
| - AnalysisMethod method = type.resolveConcreteMethod(getTargetMethod()); |
446 |
| - if (method == null || Modifier.isAbstract(method.getModifiers())) { |
447 |
| - /* |
448 |
| - * Type states can be conservative, i.e., we can have receiver types that do not |
449 |
| - * implement the method. Just ignore such types. |
450 |
| - */ |
451 |
| - while (toi.hasNextObject(type)) { |
452 |
| - // skip the rest of the objects of the same type |
453 |
| - toi.nextObject(type); |
454 |
| - } |
455 |
| - continue; |
456 |
| - } |
457 |
| - |
458 |
| - assert !Modifier.isAbstract(method.getModifiers()); |
459 |
| - |
460 |
| - CallSiteSensitiveMethodTypeFlow callee = (CallSiteSensitiveMethodTypeFlow) PointsToAnalysis.assertPointsToAnalysisMethod(method).getTypeFlow(); |
461 |
| - |
462 |
| - while (toi.hasNextObject(type)) { |
463 |
| - AnalysisObject actualReceiverObject = toi.nextObject(type); |
464 |
| - |
465 |
| - // get the context based on the actualReceiverObject |
466 |
| - AnalysisContext calleeContext = contextPolicy(bb).calleeContext(bb, actualReceiverObject, (BytecodeAnalysisContext) callerContext, callee); |
467 |
| - |
468 |
| - MethodFlowsGraph calleeFlows = callee.addContext(bb, calleeContext, this); |
469 |
| - |
470 |
| - if (calleesFlows.put(calleeFlows, Boolean.TRUE) == null) { |
471 |
| - /* register the analysis method as a callee for this invoke */ |
472 |
| - addCallee(calleeFlows.getMethod()); |
473 |
| - /* linkCallee() does not link the receiver object. */ |
474 |
| - linkCallee(bb, false, calleeFlows); |
475 |
| - } |
476 |
| - |
477 |
| - updateReceiver(bb, calleeFlows, actualReceiverObject); |
478 |
| - } |
479 |
| - |
480 |
| - } |
481 |
| - } |
482 |
| - |
483 |
| - @Override |
484 |
| - public void onObservedSaturated(PointsToAnalysis bb, TypeFlow<?> observed) { |
485 |
| - /* When the receiver flow saturates start observing the flow of the receiver type. */ |
486 |
| - replaceObservedWith(bb, receiverType); |
487 |
| - } |
488 |
| - |
489 |
| - @Override |
490 |
| - public Collection<MethodFlowsGraph> getCalleesFlows(PointsToAnalysis bb) { |
491 |
| - return new ArrayList<>(calleesFlows.keySet()); |
492 |
| - } |
493 |
| - } |
494 |
| - |
495 |
| - /** |
496 |
| - * This is a special iterator for the type state. It iterates over analysis types and objects in |
497 |
| - * tandem doing a single pass over the objects array. It relies on the fact that the types and |
498 |
| - * objects are sorted by ID. It is meant for situations where the types need some pre-processing |
499 |
| - * or checking before processing their respective objects, e.g., as in virtual method resolution |
500 |
| - * for InvokeTypeFlow. It those situations it avoids iterating over the types first and then |
501 |
| - * searching for the range of objects corresponding to that type. When only objects, or only |
502 |
| - * types, or only objects of a certain type need to be iterated use the other provided |
503 |
| - * iterators. A correct use of this iterator is as follows: |
504 |
| - * |
505 |
| - * <code> |
506 |
| - * TypesObjectsIterator toi = state.getTypesObjectsIterator(); |
507 |
| - * |
508 |
| - * while(toi.hasNextType()) { |
509 |
| - * AnalysisType t = toi.nextType(); |
510 |
| - * // use type here |
511 |
| - * |
512 |
| - * while(toi.hasNextObject(t)) { |
513 |
| - * AnalysisObject o = toi.nextObject(t); |
514 |
| - * // use object here |
515 |
| - * } |
516 |
| - * } |
517 |
| - * </code> |
518 |
| - */ |
519 |
| - public static class TypesObjectsIterator { |
520 |
| - private final int typesCount; |
521 |
| - private final AnalysisObject[] objects; |
522 |
| - private int typeIdx = 0; |
523 |
| - private int objectIdx = 0; |
524 |
| - |
525 |
| - public TypesObjectsIterator(TypeState state) { |
526 |
| - typesCount = state.typesCount(); |
527 |
| - objects = objectsArray(state); |
528 |
| - } |
529 |
| - |
530 |
| - private static AnalysisObject[] objectsArray(TypeState state) { |
531 |
| - if (state.isEmpty() || state.isNull()) { |
532 |
| - return AnalysisObject.EMPTY_ARRAY; |
533 |
| - } |
534 |
| - if (state instanceof ContextSensitiveSingleTypeState) { |
535 |
| - return ((ContextSensitiveSingleTypeState) state).objects; |
536 |
| - } |
537 |
| - if (state instanceof ContextSensitiveMultiTypeState) { |
538 |
| - return ((ContextSensitiveMultiTypeState) state).objects; |
539 |
| - } |
540 |
| - throw AnalysisError.shouldNotReachHere(); |
541 |
| - } |
542 |
| - |
543 |
| - /** |
544 |
| - * Returns true if there is a next type in the objects array, i.e., there are objects of a |
545 |
| - * type other than the current type. |
546 |
| - */ |
547 |
| - public boolean hasNextType() { |
548 |
| - return typeIdx < typesCount; |
549 |
| - } |
550 |
| - |
551 |
| - /** Returns true if there are more objects of the current type. */ |
552 |
| - public boolean hasNextObject(AnalysisType type) { |
553 |
| - return objectIdx < objects.length && objects[objectIdx].getTypeId() == type.getId(); |
554 |
| - } |
555 |
| - |
556 |
| - /** Gets the next type. */ |
557 |
| - public AnalysisType nextType() { |
558 |
| - /* Check that there is a next type. */ |
559 |
| - assert hasNextType(); |
560 |
| - /* Increment the type index. */ |
561 |
| - typeIdx++; |
562 |
| - /* Return the type at the 'objectIdx. */ |
563 |
| - return objects[objectIdx].type(); |
564 |
| - } |
565 |
| - |
566 |
| - /** Gets the next object. */ |
567 |
| - public AnalysisObject nextObject(AnalysisType type) { |
568 |
| - /* Check that there is a next object of the desired type. */ |
569 |
| - assert hasNextObject(type); |
570 |
| - /* Return the next object and increment objectIdx. */ |
571 |
| - return objects[objectIdx++]; |
572 |
| - } |
573 |
| - } |
574 |
| - |
575 |
| - private static final class BytecodeSensitiveStaticInvokeTypeFlow extends AbstractStaticInvokeTypeFlow { |
576 |
| - |
577 |
| - private AnalysisContext calleeContext; |
578 |
| - /** |
579 |
| - * Context of the caller. |
580 |
| - */ |
581 |
| - private AnalysisContext callerContext; |
582 |
| - |
583 |
| - private BytecodeSensitiveStaticInvokeTypeFlow(BytecodePosition invokeLocation, AnalysisType receiverType, PointsToAnalysisMethod targetMethod, |
584 |
| - TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, BytecodeLocation location) { |
585 |
| - super(invokeLocation, receiverType, targetMethod, actualParameters, actualReturn, location); |
586 |
| - calleeContext = null; |
587 |
| - } |
588 |
| - |
589 |
| - private BytecodeSensitiveStaticInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph methodFlows, BytecodeSensitiveStaticInvokeTypeFlow original) { |
590 |
| - super(bb, methodFlows, original); |
591 |
| - this.callerContext = ((MethodFlowsGraphClone) methodFlows).context(); |
592 |
| - } |
593 |
| - |
594 |
| - @Override |
595 |
| - public TypeFlow<BytecodePosition> copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) { |
596 |
| - return new BytecodeSensitiveStaticInvokeTypeFlow(bb, methodFlows, this); |
597 |
| - } |
598 |
| - |
599 |
| - @Override |
600 |
| - public void update(PointsToAnalysis bb) { |
601 |
| - assert this.isClone(); |
602 |
| - /* The static invokes should be updated only once and the callee should be null. */ |
603 |
| - guarantee(callee == null, "static invoke updated multiple times!"); |
604 |
| - |
605 |
| - // Unlinked methods can not be parsed |
606 |
| - if (!targetMethod.getWrapped().getDeclaringClass().isLinked()) { |
607 |
| - return; |
608 |
| - } |
609 |
| - |
610 |
| - /* |
611 |
| - * Initialize the callee lazily so that if the invoke flow is not reached in this |
612 |
| - * context, i.e. for this clone, there is no callee linked/ |
613 |
| - */ |
614 |
| - callee = targetMethod.getTypeFlow(); |
615 |
| - // set the callee in the original invoke too |
616 |
| - ((DirectInvokeTypeFlow) originalInvoke).callee = callee; |
617 |
| - |
618 |
| - calleeContext = contextPolicy(bb).staticCalleeContext(bb, location, (BytecodeAnalysisContext) callerContext, callee); |
619 |
| - MethodFlowsGraph calleeFlows = ((CallSiteSensitiveMethodTypeFlow) callee).addContext(bb, calleeContext, this); |
620 |
| - linkCallee(bb, true, calleeFlows); |
621 |
| - } |
622 |
| - |
623 |
| - @Override |
624 |
| - public Collection<MethodFlowsGraph> getCalleesFlows(PointsToAnalysis bb) { |
625 |
| - if (callee == null || calleeContext == null) { |
626 |
| - /* This static invoke was not updated. */ |
627 |
| - return Collections.emptyList(); |
628 |
| - } else { |
629 |
| - MethodFlowsGraph methodFlows = ((CallSiteSensitiveMethodTypeFlow) callee).getFlows(calleeContext); |
630 |
| - return Collections.singletonList(methodFlows); |
631 |
| - } |
632 |
| - } |
633 |
| - } |
634 |
| - |
635 |
| - private static final class BytecodeSensitiveSpecialInvokeTypeFlow extends AbstractSpecialInvokeTypeFlow { |
636 |
| - |
637 |
| - /** |
638 |
| - * Contexts of the resolved method. |
639 |
| - */ |
640 |
| - private final ConcurrentMap<MethodFlowsGraph, Object> calleesFlows = new ConcurrentHashMap<>(4, 0.75f, 1); |
641 |
| - |
642 |
| - /** |
643 |
| - * Context of the caller. |
644 |
| - */ |
645 |
| - private AnalysisContext callerContext; |
646 |
| - |
647 |
| - BytecodeSensitiveSpecialInvokeTypeFlow(BytecodePosition invokeLocation, AnalysisType receiverType, PointsToAnalysisMethod targetMethod, |
648 |
| - TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, BytecodeLocation location) { |
649 |
| - super(invokeLocation, receiverType, targetMethod, actualParameters, actualReturn, location); |
650 |
| - } |
651 |
| - |
652 |
| - private BytecodeSensitiveSpecialInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph methodFlows, BytecodeSensitiveSpecialInvokeTypeFlow original) { |
653 |
| - super(bb, methodFlows, original); |
654 |
| - this.callerContext = ((MethodFlowsGraphClone) methodFlows).context(); |
655 |
| - } |
656 |
| - |
657 |
| - @Override |
658 |
| - public TypeFlow<BytecodePosition> copy(PointsToAnalysis bb, MethodFlowsGraph methodFlows) { |
659 |
| - return new BytecodeSensitiveSpecialInvokeTypeFlow(bb, methodFlows, this); |
660 |
| - } |
661 |
| - |
662 |
| - @Override |
663 |
| - public void onObservedUpdate(PointsToAnalysis bb) { |
664 |
| - /* The receiver state has changed. Process the invoke. */ |
665 |
| - |
666 |
| - initCallee(); |
667 |
| - |
668 |
| - TypeState invokeState = filterReceiverState(bb, getReceiver().getState()); |
669 |
| - for (AnalysisObject receiverObject : invokeState.objects(bb)) { |
670 |
| - AnalysisContext calleeContext = contextPolicy(bb).calleeContext(bb, receiverObject, (BytecodeAnalysisContext) callerContext, callee); |
671 |
| - MethodFlowsGraph calleeFlows = ((CallSiteSensitiveMethodTypeFlow) callee).addContext(bb, calleeContext, this); |
672 |
| - |
673 |
| - if (calleesFlows.putIfAbsent(calleeFlows, Boolean.TRUE) == null) { |
674 |
| - linkCallee(bb, false, calleeFlows); |
675 |
| - } |
676 |
| - |
677 |
| - updateReceiver(bb, calleeFlows, receiverObject); |
678 |
| - } |
679 |
| - } |
680 |
| - |
681 |
| - @Override |
682 |
| - public Collection<MethodFlowsGraph> getCalleesFlows(PointsToAnalysis bb) { |
683 |
| - return new ArrayList<>(calleesFlows.keySet()); |
684 |
| - } |
685 |
| - } |
686 |
| - |
687 | 384 | @Override
|
688 | 385 | public TypeState forContextInsensitiveTypeState(PointsToAnalysis bb, TypeState state) {
|
689 | 386 | if (state.isEmpty() || state.isNull()) {
|
|
0 commit comments