예제 #1
0
  void compareAllVariables(String className, String methodName) throws Exception {
    println("compareAllVariables for method: " + className + "." + methodName);
    Method method = getMethod(className, methodName);
    List localVars;
    try {
      localVars = method.variables();
      println("\n Success: got a list of all method variables: " + methodName);
    } catch (com.sun.jdi.AbsentInformationException ex) {
      failure("\n AbsentInformationException has been thrown");
      return;
    }

    // We consider N*N combinations for set of N variables
    int index1 = 0;
    for (Iterator it1 = localVars.iterator(); it1.hasNext(); index1++) {
      LocalVariable lv1 = (LocalVariable) it1.next();

      int index2 = 0;
      for (Iterator it2 = localVars.iterator(); it2.hasNext(); index2++) {
        LocalVariable lv2 = (LocalVariable) it2.next();

        println("\n Two variables:");
        printVariable(lv1, index1);
        printVariable(lv2, index2);
        println("");
        if (index1 == index2) {
          compareTwoEqualVars(lv1, lv2);
        } else {
          compareTwoDifferentVars(lv1, lv2);
        }
      }
    }
    println("");
    return;
  }
예제 #2
0
  @Override
  public List<IWatchable> getVisibleWatchables() {
    try {
      StackFrame stackFrame = getStackFrame();
      List<IWatchable> result = new ArrayList<IWatchable>();

      if (stackFrame != null) {
        for (LocalVariable variable : stackFrame.visibleVariables()) {
          result.add(new JavaLocalVariable(variable, this, myClassFqName, myThreadReference));
        }

        ObjectReference thisObject = stackFrame.thisObject();
        if (thisObject != null) {
          result.add(new JavaThisObject(thisObject, this, myClassFqName, myThreadReference));
        } else {
          result.add(
              new JavaStaticContext(
                  getStackFrame().location().declaringType(), myClassFqName, myThreadReference));
        }
      }

      return result;
    } catch (InvalidStackFrameException ex) {
      LOG.warning(
          "InvalidStackFrameException",
          ex); // TODO something should be done here. See, for instance, how idea deals with those
               // exceptions
      return Collections.emptyList();
    } catch (AbsentInformationException ex) {
      // doing nothing, variables are just not available for us
      return Collections.emptyList();
    }
  }
예제 #3
0
  private void commandClear(StringTokenizer t) throws NoSessionException {
    if (!t.hasMoreTokens()) {
      // Print set breakpoints
      listEventRequests();
      return;
    }
    // ### need 'clear all'
    BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken());
    if (bpSpec != null) {
      List<EventRequestSpec> specs = runtime.eventRequestSpecs();

      if (specs.isEmpty()) {
        env.notice("No breakpoints set.");
      } else {
        List<EventRequestSpec> toDelete = new ArrayList<EventRequestSpec>();
        for (EventRequestSpec spec : specs) {
          if (spec.equals(bpSpec)) {
            toDelete.add(spec);
          }
        }
        // The request used for matching should be found
        if (toDelete.size() <= 1) {
          env.notice("No matching breakpoint set.");
        }
        for (EventRequestSpec spec : toDelete) {
          runtime.delete(spec);
        }
      }
    } else {
      env.error("Ill-formed breakpoint specification.");
    }
  }
예제 #4
0
 private void commandMethods(StringTokenizer t) throws NoSessionException {
   if (!t.hasMoreTokens()) {
     env.error("No class specified.");
     return;
   }
   String idClass = t.nextToken();
   ReferenceType cls = findClass(idClass);
   if (cls != null) {
     List<Method> methods = cls.allMethods();
     OutputSink out = env.getOutputSink();
     for (int i = 0; i < methods.size(); i++) {
       Method method = methods.get(i);
       out.print(method.declaringType().name() + " " + method.name() + "(");
       Iterator<String> it = method.argumentTypeNames().iterator();
       if (it.hasNext()) {
         while (true) {
           out.print(it.next());
           if (!it.hasNext()) {
             break;
           }
           out.print(", ");
         }
       }
       out.println(")");
     }
     out.show();
   } else {
     // ### Should validate class name syntax.
     env.failure("\"" + idClass + "\" is not a valid id or class name.");
   }
 }
