Bläddra i källkod

drafts: adapter: push/dup/convert

Mariusz Sieroń 6 år sedan
förälder
incheckning
7ecf7b5e84

+ 14 - 2
assira.drafts/src/main/java/net/ranides/assira/reflection/asm/IMethodBuilder.java

@@ -24,8 +24,6 @@ public interface IMethodBuilder {
 
     IMethodBuilder var(IArguments arguments);
 
-    IMethodBuilder ldc(Object value);
-
     IMethodBuilder load(IClass<?> type, int index);
 
     IMethodBuilder load(IArguments arguments, int index);
@@ -56,6 +54,10 @@ public interface IMethodBuilder {
 
     IMethodBuilder getStatic(IField field);
 
+    IMethodBuilder push(Object value);
+
+    IMethodBuilder push(IClass<?> type, Object value);
+
     IMethodBuilder invokeInit(IClass<?> owner, Iterable<IClass<?>> params);
 
     IMethodBuilder invokeSpecial(IClass<?> owner, String name, Iterable<IClass<?>> params, IClass<?> ret);
@@ -108,4 +110,14 @@ public interface IMethodBuilder {
 
     IMethodBuilder xor(IClass<?> type);
 
+    IMethodBuilder dup();
+
+    IMethodBuilder dup(IClass<?> type);
+
+    IMethodBuilder dup(int x);
+
+    IMethodBuilder dup(IClass<?> type, int x);
+
+    IMethodBuilder convert(IClass<?> source, IClass<?> target);
+
 }

+ 9 - 9
assira.drafts/src/main/java/net/ranides/assira/reflection/asm/cg/CGAdapter.java

@@ -114,19 +114,19 @@ public class CGAdapter {
         m.store(IClass.OBJECT, 1);
 
         m.newObject(sb);
-        m.asm().visitInsn(DUP);
+        m.dup();
 
-        m.asm().visitIntInsn(BIPUSH, prefix.length()+suffix.length());
+        m.push(prefix.length()+suffix.length());
         m.load(IClass.OBJECT, 1);
         m.invokeVirtual(IClass.STRING, "length", Collections.emptyList(), IClass.INT);
         m.add(IClass.INT);
         m.invokeInit(sb, Arrays.asList(IClass.INT));
 
-        m.ldc(prefix);
+        m.push(prefix);
         m.invokeVirtual(sb, "append", Arrays.asList(IClass.STRING), sb);
         m.load(IClass.OBJECT, 1);
         m.invokeVirtual(sb, "append", Arrays.asList(IClass.STRING), sb);
-        m.ldc(suffix);
+        m.push(suffix);
         m.invokeVirtual(sb, "append", Arrays.asList(IClass.STRING), sb);
         m.invokeVirtual(sb, "toString", Collections.emptyList(), IClass.STRING);
         m.returns(IClass.STRING);
@@ -153,25 +153,25 @@ public class CGAdapter {
         IMethodBuilder m = writer.method(IAttributes.of(IAttribute.PUBLIC), method.name(), method);
 
         m.getStatic(writer.type(), IClass.typeinfo(IMethod[].class), F_METHODS);
-        m.asm().visitIntInsn(SIPUSH, index);
+        m.push(index);
         m.loadArray(IClass.OBJECT);
 
         m.load(IClass.OBJECT, 0);
         m.getField(writer.type(), that, F_THAT);
 
-        m.asm().visitIntInsn(SIPUSH, oargs.size());
+        m.push(oargs.size());
         m.newObject(IClass.typeinfo(Object[].class));
 
         for(int i=0, n=iargs.size(); i<n; i++) {
-            m.asm().visitInsn(DUP);
-            m.asm().visitIntInsn(SIPUSH, i);
+            m.dup();
+            m.push(i);
 
             m.load(iargs.get(i), i+1);
             if(iargs.get(i).attribute(IAttribute.PRIMITIVE)) {
                 m.box(iargs.get(i));
             }
 
-            m.asm().visitInsn(AASTORE);
+            m.storeArray(IClass.OBJECT);
         }
 
         m.invokeVirtual(IClass.typeinfo(IMethod.class), "invoke", Arrays.asList(IClass.OBJECT, IClass.typeinfo(Object[].class)), IClass.OBJECT);

+ 4 - 0
assira.drafts/src/main/java/net/ranides/assira/reflection/asm/impl/AsmSupport.java

@@ -171,4 +171,8 @@ public class AsmSupport {
         throw new IllegalArgumentException("Invalid array component: " + raw);
     }
 
+    public static int size(IClass<?> type) {
+        return type.attribute(IAttribute.SYMBOLIC) ? 1 : Type.getType(type.raw()).getSize();
+    }
+
 }

+ 178 - 3
assira.drafts/src/main/java/net/ranides/assira/reflection/asm/impl/CMethodBuilder.java

@@ -1,5 +1,6 @@
 package net.ranides.assira.reflection.asm.impl;
 
+import net.ranides.assira.math.MathUtils;
 import net.ranides.assira.reflection.*;
 import net.ranides.assira.reflection.asm.IClassBuilder;
 import net.ranides.assira.reflection.asm.IMethodBuilder;
@@ -75,10 +76,92 @@ public class CMethodBuilder implements IMethodBuilder {
         return this;
     }
 
+    public IMethodBuilder push(Object value) {
+        return push(IClass.typefor(value), value);
+    }
+
     @Override
-    public IMethodBuilder ldc(Object value) {
-        mv.visitLdcInsn(value);
-        return this;
+    public IMethodBuilder push(IClass<?> type, Object value) {
+        if(null == value) {
+            return ins(ACONST_NULL);
+        }
+        if(IClass.DOUBLE.isEquivalent(type)) {
+            return pushDouble(((Number)value).doubleValue());
+        }
+        if(IClass.FLOAT.isEquivalent(type)) {
+            return pushFloat(((Number)value).floatValue());
+        }
+        if(IClass.LONG.isEquivalent(type)) {
+            return pushLong(((Number)value).longValue());
+        }
+        if(type.attribute(IAttribute.NUMBER)) {
+            return pushInt((Number)value);
+        }
+        if(type.attribute(IAttribute.BOOLEAN)) {
+            return pushInt((Boolean)value ? 1 : 0);
+        }
+        return ldc(value);
+    }
+
+    public IMethodBuilder pushDouble(Number value) {
+        if(value.doubleValue() == 0.0) {
+            return ins(DCONST_0);
+        }
+        if(value.doubleValue() == 1.0) {
+            return ins(DCONST_1);
+        }
+        return ldc(value.doubleValue());
+    }
+
+    public IMethodBuilder pushFloat(Number value) {
+        if(value.floatValue() == 0.0) {
+            return ins(FCONST_0);
+        }
+        if(value.floatValue() == 1.0) {
+            return ins(FCONST_1);
+        }
+        if(value.floatValue() == 2.0) {
+            return ins(FCONST_2);
+        }
+        return ldc(value.floatValue());
+    }
+
+    public IMethodBuilder pushLong(long value) {
+        if(value == 0) {
+            return ins(LCONST_0);
+        }
+        if(value == 1) {
+            return ins(LCONST_1);
+        }
+        return ldc(value);
+    }
+
+    public IMethodBuilder pushInt(Number value) {
+        switch (value.intValue()) {
+            case -1:
+                return ins(ICONST_M1);
+            case 0:
+                return ins(ICONST_0);
+            case 1:
+                return ins(ICONST_1);
+            case 2:
+                return ins(ICONST_2);
+            case 3:
+                return ins(ICONST_3);
+            case 4:
+                return ins(ICONST_4);
+            case 5:
+                return ins(ICONST_5);
+        }
+        if(value.byteValue() == value.longValue()) {
+            mv.visitIntInsn(BIPUSH, value.byteValue());
+            return this;
+        }
+        if(value.shortValue() == value.longValue()) {
+            mv.visitIntInsn(SIPUSH, value.shortValue());
+            return this;
+        }
+        return ldc(value.intValue());
     }
 
     @Override
@@ -274,6 +357,16 @@ public class CMethodBuilder implements IMethodBuilder {
         return invokeStatic(wrapper, "valueOf", Arrays.asList(type), wrapper);
     }
 
+    private IMethodBuilder ldc(Object v) {
+        mv.visitLdcInsn(v);
+        return this;
+    }
+
+    private IMethodBuilder ins(int oc) {
+        mv.visitInsn(oc);
+        return this;
+    }
+
     private IMethodBuilder ins(int oc, IClass<?> type) {
         mv.visitInsn(AsmSupport.opcode(oc, type));
         return this;
@@ -323,4 +416,86 @@ public class CMethodBuilder implements IMethodBuilder {
         return ins(IXOR, type);
     }
 
+    @Override
+    public IMethodBuilder dup() {
+        return ins(DUP);
+    }
+
+    @Override
+    public IMethodBuilder dup(IClass<?> type) {
+        return dup(type, 0);
+    }
+
+    @Override
+    public IMethodBuilder dup(int x) {
+        return dup(IClass.INT, x);
+    }
+
+    @Override
+    public IMethodBuilder dup(IClass<?> type, int x) {
+        switch (x) {
+            case 0: ins(AsmSupport.size(type) == 2 ? DUP2 : DUP);
+            case 1: ins(AsmSupport.size(type) == 2 ? DUP2_X1 : DUP_X1);
+            case 2: ins(AsmSupport.size(type) == 2 ? DUP2_X2 : DUP_X2);
+        }
+        throw new UnsupportedOperationException("DUP_X"+x + " does not exist.");
+    }
+
+    @Override
+    public IMethodBuilder convert(IClass<?> source, IClass<?> target) {
+        if(source.equals(IClass.DOUBLE)) {
+            if(target.equals(IClass.FLOAT)) {
+                return ins(D2F);
+            }
+            if(target.equals(IClass.LONG)) {
+                return ins(D2L);
+            }
+            if(target.attribute(IAttribute.NUMBER)) {
+                return ins(D2I);
+            }
+        }
+        if(source.equals(IClass.FLOAT)) {
+            if(target.equals(IClass.DOUBLE)) {
+                return ins(F2D);
+            }
+            if(target.equals(IClass.LONG)) {
+                return ins(F2D);
+            }
+            if(target.attribute(IAttribute.NUMBER)) {
+                return ins(F2I);
+            }
+        }
+        if(source.equals(IClass.LONG)) {
+            if(target.equals(IClass.DOUBLE)) {
+                return ins(L2D);
+            }
+            if(target.equals(IClass.FLOAT)) {
+                return ins(L2F);
+            }
+            if(target.attribute(IAttribute.NUMBER)) {
+                return ins(L2I);
+            }
+        }
+        if(source.equals(IClass.INT)) {
+            if(target.equals(IClass.BOOL)) {
+                return ins(I2B);
+            }
+            if(target.equals(IClass.CHAR)) {
+                return ins(I2C);
+            }
+            if(target.equals(IClass.DOUBLE)) {
+                return ins(I2D);
+            }
+            if(target.equals(IClass.FLOAT)) {
+                return ins(I2F);
+            }
+            if(target.equals(IClass.LONG)) {
+                return ins(I2L);
+            }
+            if(target.equals(IClass.SHORT)) {
+                return ins(I2S);
+            }
+        }
+        throw new UnsupportedOperationException("Unsupported conversion " + source + " => " + target);
+    }
 }

+ 1 - 1
assira/src/main/java/net/ranides/assira/reflection/impl/AClass.java

@@ -20,7 +20,7 @@ import net.ranides.assira.collection.query.CQueryBuilder;
  */
 public abstract class AClass<T> implements IClass<T> {
     
-    private static final IAttributes ATTRS = IAttributes.of(IAttribute.FINAL, IAttribute.NATIVE, IAttribute.PUBLIC).immutable();
+    private static final IAttributes ATTRS = IAttributes.of(IAttribute.FINAL, IAttribute.NATIVE, IAttribute.PUBLIC, IAttribute.SYMBOLIC).immutable();
     
     private static final Object[] EMPTY_ARGS = new Object[0];