28
28
import static java .lang .ClassLoader .getSystemClassLoader ;
29
29
import static java .lang .Double .*;
30
30
import static java .lang .Math .floorMod ;
31
+ import static java .lang .Math .toIntExact ;
31
32
import static java .lang .String .format ;
32
33
import static java .lang .System .*;
33
34
import static java .lang .invoke .MethodHandleProxies .asInterfaceInstance ;
49
50
import static jdk .internal .org .objectweb .asm .ClassReader .SKIP_DEBUG ;
50
51
import static jdk .internal .org .objectweb .asm .ClassWriter .COMPUTE_FRAMES ;
51
52
import static jdk .internal .org .objectweb .asm .Type .*;
52
- import static shen .Shen .Compiler .typeHint ;
53
+ import static jdk .internal .org .objectweb .asm .commons .GeneratorAdapter .*;
54
+ import static shen .Shen .Compiler .*;
53
55
import static shen .Shen .Cons .toCons ;
54
56
import static shen .Shen .KLReader .lines ;
55
57
import static shen .Shen .KLReader .read ;
@@ -91,53 +93,168 @@ public static void main(String... args) throws Throwable {
91
93
interface LLPredicate { boolean test (long a , long b ); }
92
94
interface Invokable { MethodHandle invoker () throws Exception ; }
93
95
94
- public static class Numbers {
96
+ public static class Numbers implements Opcodes {
95
97
static final long tag = 1 , real = 0 , integer = 1 ;
96
-
97
98
static final Set <Symbol > operators = new HashSet <>();
98
99
100
+ // longs are either 63 bit signed integers or doubleToLongBits with bit 0 used as tag, 0 = double, 1 = long.
101
+ // Java: 5ms, Shen.java: 10ms, Boxed Java: 15ms. Which ever branch that starts will be faster for some reason.
99
102
static {
100
- // longs are either 63 bit signed integers or doubleToLongBits with bit 0 used as tag, 0 = double, 1 = long.
101
- // Java: 5ms, Shen.java: 10ms, Boxed Java: 15ms. Which ever branch that starts will be faster for some reason.
102
- op ("+" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
103
- ? ~tag & doubleToRawLongBits (((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) + ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ))
104
- : l + (r & ~tag ));
105
- op ("-" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
106
- ? ~tag & doubleToRawLongBits (((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) - ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ))
107
- : l - (r & ~tag ));
108
- op ("*" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
109
- ? ~tag & doubleToRawLongBits (((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) * ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ))
110
- : (l & ~tag ) * (r & ~tag ) >> tag | tag );
111
- op ("/" , (l , r ) -> {
112
- if (r == real || r == tag ) throw new ArithmeticException ("Division by zero" );
113
- return ~tag & doubleToRawLongBits (((tag & l ) == real
114
- ? longBitsToDouble (l ) : l >> tag ) / ((tag & r ) == real
115
- ? longBitsToDouble (r ) : r >> tag ));
116
- });
117
- op ("<" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
118
- ? ((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) < ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ) : l < r );
119
- op ("<=" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
120
- ? ((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) <= ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ) : l <= r );
121
- op (">" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
122
- ? ((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) > ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ) : l > r );
123
- op (">=" , (l , r ) -> (tag & l ) == 0 || (tag & r ) == 0
124
- ? ((tag & l ) == 0 ? longBitsToDouble (l ) : l >> tag ) >= ((tag & r ) == 0 ? longBitsToDouble (r ) : r >> tag ) : l >= r );
103
+ ClassWriter cw = new ClassWriter (ClassWriter .COMPUTE_FRAMES );
104
+ cw .visit (V1_7 , ACC_PUBLIC | ACC_FINAL , "shen/Shen$Operators" , null , getInternalName (Object .class ), null );
105
+
106
+ binaryOp (cw , "+" , ADD );
107
+ binaryOp (cw , "-" , SUB );
108
+ binaryOp (cw , "*" , MUL );
109
+ binaryOp (cw , "/" , realOp (DIV ), integerDivision ());
110
+ binaryComp (cw , "<" , LT );
111
+ binaryComp (cw , "<=" , LE );
112
+ binaryComp (cw , ">" , GT );
113
+ binaryComp (cw , ">=" , GE );
114
+
115
+ register (loader .loadClass (cw .toByteArray ()), Numbers ::op );
116
+ }
117
+
118
+ static Consumer <GeneratorAdapter > integerOp (int op ) {
119
+ return mv -> toInteger (mv , op );
120
+ }
121
+
122
+ static Consumer <GeneratorAdapter > realOp (int op ) {
123
+ return mv -> toReal (mv , op );
124
+ }
125
+
126
+ static Consumer <GeneratorAdapter > integerDivision () {
127
+ return mv -> {
128
+ Label notZero = new Label ();
129
+ mv .dup2 ();
130
+ mv .visitInsn (L2I );
131
+ mv .ifZCmp (IFNE , notZero );
132
+ mv .newInstance (getType (ArithmeticException .class ));
133
+ mv .dup ();
134
+ mv .push ("Division by zero" );
135
+ mv .invokeConstructor (getType (ArithmeticException .class ), method ("<init>" , desc (void .class , String .class )));
136
+ mv .throwException ();
137
+ mv .visitLabel (notZero );
138
+ mv .visitInsn (L2D );
139
+ mv .swap (DOUBLE_TYPE , LONG_TYPE );
140
+ mv .visitInsn (L2D );
141
+ mv .swap (DOUBLE_TYPE , DOUBLE_TYPE );
142
+ toReal (mv , DIV );
143
+ };
144
+ }
145
+
146
+ static void toInteger (GeneratorAdapter mv , int op ) {
147
+ mv .math (op , LONG_TYPE );
148
+ mv .push ((int ) tag );
149
+ mv .visitInsn (LSHL );
150
+ mv .push (integer );
151
+ mv .visitInsn (LOR );
152
+ }
153
+
154
+ static void toReal (GeneratorAdapter mv , int op ) {
155
+ mv .math (op , DOUBLE_TYPE );
156
+ mv .invokeStatic (getType (Double .class ), method ("doubleToRawLongBits" , desc (long .class , double .class )));
157
+ mv .push (~integer );
158
+ mv .visitInsn (LAND );
159
+ }
160
+
161
+ static void binaryComp (ClassWriter cw , String op , int test ) {
162
+ binaryOp (cw , op , boolean .class , comparison (DOUBLE_TYPE , test ), comparison (LONG_TYPE , test ));
163
+ }
164
+
165
+ static Consumer <GeneratorAdapter > comparison (Type type , int test ) {
166
+ return mv -> {
167
+ Label _else = new Label ();
168
+ mv .ifCmp (type , test , _else );
169
+ mv .push (false );
170
+ mv .returnValue ();
171
+ mv .visitLabel (_else );
172
+ mv .push (true );
173
+ mv .returnValue ();
174
+ };
175
+ }
176
+
177
+ static void binaryOp (ClassWriter cw , String op , int instruction ) {
178
+ binaryOp (cw , op , long .class , realOp (instruction ), integerOp (instruction ));
179
+ }
180
+
181
+ static void binaryOp (ClassWriter cw , String op , Consumer <GeneratorAdapter > realOp , Consumer <GeneratorAdapter > longOp ) {
182
+ binaryOp (cw , op , long .class , realOp , longOp );
183
+ }
184
+
185
+ static void binaryOp (ClassWriter cw , String op , Class <?> returnType , Consumer <GeneratorAdapter > realOp ,
186
+ Consumer <GeneratorAdapter > integerOp ) {
187
+ GeneratorAdapter mv = new GeneratorAdapter (ACC_PUBLIC + ACC_STATIC ,
188
+ method (toBytecodeName (op ), desc (returnType , long .class , long .class )), null , null , cw );
189
+
190
+ isInteger (mv , 0 );
191
+ Label argOneIsLong = new Label ();
192
+ mv .ifZCmp (IFNE , argOneIsLong );
193
+ asDouble (mv , 0 );
194
+ isInteger (mv , 1 );
195
+ Label argTwoIsLong = new Label ();
196
+ mv .ifZCmp (IFNE , argTwoIsLong );
197
+ asDouble (mv , 1 );
198
+ Label doubleOperation = new Label ();
199
+ mv .goTo (doubleOperation );
200
+ mv .visitLabel (argTwoIsLong );
201
+ asLong (mv , 1 );
202
+ mv .visitInsn (L2D );
203
+ mv .goTo (doubleOperation );
204
+ mv .visitLabel (argOneIsLong );
205
+ isInteger (mv , 1 );
206
+ Label longOperation = new Label ();
207
+ mv .ifZCmp (IFNE , longOperation );
208
+ asLong (mv , 0 );
209
+ mv .visitInsn (L2D );
210
+ asDouble (mv , 1 );
211
+ mv .visitLabel (doubleOperation );
212
+ realOp .accept (mv );
213
+ mv .returnValue ();
214
+ mv .visitLabel (longOperation );
215
+ asLong (mv , 0 );
216
+ asLong (mv , 1 );
217
+ integerOp .accept (mv );
218
+ mv .returnValue ();
219
+ mv .endMethod ();
125
220
}
126
221
127
- static void op ( String name , LongBinaryOperator op ) {
128
- intern ( name ). fn . add ( findSAM ( op ) );
129
- operators . add ( intern ( name ));
222
+ static void asDouble ( GeneratorAdapter mv , int arg ) {
223
+ mv . loadArg ( arg );
224
+ mv . invokeStatic ( getType ( Double . class ), method ( "longBitsToDouble" , desc ( double . class , long . class ) ));
130
225
}
131
226
132
- static void op (String name , LLPredicate op ) {
133
- intern (name ).fn .add (findSAM (op ));
134
- operators .add (intern (name ));
227
+ static void asLong (GeneratorAdapter mv , int arg ) {
228
+ mv .loadArg (arg );
229
+ mv .push ((int ) tag );
230
+ mv .visitInsn (LSHR );
231
+ }
232
+
233
+ static void isInteger (GeneratorAdapter mv , int arg ) {
234
+ mv .loadArg (arg );
235
+ mv .visitInsn (L2I );
236
+ mv .push ((int ) tag );
237
+ mv .visitInsn (IAND );
238
+ }
239
+
240
+ static void op (Method op ) {
241
+ try {
242
+ Symbol symbol = intern (toSourceName (op .getName ()));
243
+ symbol .fn .add (lookup .unreflect (op ));
244
+ operators .add (symbol );
245
+ } catch (IllegalAccessException e ) {
246
+ throw uncheck (e );
247
+ }
135
248
}
136
249
137
250
static Object maybeNumber (Object o ) {
138
251
return o instanceof Long ? asNumber ((Long ) o ) : o ;
139
252
}
140
253
254
+ public static long number (Number n ) {
255
+ return n instanceof Double ? real (n .doubleValue ()) : integer (n .longValue ());
256
+ }
257
+
141
258
static long real (double d ) {
142
259
return ~tag & doubleToLongBits (d );
143
260
}
@@ -150,7 +267,11 @@ static double asDouble(long l) {
150
267
return isInteger (l ) ? l >> tag : longBitsToDouble (l );
151
268
}
152
269
153
- static Number asNumber (long fp ) { //noinspection RedundantCast
270
+ public static int asInt (long l ) {
271
+ return toIntExact (asNumber (l ).longValue ());
272
+ }
273
+
274
+ public static Number asNumber (long fp ) { //noinspection RedundantCast
154
275
return isInteger (fp ) ? (Number ) (fp >> tag ) : (Number ) longBitsToDouble (fp );
155
276
}
156
277
@@ -651,6 +772,8 @@ public static class RT {
651
772
static final MethodHandle
652
773
link = mh (RT .class , "link" ), proxy = mh (RT .class , "proxy" ),
653
774
checkClass = mh (RT .class , "checkClass" ), toIntExact = mh (Math .class , "toIntExact" ),
775
+ asNumber = mh (Numbers .class , "asNumber" ), number = mh (Numbers .class , "number" ),
776
+ asInt = mh (Numbers .class , "asInt" ), toList = mh (Cons .class , "toList" ),
654
777
partial = mh (RT .class , "partial" ), arityCheck = mh (RT .class , "arityCheck" );
655
778
656
779
public static Object link (MutableCallSite site , String name , Object ... args ) throws Throwable {
@@ -846,10 +969,11 @@ static MethodHandle filterJavaTypes(MethodHandle method) throws IllegalAccessExc
846
969
filters [i ] = proxy .bindTo (findSAM (method .type ().parameterType (i )))
847
970
.asType (methodType (method .type ().parameterType (i ), Object .class ));
848
971
else if (canCast (method .type ().parameterType (i ), int .class ))
849
- filters [i ] = toIntExact .asType (methodType (method .type ().parameterType (i ), Object .class ));
850
- if (canCast (method .type ().returnType (), int .class ))
851
- method = method .asType (method .type ()
852
- .changeReturnType (method .type ().returnType ().isPrimitive () ? long .class : Long .class ));
972
+ filters [i ] = asInt .asType (methodType (method .type ().parameterType (i ), Object .class ));
973
+ else if (canCast (method .type ().wrap ().parameterType (i ), Number .class ))
974
+ filters [i ] = asNumber .asType (methodType (method .type ().parameterType (i ), Object .class ));
975
+ if (canCast (method .type ().wrap ().returnType (), Number .class ))
976
+ method = filterReturnValue (method , number .asType (methodType (long .class , method .type ().returnType ())));
853
977
return filterArguments (method , 0 , filters );
854
978
}
855
979
@@ -1615,7 +1739,7 @@ static <T> List<T> rest(List<T> coll) {
1615
1739
1616
1740
static RuntimeException uncheck (Throwable t ) {
1617
1741
return uncheckAndThrow (t );
1618
- }
1742
+ }
1619
1743
1620
1744
static <T extends Throwable > T uncheckAndThrow (Throwable t ) throws T { //noinspection unchecked
1621
1745
throw (T ) t ;
0 commit comments