예제 #5
0
파일: Env.java 프로젝트: NathanEEvans/api
 static ReferenceType getReferenceTypeFromToken(String idToken) {
   ReferenceType cls = null;
   if (Character.isDigit(idToken.charAt(0))) {
     cls = null;
   } else if (idToken.startsWith("*.")) {
     // This notation saves typing by letting the user omit leading
     // package names. The first
     // loaded class whose name matches this limited regular
     // expression is selected.
     idToken = idToken.substring(1);
     for (ReferenceType type : Env.vm().allClasses()) {
       if (type.name().endsWith(idToken)) {
         cls = type;
         break;
       }
     }
   } else {
     // It's a class name
     List<ReferenceType> classes = Env.vm().classesByName(idToken);
     if (classes.size() > 0) {
       // TO DO: handle multiples
       cls = classes.get(0);
     }
   }
   return cls;
 }
예제 #6
0
파일: Env.java 프로젝트: NathanEEvans/api
  static synchronized String sourceLine(Location location, int lineNumber) throws IOException {
    if (lineNumber == -1) {
      throw new IllegalArgumentException();
    }

    try {
      String fileName = location.sourceName();

      Iterator<SourceCode> iter = sourceCache.iterator();
      SourceCode code = null;
      while (iter.hasNext()) {
        SourceCode candidate = iter.next();
        if (candidate.fileName().equals(fileName)) {
          code = candidate;
          iter.remove();
          break;
        }
      }
      if (code == null) {
        BufferedReader reader = sourceReader(location);
        if (reader == null) {
          throw new FileNotFoundException(fileName);
        }
        code = new SourceCode(fileName, reader);
        if (sourceCache.size() == SOURCE_CACHE_SIZE) {
          sourceCache.remove(sourceCache.size() - 1);
        }
      }
      sourceCache.add(0, code);
      return code.sourceLine(lineNumber);
    } catch (AbsentInformationException e) {
      throw new IllegalArgumentException();
    }
  }
 private static AttachingConnector getAttachingConnectorFor(String transport) {
   List acs = Bootstrap.virtualMachineManager().attachingConnectors();
   AttachingConnector ac;
   int i, k = acs.size();
   for (i = 0; i < k; i++)
     if ((ac = (AttachingConnector) acs.get(i)).transport().name().equals(transport)) return ac;
   return null;
 }
예제 #8
0
파일: Env.java 프로젝트: NathanEEvans/api
 String sourceLine(int number) {
   int index = number - 1; // list is 0-indexed
   if (index >= sourceLines.size()) {
     return null;
   } else {
     return sourceLines.get(index);
   }
 }
예제 #9
0
파일: Env.java 프로젝트: NathanEEvans/api
 static void setExcludes(String excludeString) {
   StringTokenizer t = new StringTokenizer(excludeString, " ,;");
   List<String> list = new ArrayList<String>();
   while (t.hasMoreTokens()) {
     list.add(t.nextToken());
   }
   excludes = list;
 }
예제 #10
0
 private ReferenceType findClass(String pattern) throws NoSessionException {
   List<ReferenceType> results = runtime.findClassesMatchingPattern(pattern);
   if (results.size() > 0) {
     // ### Should handle multiple results sensibly.
     return results.get(0);
   }
   return null;
 }
예제 #11
0
 List<ReferenceType> inheritedTypes() {
   List<ReferenceType> inherited = new ArrayList<ReferenceType>();
   if (superclass() != null) {
     inherited.add(0, (ReferenceType) superclass()); /* insert at front */
   }
   for (ReferenceType rt : interfaces()) {
     inherited.add(rt);
   }
   return inherited;
 }
 EventRequest request(int eventCmd, int requestId) {
   List rl = requestList(eventCmd);
   for (int i = rl.size() - 1; i >= 0; i--) {
     EventRequestImpl er = (EventRequestImpl) rl.get(i);
     if (er.id == requestId) {
       return er;
     }
   }
   return null;
 }
예제 #13
0
 private ThreadReference[] threads() throws NoSessionException {
   if (threads == null) {
     ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup());
     List<ThreadReference> tlist = new ArrayList<ThreadReference>();
     while (ti.hasNext()) {
       tlist.add(ti.nextThread());
     }
     threads = tlist.toArray(new ThreadReference[tlist.size()]);
   }
   return threads;
 }
