|
|
@@ -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);
|
|
|
+ }
|
|
|
}
|