private MethodHolder readMethod(InputStream stream) throws IOException { DataInputStream input = new DataInputStream(stream); MethodHolder method = new MethodHolder(MethodDescriptor.parse(symbolTable.at(input.readInt()))); method.setLevel(accessLevels[input.readByte()]); method.getModifiers().addAll(unpackModifiers(input.readInt())); readAnnotations(input, method.getAnnotations()); for (int i = 0; i < method.parameterCount(); ++i) { readAnnotations(input, method.parameterAnnotation(i)); } if (input.readBoolean()) { method.setAnnotationDefault(readAnnotationValue(input)); } boolean hasProgram = input.readBoolean(); if (hasProgram) { method.setProgram(programIO.read(input)); } return method; }
void processMemberMethods(ClassHolder cls) { for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) { if (method.hasModifier(ElementModifier.STATIC)) { continue; } if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { ValueType[] staticSignature = getStaticSignature(method.getReference()); MethodHolder callerMethod = new MethodHolder(new MethodDescriptor(method.getName() + "$static", staticSignature)); callerMethod.getModifiers().add(ElementModifier.STATIC); Program program = ProgramUtils.copy(method.getProgram()); program.createVariable(); InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> program.variableAt(var.getIndex() + 1)); for (int i = program.variableCount() - 1; i > 0; --i) { program.variableAt(i).setDebugName(program.variableAt(i - 1).getDebugName()); program.variableAt(i).setLabel(program.variableAt(i - 1).getLabel()); } for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); variableMapper.apply(block); } callerMethod.setProgram(program); ModelUtils.copyAnnotations(method.getAnnotations(), callerMethod.getAnnotations()); cls.addMethod(callerMethod); } } }
public NativeMethodNode decompileNative(MethodHolder method) { Generator generator = generators.get(method.getReference()); if (generator == null && !isBootstrap()) { AnnotationHolder annotHolder = method.getAnnotations().get(GeneratedBy.class.getName()); if (annotHolder == null) { throw new DecompilationException("Method " + method.getOwnerName() + "." + method.getDescriptor() + " is native, but no " + GeneratedBy.class.getName() + " annotation found"); } ValueType annotValue = annotHolder.getValues().get("value").getJavaClass(); String generatorClassName = ((ValueType.Object) annotValue).getClassName(); try { Class<?> generatorClass = Class.forName(generatorClassName, true, classLoader); generator = (Generator) generatorClass.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new DecompilationException("Error instantiating generator " + generatorClassName + " for native method " + method.getOwnerName() + "." + method.getDescriptor()); } } NativeMethodNode methodNode = new NativeMethodNode(method.getReference()); methodNode.getModifiers().addAll(method.getModifiers()); methodNode.setGenerator(generator); methodNode.setAsync(asyncMethods.contains(method.getReference())); return methodNode; }
public void addMethod(MethodHolder method) { if (method.getOwner() != null) { throw new IllegalArgumentException("Method " + method.getDescriptor() + " is already in another class (" + method.getOwner().getName() + ")"); } method.setOwner(this); MethodHolder oldMethod = methods.put(method.getDescriptor(), method); if (oldMethod != null) { oldMethod.setOwner(null); } }
public void processMethod(MethodHolder method) { processMethod(method.getReference(), method.getProgram()); }
public static MethodDescriptor get(MethodHolder method) { return new MethodDescriptor(method.getName(), method.getSignature()); }
public MethodHolder rename(MethodHolder method) { String methodName = method.getName(); AnnotationHolder renameAnnot = method.getAnnotations().get(Rename.class.getName()); if (renameAnnot != null) { methodName = renameAnnot.getValues().get("value").getString(); } ValueType[] signature = method.getSignature(); for (int i = 0; i < signature.length; ++i) { signature[i] = rename(signature[i]); } MethodHolder renamedMethod = new MethodHolder(methodName, signature); renamedMethod.getModifiers().addAll(method.getModifiers()); renamedMethod.setLevel(method.getLevel()); renamedMethod.setProgram(method.getProgram()); rename(method.getAnnotations(), renamedMethod.getAnnotations()); rename(renamedMethod.getProgram()); return renamedMethod; }
field.setType(method.getResultType()); field.setLevel(AccessLevel.PRIVATE); field.getModifiers().add(ElementModifier.STATIC); cls.addField(field); MethodHolder createMethod = new MethodHolder(method.getName() + "$$create", method.getSignature()); createMethod.setLevel(AccessLevel.PRIVATE); createMethod.getModifiers().add(ElementModifier.NATIVE); createMethod.getModifiers().add(ElementModifier.STATIC); cls.addMethod(createMethod); AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName()); genAnnot.getValues().put("value", new AnnotationValue(ValueType.object( MetadataProviderNativeGenerator.class.getName()))); createMethod.getAnnotations().add(genAnnot); ModelUtils.copyAnnotations(method.getAnnotations(), createMethod.getAnnotations()); refAnnot.getValues().put("value", new AnnotationValue(method.getReference().toString())); createMethod.getAnnotations().add(refAnnot); method.getModifiers().remove(ElementModifier.NATIVE); ProgramEmitter pe = ProgramEmitter.create(method, hierarchy); pe.when(pe.getField(field.getReference(), field.getType()).isNull()) .thenDo(() -> pe.setField(field.getReference(), pe.invoke(createMethod.getReference().getClassName(), createMethod.getReference().getName(), createMethod.getResultType()))); pe.getField(field.getReference(), field.getType()) .returnValue();
node = nodeWithoutJsr; ValueType[] signature = MethodDescriptor.parseSignature(node.desc); MethodHolder method = new MethodHolder(referenceCache.getCached(new MethodDescriptor(node.name, signature))); parseModifiers(node.access, method, DECL_METHOD); new UnreachableBasicBlockEliminator().optimize(program); PhiUpdater phiUpdater = new PhiUpdater(); Variable[] argumentMapping = applySignature(program, method.getParameterTypes()); phiUpdater.updatePhis(program, argumentMapping); method.setProgram(program); applyDebugNames(program, phiUpdater, programParser, argumentMapping); parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); applyDebugNames(program, phiUpdater, programParser, applySignature(program, method.getDescriptor().getParameterTypes())); while (program.variableCount() <= method.parameterCount()) { program.createVariable(); method.setAnnotationDefault(parseAnnotationValue(node.annotationDefault)); for (int i = 0; i < method.parameterCount(); ++i) { parseAnnotations(method.parameterAnnotation(i), node.visibleParameterAnnotations != null ? node.visibleParameterAnnotations[i] : null, node.invisibleParameterAnnotations != null ? node.invisibleParameterAnnotations[i] : null);
ClassHolder cls = classes.get(className); for (MethodHolder method : cls.getMethods()) { if (context.getIntrinsic(method.getReference()) != null) { continue; module.add(generator.generateDefinition(method.getReference())); methods.add(method); ClassHolder cls = classes.get(method.getOwnerName()); AnnotationHolder delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); if (delegateAnnot != null) { String methodName = delegateAnnot.getValue("value").getString(); boolean found = false; for (MethodHolder candidate : cls.getMethods()) { if (candidate.getName().equals(methodName)) { if (found) { controller.getDiagnostics().error(new CallLocation(method.getReference()), "Method is delegated to " + methodName + " but several implementations " + "found"); if (implementor.hasModifier(ElementModifier.NATIVE)) { WasmMethodGenerator methodGenerator = context.getGenerator(method.getReference()); if (methodGenerator != null) { WasmFunction function = context.getFunction(context.names.forMethod(method.getReference())); methodGenerator.apply(method.getReference(), function, methodGeneratorContext); } else { if (context.getImportedMethod(method.getReference()) == null) { CallLocation location = new CallLocation(method.getReference());
MethodHolder methodHolder = new MethodHolder(methodImpl.method.getDescriptor()); methodHolder.setLevel(AccessLevel.PUBLIC); CompositeMethodGenerator generatorBackup = generator; try { returnType = methodHolder.getResultType(); varContext = nestedVarContext; generator = new CompositeMethodGenerator(varContext, new Program()); nestedVarContext.init(startBlock); methodHolder.setProgram(program); Variable thisVar = program.createVariable(); int argumentCount = methodImpl.method.parameterCount(); startBlock.add(jumpToStart); new Optimizations().apply(program, new MethodReference(cls.getName(), methodHolder.getDescriptor())); cls.addMethod(methodHolder); } finally {
cls.setParent("java.lang.Object"); MethodHolder method = new MethodHolder(implRef.getDescriptor()); method.setLevel(AccessLevel.PUBLIC); method.getModifiers().add(ElementModifier.STATIC); method.setProgram(program); cls.addMethod(method);
@Override public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) { for (MethodHolder method : cls.getMethods()) { if (method.hasModifier(ElementModifier.NATIVE) && method.getAnnotations().get(Async.class.getName()) != null && method.getAnnotations().get(GeneratedBy.class.getName()) == null) { ValueType[] signature = new ValueType[method.parameterCount() + 2]; for (int i = 0; i < method.parameterCount(); ++i) { signature[i] = method.parameterType(i); } signature[method.parameterCount()] = ValueType.parse(AsyncCallback.class); signature[method.parameterCount() + 1] = ValueType.VOID; MethodDescriptor asyncDesc = new MethodDescriptor(method.getName(), signature); MethodHolder asyncMethod = cls.getMethod(asyncDesc); if (asyncMethod != null) { if (asyncMethod.hasModifier(ElementModifier.STATIC) != method.hasModifier(ElementModifier.STATIC)) { context.getDiagnostics().error(new CallLocation(method.getReference()), "Methods {{m0}} and {{m1}} must both be either static or non-static", method.getReference(), asyncMethod.getReference()); } } } } } }
MethodHolder ctor = new MethodHolder("<init>", signature); ctor.setLevel(AccessLevel.PUBLIC); Program ctorProgram = new Program(); ctor.setProgram(ctorProgram); BasicBlock ctorBlock = ctorProgram.createBasicBlock(); initInsn.setMethod(ctor.getReference()); initInsn.setType(InvocationType.SPECIAL); Variable[] initArgs = new Variable[capturedValues.size()];
@Override public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) { for (MethodHolder method : cls.getMethods()) { AnnotationReader delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); if (delegateAnnot != null) { method.setProgram(null); method.getModifiers().add(ElementModifier.NATIVE); } } } }
private void writeMethod(OutputStream stream, MethodHolder method) throws IOException { DataOutputStream output = new DataOutputStream(stream); output.writeInt(symbolTable.lookup(method.getDescriptor().toString())); output.writeByte(method.getLevel().ordinal()); output.writeInt(packModifiers(method.getModifiers())); writeAnnotations(output, method.getAnnotations()); for (AnnotationContainer parameterAnnotation : method.getParameterAnnotations()) { writeAnnotations(output, parameterAnnotation); } if (method.getAnnotationDefault() != null) { output.writeBoolean(true); writeAnnotationValue(output, method.getAnnotationDefault()); } else { output.writeBoolean(false); } if (method.getProgram() != null) { output.writeBoolean(true); programIO.write(method.getProgram(), output); } else { output.writeBoolean(false); } }
private void preprocessNativeMethod(MethodHolder method, Decompiler decompiler) { if (!method.getModifiers().contains(ElementModifier.NATIVE) || methodGenerators.get(method.getReference()) != null || methodInjectors.get(method.getReference()) != null) { return; ProviderContext context = new ProviderContextImpl(method.getReference()); for (Function<ProviderContext, Generator> provider : generatorProviders) { Generator generator = provider.apply(context); if (generator != null) { methodGenerators.put(method.getReference(), generator); decompiler.addGenerator(method.getReference(), generator); found = true; break; Injector injector = provider.apply(context); if (injector != null) { methodInjectors.put(method.getReference(), injector); decompiler.addMethodToSkip(method.getReference()); found = true; break; if (method.getAnnotations().get(GeneratedBy.class.getName()) != null || method.getAnnotations().get(InjectedBy.class.getName()) != null) { return; method.getModifiers().remove(ElementModifier.NATIVE); method.setProgram(program);
throw new IllegalArgumentException("Method already exists: " + methodRef.getClassName()); MethodHolder method = new MethodHolder(methodRef.getDescriptor()); method.getModifiers().add(ElementModifier.STATIC); method.setProgram(ProgramUtils.copy(program)); new UnreachableBasicBlockEliminator().optimize(program); cls.addMethod(method); if (!method.hasModifier(ElementModifier.NATIVE)) { throw new IllegalArgumentException("Method is not native: " + methodRef); return; method.getModifiers().remove(ElementModifier.NATIVE); method.setProgram(ProgramUtils.copy(program)); new UnreachableBasicBlockEliminator().optimize(method.getProgram());
void createJSMethods(ClassHolder cls) { for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) { MethodReference methodRef = method.getReference(); if (method.getAnnotations().get(JSBody.class.getName()) == null) { continue; } requireJSBody(diagnostics, method); if (!repository.methodMap.containsKey(method.getReference())) { continue; } MethodReference proxyRef = repository.methodMap.get(methodRef); MethodHolder proxyMethod = new MethodHolder(proxyRef.getDescriptor()); proxyMethod.getModifiers().add(ElementModifier.NATIVE); proxyMethod.getModifiers().add(ElementModifier.STATIC); boolean inline = repository.inlineMethods.contains(methodRef); AnnotationHolder generatorAnnot = new AnnotationHolder(inline ? DynamicInjector.class.getName() : DynamicGenerator.class.getName()); proxyMethod.getAnnotations().add(generatorAnnot); cls.addMethod(proxyMethod); Set<MethodReference> callbacks = repository.callbackMethods.get(proxyRef); if (callbacks != null) { for (MethodReference callback : callbacks) { generateCallbackCaller(cls, callback); } } } }
public void link(ClassHolder cls) { for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) { MethodReference methodRef = method.getReference(); MethodDependencyInfo methodDep = dependency.getMethod(methodRef); if (methodDep == null) { cls.removeMethod(method); } else if (!methodDep.isUsed()) { method.getModifiers().add(ElementModifier.ABSTRACT); method.setProgram(null); } else if (method.getProgram() != null) { link(method.getReference(), method.getProgram()); } } for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) { FieldReference fieldRef = new FieldReference(cls.getName(), field.getName()); if (dependency.getField(fieldRef) == null) { cls.removeField(field); } } }