예제 #14
0
 private void dumpStack(ThreadReference thread, boolean showPC) {
   // ### Check for these.
   // env.failure("Thread no longer exists.");
   // env.failure("Target VM must be in interrupted state.");
   // env.failure("Current thread isn't suspended.");
   // ### Should handle extremely long stack traces sensibly for user.
   List<StackFrame> stack = null;
   try {
     stack = thread.frames();
   } catch (IncompatibleThreadStateException e) {
     env.failure("Thread is not suspended.");
   }
   // ### Fix this!
   // ### Previously mishandled cases where thread was not current.
   // ### Now, prints all of the stack regardless of current frame.
   int frameIndex = 0;
   // int frameIndex = context.getCurrentFrameIndex();
   if (stack == null) {
     env.failure("Thread is not running (no stack).");
   } else {
     OutputSink out = env.getOutputSink();
     int nFrames = stack.size();
     for (int i = frameIndex; i < nFrames; i++) {
       StackFrame frame = stack.get(i);
       Location loc = frame.location();
       Method meth = loc.method();
       out.print("  [" + (i + 1) + "] ");
       out.print(meth.declaringType().name());
       out.print('.');
       out.print(meth.name());
       out.print(" (");
       if (meth.isNative()) {
         out.print("native method");
       } else if (loc.lineNumber() != -1) {
         try {
           out.print(loc.sourceName());
         } catch (AbsentInformationException e) {
           out.print("<unknown>");
         }
         out.print(':');
         out.print(loc.lineNumber());
       }
       out.print(')');
       if (showPC) {
         long pc = loc.codeIndex();
         if (pc != -1) {
           out.print(", pc = " + pc);
         }
       }
       out.println();
     }
     out.show();
   }
 }
예제 #15
0
 /*
  * Find Connector by name
  */
 private static Connector findConnector(String name) {
   List connectors = Bootstrap.virtualMachineManager().allConnectors();
   Iterator iter = connectors.iterator();
   while (iter.hasNext()) {
     Connector connector = (Connector) iter.next();
     if (connector.name().equals(name)) {
       return connector;
     }
   }
   return null;
 }
예제 #16
0
  /** @return a list of threadGroupProxies */
  public List<ThreadGroupReferenceProxyImpl> topLevelThreadGroups() {
    List<ThreadGroupReference> list = getVirtualMachine().topLevelThreadGroups();

    List<ThreadGroupReferenceProxyImpl> result = new ArrayList<>(list.size());

    for (ThreadGroupReference threadGroup : list) {
      result.add(getThreadGroupReferenceProxy(threadGroup));
    }

    return result;
  }
예제 #17
0
  public static ClassFilter[] readFilters(List<Element> children) throws InvalidDataException {
    if (ContainerUtil.isEmpty(children)) {
      return ClassFilter.EMPTY_ARRAY;
    }

    ClassFilter[] filters = new ClassFilter[children.size()];
    for (int i = 0, size = children.size(); i < size; i++) {
      filters[i] = create(children.get(i));
    }
    return filters;
  }
예제 #18
0
  protected void runTests() throws Exception {
    /*
     * Get to the top of main()
     * to determine targetClass and mainThread
     */
    BreakpointEvent bpe = startToMain("GetLocalVariables2Targ");
    targetClass = bpe.location().declaringType();
    mainThread = bpe.thread();
    EventRequestManager erm = vm().eventRequestManager();

    bpe = resumeTo("GetLocalVariables2Targ", "bar", "(I)Z");

    /*
     * Inspect the stack frame for main(), not bar()...
     */
    StackFrame frame = bpe.thread().frame(1);
    List localVars = frame.visibleVariables();
    System.out.println("    Visible variables at this point are: ");
    for (Iterator it = localVars.iterator(); it.hasNext(); ) {
      LocalVariable lv = (LocalVariable) it.next();
      System.out.print(lv.name());
      System.out.print(" typeName: ");
      System.out.print(lv.typeName());
      System.out.print(" signature: ");
      System.out.print(lv.type().signature());
      System.out.print(" primitive type: ");
      System.out.println(lv.type().name());

      if ("command".equals(lv.name())) {
        failure("Failure: LocalVariable \"command\" should not be visible at this point.");
        if (lv.isVisible(frame)) {
          System.out.println("Failure: \"command.isvisible(frame)\" returned true.");
        }
      }
    }

    /*
     * resume the target listening for events
     */
    listenUntilVMDisconnect();

    /*
     * deal with results of test
     * if anything has called failure("foo") testFailed will be true
     */
    if (!testFailed) {
      println("GetLocalVariables2Test: passed");
    } else {
      throw new Exception("GetLocalVariables2Test: failed");
    }
  }
