private void createObserverCreatorMethod(ClassGen cg, ObserverDescription observer, String observerClassName) { final String methodName = "create" + observer.getName(); InstructionList il = new InstructionList(); InstructionFactory ifact = new InstructionFactory(cg); MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, new ObjectType(observerClassName), new Type[] { } , null, methodName, cg.getClassName(), il, cg.getConstantPool()); il.append(ifact.createNew(observerClassName)); il.append(InstructionConstants.DUP); il.append(InstructionConstants.THIS); il.append(ifact.createInvoke(observerClassName, "<init>", Type.VOID, new Type[] { DefaultTypes.QoolTransformation }, Constants.INVOKESPECIAL)); il.append(InstructionFactory.ARETURN); mg.setMaxLocals(); mg.setMaxStack(); cg.addMethod(mg.getMethod()); }
boolean isNonEscapingConstructor(INVOKESPECIAL invoker) { ReferenceType cls = invoker.getReferenceType(methodGen.getConstantPool()); String className = (cls instanceof ObjectType) ? ((ObjectType) cls).getClassName() : "java.lang.Object"; JavaClass javaClass; try { javaClass = Repository.lookupClass(className); } catch(ClassNotFoundException e) { return false; } return nonEscapingConstructor(javaClass, invoker.getSignature(methodGen.getConstantPool())); }
public boolean isStreamOpen(BasicBlock basicBlock, InstructionHandle handle, ConstantPoolGen cpg, ResourceValueFrame frame) { if (isOpenOnCreation) return false; Instruction ins = handle.getInstruction(); if (!(ins instanceof INVOKESPECIAL)) return false; // Does this instruction open the stream? INVOKESPECIAL inv = (INVOKESPECIAL) ins; return frame.isValid() && getInstanceValue(frame, inv, cpg).isInstance() && matchMethod(inv, cpg, this.getResourceClass(), "<init>"); }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL obj) { if (returnsString(obj)) handleInstanceMethod(obj); else super.visitINVOKESPECIAL(obj); }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL obj) { // Don't know what this method invocation is doing. // Kill all loads. killLoadsOfObjectsPassed(obj); handleNormalInstruction(obj); }
private void createConstructor(GenScope scope, ClassGen cg) { InstructionList il = new InstructionList(); InstructionFactory ifact = new InstructionFactory(cg); // Call super il.append(InstructionConstants.THIS); il.append(new INVOKESPECIAL(cg.getConstantPool().addMethodref(cg.getSuperclassName(), "<init>", "()V"))); // Instantiate and register each transformation to be executed for (TransformationExecution exec : getExecutions()) { // TODO: Ensure the name obtained with "getTransformationName" is the one of the generated transformation (weak link now!) String transformationClassName = exec.getTransformationName(); // TODO: Find out the class package name!! transformationClassName = "eclectic." + transformationClassName; il.append(ifact.createNew(transformationClassName)); il.append(new DUP()); il.append(ifact.createInvoke(transformationClassName, "<init>", Type.VOID, new Type[] { }, Constants.INVOKESPECIAL)); il.append(InstructionConstants.THIS); il.append(InstructionConstants.SWAP); il.append(ifact.createInvoke(cg.getClassName(), "register", Type.VOID, new Type[] { DefaultTypes.IdcTransformation }, Constants.INVOKEVIRTUAL)); } il.append(InstructionConstants.RETURN); MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] { } , null, "<init>", cg.getClassName(), il, cg.getConstantPool()); mg.setMaxStack(); cg.addMethod(mg.getMethod()); }
@Override public void generate(GenScope scope) { InstructionList il = scope.getInstructionList(); InstructionFactory ifact = scope.getInstructionFactory(); NewScopeResult closureClassScope = createClosureClass(scope); ClassGen closureClass = closureClassScope.cg; ClosureScope closureScope = (ClosureScope) closureClassScope.scope; scope.getTransformationContext().addExtraClass(closureClass.getJavaClass()); LocalVariableGen lvg = scope.newLocalVariable(this, Type.OBJECT); // Create the closure instance il.append(ifact.createNew(closureClass.getClassName())); il.append(new DUP()); scope.generateGetTransformation(); scope.generateGetModelManager(); il.append(ifact.createInvoke(closureClass.getClassName(), "<init>", Type.VOID, new Type[] { DefaultTypes.IdcTransformation, DefaultTypes.ModelManager }, Constants.INVOKESPECIAL)); //Type.VOID, new Type[] { DefaultTypes.ModelManager }, Constants.INVOKESPECIAL)); // This is a bit hard-wired because the OuterVariableSet // is computed as a result of creating the closureClass... OuterVariableSet outers = closureScope.getOuterVariables(); Set<Variable> o = outers.get(); for (Variable variable : o) { il.append(new DUP()); scope.loadVariable(variable, il); il.append(scope.getInstructionFactory().createPutField(closureClass.getClassName(), variable.getName(), Type.OBJECT)); } il.append(new ASTORE(lvg.getIndex())); }
private void createConstructor(GenScope scope, ClassGen closureClass) { InstructionList il = new InstructionList(); il.append(InstructionConstants.THIS); // Push `this' il.append(new INVOKESPECIAL(closureClass.getConstantPool().addMethodref(closureClass.getSuperclassName(), "<init>", "()V"))); il.append(InstructionConstants.THIS); // Push `this' il.append(scope.getInstructionFactory().createConstant(this.getFormalParameters().size())); il.append(scope.getInstructionFactory().createPutField(DefaultTypes.IClosure.getClassName(), "numParameters_", Type.INT)); il.append(InstructionConstants.THIS); // Push `this' il.append(new ALOAD(1)); // first parameter il.append(scope.getInstructionFactory().createPutField(DefaultTypes.IClosure.getClassName(), "transformation_", DefaultTypes.IdcTransformation)); il.append(InstructionConstants.THIS); // Push `this' il.append(new ALOAD(2)); // second parameter il.append(scope.getInstructionFactory().createPutField(DefaultTypes.IClosure.getClassName(), "modelManager_", DefaultTypes.ModelManager)); // TODO: It would be nice to have cross-checking between code being generated and framework code /* il.append(InstructionConstants.THIS); // Push `this' il.append(new ALOAD(1)); // first parameter il.append(scope.getInstructionFactory().createPutField(DefaultTypes.IClosure.getClassName(), "modelManager_", DefaultTypes.ModelManager)); */ il.append(InstructionConstants.RETURN); MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] { DefaultTypes.IdcTransformation, DefaultTypes.ModelManager } , null, "<init>", closureClass.getClassName(), il, closureClass.getConstantPool()); // mg.setMaxStack(3); mg.setMaxStack(); closureClass.addMethod(mg.getMethod()); }
private void createConstructor(GenScope scope, ClassGen cg) { InstructionList il = new InstructionList(); InstructionFactory ifact = new InstructionFactory(cg); MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] { } , null, "<init>", cg.getClassName(), il, cg.getConstantPool()); scope.processMethod(mg); // call super il.append(InstructionConstants.THIS); // Push `this' il.append(new INVOKESPECIAL(cg.getConstantPool().addMethodref(cg.getSuperclassName(), "<init>", "()V"))); // Set name il.append( InstructionConstants.THIS ); il.append( ifact.createConstant(this.getName()) ); il.append( ifact.createPutField(cg.getClassName(), "name", Type.STRING) ); Collection<Queue> queues = CommonGen.allQueues(this); for (Queue q : queues) { QueueJVMGen jvmQ = (QueueJVMGen) q; jvmQ.generateInitField(il, ifact, scope); } il.append(InstructionConstants.RETURN); mg.setMaxStack(); cg.addMethod(mg.getMethod()); }
private void createConstructor(GenScope scope, ClassGen cg) { InstructionList il = new InstructionList(); InstructionFactory ifact = new InstructionFactory(cg); MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] { } , null, "<init>", cg.getClassName(), il, cg.getConstantPool()); scope.processMethod(mg); // call super il.append(InstructionConstants.THIS); // Push `this' il.append(new INVOKESPECIAL(cg.getConstantPool().addMethodref(cg.getSuperclassName(), "<init>", "()V"))); // Set name il.append( InstructionConstants.THIS ); il.append( ifact.createConstant(this.getName()) ); il.append( ifact.createPutField(cg.getClassName(), "name", Type.STRING) ); Collection<Queue> queues = CommonGen.getImportedQueues(this); for (Queue q : queues) { QueueJVMGen jvmQ = (QueueJVMGen) q; jvmQ.generateInitField(il, ifact, scope); } il.append(InstructionConstants.RETURN); mg.setMaxStack(); cg.addMethod(mg.getMethod()); }
/** @see org.apache.bcel.generic.Visitor */ public void visitINVOKESPECIAL(INVOKESPECIAL aINVOKESPECIAL) { addInvokeReference( new InvokeReference(aINVOKESPECIAL, mCurrentPoolGen)); }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL obj) { visitInvoke(obj); }
/** * Checks that any store in this basic block to the specified variable is the * result of a new() or a null. * @param ih handle up to where to investigate. * @param localVarIndex the local variable index * @return true if all stores are OK or there are no stores. */ boolean noAliasesStoreWithIndexBefore(InstructionHandle ih, LocalVariableGen lg) { InstructionHandle prev = null; for (InstructionContext ic : instructions) { InstructionHandle current = ic.getInstruction(); if (current.equals(ih)) { break; } if (methodGen.instructionStoresTo(current, lg.getIndex())) { LocalVariableGen l1 = methodGen.findLocalVar(current, lg.getIndex(), false); if (l1 != lg) { prev = current; continue; } if (prev != null) { Instruction i = prev.getInstruction(); if (i instanceof INVOKESPECIAL) { INVOKESPECIAL invoker = (INVOKESPECIAL) i; if (invoker.getMethodName(methodGen.getConstantPool()).equals("<init>") && isNonEscapingConstructor(invoker)) { continue; } } if (i instanceof CHECKCAST) { InstructionHandle pp = prev.getPrev(); if (pp != null) { i = pp.getInstruction(); } } if (i instanceof NEWARRAY || i instanceof ANEWARRAY || i instanceof MULTIANEWARRAY || i instanceof ConstantPushInstruction || i instanceof ACONST_NULL) { prev = current; continue; } } return false; } prev = current; } return true; }
boolean nonEscapingConstructor(JavaClass javaClass, String constructorSignature) { if (javaClass.getClassName().equals("java.lang.Object")) { return true; } JavaClass superClass; try { superClass = javaClass.getSuperClass(); } catch(ClassNotFoundException e) { throw new Error("Superclass of " + javaClass.getClassName() + " not found"); } Method[] methods = javaClass.getMethods(); for (Method method : methods) { if (method.getName().equals("<init>") && method.getSignature().equals(constructorSignature)) { if (nonEscapingConstructor(superClass, "()V")) { ClassGen cg = new ClassGen(javaClass); MethodGen mg = new MethodGen(method, javaClass.getClassName(), cg.getConstantPool()); // Now check all ALOAD 0 instructions. They may only be used for // PUTFIELD and for calling super(). InstructionHandle h = mg.getInstructionList().getStart(); while (h != null) { Instruction i = h.getInstruction(); if (i instanceof ALOAD && ((ALOAD) i).getIndex() == 0) { if (! mg.isUsedForPutField(h)) { // Find instructions that consume exactly this load (but not more, // otherwise it could be a parameter to another constructor). InstructionHandle[] users = mg.findExactInstructionConsumers(h); if (users.length != 1) { return false; } i = users[0].getInstruction(); if (i instanceof INVOKESPECIAL) { INVOKESPECIAL invoker = (INVOKESPECIAL) i; if (! invoker.getMethodName(mg.getConstantPool()).equals("<init>") || ! nonEscapingConstructor(superClass, invoker.getSignature(mg.getConstantPool()))) { return false; } } else { return false; } } } h = h.getNext(); } return true; } } } return false; }
@Override public void run() { String args[] = EntryPoint.getArgs(); String inputJarFileName = args[0]; String outputSrgMappingsFileName = args[1]; try ( PrintWriter outputSrgMappingWriter = new PrintWriter(outputSrgMappingsFileName); JarFile inputJarFile = new JarFile(inputJarFileName) ) { for (JarEntry jarEntry : new EnumerationIterator<>(inputJarFile.entries())) { if (jarEntry.isDirectory() || !jarEntry.getName().endsWith(".class")) { continue; } String original = Utils.stripClassEnding(jarEntry.getName()); JavaClass clazz = new ClassParser(inputJarFile.getInputStream(jarEntry), original).parse(); if (clazz.isEnum()) { Method staticInit = getCLInit(clazz); //skip enums with no static init method if (staticInit == null) { continue; } ConstantPoolGen cpGen = new ClassGen(clazz).getConstantPool(); MethodGen methodGen = new MethodGen(staticInit, clazz.getClassName(), cpGen); Iterator<Instruction> instrIter = Arrays.asList(methodGen.getInstructionList().getInstructions()).iterator(); while (instrIter.hasNext()) { //first goes NEW Instruction instr = instrIter.next(); if (!(instr instanceof NEW)) { break; } //but it may actually be another new, so we check if it is for enum constant if (!((NEW) instr).getLoadClassType(cpGen).getClassName().equals(clazz.getClassName())) { break; } //then goes dup, skip it instrIter.next(); //LDC with our real enum name String realName = (String) ((LDC) instrIter.next()).getValue(cpGen); //now skip everything, until we reach invokespecial with <init> for this enum field while (true) { Instruction nextInstr = instrIter.next(); if (nextInstr instanceof INVOKESPECIAL) { INVOKESPECIAL ispecial = ((INVOKESPECIAL) nextInstr); if (ispecial.getMethodName(cpGen).equals("<init>") && (ispecial.getClassName(cpGen).equals(clazz.getClassName()))) { break; } } } //next is putstatic with our obufscated field name PUTSTATIC putstatic = (PUTSTATIC) instrIter.next(); String obfName = putstatic.getFieldName(cpGen); //now print the mapping outputSrgMappingWriter.println(MappingUtils.createSRG(clazz.getClassName(), obfName, realName)); } } } } catch (Throwable t) { t.printStackTrace(); } }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL inv) { handleInvoke(inv); }
public static @CheckForNull XMethod findInvocationLeastUpperBound(InvokeInstruction inv, ConstantPoolGen cpg, JavaClassAndMethodChooser methodChooser) { if (DEBUG_METHOD_LOOKUP) { System.out.println("Find prototype method for " + SignatureConverter.convertMethodSignature(inv, cpg)); } short opcode = inv.getOpcode(); if (opcode == Constants.INVOKESTATIC) { if (methodChooser == INSTANCE_METHOD) return null; } else { if (methodChooser == STATIC_METHOD) return null; } // Find the method if (opcode == Constants.INVOKESPECIAL) { // Non-virtual dispatch return findExactMethod(inv, cpg, methodChooser); } else { String className = inv.getClassName(cpg); String methodName = inv.getName(cpg); String methodSig = inv.getSignature(cpg); if (DEBUG_METHOD_LOOKUP) { System.out.println("[Class name is " + className + "]"); System.out.println("[Method name is " + methodName + "]"); System.out.println("[Method signature is " + methodSig + "]"); } if (className.startsWith("[")) { // Java 1.5 allows array classes to appear as the class name className = "java.lang.Object"; } try { return thisOrNothing( findInvocationLeastUpperBound(getXClassFromDottedClassName(className), methodName, methodSig, opcode == Constants.INVOKESTATIC, opcode == Constants.INVOKEINTERFACE), methodChooser); } catch (CheckedAnalysisException e) { return null; } } }
/** * Resolve possible method call targets. This works for both static and * instance method calls. * * @param invokeInstruction * the InvokeInstruction * @param typeFrame * the TypeFrame containing the types of stack values * @param cpg * the ConstantPoolGen * @return Set of methods which might be called * @throws DataflowAnalysisException * @throws ClassNotFoundException */ public static @Nonnull Set<XMethod> resolveMethodCallTargets(InvokeInstruction invokeInstruction, TypeFrame typeFrame, ConstantPoolGen cpg) throws DataflowAnalysisException, ClassNotFoundException { short opcode = invokeInstruction.getOpcode(); if (opcode == Constants.INVOKESTATIC) { return Util.emptyOrNonnullSingleton(findInvocationLeastUpperBound(invokeInstruction, cpg, STATIC_METHOD)); } if (!typeFrame.isValid()) { return Collections.<XMethod> emptySet(); } Type receiverType; boolean receiverTypeIsExact; if (opcode == Constants.INVOKESPECIAL) { // invokespecial instructions are dispatched to EXACTLY // the class specified by the instruction receiverType = ObjectTypeFactory.getInstance(invokeInstruction.getClassName(cpg)); receiverTypeIsExact = false; // Doesn't actually matter } else { // For invokevirtual and invokeinterface instructions, we have // virtual dispatch. By taking the receiver type (which may be a // subtype of the class specified by the instruction), // we may get a more precise set of call targets. int instanceStackLocation = typeFrame.getInstanceStackLocation(invokeInstruction, cpg); receiverType = typeFrame.getStackValue(instanceStackLocation); if (!(receiverType instanceof ReferenceType)) { return Collections.<XMethod> emptySet(); } receiverTypeIsExact = typeFrame.isExact(instanceStackLocation); } if (DEBUG_METHOD_LOOKUP) { System.out.println("[receiver type is " + receiverType + ", " + (receiverTypeIsExact ? "exact]" : " not exact]")); } return resolveMethodCallTargets((ReferenceType) receiverType, invokeInstruction, cpg, receiverTypeIsExact); }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL obj) { handleInvoke(obj); }
/** Checks if the constraints of operands of the said instruction(s) are satisfied. */ public void visitINVOKESPECIAL(INVOKESPECIAL o){ try { // INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in, // is therefore resolved/verified. // INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified, // too. So are the allowed method names. String classname = o.getClassName(cpg); JavaClass jc = Repository.lookupClass(classname); Method[] ms = jc.getMethods(); Method m = null; for (int i=0; i<ms.length; i++){ if ( (ms[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ m = ms[i]; break; } } if (m == null){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); } JavaClass current = Repository.lookupClass(myOwner.getClassName()); if (current.isSuper()){ if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){ if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){ // Special lookup procedure for ACC_SUPER classes. int supidx = -1; Method meth = null; while (supidx != 0){ supidx = current.getSuperclassNameIndex(); current = Repository.lookupClass(current.getSuperclassName()); Method[] meths = current.getMethods(); for (int i=0; i<meths.length; i++){ if ( (meths[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){ meth = meths[i]; break; } } if (meth != null) { break; } } if (meth == null){ constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy."); } } } } } catch (ClassNotFoundException e) { // FIXME: maybe not the best way to handle this throw new AssertionViolatedException("Missing class: " + e.toString()); } }
@Override public void visitINVOKESPECIAL(INVOKESPECIAL invoke) { addMethodCall(method, invoke, constantPoolGen); }
private String generateObserverClass(ModelDefinition model, ObserverDescription observer, TransformationContext context) { final String className = context.getRuntimeClassName() + "$" + observer.getName(); final String transformationFieldName = "transformation_"; ClassGen cg = new ClassGen(className, observer.getObserverClass(), context.getFilename(), Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {}); cg.addField(new FieldGen(Constants.ACC_PUBLIC, DefaultTypes.QoolTransformation, transformationFieldName, cg.getConstantPool()).getField()); // constructor InstructionList constructorIl = new InstructionList(); InstructionFactory constructorIfact = new InstructionFactory(cg); MethodGen constructor = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] { DefaultTypes.QoolTransformation } , null, "<init>", cg.getClassName(), constructorIl, cg.getConstantPool()); constructorIl.append(InstructionConstants.THIS); // Push `this' constructorIl.append(new INVOKESPECIAL(cg.getConstantPool().addMethodref(cg.getSuperclassName(), "<init>", "()V"))); constructorIl.append(InstructionFactory.THIS); constructorIl.append(new ALOAD(1)); constructorIl.append( constructorIfact.createPutField(cg.getClassName(), transformationFieldName, DefaultTypes.QoolTransformation) ); constructorIl.append(InstructionFactory.RETURN); constructor.setMaxLocals(); constructor.setMaxStack(); cg.addMethod(constructor.getMethod()); // end-of constructor EList<UpdateMethod> methods = observer.getUpdateMethods(); for (UpdateMethod updateMethod : methods) { EList<String> ptypes = updateMethod.getParameterTypes(); InstructionList il = new InstructionList(); InstructionFactory ifact = new InstructionFactory(cg); // TODO: Assuming void return type // TODO: Assuming object types Type[] types = new Type[ptypes.size()]; int i = 0; for(String strType : ptypes) { types[i++] = new ObjectType(strType); } MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, types, null, updateMethod.getName(), cg.getClassName(), il, cg.getConstantPool()); // TODO: assuming only 1 interest parameter assert(updateMethod.getInterest().size() == 1); il.append(InstructionConstants.THIS); il.append(ifact.createGetField(className, transformationFieldName, DefaultTypes.QoolTransformation)); il.append(ifact.createConstant(model.getName())); il.append(new ALOAD(updateMethod.getInterest().get(0) + 1)); il.append(ifact.createInvoke(DefaultTypes.QoolTransformation.getClassName(), "addObjectToQueues", Type.VOID, new Type[] { Type.STRING, Type.OBJECT }, Constants.INVOKEVIRTUAL)); il.append(InstructionFactory.RETURN); mg.setMaxLocals(); mg.setMaxStack(); cg.addMethod(mg.getMethod()); } context.addExtraClass(cg.getJavaClass()); return className; }