@Test
 @ToolsJarRule.Enforce
 public void testAgentSelfInitializationAuxiliaryTypes() throws Exception {
   assertThat(ByteBuddyAgent.installOnOpenJDK(), instanceOf(Instrumentation.class));
   ClassFileTransformer classFileTransformer =
       new AgentBuilder.Default()
           .rebase(isAnnotatedWith(ShouldRebase.class), ElementMatchers.is(classLoader))
           .transform(new QuxTransformer())
           .installOnByteBuddyAgent();
   try {
     Class<?> type = classLoader.loadClass(Qux.class.getName());
     assertThat(type.getDeclaredMethod(FOO).invoke(type.newInstance()), is((Object) (FOO + BAR)));
   } finally {
     ByteBuddyAgent.getInstrumentation().removeTransformer(classFileTransformer);
   }
 }
 @Test
 @ToolsJarRule.Enforce
 public void testAgentWithoutSelfInitializationWithNativeMethodPrefix() throws Exception {
   assertThat(ByteBuddyAgent.installOnOpenJDK(), instanceOf(Instrumentation.class));
   ClassFileTransformer classFileTransformer =
       new AgentBuilder.Default()
           .disableSelfInitialization()
           .withNativeMethodPrefix(QUX)
           .rebase(isAnnotatedWith(ShouldRebase.class), ElementMatchers.is(classLoader))
           .transform(new FooTransformer())
           .installOnByteBuddyAgent();
   try {
     Class<?> type = classLoader.loadClass(Baz.class.getName());
     assertThat(type.getDeclaredMethod(FOO).invoke(type.newInstance()), is((Object) BAR));
     assertThat(type.getDeclaredMethod(QUX + FOO), notNullValue(Method.class));
   } finally {
     ByteBuddyAgent.getInstrumentation().removeTransformer(classFileTransformer);
   }
 }
Пример #3
0
  /**
   * Generates a subclass of {@link CompiledFunction} with a static method "call" and static methods
   * for getting information from a {@link DebugInfo} instance.
   *
   * <p>The "call" method contains the compiled version of this function's AST.
   */
  private Optional<Method> buildCompiledFunction() throws EvalException {
    // replace the / character in the path so we have file system compatible class names
    // the java specification mentions that $ should be used in generated code
    // see http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.8
    String path =
        location.getPath() != null ? location.getPath().getPathString().replace('/', '$') : "";
    String compiledFunctionClassName =
        CompiledFunction.class.getCanonicalName() + path + "$" + getName();
    compilerDebug("Compiling " + getLocationPathAndLine() + " " + getName());
    try {
      int publicStatic = Visibility.PUBLIC.getMask() | Ownership.STATIC.getMask();
      TypeDescription.Latent latentCompiledFunctionClass =
          new TypeDescription.Latent(
              compiledFunctionClassName,
              publicStatic | TypeManifestation.FINAL.getMask(),
              new TypeDescription.ForLoadedType(CompiledFunction.class),
              Collections.<TypeDescription>emptyList());
      MethodDescription getAstNode =
          new MethodDescription.Latent(
              latentCompiledFunctionClass,
              new MethodDescription.Token(
                  "getAstNode",
                  publicStatic | MethodManifestation.FINAL.getMask(),
                  new TypeDescription.ForLoadedType(ASTNode.class),
                  Arrays.asList(new TypeDescription.ForLoadedType(int.class))));
      MethodDescription getLocation =
          new MethodDescription.Latent(
              latentCompiledFunctionClass,
              new MethodDescription.Token(
                  "getLocation",
                  publicStatic | MethodManifestation.FINAL.getMask(),
                  new TypeDescription.ForLoadedType(Location.class),
                  Arrays.asList(new TypeDescription.ForLoadedType(int.class))));

      DebugInfo debugInfo = new DebugInfo(getAstNode, getLocation);
      FunctionSignature sig = signature.getSignature();
      VariableScope scope = VariableScope.function(sig.getNames());
      Implementation compiledImplementation = compileBody(scope, debugInfo);

      List<Class<?>> parameterTypes = sig.getShape().toClasses();
      parameterTypes.add(Environment.class);
      Unloaded<CompiledFunction> unloadedImplementation =
          new ByteBuddy()
              .withClassVisitor(new StackMapFrameClassVisitor(debugCompilerPrintByteCode))
              .subclass(CompiledFunction.class)
              .name(compiledFunctionClassName)
              .defineMethod(
                  "call",
                  Object.class,
                  parameterTypes,
                  Visibility.PUBLIC,
                  Ownership.STATIC,
                  MethodManifestation.FINAL)
              .intercept(compiledImplementation)
              .defineMethod(getAstNode)
              // TODO(bazel-team) unify the two delegate fields into one, probably needs a custom
              // ImplementationDelegate that adds it only once? or just create the static field
              // itself with the correct value and create getAstNode & getLocation with a custom
              // implementation using it
              .intercept(
                  MethodDelegation.to(debugInfo, DebugInfo.class, "getAstNodeDelegate")
                      .filter(ElementMatchers.named("getAstNode")))
              .defineMethod(getLocation)
              .intercept(
                  MethodDelegation.to(debugInfo, DebugInfo.class, "getLocationDelegate")
                      .filter(ElementMatchers.named("getLocation")))
              .make();
      saveByteCode(unloadedImplementation);
      Class<? extends CompiledFunction> functionClass =
          unloadedImplementation
              .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
              .getLoaded();

      return Optional.of(
          ReflectionUtils.getMethod(
                  functionClass,
                  "call",
                  parameterTypes.toArray(new Class<?>[parameterTypes.size()]))
              .getLoadedMethod());
    } catch (EvalException e) {
      // don't capture EvalExceptions
      throw e;
    } catch (Throwable e) {
      compilerDebug("Error while compiling", e);
      // TODO(bazel-team) don't capture all throwables? couldn't compile this, log somewhere?
    }
    return Optional.absent();
  }
Пример #4
0
 private <E> DynamicType.Builder<E> getNode(
     final DynamicType.Builder<E> builder, final Method method, final Annotation annotation) {
   return builder
       .method(ElementMatchers.is(method))
       .intercept(MethodDelegation.to(getVertexInterceptor.class));
 }