예제 #19
0
 private void listEventRequests() throws NoSessionException {
   // Print set breakpoints
   List<EventRequestSpec> specs = runtime.eventRequestSpecs();
   if (specs.isEmpty()) {
     env.notice("No breakpoints/watchpoints/exceptions set.");
   } else {
     OutputSink out = env.getOutputSink();
     out.println("Current breakpoints/watchpoints/exceptions set:");
     for (EventRequestSpec bp : specs) {
       out.println("\t" + bp);
     }
     out.show();
   }
 }
예제 #20
0
  public List<ClassType> subclasses() {
    List<ClassType> subs = new ArrayList<ClassType>();
    for (ReferenceType refType : vm.allClasses()) {
      if (refType instanceof ClassType) {
        ClassType clazz = (ClassType) refType;
        ClassType superclass = clazz.superclass();
        if ((superclass != null) && superclass.equals(this)) {
          subs.add((ClassType) refType);
        }
      }
    }

    return subs;
  }
예제 #21
0
  void addInterfaces(List<InterfaceType> list) {
    List<InterfaceType> immediate = interfaces();
    list.addAll(interfaces());

    Iterator iter = immediate.iterator();
    while (iter.hasNext()) {
      InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next();
      interfaze.addSuperinterfaces(list);
    }

    ClassTypeImpl superclass = (ClassTypeImpl) superclass();
    if (superclass != null) {
      superclass.addInterfaces(list);
    }
  }
예제 #22
0
  private static boolean elementListsEqual(List<Element> l1, List<Element> l2) {
    if (l1 == null) return l2 == null;
    if (l2 == null) return false;

    if (l1.size() != l2.size()) return false;

    Iterator<Element> i1 = l1.iterator();

    for (Element aL2 : l2) {
      Element elem1 = i1.next();

      if (!elementsEqual(elem1, aL2)) return false;
    }
    return true;
  }
예제 #23
0
  private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) {
    out.println("Group " + tg.name() + ":");
    List<ThreadReference> tlist = tg.threads();
    int maxId = 0;
    int maxName = 0;
    for (int i = 0; i < tlist.size(); i++) {
      ThreadReference thr = tlist.get(i);
      int len = Utils.description(thr).length();
      if (len > maxId) {
        maxId = len;
      }
      String name = thr.name();
      int iDot = name.lastIndexOf('.');
      if (iDot >= 0 && name.length() > iDot) {
        name = name.substring(iDot + 1);
      }
      if (name.length() > maxName) {
        maxName = name.length();
      }
    }
    String maxNumString = String.valueOf(iThread + tlist.size());
    int maxNumDigits = maxNumString.length();
    for (int i = 0; i < tlist.size(); i++) {
      ThreadReference thr = tlist.get(i);
      char buf[] = new char[80];
      for (int j = 0; j < 79; j++) {
        buf[j] = ' ';
      }
      buf[79] = '\0';
      StringBuffer sbOut = new StringBuffer();
      sbOut.append(buf);

      // Right-justify the thread number at start of output string
      String numString = String.valueOf(iThread + i + 1);
      sbOut.insert(maxNumDigits - numString.length(), numString);
      sbOut.insert(maxNumDigits, ".");

      int iBuf = maxNumDigits + 2;
      sbOut.insert(iBuf, Utils.description(thr));
      iBuf += maxId + 1;
      String name = thr.name();
      int iDot = name.lastIndexOf('.');
      if (iDot >= 0 && name.length() > iDot) {
        name = name.substring(iDot + 1);
      }
      sbOut.insert(iBuf, name);
      iBuf += maxName + 1;
      sbOut.insert(iBuf, Utils.getStatus(thr));
      sbOut.setLength(79);
      out.println(sbOut.toString());
    }
    for (ThreadGroupReference tg0 : tg.threadGroups()) {
      if (!tg.equals(tg0)) { // TODO ref mgt
        iThread += printThreadGroup(out, tg0, iThread + tlist.size());
      }
    }
    return tlist.size();
  }
