diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java index cbb343123..c767f169d 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java @@ -15,9 +15,15 @@ */ package org.teavm.platform.plugin; -import org.teavm.model.ClassHolder; -import org.teavm.model.ClassHolderTransformer; -import org.teavm.model.ClassReaderSource; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.teavm.model.*; +import org.teavm.model.instructions.EmptyInstruction; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.InvokeInstruction; +import org.teavm.model.instructions.StringConstantInstruction; +import org.teavm.platform.metadata.Resource; /** * @@ -26,5 +32,110 @@ import org.teavm.model.ClassReaderSource; class ResourceTransformer implements ClassHolderTransformer { @Override public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + for (MethodHolder method : cls.getMethods()) { + Program program = method.getProgram(); + if (program != null) { + transformProgram(innerSource, program); + } + } + } + + private void transformProgram(ClassReaderSource innerSource, Program program) { + for (int i = 0; i < program.basicBlockCount(); ++i) { + transformBasicBlock(innerSource, program.basicBlockAt(i)); + } + } + + private void transformBasicBlock(ClassReaderSource innerSource, BasicBlock block) { + List instructions = block.getInstructions(); + for (int i = 0; i < instructions.size(); ++i) { + Instruction insn = instructions.get(i); + if (insn instanceof InvokeInstruction) { + InvokeInstruction invoke = (InvokeInstruction)insn; + List replacement = transformInvoke(innerSource, invoke); + if (replacement != null) { + instructions.set(i, new EmptyInstruction()); + instructions.addAll(i, replacement); + i += replacement.size(); + } + } + } + } + + private List transformInvoke(ClassReaderSource innerSource, InvokeInstruction insn) { + if (insn.getType() != InvocationType.VIRTUAL) { + return null; + } + MethodReference method = insn.getMethod(); + ClassReader iface = innerSource.get(method.getClassName()); + if (iface.getAnnotations().get(Resource.class.getName()) == null) { + return null; + } + if (method.getName().startsWith("get")) { + if (method.getName().length() > 3) { + return transformGetterInvocation(insn, method.getName().substring(3)); + } + } else if (method.getName().startsWith("is")) { + if (method.getName().length() > 2) { + return transformGetterInvocation(insn, method.getName().substring(2)); + } + } else if (method.getName().startsWith("set")) { + if (method.getName().length() > 3) { + return transformSetterInvocation(insn, method.getName().substring(3)); + } + } + return null; + } + + private List transformGetterInvocation(InvokeInstruction insn, String property) { + if (insn.getReceiver() == null) { + return Collections.emptyList(); + } + ValueType type = insn.getMethod().getDescriptor().getResultType(); + Program program = insn.getProgram(); + List instructions = new ArrayList<>(); + if (type instanceof ValueType.Primitive) { + switch (((ValueType.Primitive)type).getKind()) { + case BOOLEAN: + Variable nameVar = program.createVariable(); + Variable resultVar = program.createVariable(); + StringConstantInstruction nameInsn = new StringConstantInstruction(); + nameInsn.setConstant(property); + nameInsn.setReceiver(nameVar); + instructions.add(nameInsn); + InvokeInstruction accessorInvoke = new InvokeInstruction(); + accessorInvoke.setType(InvocationType.SPECIAL); + accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get", + Object.class, String.class, Object.class)); + accessorInvoke.getArguments().add(insn.getInstance()); + accessorInvoke.getArguments().add(nameVar); + accessorInvoke.setReceiver(resultVar); + instructions.add(accessorInvoke); + InvokeInstruction castInvoke = new InvokeInstruction(); + castInvoke.setType(InvocationType.SPECIAL); + castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToBoolean", Object.class, + boolean.class)); + castInvoke.getArguments().add(resultVar); + castInvoke.setReceiver(insn.getReceiver()); + return instructions; + } + } else if (type instanceof ValueType.Object) { + + } + return null; + } + + private List transformSetterInvocation(InvokeInstruction insn, String property) { + return null; + } + + private String getPropertyName(String name) { + if (name.length() == 1) { + return name; + } + if (Character.isUpperCase(name.charAt(1))) { + return name; + } + return Character.toLowerCase(name.charAt(0)) + name.substring(1); } }