예제 #1
0
  @Override
  public void visit(
      int version,
      int access,
      String name,
      String signature,
      String superName,
      String[] interfaces) {
    this.className = name;
    this.classEntry = db.getOrCreateClassEntry(className, superName);
    classEntry.setInterfaces(interfaces);

    forceInstrumentation |= classEntry.requiresInstrumentation();

    // need atleast 1.5 for annotations to work
    if (version < Opcodes.V1_5) version = Opcodes.V1_5;

    // When Java allows adding interfaces in retransformation, we can mark the class with an
    // interface, which makes checking whether it's instrumented faster (with instanceof)
    //        if(classEntry.requiresInstrumentation() && !contains(interfaces, SUSPENDABLE_NAME)) {
    //            System.out.println("XX: Marking " + className + " as " + SUSPENDABLE_NAME);
    //            interfaces = add(interfaces, SUSPENDABLE_NAME);
    //        }

    super.visit(version, access, name, signature, superName, interfaces);
  }
예제 #2
0
  @Override
  @SuppressWarnings("CallToThreadDumpStack")
  public void visitEnd() {
    classEntry.setRequiresInstrumentation(false);
    db.recordSuspendableMethods(className, classEntry);

    if (methods != null && !methods.isEmpty()) {
      if (alreadyInstrumented && !forceInstrumentation) {
        for (MethodNode mn : methods) mn.accept(makeOutMV(mn));
      } else {
        if (!alreadyInstrumented) {
          super.visitAnnotation(ALREADY_INSTRUMENTED_NAME, true);
          classEntry.setInstrumented(true);
        }

        for (MethodNode mn : methods) {
          final MethodVisitor outMV = makeOutMV(mn);
          try {
            InstrumentMethod im = new InstrumentMethod(db, className, mn);
            if (db.isDebug())
              db.log(
                  LogLevel.INFO, "About to instrument method %s#%s%s", className, mn.name, mn.desc);

            if (im.collectCodeBlocks()) {
              if (mn.name.charAt(0) == '<')
                throw new UnableToInstrumentException(
                    "special method", className, mn.name, mn.desc);
              im.accept(outMV, hasAnnotation(mn));
            } else mn.accept(outMV);
          } catch (AnalyzerException ex) {
            ex.printStackTrace();
            throw new InternalError(ex.getMessage());
          }
        }
      }
    } else {
      // if we don't have any suspendable methods, but our superclass is instrumented, we mark this
      // class as instrumented, too.
      if (!alreadyInstrumented && classEntry.getSuperName() != null) {
        ClassEntry superClass = db.getClassEntry(classEntry.getSuperName());
        if (superClass != null && superClass.isInstrumented()) {
          super.visitAnnotation(ALREADY_INSTRUMENTED_NAME, true);
          classEntry.setInstrumented(true);
        }
      }
    }
    super.visitEnd();
  }
예제 #3
0
  @Override
  public MethodVisitor visitMethod(
      final int access,
      final String name,
      final String desc,
      final String signature,
      final String[] exceptions) {
    final SuspendableType markedSuspendable =
        SuspendableClassifierService.isSuspendable(
            className, classEntry, name, desc, signature, exceptions);
    final SuspendableType setSuspendable = classEntry.check(name, desc);

    if (setSuspendable == null)
      classEntry.set(
          name,
          desc,
          markedSuspendable != null ? markedSuspendable : SuspendableType.NON_SUSPENDABLE);

    final boolean suspendable =
        markedSuspendable == SuspendableType.SUSPENDABLE
            | setSuspendable == SuspendableType.SUSPENDABLE;

    if (checkAccess(access) && !isYieldMethod(className, name)) {
      if (methods == null) methods = new ArrayList<MethodNode>();
      final MethodNode mn = new MethodNode(access, name, desc, signature, exceptions);

      if (suspendable) {
        if (db.isDebug())
          db.log(
              LogLevel.INFO,
              "Method %s#%s suspendable: %s (markedSuspendable: %s setSuspendable: %s)",
              className,
              name,
              suspendable,
              markedSuspendable,
              setSuspendable);

        methods.add(mn);
        return mn; // this causes the mn to be initialized
      } else { // look for @Suspendable annotation
        return new MethodVisitor(Opcodes.ASM4, mn) {
          private boolean susp = false;
          private boolean commited = false;

          @Override
          public AnnotationVisitor visitAnnotation(String adesc, boolean visible) {
            if (adesc.equals(ANNOTATION_DESC)) susp = true;
            return super.visitAnnotation(adesc, visible);
          }

          @Override
          public void visitCode() {
            commit();
            super.visitCode();
          }

          @Override
          public void visitEnd() {
            commit();
            super.visitEnd();
          }

          private void commit() {
            if (commited) return;
            commited = true;
            if (db.isDebug())
              db.log(
                  LogLevel.INFO,
                  "Method %s#%s suspendable: %s (markedSuspendable: %s setSuspendable: %s)",
                  className,
                  name,
                  susp,
                  susp,
                  false);
            classEntry.set(
                name, desc, susp ? SuspendableType.SUSPENDABLE : SuspendableType.NON_SUSPENDABLE);

            if (susp) methods.add(mn);
            else {
              MethodVisitor _mv = makeOutMV(mn);
              _mv = new JSRInlinerAdapter(_mv, access, name, desc, signature, exceptions);
              mn.accept(
                  new MethodVisitor(Opcodes.ASM4, _mv) {
                    @Override
                    public void visitEnd() {
                      // don't call visitEnd on MV
                    }
                  }); // write method as-is
              this.mv = _mv;
            }
          }
        };
      }
    }
    return super.visitMethod(access, name, desc, signature, exceptions);
  }