예제 #24
0
  private void commandLocals() throws NoSessionException {
    ThreadReference current = context.getCurrentThread();
    if (current == null) {
      env.failure("No default thread specified: " + "use the \"thread\" command first.");
      return;
    }
    StackFrame frame;
    try {
      frame = context.getCurrentFrame(current);
      if (frame == null) {
        env.failure("Thread has not yet created any stack frames.");
        return;
      }
    } catch (VMNotInterruptedException e) {
      env.failure("Target VM must be in interrupted state.");
      return;
    }

    List<LocalVariable> vars;
    try {
      vars = frame.visibleVariables();
      if (vars == null || vars.size() == 0) {
        env.failure("No local variables");
        return;
      }
    } catch (AbsentInformationException e) {
      env.failure(
          "Local variable information not available."
              + " Compile with -g to generate variable information");
      return;
    }

    OutputSink out = env.getOutputSink();
    out.println("Method arguments:");
    for (LocalVariable var : vars) {
      if (var.isArgument()) {
        printVar(out, var, frame);
      }
    }
    out.println("Local variables:");
    for (LocalVariable var : vars) {
      if (!var.isArgument()) {
        printVar(out, var, frame);
      }
    }
    out.show();
    return;
  }
예제 #25
0
  public List<ReferenceType> nestedTypes(ReferenceType refType) {
    List<ReferenceType> nestedTypes = myNestedClassesCache.get(refType);
    if (nestedTypes == null) {
      List<ReferenceType> list = Collections.emptyList();
      try {
        list = refType.nestedTypes();
      } catch (Throwable e) {
        // sometimes some strange errors are thrown from JDI. Do not crash debugger because of this.
        // Example:
        // java.lang.StringIndexOutOfBoundsException: String index out of range: 487700285
        //	at java.lang.String.checkBounds(String.java:375)
        //	at java.lang.String.<init>(String.java:415)
        //	at com.sun.tools.jdi.PacketStream.readString(PacketStream.java:392)
        //	at
        // com.sun.tools.jdi.JDWP$VirtualMachine$AllClassesWithGeneric$ClassInfo.<init>(JDWP.java:1644)
        LOG.info(e);
      }
      if (!list.isEmpty()) {
        final Set<ReferenceType> candidates = new HashSet<>();
        final ClassLoaderReference outerLoader = refType.classLoader();
        for (ReferenceType nested : list) {
          try {
            if (outerLoader == null
                ? nested.classLoader() == null
                : outerLoader.equals(nested.classLoader())) {
              candidates.add(nested);
            }
          } catch (ObjectCollectedException ignored) {
          }
        }

        if (!candidates.isEmpty()) {
          // keep only direct nested types
          final Set<ReferenceType> nested2 = new HashSet<>();
          for (final ReferenceType candidate : candidates) {
            nested2.addAll(nestedTypes(candidate));
          }
          candidates.removeAll(nested2);
        }

        nestedTypes = candidates.isEmpty() ? Collections.emptyList() : new ArrayList<>(candidates);
      } else {
        nestedTypes = Collections.emptyList();
      }
      myNestedClassesCache.put(refType, nestedTypes);
    }
    return nestedTypes;
  }
예제 #26
0
 /**
  * @param context
  * @return all CodeFragmentFactoryProviders that provide code fragment factories suitable in the
  *     context given
  */
 public static List<CodeFragmentFactory> getCodeFragmentFactories(@Nullable PsiElement context) {
   final DefaultCodeFragmentFactory defaultFactory = DefaultCodeFragmentFactory.getInstance();
   final CodeFragmentFactory[] providers =
       ApplicationManager.getApplication().getExtensions(CodeFragmentFactory.EXTENSION_POINT_NAME);
   final List<CodeFragmentFactory> suitableFactories =
       new ArrayList<CodeFragmentFactory>(providers.length);
   if (providers.length > 0) {
     for (CodeFragmentFactory factory : providers) {
       if (factory != defaultFactory && factory.isContextAccepted(context)) {
         suitableFactories.add(factory);
       }
     }
   }
   suitableFactories.add(defaultFactory); // let default factory be the last one
   return suitableFactories;
 }
예제 #27
0
  public static List<PsiLambdaExpression> collectLambdas(
      @NotNull SourcePosition position, final boolean onlyOnTheLine) {
    ApplicationManager.getApplication().assertReadAccessAllowed();
    PsiFile file = position.getFile();
    final int line = position.getLine();
    final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
    if (document == null || line >= document.getLineCount()) {
      return Collections.emptyList();
    }
    PsiElement element = position.getElementAt();
    final TextRange lineRange = DocumentUtil.getLineTextRange(document, line);
    do {
      PsiElement parent = element.getParent();
      if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) {
        break;
      }
      element = parent;
    } while (true);

    final List<PsiLambdaExpression> lambdas = new ArrayList<PsiLambdaExpression>(3);
    final PsiElementVisitor lambdaCollector =
        new JavaRecursiveElementVisitor() {
          @Override
          public void visitLambdaExpression(PsiLambdaExpression expression) {
            super.visitLambdaExpression(expression);
            if (!onlyOnTheLine || getFirstElementOnTheLine(expression, document, line) != null) {
              lambdas.add(expression);
            }
          }
        };
    element.accept(lambdaCollector);
    // add initial lambda if we're inside already
    PsiElement method = getContainingMethod(element);
    if (method instanceof PsiLambdaExpression) {
      lambdas.add((PsiLambdaExpression) method);
    }
    for (PsiElement sibling = getNextElement(element);
        sibling != null;
        sibling = getNextElement(sibling)) {
      if (!intersects(lineRange, sibling)) {
        break;
      }
      sibling.accept(lambdaCollector);
    }
    return lambdas;
  }
    StepRequestImpl(ThreadReference thread, int size, int depth) {
      this.thread = (ThreadReferenceImpl) thread;
      this.size = size;
      this.depth = depth;

      /*
       * Make sure this isn't a duplicate
       */
      List requests = stepRequests();
      Iterator iter = requests.iterator();
      while (iter.hasNext()) {
        StepRequest request = (StepRequest) iter.next();
        if ((request != this) && request.isEnabled() && request.thread().equals(thread)) {
          throw new DuplicateRequestException("Only one step request allowed per thread");
        }
      }
    }
  private static boolean elementListsEqual(List<Element> l1, List<Element> l2) {
    if (l1 == null) return l2 == null;
    if (l2 == null) return false;

    if (l1.size() != l2.size()) return false;

    Iterator<Element> i1 = l1.iterator();
    Iterator<Element> i2 = l2.iterator();

    while (i2.hasNext()) {
      Element elem1 = i1.next();
      Element elem2 = i2.next();

      if (!elementsEqual(elem1, elem2)) return false;
    }
    return true;
  }
예제 #30
0
  public Value invokeMethod(
      ThreadReference threadIntf,
      Method methodIntf,
      List<? extends Value> origArguments,
      int options)
      throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException,
          InvocationException {
    validateMirror(threadIntf);
    validateMirror(methodIntf);
    validateMirrorsOrNulls(origArguments);

    MethodImpl method = (MethodImpl) methodIntf;
    ThreadReferenceImpl thread = (ThreadReferenceImpl) threadIntf;

    validateMethodInvocation(method);

    List<? extends Value> arguments = method.validateAndPrepareArgumentsForInvoke(origArguments);

    ValueImpl[] args = arguments.toArray(new ValueImpl[0]);
    JDWP.ClassType.InvokeMethod ret;
    try {
      PacketStream stream = sendInvokeCommand(thread, method, args, options);
      ret = JDWP.ClassType.InvokeMethod.waitForReply(vm, stream);
    } catch (JDWPException exc) {
      if (exc.errorCode() == JDWP.Error.INVALID_THREAD) {
        throw new IncompatibleThreadStateException();
      } else {
        throw exc.toJDIException();
      }
    }

    /*
     * There is an implict VM-wide suspend at the conclusion
     * of a normal (non-single-threaded) method invoke
     */
    if ((options & INVOKE_SINGLE_THREADED) == 0) {
      vm.notifySuspend();
    }

    if (ret.exception != null) {
      throw new InvocationException(ret.exception);
    } else {
      return ret.returnValue;
    }
  }