1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.test.lib.jittester.visitors; 25 26 import java.util.ArrayDeque; 27 import java.util.Deque; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.NoSuchElementException; 31 import java.util.Objects; 32 import java.util.SortedMap; 33 import java.util.TreeMap; 34 import java.util.stream.Collectors; 35 import java.util.stream.Stream; 36 37 import jdk.internal.org.objectweb.asm.ClassWriter; 38 import jdk.internal.org.objectweb.asm.FieldVisitor; 39 import jdk.internal.org.objectweb.asm.Label; 40 import jdk.internal.org.objectweb.asm.MethodVisitor; 41 import jdk.internal.org.objectweb.asm.Opcodes; 42 import jdk.test.lib.Pair; 43 import jdk.test.lib.jittester.BinaryOperator; 44 import jdk.test.lib.jittester.Block; 45 import jdk.test.lib.jittester.BuiltInType; 46 import jdk.test.lib.jittester.Break; 47 import jdk.test.lib.jittester.CastOperator; 48 import jdk.test.lib.jittester.CatchBlock; 49 import jdk.test.lib.jittester.Continue; 50 import jdk.test.lib.jittester.Declaration; 51 import jdk.test.lib.jittester.IRNode; 52 import jdk.test.lib.jittester.If; 53 import jdk.test.lib.jittester.Initialization; 54 import jdk.test.lib.jittester.Literal; 55 import jdk.test.lib.jittester.LocalVariable; 56 import jdk.test.lib.jittester.NonStaticMemberVariable; 57 import jdk.test.lib.jittester.Nothing; 58 import jdk.test.lib.jittester.Operator; 59 import jdk.test.lib.jittester.OperatorKind; 60 import jdk.test.lib.jittester.PrintVariables; 61 import jdk.test.lib.jittester.ProductionParams; 62 import jdk.test.lib.jittester.Statement; 63 import jdk.test.lib.jittester.StaticMemberVariable; 64 import jdk.test.lib.jittester.Switch; 65 import jdk.test.lib.jittester.Symbol; 66 import jdk.test.lib.jittester.TernaryOperator; 67 import jdk.test.lib.jittester.Throw; 68 import jdk.test.lib.jittester.TryCatchBlock; 69 import jdk.test.lib.jittester.Type; 70 import jdk.test.lib.jittester.TypeList; 71 import jdk.test.lib.jittester.UnaryOperator; 72 import jdk.test.lib.jittester.VariableBase; 73 import jdk.test.lib.jittester.VariableDeclaration; 74 import jdk.test.lib.jittester.VariableDeclarationBlock; 75 import jdk.test.lib.jittester.VariableInfo; 76 import jdk.test.lib.jittester.VariableInitialization; 77 import jdk.test.lib.jittester.arrays.ArrayCreation; 78 import jdk.test.lib.jittester.arrays.ArrayElement; 79 import jdk.test.lib.jittester.arrays.ArrayExtraction; 80 import jdk.test.lib.jittester.classes.ClassDefinitionBlock; 81 import jdk.test.lib.jittester.classes.Interface; 82 import jdk.test.lib.jittester.classes.Klass; 83 import jdk.test.lib.jittester.classes.MainKlass; 84 import jdk.test.lib.jittester.functions.ArgumentDeclaration; 85 import jdk.test.lib.jittester.functions.ConstructorDefinition; 86 import jdk.test.lib.jittester.functions.ConstructorDefinitionBlock; 87 import jdk.test.lib.jittester.functions.Function; 88 import jdk.test.lib.jittester.functions.FunctionDeclaration; 89 import jdk.test.lib.jittester.functions.FunctionDeclarationBlock; 90 import jdk.test.lib.jittester.functions.FunctionDefinition; 91 import jdk.test.lib.jittester.functions.FunctionDefinitionBlock; 92 import jdk.test.lib.jittester.functions.FunctionInfo; 93 import jdk.test.lib.jittester.functions.FunctionRedefinition; 94 import jdk.test.lib.jittester.functions.FunctionRedefinitionBlock; 95 import jdk.test.lib.jittester.functions.Return; 96 import jdk.test.lib.jittester.functions.StaticConstructorDefinition; 97 import jdk.test.lib.jittester.loops.CounterInitializer; 98 import jdk.test.lib.jittester.loops.CounterManipulator; 99 import jdk.test.lib.jittester.loops.DoWhile; 100 import jdk.test.lib.jittester.loops.For; 101 import jdk.test.lib.jittester.loops.Loop; 102 import jdk.test.lib.jittester.loops.LoopingCondition; 103 import jdk.test.lib.jittester.loops.While; 104 import jdk.test.lib.jittester.types.TypeArray; 105 import jdk.test.lib.jittester.types.TypeKlass; 106 import jdk.test.lib.jittester.utils.FixedTrees; 107 import jdk.test.lib.jittester.utils.PseudoRandom; 108 109 public class ByteCodeVisitor implements Visitor<byte[]> { 110 private final GeneratedClassesContext context = new GeneratedClassesContext(); 111 private final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 112 private final int CLASS_WRITER_FLAGS = ContextDependedClassWriter.COMPUTE_MAXS | ContextDependedClassWriter.COMPUTE_FRAMES; 113 private final HashMap<String, ContextDependedClassWriter> classWriters = new HashMap<>(); 114 private MethodVisitor currentMV; 115 private TypeKlass currentClass; 116 private final LocalVariablesTable locals = new LocalVariablesTable(); 117 private final Deque<Label> endLabels = new ArrayDeque<>(); 118 private final Deque<Label> beginLabels = new ArrayDeque<>(); 119 120 @Override 121 public byte[] visit(ArgumentDeclaration node) { 122 /* handled by FunctionDefinition for ByteCodeVisitor */ 123 return EMPTY_BYTE_ARRAY; 124 } 125 126 @Override 127 public byte[] visit(ArrayCreation node) { 128 int dimensions = node.getDimensionsCount(); 129 TypeArray arrayType = node.getArrayType(); 130 Type basicType = arrayType.type; 131 for (IRNode child : node.getChildren()) { 132 child.accept(this); 133 } 134 if (dimensions == 1) { 135 if (basicType.equals(TypeList.BOOLEAN)) { 136 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BOOLEAN); 137 } else if (basicType.equals(TypeList.BYTE)) { 138 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE); 139 } else if (basicType.equals(TypeList.CHAR)) { 140 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_CHAR); 141 } else if (basicType.equals(TypeList.SHORT)) { 142 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_SHORT); 143 } else if (basicType.equals(TypeList.INT)) { 144 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT); 145 } else if (basicType.equals(TypeList.LONG)) { 146 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_LONG); 147 } else if (basicType.equals(TypeList.FLOAT)) { 148 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_FLOAT); 149 } else if (basicType.equals(TypeList.DOUBLE)) { 150 currentMV.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_DOUBLE); 151 } else { 152 currentMV.visitTypeInsn(Opcodes.ANEWARRAY, asInternalName(basicType.getName())); 153 } 154 } else { 155 currentMV.visitMultiANewArrayInsn(new String(arrayType.accept(this)), dimensions); 156 } 157 return EMPTY_BYTE_ARRAY; 158 } 159 160 @Override 161 public byte[] visit(ArrayElement node) { 162 node.getChild(0).accept(this); 163 int dimensions = node.getChildren().size() - 1; 164 Type resultType = node.getResultType(); 165 for (int i = 1; i < dimensions; i++) { 166 node.getChild(i).accept(this); 167 currentMV.visitInsn(Opcodes.AALOAD); 168 } 169 node.getChild(dimensions).accept(this); 170 if (resultType.equals(TypeList.BOOLEAN) || resultType.equals(TypeList.BYTE)) { 171 currentMV.visitInsn(Opcodes.BALOAD); 172 } else if (resultType.equals(TypeList.CHAR)) { 173 currentMV.visitInsn(Opcodes.CALOAD); 174 } else if (resultType.equals(TypeList.SHORT)) { 175 currentMV.visitInsn(Opcodes.SALOAD); 176 } else if (resultType.equals(TypeList.INT)) { 177 currentMV.visitInsn(Opcodes.IALOAD); 178 } else if (resultType.equals(TypeList.LONG)) { 179 currentMV.visitInsn(Opcodes.LALOAD); 180 } else if (resultType.equals(TypeList.FLOAT)) { 181 currentMV.visitInsn(Opcodes.FALOAD); 182 } else if (resultType.equals(TypeList.DOUBLE)) { 183 currentMV.visitInsn(Opcodes.DALOAD); 184 } else { 185 currentMV.visitInsn(Opcodes.AALOAD); 186 } 187 return EMPTY_BYTE_ARRAY; 188 } 189 190 @Override 191 public byte[] visit(ArrayExtraction node) { 192 node.getChild(0).accept(this); 193 int dimensions = node.getChildren().size() - 1; 194 Type resultType = node.getResultType(); 195 for (int i = 1; i < dimensions; i++) { 196 node.getChild(i).accept(this); 197 currentMV.visitInsn(Opcodes.AALOAD); 198 } 199 node.getChild(dimensions).accept(this); 200 if (resultType.equals(TypeList.BOOLEAN) || resultType.equals(TypeList.BYTE)) { 201 currentMV.visitInsn(Opcodes.BALOAD); 202 } else if (resultType.equals(TypeList.CHAR)) { 203 currentMV.visitInsn(Opcodes.CALOAD); 204 } else if (resultType.equals(TypeList.SHORT)) { 205 currentMV.visitInsn(Opcodes.SALOAD); 206 } else if (resultType.equals(TypeList.INT)) { 207 currentMV.visitInsn(Opcodes.IALOAD); 208 } else if (resultType.equals(TypeList.LONG)) { 209 currentMV.visitInsn(Opcodes.LALOAD); 210 } else if (resultType.equals(TypeList.FLOAT)) { 211 currentMV.visitInsn(Opcodes.FALOAD); 212 } else if (resultType.equals(TypeList.DOUBLE)) { 213 currentMV.visitInsn(Opcodes.DALOAD); 214 } else { 215 currentMV.visitInsn(Opcodes.AALOAD); 216 } 217 return EMPTY_BYTE_ARRAY; 218 } 219 220 @Override 221 public byte[] visit(BinaryOperator node) { 222 OperatorKind kind = node.getOperationKind(); 223 IRNode left = node.getChild(Operator.Order.LEFT.ordinal()); 224 IRNode right = node.getChild(Operator.Order.RIGHT.ordinal()); 225 Type resultType = node.getResultType(); 226 if (left == null || right == null) { 227 return EMPTY_BYTE_ARRAY; 228 } 229 boolean needTypeConversion = false; 230 boolean convertRightArg = false; 231 Type leftType = left.getResultType(); 232 Type rightType = right.getResultType(); 233 if (!leftType.equals(rightType) && leftType instanceof BuiltInType 234 && rightType instanceof BuiltInType 235 && kind != OperatorKind.SAR && kind != OperatorKind.SHL 236 && kind != OperatorKind.SHR && kind != OperatorKind.ASSIGN 237 && kind != OperatorKind.AND && kind != OperatorKind.OR) { 238 needTypeConversion = true; 239 BuiltInType leftBuiltIn = (BuiltInType) leftType; 240 BuiltInType rightBuiltIn = (BuiltInType) rightType; 241 convertRightArg = leftBuiltIn.isMoreCapaciousThan(rightBuiltIn); 242 } 243 Type mostCapacious = convertRightArg ? leftType : rightType; 244 if (!rightType.equals(TypeList.INT) 245 && (kind == OperatorKind.SHL || kind == OperatorKind.SHR 246 || kind == OperatorKind.SAR)) { 247 left.accept(this); 248 right.accept(this); 249 convertTopType(rightType, TypeList.INT); 250 } else if (kind != OperatorKind.ASSIGN && kind != OperatorKind.OR 251 && kind != OperatorKind.AND && kind != OperatorKind.COMPOUND_ADD 252 && kind != OperatorKind.COMPOUND_AND && kind != OperatorKind.COMPOUND_DIV 253 && kind != OperatorKind.COMPOUND_MOD && kind != OperatorKind.COMPOUND_MUL 254 && kind != OperatorKind.COMPOUND_OR && kind != OperatorKind.COMPOUND_SAR 255 && kind != OperatorKind.COMPOUND_SHL && kind != OperatorKind.COMPOUND_SHR 256 && kind != OperatorKind.COMPOUND_SUB && kind != OperatorKind.COMPOUND_XOR 257 && kind != OperatorKind.STRADD) { 258 /* "assign", "and", "or", concat and all compound operators are 259 handled differently and shouldn't just place left and right 260 operands on stack */ 261 left.accept(this); 262 if (needTypeConversion && !convertRightArg) { 263 convertTopType(leftType, rightType); 264 } 265 right.accept(this); 266 if (needTypeConversion && convertRightArg) { 267 convertTopType(rightType, leftType); 268 } 269 } 270 switch (kind) { 271 case ASSIGN: 272 VariableInfo vi = ((VariableBase)left).getVariableInfo(); 273 Type varType = vi.type; 274 if (left instanceof LocalVariable) { 275 right.accept(this); 276 convertTopType(rightType, leftType); 277 int index = locals.getLocalIndex(vi); 278 if (varType.equals(TypeList.LONG)) { 279 currentMV.visitVarInsn(Opcodes.LSTORE, index); 280 currentMV.visitVarInsn(Opcodes.LLOAD, index); 281 } else if (varType.equals(TypeList.DOUBLE)) { 282 currentMV.visitVarInsn(Opcodes.DSTORE, index); 283 currentMV.visitVarInsn(Opcodes.DLOAD, index); 284 } else if (varType.equals(TypeList.FLOAT)) { 285 currentMV.visitVarInsn(Opcodes.FSTORE, index); 286 currentMV.visitVarInsn(Opcodes.FLOAD, index); 287 } else if (varType instanceof TypeKlass) { 288 currentMV.visitVarInsn(Opcodes.ASTORE, index); 289 currentMV.visitVarInsn(Opcodes.ALOAD, index); 290 } else { 291 currentMV.visitVarInsn(Opcodes.ISTORE, index); 292 currentMV.visitVarInsn(Opcodes.ILOAD, index); 293 } 294 } else if (left instanceof StaticMemberVariable) { 295 right.accept(this); 296 convertTopType(rightType, leftType); 297 String typeDescr = new String(vi.type.accept(this)); 298 String ownerName = asInternalName(vi.getOwner().getName()); 299 currentMV.visitFieldInsn(Opcodes.PUTSTATIC, ownerName, 300 vi.name, typeDescr); 301 currentMV.visitFieldInsn(Opcodes.GETSTATIC, ownerName, 302 vi.name, typeDescr); 303 } else if (left instanceof NonStaticMemberVariable) { 304 // put object to stack for putfield 305 left.getChild(0).accept(this); 306 // put object to stack for getfield 307 currentMV.visitInsn(Opcodes.DUP); 308 right.accept(this); 309 convertTopType(rightType, leftType); 310 String typeDescr = new String(vi.type.accept(this)); 311 String ownerName = asInternalName(vi.getOwner().getName()); 312 currentMV.visitFieldInsn(Opcodes.PUTFIELD, ownerName, 313 vi.name, typeDescr); 314 currentMV.visitFieldInsn(Opcodes.GETFIELD, ownerName, 315 vi.name, typeDescr); 316 } else { 317 throw new IllegalArgumentException("illegal left operand : " 318 + left + "("+left.getClass()+")"); 319 } 320 break; 321 case OR: 322 generateBasicLogicOperator(Opcodes.IFNE, false, left, right); 323 break; 324 case AND: 325 generateBasicLogicOperator(Opcodes.IFEQ, true, left, right); 326 break; 327 case BIT_OR: 328 if (mostCapacious.equals(TypeList.LONG)) { 329 currentMV.visitInsn(Opcodes.LOR); 330 } else { 331 currentMV.visitInsn(Opcodes.IOR); 332 } 333 break; 334 case BIT_XOR: 335 if (mostCapacious.equals(TypeList.LONG)) { 336 currentMV.visitInsn(Opcodes.LXOR); 337 } else { 338 currentMV.visitInsn(Opcodes.IXOR); 339 } 340 break; 341 case BIT_AND: 342 if (mostCapacious.equals(TypeList.LONG)) { 343 currentMV.visitInsn(Opcodes.LAND); 344 } else { 345 currentMV.visitInsn(Opcodes.IAND); 346 } 347 break; 348 case EQ: 349 generateCmpBasedCode(mostCapacious, Opcodes.IFEQ, Opcodes.IF_ICMPEQ); 350 break; 351 case NE: 352 generateCmpBasedCode(mostCapacious, Opcodes.IFNE, Opcodes.IF_ICMPNE); 353 break; 354 case GT: 355 generateCmpBasedCode(mostCapacious, Opcodes.IFGT, Opcodes.IF_ICMPGT); 356 break; 357 case LT: 358 generateCmpBasedCode(mostCapacious, Opcodes.IFLT, Opcodes.IF_ICMPLT); 359 break; 360 case GE: 361 generateCmpBasedCode(mostCapacious, Opcodes.IFGE, Opcodes.IF_ICMPGE); 362 break; 363 case LE: 364 generateCmpBasedCode(mostCapacious, Opcodes.IFLE, Opcodes.IF_ICMPLE); 365 break; 366 case SHR: 367 if (leftType.equals(TypeList.LONG)) { 368 currentMV.visitInsn(Opcodes.LSHR); 369 } else { 370 currentMV.visitInsn(Opcodes.ISHR); 371 } 372 break; 373 case SHL: 374 if (leftType.equals(TypeList.LONG)) { 375 currentMV.visitInsn(Opcodes.LSHL); 376 } else { 377 currentMV.visitInsn(Opcodes.ISHL); 378 } 379 break; 380 case SAR: 381 if (leftType.equals(TypeList.LONG)) { 382 currentMV.visitInsn(Opcodes.LUSHR); 383 } else { 384 currentMV.visitInsn(Opcodes.IUSHR); 385 } 386 break; 387 case STRADD: 388 // we use String::valueOf to change null to "null" 389 left.accept(this); 390 currentMV.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", 391 "(Ljava/lang/Object;)Ljava/lang/String;", false /* not interface */); 392 right.accept(this); 393 currentMV.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", 394 "(Ljava/lang/Object;)Ljava/lang/String;", false /* not interface */); 395 currentMV.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "concat", 396 "(Ljava/lang/String;)Ljava/lang/String;", false /* not interface */); 397 break; 398 case ADD: 399 if (mostCapacious.equals(TypeList.LONG)) { 400 currentMV.visitInsn(Opcodes.LADD); 401 } else if (mostCapacious.equals(TypeList.DOUBLE)) { 402 currentMV.visitInsn(Opcodes.DADD); 403 } else if (mostCapacious.equals(TypeList.FLOAT)) { 404 currentMV.visitInsn(Opcodes.FADD); 405 } else { 406 currentMV.visitInsn(Opcodes.IADD); 407 } 408 break; 409 case SUB: 410 if (mostCapacious.equals(TypeList.LONG)) { 411 currentMV.visitInsn(Opcodes.LSUB); 412 } else if (mostCapacious.equals(TypeList.DOUBLE)) { 413 currentMV.visitInsn(Opcodes.DSUB); 414 } else if (mostCapacious.equals(TypeList.FLOAT)) { 415 currentMV.visitInsn(Opcodes.FSUB); 416 } else { 417 currentMV.visitInsn(Opcodes.ISUB); 418 } 419 break; 420 case MUL: 421 if (mostCapacious.equals(TypeList.LONG)) { 422 currentMV.visitInsn(Opcodes.LMUL); 423 } else if (mostCapacious.equals(TypeList.DOUBLE)) { 424 currentMV.visitInsn(Opcodes.DMUL); 425 } else if (mostCapacious.equals(TypeList.FLOAT)) { 426 currentMV.visitInsn(Opcodes.FMUL); 427 } else { 428 currentMV.visitInsn(Opcodes.IMUL); 429 } 430 break; 431 case DIV: 432 if (mostCapacious.equals(TypeList.LONG)) { 433 currentMV.visitInsn(Opcodes.LDIV); 434 } else if (mostCapacious.equals(TypeList.DOUBLE)) { 435 currentMV.visitInsn(Opcodes.DDIV); 436 } else if (mostCapacious.equals(TypeList.FLOAT)) { 437 currentMV.visitInsn(Opcodes.FDIV); 438 } else { 439 currentMV.visitInsn(Opcodes.IDIV); 440 } 441 break; 442 case MOD: 443 if (mostCapacious.equals(TypeList.LONG)) { 444 currentMV.visitInsn(Opcodes.LREM); 445 } else if (mostCapacious.equals(TypeList.DOUBLE)) { 446 currentMV.visitInsn(Opcodes.DREM); 447 } else if (mostCapacious.equals(TypeList.FLOAT)) { 448 currentMV.visitInsn(Opcodes.FREM); 449 } else { 450 currentMV.visitInsn(Opcodes.IREM); 451 } 452 break; 453 case COMPOUND_ADD: 454 lowerCompoundBinaryOperator("java.lang.String".equals(leftType.getName()) 455 ? OperatorKind.STRADD : OperatorKind.ADD, node); 456 break; 457 case COMPOUND_SUB: 458 lowerCompoundBinaryOperator(OperatorKind.SUB, node); 459 break; 460 case COMPOUND_MUL: 461 lowerCompoundBinaryOperator(OperatorKind.MUL, node); 462 break; 463 case COMPOUND_DIV: 464 lowerCompoundBinaryOperator(OperatorKind.DIV, node); 465 break; 466 case COMPOUND_MOD: 467 lowerCompoundBinaryOperator(OperatorKind.MOD, node); 468 break; 469 case COMPOUND_AND: 470 lowerCompoundBinaryOperator(leftType.equals(TypeList.BOOLEAN) 471 ? OperatorKind.AND : OperatorKind.BIT_AND, node); 472 break; 473 case COMPOUND_OR: 474 lowerCompoundBinaryOperator(leftType.equals(TypeList.BOOLEAN) 475 ? OperatorKind.OR : OperatorKind.BIT_OR, node); 476 break; 477 case COMPOUND_XOR: 478 lowerCompoundBinaryOperator(OperatorKind.BIT_XOR, node); 479 break; 480 case COMPOUND_SHR: 481 lowerCompoundBinaryOperator(OperatorKind.SHR, node); 482 break; 483 case COMPOUND_SHL: 484 lowerCompoundBinaryOperator(OperatorKind.SHL, node); 485 break; 486 case COMPOUND_SAR: 487 lowerCompoundBinaryOperator(OperatorKind.SAR, node); 488 break; 489 default: 490 throw new Error("Unsupported binary operator"); 491 } 492 return EMPTY_BYTE_ARRAY; 493 } 494 495 private static int tmpObject; 496 private void lowerCompoundBinaryOperator(OperatorKind kind, IRNode node) { 497 IRNode left = node.getChild(Operator.Order.LEFT.ordinal()); 498 IRNode right = node.getChild(Operator.Order.RIGHT.ordinal()); 499 500 if (left instanceof NonStaticMemberVariable) { 501 NonStaticMemberVariable var = (NonStaticMemberVariable) left; 502 IRNode holder = var.getChild(0); 503 Type type = holder.getResultType(); 504 VariableInfo tmpInfo = new VariableInfo("tmpObject_" + tmpObject++, 505 currentClass, type, VariableInfo.LOCAL); 506 new Statement(new VariableInitialization(tmpInfo, holder), true).accept(this); 507 left = new NonStaticMemberVariable(new LocalVariable(tmpInfo), var.getVariableInfo()); 508 } 509 Type leftType = left.getResultType(); 510 Type rightType = right.getResultType(); 511 Type resultType = leftType; 512 if (leftType instanceof BuiltInType && rightType instanceof BuiltInType) { 513 if (kind != OperatorKind.SHL && kind != OperatorKind.SHR && kind != OperatorKind.SAR 514 && ((BuiltInType) rightType).isMoreCapaciousThan((BuiltInType) leftType)) { 515 resultType = rightType; 516 } 517 } 518 IRNode result = new CastOperator(leftType, 519 new BinaryOperator(kind, resultType, left, right)); 520 new BinaryOperator(OperatorKind.ASSIGN, leftType, left, result).accept(this); 521 } 522 523 private void generateBasicLogicOperator(int ifOpcode, boolean retTrueFirst, IRNode left, 524 IRNode right) { 525 Label secondCase = new Label(); 526 Label endLabel = new Label(); 527 left.accept(this); 528 currentMV.visitJumpInsn(ifOpcode, secondCase); 529 right.accept(this); 530 currentMV.visitJumpInsn(ifOpcode, secondCase); 531 currentMV.visitInsn(retTrueFirst ? Opcodes.ICONST_1 : Opcodes.ICONST_0); 532 currentMV.visitJumpInsn(Opcodes.GOTO, endLabel); 533 currentMV.visitLabel(secondCase); 534 currentMV.visitInsn(retTrueFirst ? Opcodes.ICONST_0 : Opcodes.ICONST_1); 535 currentMV.visitLabel(endLabel); 536 } 537 538 private void generateCmpBasedCode(Type type, int nonIntOpcode, int intOpcode) { 539 boolean useNonIntOpcode = false; 540 if (type.equals(TypeList.LONG) || type.equals(TypeList.FLOAT) 541 || type.equals(TypeList.DOUBLE)) { 542 if (type.equals(TypeList.LONG)) { 543 currentMV.visitInsn(Opcodes.LCMP); 544 } else if (type.equals(TypeList.FLOAT)) { 545 currentMV.visitInsn(Opcodes.FCMPL); 546 } else { 547 currentMV.visitInsn(Opcodes.DCMPL); 548 } 549 useNonIntOpcode = true; 550 } 551 int opcodeToUse; 552 if (!useNonIntOpcode) { 553 if (type instanceof TypeKlass) { 554 if (intOpcode == Opcodes.IF_ICMPEQ) { 555 opcodeToUse = Opcodes.IF_ACMPEQ; 556 } else if (intOpcode == Opcodes.IF_ICMPNE) { 557 opcodeToUse = Opcodes.IF_ACMPNE; 558 } else { 559 throw new Error("Can't compare references"); 560 } 561 } else { 562 opcodeToUse = intOpcode; 563 } 564 } else { 565 opcodeToUse = nonIntOpcode; 566 } 567 Label retTrue = new Label(); 568 Label end = new Label(); 569 currentMV.visitJumpInsn(opcodeToUse, retTrue); 570 currentMV.visitInsn(Opcodes.ICONST_0); 571 currentMV.visitJumpInsn(Opcodes.GOTO, end); 572 currentMV.visitLabel(retTrue); 573 currentMV.visitInsn(Opcodes.ICONST_1); 574 currentMV.visitLabel(end); 575 } 576 577 /* 578 * Converts top-stack element from one builtin type to another 579 */ 580 private void convertTopType(Type from, Type to) { 581 if (!(from instanceof BuiltInType) || !(to instanceof BuiltInType) || from.equals(to)) { 582 return; // skip 583 } 584 boolean castedToInt = false; 585 if (from.equals(TypeList.FLOAT)) { 586 if (to.equals(TypeList.DOUBLE)) { 587 currentMV.visitInsn(Opcodes.F2D); 588 } else if (to.equals(TypeList.LONG)) { 589 currentMV.visitInsn(Opcodes.F2L); 590 } else { 591 currentMV.visitInsn(Opcodes.F2I); 592 castedToInt = true; 593 } 594 } else if (from.equals(TypeList.DOUBLE)) { 595 if (to.equals(TypeList.FLOAT)) { 596 currentMV.visitInsn(Opcodes.D2F); 597 } else if (to.equals(TypeList.LONG)) { 598 currentMV.visitInsn(Opcodes.D2L); 599 } else { 600 currentMV.visitInsn(Opcodes.D2I); 601 castedToInt = true; 602 } 603 } else if (from.equals(TypeList.LONG)) { 604 if (to.equals(TypeList.DOUBLE)) { 605 currentMV.visitInsn(Opcodes.L2D); 606 } else if (to.equals(TypeList.FLOAT)) { 607 currentMV.visitInsn(Opcodes.L2F); 608 } else { 609 currentMV.visitInsn(Opcodes.L2I); 610 castedToInt = true; 611 } 612 } else { 613 if (to.equals(TypeList.BYTE)) { 614 currentMV.visitInsn(Opcodes.I2B); 615 } else if (to.equals(TypeList.CHAR)) { 616 currentMV.visitInsn(Opcodes.I2C); 617 } else if (to.equals(TypeList.SHORT)) { 618 currentMV.visitInsn(Opcodes.I2S); 619 } else if (to.equals(TypeList.LONG)) { 620 currentMV.visitInsn(Opcodes.I2L); 621 } else if (to.equals(TypeList.FLOAT)) { 622 currentMV.visitInsn(Opcodes.I2F); 623 } else if (to.equals(TypeList.DOUBLE)) { 624 currentMV.visitInsn(Opcodes.I2D); 625 } 626 } 627 if (castedToInt) { 628 if (to.equals(TypeList.BYTE)) { 629 currentMV.visitInsn(Opcodes.I2B); 630 } else if (to.equals(TypeList.CHAR)) { 631 currentMV.visitInsn(Opcodes.I2C); 632 } else if (to.equals(TypeList.SHORT)) { 633 currentMV.visitInsn(Opcodes.I2S); 634 } 635 } 636 } 637 638 @Override 639 public byte[] visit(Block node) { 640 return iterateBlock(node); 641 } 642 643 @Override 644 public byte[] visit(Break node) { 645 Label label = endLabels.peek(); 646 if (label != null) { 647 currentMV.visitJumpInsn(Opcodes.GOTO, label); 648 } 649 return EMPTY_BYTE_ARRAY; 650 } 651 652 @Override 653 public byte[] visit(CastOperator node) { 654 IRNode expression = node.getChild(0); 655 expression.accept(this); 656 Type to = node.getResultType(); 657 Type from = expression.getResultType(); 658 // TODO boxing/unboxing 659 if (!TypeList.isBuiltIn(to) || !TypeList.isBuiltIn(from)) { 660 // class cast 661 currentMV.visitTypeInsn(Opcodes.CHECKCAST, asInternalName(to.getName())); 662 } else { 663 convertTopType(from, to); 664 } 665 return EMPTY_BYTE_ARRAY; 666 } 667 668 @Override 669 public byte[] visit(CatchBlock node) { 670 Type type = node.throwables.get(0); 671 VariableInfo exInfo = new VariableInfo("ex", currentClass, 672 type, VariableInfo.LOCAL); 673 int index = locals.getLocalIndex(exInfo); 674 currentMV.visitVarInsn(Opcodes.ASTORE, index); 675 node.getChild(0).accept(this); 676 return EMPTY_BYTE_ARRAY; 677 } 678 679 @Override 680 public byte[] visit(ClassDefinitionBlock node) { 681 return iterateBlock(node); 682 } 683 684 @Override 685 public byte[] visit(ConstructorDefinition node) { 686 FunctionInfo info = node.getFunctionInfo(); 687 String ownerName = node.getOwner().getName(); 688 TypeKlass parentClass = currentClass.getParent(); 689 ContextDependedClassWriter cw = classWriters.get(ownerName); 690 691 String descriptor = getDescriptor(node, 1, "V"); 692 currentMV = cw.visitMethod(asAccessFlags(info), "<init>", descriptor, null, null); 693 currentMV.visitVarInsn(Opcodes.ALOAD, 0); 694 currentMV.visitMethodInsn(Opcodes.INVOKESPECIAL, 695 parentClass != null ? asInternalName(parentClass.getName()) : "java/lang/Object", 696 "<init>", "()V", false); 697 locals.initConstructorArguments(node.getOwner(), info); 698 // TODO: add datamemebers as child to all ctors 699 generateDataMembers(node.getParent().getParent().getChild(Klass.KlassPart.DATA_MEMBERS.ordinal())); 700 IRNode body = node.getChild(0); 701 body.accept(this); 702 currentMV.visitInsn(Opcodes.RETURN); 703 currentMV.visitMaxs(0, 0); 704 currentMV.visitEnd(); 705 return EMPTY_BYTE_ARRAY; 706 } 707 708 private void generateDataMembers(IRNode node) { 709 // TODO shouldn't we skip declaration? 710 if (node != null) { 711 node.accept(this); 712 } 713 } 714 715 @Override 716 public byte[] visit(ConstructorDefinitionBlock node) { 717 return iterateBlock(node); 718 } 719 720 @Override 721 public byte[] visit(Continue node) { 722 Label label = beginLabels.peek(); 723 if (label != null) { 724 currentMV.visitJumpInsn(Opcodes.GOTO, label); 725 } 726 return EMPTY_BYTE_ARRAY; 727 } 728 729 @Override 730 public byte[] visit(CounterInitializer node) { 731 visitLocalVar(node); 732 emitPop(node.getVariableInfo().type); 733 return EMPTY_BYTE_ARRAY; 734 } 735 736 private byte[] visitLocalVar(Initialization node) { 737 VariableInfo vi = node.getVariableInfo(); 738 int index = locals.addLocal(vi); 739 int store; 740 node.getChild(0).accept(this); // place initialization expression on stack 741 emitDup(vi.type); 742 if (vi.type instanceof TypeKlass) { 743 store = Opcodes.ASTORE; 744 } else if (vi.type.equals(TypeList.DOUBLE)) { 745 store = Opcodes.DSTORE; 746 } else if (vi.type.equals(TypeList.LONG)) { 747 store = Opcodes.LSTORE; 748 } else if (vi.type.equals(TypeList.FLOAT)) { 749 store = Opcodes.FSTORE; 750 } else { 751 store = Opcodes.ISTORE; 752 } 753 currentMV.visitVarInsn(store, index); 754 return EMPTY_BYTE_ARRAY; 755 } 756 757 @Override 758 public byte[] visit(CounterManipulator node) { 759 return node.getChild(0).accept(this); 760 } 761 762 @Override 763 public byte[] visit(Declaration node) { 764 IRNode child = node.getChild(0); 765 child.accept(this); 766 if (child instanceof Initialization) { 767 emitPop(((Initialization) child).getVariableInfo().type); 768 } 769 return EMPTY_BYTE_ARRAY; 770 } 771 772 @Override 773 public byte[] visit(DoWhile node) { 774 Loop loop = node.getLoop(); 775 loop.initialization.accept(this); 776 node.getChild(DoWhile.DoWhilePart.HEADER.ordinal()).accept(this); 777 Label currentLoopBegin = new Label(); 778 beginLabels.push(currentLoopBegin); 779 Label currentLoopEnd = new Label(); 780 endLabels.push(currentLoopEnd); 781 currentMV.visitLabel(currentLoopBegin); 782 node.getChild(DoWhile.DoWhilePart.BODY1.ordinal()).accept(this); 783 loop.manipulator.accept(this); 784 node.getChild(DoWhile.DoWhilePart.BODY2.ordinal()).accept(this); 785 loop.condition.accept(this); 786 assert loop.condition.getResultType() == TypeList.BOOLEAN; 787 currentMV.visitJumpInsn(Opcodes.IFEQ, currentLoopBegin); 788 currentMV.visitLabel(currentLoopEnd); 789 Label a = beginLabels.pop(); 790 assert currentLoopBegin == a; 791 a = endLabels.pop(); 792 assert currentLoopEnd == a; 793 return EMPTY_BYTE_ARRAY; 794 } 795 796 @Override 797 public byte[] visit(For node) { 798 Loop loop = node.getLoop(); 799 loop.initialization.accept(this); 800 node.getChild(For.ForPart.HEADER.ordinal()).accept(this); 801 node.getChild(For.ForPart.STATEMENT1.ordinal()).accept(this); 802 Label currentLoopBegin = new Label(); 803 beginLabels.push(currentLoopBegin); 804 currentMV.visitLabel(currentLoopBegin); 805 loop.condition.accept(this); 806 assert loop.condition.getResultType() == TypeList.BOOLEAN; 807 Label currentLoopEnd = new Label(); 808 endLabels.push(currentLoopEnd); 809 currentMV.visitJumpInsn(Opcodes.IFEQ, currentLoopEnd); 810 node.getChild(For.ForPart.STATEMENT2.ordinal()).accept(this); 811 node.getChild(For.ForPart.BODY1.ordinal()).accept(this); 812 loop.manipulator.accept(this); 813 node.getChild(For.ForPart.BODY2.ordinal()).accept(this); 814 node.getChild(For.ForPart.BODY3.ordinal()).accept(this); 815 currentMV.visitJumpInsn(Opcodes.GOTO, currentLoopBegin); 816 currentMV.visitLabel(currentLoopEnd); 817 Label a = beginLabels.pop(); 818 assert currentLoopBegin == a; 819 a = endLabels.pop(); 820 assert currentLoopEnd == a; 821 return EMPTY_BYTE_ARRAY; 822 } 823 824 @Override 825 public byte[] visit(Function node) { 826 FunctionInfo info = node.getValue(); 827 boolean needInstance = !info.isStatic() && !info.isConstructor(); 828 if (needInstance) { 829 node.getChild(0).accept(this); // placing instance on stack 830 } 831 // call itself with specific invoke* 832 String signature = info.argTypes.stream() 833 .skip(!needInstance ? 0 : 1) 834 .map(vi -> new String(vi.type.accept(this))) 835 .collect(Collectors.joining("", "(", ")")) 836 + (info.isConstructor() ? "V" : new String(node.getResultType().accept(this))); 837 int invokeCode = Opcodes.INVOKEVIRTUAL; 838 if (info.isStatic()) { 839 invokeCode = Opcodes.INVOKESTATIC; 840 } else if (info.isConstructor() || info.isPrivate()) { 841 // TODO : superclass method invocation? 842 invokeCode = Opcodes.INVOKESPECIAL; 843 } else { 844 if (info.owner.isInterface()) { 845 invokeCode = Opcodes.INVOKEINTERFACE; 846 } 847 } 848 if (info.isConstructor()) { 849 currentMV.visitTypeInsn(Opcodes.NEW, asInternalName(info.owner.getName())); 850 currentMV.visitInsn(Opcodes.DUP); 851 } 852 // calculating parameters 853 node.getChildren().stream() 854 .skip(!needInstance ? 0 : 1) 855 .forEachOrdered(c -> c.accept(this)); 856 currentMV.visitMethodInsn(invokeCode, asInternalName(info.owner.getName()), 857 info.isConstructor() ? "<init>" : info.name, signature, 858 invokeCode == Opcodes.INVOKEINTERFACE); 859 return EMPTY_BYTE_ARRAY; 860 } 861 862 @Override 863 public byte[] visit(FunctionDeclaration node) { 864 FunctionInfo info = node.getFunctionInfo(); 865 String ownerName = node.getOwner().getName(); 866 ContextDependedClassWriter cw = classWriters.get(ownerName); 867 String returnType = new String(info.type.accept(this)); 868 869 String descriptor = getDescriptor(node, 0, returnType); 870 currentMV = cw.visitMethod(asAccessFlags(info) + Opcodes.ACC_ABSTRACT, 871 info.name, descriptor, null, null); 872 currentMV.visitEnd(); 873 return EMPTY_BYTE_ARRAY; 874 } 875 876 @Override 877 public byte[] visit(FunctionDeclarationBlock node) { 878 return iterateBlock(node); 879 } 880 881 @Override 882 public byte[] visit(FunctionDefinition node) { 883 FunctionInfo info = node.getFunctionInfo(); 884 String ownerName = node.getOwner().getName(); 885 ContextDependedClassWriter cw = classWriters.get(ownerName); 886 String returnType = new String(info.type.accept(this)); 887 888 String descriptor = getDescriptor(node, 2, returnType); 889 currentMV = cw.visitMethod(asAccessFlags(info), info.name, descriptor, null, null); 890 locals.initFunctionArguments(info); 891 IRNode body = node.getChild(0); 892 body.accept(this); 893 IRNode ret = node.getChild(1); 894 ret.accept(this); 895 currentMV.visitMaxs(0, 0); 896 currentMV.visitEnd(); 897 return EMPTY_BYTE_ARRAY; 898 } 899 900 @Override 901 public byte[] visit(FunctionDefinitionBlock node) { 902 return iterateBlock(node); 903 } 904 905 @Override 906 public byte[] visit(FunctionRedefinition node) { 907 FunctionInfo info = node.getFunctionInfo(); 908 String ownerName = node.getOwner().getName(); 909 ContextDependedClassWriter cw = classWriters.get(ownerName); 910 String returnType = new String(info.type.accept(this)); 911 String descriptor = getDescriptor(node, 2, returnType); 912 currentMV = cw.visitMethod(asAccessFlags(info), info.name, descriptor, null, null); 913 locals.initFunctionArguments(info); 914 IRNode body = node.getChild(0); 915 body.accept(this); 916 IRNode ret = node.getChild(1); 917 ret.accept(this); 918 currentMV.visitMaxs(0, 0); 919 currentMV.visitEnd(); 920 return EMPTY_BYTE_ARRAY; 921 } 922 923 @Override 924 public byte[] visit(FunctionRedefinitionBlock node) { 925 return iterateBlock(node); 926 } 927 928 @Override 929 public byte[] visit(If node) { 930 IRNode conditionBlock = node.getChild(If.IfPart.CONDITION.ordinal()); 931 // get the condition type to emit correct if 932 conditionBlock.accept(this); 933 generateIf(Opcodes.IFEQ, node.getChild(If.IfPart.THEN.ordinal()), 934 node.getChild(If.IfPart.ELSE.ordinal())); 935 return EMPTY_BYTE_ARRAY; 936 } 937 938 /* 939 * Generates if block with then and else blocks for the given IF opcode 940 */ 941 private void generateIf(int ifOpcode, IRNode thenBlock, IRNode elseBlock) { 942 Label elseLabel = new Label(); 943 // if the opposite condition is met then go to the else statement 944 currentMV.visitJumpInsn(ifOpcode, elseLabel); 945 // write THEN block 946 thenBlock.accept(this); 947 if (elseBlock != null) { 948 // goto the end after THEN 949 Label endLabel = new Label(); 950 currentMV.visitJumpInsn(Opcodes.GOTO, endLabel); 951 // ELSE block 952 currentMV.visitLabel(elseLabel); 953 elseBlock.accept(this); 954 currentMV.visitLabel(endLabel); 955 } else { 956 currentMV.visitLabel(elseLabel); 957 } 958 } 959 960 @Override 961 public byte[] visit(Initialization node) { 962 VariableInfo vi = node.getVariableInfo(); 963 if (vi.isLocal()) { 964 return visitLocalVar(node); 965 } 966 String ownerName = vi.getOwner().getName(); 967 ContextDependedClassWriter cw = classWriters.get(ownerName); 968 String typeName = new String(vi.type.accept(this)); 969 // constant value used only for final static fields 970 FieldVisitor fw = cw.visitField(asAccessFlags(vi), vi.name, 971 typeName, 972 null /* Generic */, 973 null /* Constant value */); 974 fw.visitEnd(); // doesn't need visitAnnotation and visitAttribute 975 if (vi.isStatic()) { 976 node.getChild(0).accept(this); // put value to stack 977 emitDup(vi.type); 978 currentMV.visitFieldInsn(Opcodes.PUTSTATIC, 979 asInternalName(vi.getOwner().getName()), 980 vi.name, 981 new String(vi.type.accept(this))); 982 } else { 983 // TODO : can it be another object? 984 currentMV.visitVarInsn(Opcodes.ALOAD, 0); // put this to stack 985 node.getChild(0).accept(this); // put value to stack 986 emitDupX1(vi.type); 987 currentMV.visitFieldInsn(Opcodes.PUTFIELD, 988 asInternalName(vi.getOwner().getName()), 989 vi.name, 990 new String(vi.type.accept(this))); 991 } 992 return EMPTY_BYTE_ARRAY; 993 } 994 995 private void emitDupX1(Type type) { 996 if (TypeList.DOUBLE.equals(type) || TypeList.LONG.equals(type)) { 997 currentMV.visitInsn(Opcodes.DUP2_X1); 998 } else if (!TypeList.VOID.equals(type)){ 999 currentMV.visitInsn(Opcodes.DUP_X1); 1000 } 1001 } 1002 1003 private void emitDup(Type type) { 1004 if (TypeList.DOUBLE.equals(type) || TypeList.LONG.equals(type)) { 1005 currentMV.visitInsn(Opcodes.DUP2); 1006 } else if (!TypeList.VOID.equals(type)){ 1007 currentMV.visitInsn(Opcodes.DUP); 1008 } 1009 } 1010 1011 @Override 1012 public byte[] visit(Interface node) { 1013 String name = node.getName(); 1014 ContextDependedClassWriter classWriter = new ContextDependedClassWriter(context, CLASS_WRITER_FLAGS); 1015 classWriters.put(name, classWriter); 1016 TypeKlass parentKlass = node.getParentKlass(); 1017 classWriter.visit(Opcodes.V1_8, 1018 Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE, 1019 asInternalName(name), 1020 null /* Generic */, 1021 "java/lang/Object", 1022 parentKlass == null ? null : new String[] { 1023 asInternalName(parentKlass.getName())}); 1024 if (node.getChildren().size() > 0) { 1025 node.getChild(0).accept(this); 1026 } 1027 1028 classWriter.visitEnd(); 1029 byte[] byteCode = classWriter.toByteArray(); 1030 context.register(name, byteCode); 1031 return byteCode; 1032 } 1033 1034 @Override 1035 public byte[] visit(Klass node) { 1036 String name = node.getName(); 1037 TypeKlass prevClass = currentClass; 1038 currentClass = node.getThisKlass(); 1039 ContextDependedClassWriter classWriter = new ContextDependedClassWriter(context, CLASS_WRITER_FLAGS); 1040 classWriters.put(name, classWriter); 1041 TypeKlass thisClass = node.getThisKlass(); 1042 TypeKlass parentClass = node.getParentKlass(); 1043 String[] interfaces = node.getInterfaces().stream() 1044 .map(IRNode::getName) 1045 .map(ByteCodeVisitor::asInternalName) 1046 .toArray(String[]::new); 1047 classWriter.visit(Opcodes.V1_8, asAccessFlags(thisClass), 1048 asInternalName(name), 1049 null /* Generic */, 1050 parentClass != null ? asInternalName(parentClass.getName()) : "java/lang/Object", 1051 interfaces); 1052 1053 IRNode constructors = node.getChild(Klass.KlassPart.CONSTRUCTORS.ordinal()); 1054 if (constructors != null) { 1055 constructors.accept(this); 1056 } else { 1057 // generate default ctor 1058 currentMV = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); 1059 currentMV.visitVarInsn(Opcodes.ALOAD, 0); 1060 currentMV.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 1061 locals.clear(); 1062 locals.addLocal(new VariableInfo("this", thisClass, thisClass, VariableInfo.NONE)); 1063 generateDataMembers(node.getChild(Klass.KlassPart.DATA_MEMBERS.ordinal())); 1064 currentMV.visitInsn(Opcodes.RETURN); 1065 currentMV.visitMaxs(0, 0); 1066 currentMV.visitEnd(); 1067 } 1068 IRNode redefinedFunctions = node.getChild(Klass.KlassPart.REDEFINED_FUNCTIONS.ordinal()); 1069 if (redefinedFunctions != null) { 1070 redefinedFunctions.accept(this); 1071 } 1072 IRNode overridenFunctions = node.getChild(Klass.KlassPart.OVERRIDEN_FUNCTIONS.ordinal()); 1073 if (overridenFunctions != null) { 1074 overridenFunctions.accept(this); 1075 } 1076 IRNode memberFunctions = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS.ordinal()); 1077 if (memberFunctions != null) { 1078 memberFunctions.accept(this); 1079 } 1080 IRNode memberFunctionDecls = node.getChild(Klass.KlassPart.MEMBER_FUNCTIONS_DECLARATIONS.ordinal()); 1081 if (memberFunctionDecls != null) { 1082 memberFunctionDecls.accept(this); 1083 } 1084 IRNode printVariables = node.getChild(Klass.KlassPart.PRINT_VARIABLES.ordinal()); 1085 if (printVariables != null) { 1086 printVariables.accept(this); 1087 } 1088 classWriter.visitEnd(); 1089 byte[] byteCode = classWriter.toByteArray(); 1090 context.register(name, byteCode); 1091 currentClass = prevClass; 1092 return byteCode; 1093 } 1094 1095 private void visitLiteral(boolean value) { 1096 double chance = PseudoRandom.random(); 1097 if (chance < CONSTANT_INST_CHANCE) { 1098 currentMV.visitInsn(value ? Opcodes.ICONST_1 : Opcodes.ICONST_0); 1099 } else { 1100 currentMV.visitIntInsn(Opcodes.BIPUSH, value ? 1 : 0); 1101 } 1102 } 1103 1104 private void visitLiteral(byte value) { 1105 double chance = PseudoRandom.random(); 1106 if (chance < CONSTANT_INST_CHANCE && value > -2 && value < 6) { 1107 currentMV.visitInsn(Opcodes.ICONST_0 + value); 1108 } else { 1109 currentMV.visitIntInsn(Opcodes.BIPUSH, value); 1110 } 1111 } 1112 1113 private void visitLiteral(short value) { 1114 double chance = PseudoRandom.random(); 1115 if (chance < CONSTANT_INST_CHANCE && value > -2 && value < 6) { 1116 currentMV.visitInsn(Opcodes.ICONST_0 + value); 1117 } else { 1118 currentMV.visitIntInsn(Opcodes.SIPUSH, value); 1119 } 1120 } 1121 1122 private void visitLiteral(char value) { 1123 double chance = PseudoRandom.random(); 1124 if (chance < CONSTANT_INST_CHANCE && value < 6) { 1125 currentMV.visitInsn(Opcodes.ICONST_0 + value); 1126 } else { 1127 // TODO : check for widechar/unicode 1128 currentMV.visitIntInsn(Opcodes.BIPUSH, value); 1129 } 1130 } 1131 1132 private void visitLiteral(int value) { 1133 double chance = PseudoRandom.random(); 1134 if (chance < CONSTANT_INST_CHANCE && value > -2 && value < 6) { 1135 currentMV.visitInsn(Opcodes.ICONST_0 + value); 1136 } else { 1137 currentMV.visitLdcInsn(value); 1138 } 1139 } 1140 1141 private void visitLiteral(long value) { 1142 double chance = PseudoRandom.random(); 1143 if (chance < CONSTANT_INST_CHANCE && value > -1 && value < 2) { 1144 currentMV.visitInsn(Opcodes.LCONST_0 + (int)value); 1145 } else { 1146 currentMV.visitLdcInsn(value); 1147 } 1148 } 1149 1150 private void visitLiteral(float value) { 1151 double chance = PseudoRandom.random(); 1152 if (chance < CONSTANT_INST_CHANCE && (value == 0.0f || value == 1.0f || value == 2.0f)) { 1153 currentMV.visitInsn(Opcodes.FCONST_0 + (int)value); 1154 } else { 1155 currentMV.visitLdcInsn(value); 1156 } 1157 } 1158 1159 private void visitLiteral(double value) { 1160 double chance = PseudoRandom.random(); 1161 if (chance < CONSTANT_INST_CHANCE && (value == 0.0 || value == 1.0)) { 1162 currentMV.visitInsn(Opcodes.DCONST_0 + (int)value); 1163 } else { 1164 currentMV.visitLdcInsn(value); 1165 } 1166 } 1167 1168 @Override 1169 public byte[] visit(Literal node) { 1170 /* 1171 ICONST_n (−1 ≤ n ≤ 5) <==> BIPUSH <n> 1172 LCONST_n (0 ≤ n ≤ 1) 1173 FCONST_n (0 ≤ n ≤ 2) 1174 DCONST_n (0 ≤ n ≤ 1) 1175 ACONST_NULL 1176 1177 BIPUSH b, −128 ≤ b < 127 1178 SIPUSH s, −32768 ≤ s < 32767 1179 LDC cst (int, float, long, double, String or Type) 1180 */ 1181 Type type = node.getResultType(); 1182 double chance = PseudoRandom.random(); 1183 if (type.equals(TypeList.BOOLEAN)) { 1184 visitLiteral(Boolean.valueOf(node.getValue().toString())); 1185 } else if (type.equals(TypeList.BYTE)) { 1186 visitLiteral(Byte.valueOf(node.getValue().toString())); 1187 } else if (type.equals(TypeList.SHORT)) { 1188 visitLiteral(Short.valueOf(node.getValue().toString())); 1189 } else if (type.equals(TypeList.CHAR)) { 1190 visitLiteral(node.getValue().toString().charAt(0)); 1191 } else if (type.equals(TypeList.INT)) { 1192 visitLiteral(Integer.valueOf(node.getValue().toString())); 1193 } else if (type.equals(TypeList.LONG)) { 1194 visitLiteral(Long.valueOf(node.getValue().toString())); 1195 } else if (type.equals(TypeList.FLOAT)) { 1196 visitLiteral(Float.valueOf(node.getValue().toString())); 1197 } else if (type.equals(TypeList.DOUBLE)) { 1198 visitLiteral(Double.valueOf(node.getValue().toString())); 1199 } else { 1200 currentMV.visitLdcInsn(node.getValue()); 1201 } 1202 return EMPTY_BYTE_ARRAY; 1203 } 1204 private static final double CONSTANT_INST_CHANCE = 0.5; 1205 1206 @Override 1207 public byte[] visit(LocalVariable node) { 1208 // This node is for "reading" only. Writing is handled in BinaryOperator visit(see ASSIGN) 1209 VariableInfo vi = node.getVariableInfo(); 1210 Type varType = vi.type; 1211 int index = locals.getLocalIndex(vi); 1212 if (varType.equals(TypeList.LONG)) { 1213 currentMV.visitVarInsn(Opcodes.LLOAD, index); 1214 } else if (varType.equals(TypeList.DOUBLE)) { 1215 currentMV.visitVarInsn(Opcodes.DLOAD, index); 1216 } else if (varType.equals(TypeList.FLOAT)) { 1217 currentMV.visitVarInsn(Opcodes.FLOAD, index); 1218 } else if (varType instanceof TypeKlass) { 1219 currentMV.visitVarInsn(Opcodes.ALOAD, index); 1220 } else { 1221 currentMV.visitVarInsn(Opcodes.ILOAD, index); 1222 } 1223 return EMPTY_BYTE_ARRAY; 1224 } 1225 1226 @Override 1227 public byte[] visit(LoopingCondition node) { 1228 return node.getCondition().accept(this); 1229 } 1230 1231 @Override 1232 public byte[] visit(MainKlass node) { 1233 TypeKlass prevClass = currentClass; 1234 currentClass = node.getThisKlass(); 1235 String name = node.getName(); 1236 ContextDependedClassWriter mainClassWriter = new ContextDependedClassWriter(context, CLASS_WRITER_FLAGS); 1237 classWriters.put(name, mainClassWriter); 1238 1239 TypeKlass thisClass = node.getThisKlass(); 1240 mainClassWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, 1241 asInternalName(name), 1242 null /* Generic */, 1243 "java/lang/Object", 1244 null /* interfaces */); 1245 // TODO: constructor for main class 1246 currentMV = mainClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); 1247 currentMV.visitVarInsn(Opcodes.ALOAD, 0); 1248 currentMV.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 1249 locals.clear(); 1250 locals.addLocal(new VariableInfo("this", thisClass, thisClass, VariableInfo.NONE)); 1251 generateDataMembers(node.getChild(MainKlass.MainKlassPart.DATA_MEMBERS.ordinal())); 1252 currentMV.visitInsn(Opcodes.RETURN); 1253 currentMV.visitMaxs(0, 0); 1254 currentMV.visitEnd(); 1255 1256 IRNode memberFunctions = node.getChild(MainKlass.MainKlassPart.MEMBER_FUNCTIONS.ordinal()); 1257 if (memberFunctions != null) { 1258 memberFunctions.accept(this); 1259 } 1260 IRNode testFunction = node.getChild(MainKlass.MainKlassPart.TEST_FUNCTION.ordinal()); 1261 if (testFunction != null) { 1262 currentMV = mainClassWriter.visitMethod( 1263 Opcodes.ACC_PRIVATE, 1264 "test", 1265 "()V", 1266 null, 1267 null); 1268 locals.clear(); 1269 locals.addLocal(new VariableInfo("this", thisClass, thisClass, VariableInfo.NONE)); 1270 testFunction.accept(this); 1271 currentMV.visitInsn(Opcodes.RETURN); 1272 currentMV.visitMaxs(0, 0); 1273 currentMV.visitEnd(); 1274 } 1275 IRNode printVariables = node.getChild(MainKlass.MainKlassPart.PRINT_VARIABLES.ordinal()); 1276 if (printVariables != null) { 1277 printVariables.accept(this); 1278 } 1279 1280 mainClassWriter.visitEnd(); 1281 1282 byte[] byteCode = mainClassWriter.toByteArray(); 1283 context.register(name, byteCode); 1284 currentClass = prevClass; 1285 return byteCode; 1286 } 1287 1288 @Override 1289 public byte[] visit(NonStaticMemberVariable node) { 1290 // This node is for "reading" only. Writing is handled in BinaryOperator visit(see ASSIGN) 1291 VariableInfo vi = node.getVariableInfo(); 1292 // put object to stack 1293 node.getChild(0).accept(this); 1294 currentMV.visitFieldInsn(Opcodes.GETFIELD, asInternalName(vi.getOwner().getName()), vi.name, 1295 new String(vi.type.accept(this))); 1296 return EMPTY_BYTE_ARRAY; 1297 } 1298 1299 @Override 1300 public byte[] visit(Nothing node) { 1301 // TODO : add randomness 1302 currentMV.visitInsn(Opcodes.NOP); 1303 return EMPTY_BYTE_ARRAY; 1304 } 1305 1306 @Override 1307 public byte[] visit(PrintVariables node) { 1308 return FixedTrees.printVariablesAsFunction(node).accept(this); 1309 } 1310 1311 @Override 1312 public byte[] visit(Return node) { 1313 node.getExpression().accept(this); 1314 Type result = node.getResultType(); 1315 if (result instanceof TypeKlass) { 1316 currentMV.visitInsn(Opcodes.ARETURN); 1317 } else if (result.equals(TypeList.VOID)) { 1318 currentMV.visitInsn(Opcodes.RETURN); 1319 } else if (result.equals(TypeList.DOUBLE)) { 1320 currentMV.visitInsn(Opcodes.DRETURN); 1321 } else if (result.equals(TypeList.FLOAT)) { 1322 currentMV.visitInsn(Opcodes.FRETURN); 1323 } else if (result.equals(TypeList.LONG)) { 1324 currentMV.visitInsn(Opcodes.LRETURN); 1325 } else { 1326 currentMV.visitInsn(Opcodes.IRETURN); 1327 } 1328 return EMPTY_BYTE_ARRAY; 1329 } 1330 1331 @Override 1332 public byte[] visit(Statement node) { 1333 IRNode child = node.getChild(0); 1334 child.accept(this); 1335 Type resultType = child.getResultType(); 1336 emitPop(resultType); 1337 return EMPTY_BYTE_ARRAY; 1338 } 1339 1340 private void emitPop(Type resultType) { 1341 if (resultType.equals(TypeList.LONG) || resultType.equals(TypeList.DOUBLE)) { 1342 currentMV.visitInsn(Opcodes.POP2); 1343 } else if (!resultType.equals(TypeList.VOID)) { 1344 currentMV.visitInsn(Opcodes.POP); 1345 } 1346 } 1347 1348 @Override 1349 public byte[] visit(StaticConstructorDefinition node) { 1350 String ownerName = node.getOwner().getName(); 1351 ContextDependedClassWriter cw = classWriters.get(ownerName); 1352 String descriptor = getDescriptor(node, 1, "V"); 1353 currentMV = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>", descriptor, null, null); 1354 locals.clear(); 1355 IRNode body = node.getChild(0); 1356 body.accept(this); 1357 currentMV.visitInsn(Opcodes.RETURN); 1358 currentMV.visitMaxs(0, 0); 1359 currentMV.visitEnd(); 1360 return EMPTY_BYTE_ARRAY; 1361 } 1362 1363 @Override 1364 public byte[] visit(StaticMemberVariable node) { 1365 // This node is for "reading" only. Writing is handled in BinaryOperator visit(see ASSIGN) 1366 VariableInfo vi = node.getVariableInfo(); 1367 currentMV.visitFieldInsn(Opcodes.GETSTATIC, 1368 asInternalName(vi.getOwner().getName()), 1369 vi.name, 1370 new String(vi.type.accept(this))); 1371 return EMPTY_BYTE_ARRAY; 1372 } 1373 1374 @Override 1375 public byte[] visit(Switch node) { 1376 node.getChild(0).accept(this); 1377 int caseBlockIdx = node.getCaseBlockIndex(); 1378 Label defaultCase = new Label(); 1379 IRNode defaultBlock = null; 1380 SortedMap<Integer, Pair<Label, IRNode>> cases = new TreeMap<>(); 1381 for (int i = 0; i < caseBlockIdx - 1; ++i) { 1382 if (node.getChild(i + 1) instanceof Nothing) { 1383 defaultBlock = node.getChild(i + caseBlockIdx); 1384 } else { 1385 Literal literal = (Literal) node.getChild(i + 1); 1386 int value = 0; 1387 if (literal.value instanceof Integer) { 1388 value = (Integer) literal.value; 1389 } else if (literal.value instanceof Short) { 1390 value = (Short) literal.value; 1391 } else if (literal.value instanceof Byte) { 1392 value = (Byte) literal.value; 1393 } else if (literal.value instanceof Character) { 1394 value = (Character) literal.value; 1395 } 1396 cases.put(value, new Pair<>(new Label(), node.getChild(i + caseBlockIdx))); 1397 } 1398 } 1399 Label breakLabel = new Label(); 1400 endLabels.push(breakLabel); 1401 currentMV.visitLookupSwitchInsn(defaultCase, 1402 cases.keySet().stream() 1403 .mapToInt(Integer::intValue) 1404 .toArray(), 1405 cases.values().stream() 1406 .map(p -> p.first) 1407 .toArray(Label[]::new)); 1408 for (Pair<Label, IRNode> p : cases.values()) { 1409 currentMV.visitLabel(p.first); 1410 p.second.accept(this); 1411 } 1412 currentMV.visitLabel(defaultCase); 1413 if (defaultBlock != null) { 1414 defaultBlock.accept(this); 1415 } 1416 Label a = endLabels.pop(); 1417 assert breakLabel == a; 1418 currentMV.visitLabel(breakLabel); 1419 return EMPTY_BYTE_ARRAY; 1420 } 1421 1422 @Override 1423 public byte[] visit(TernaryOperator node) { 1424 IRNode conditionBlock = node.getChild(TernaryOperator.TernaryPart.CONDITION.ordinal()); 1425 // get the condition type to emit correct if 1426 conditionBlock.accept(this); 1427 generateIf(Opcodes.IFEQ, node.getChild(TernaryOperator.TernaryPart.TRUE.ordinal()), 1428 node.getChild(TernaryOperator.TernaryPart.FALSE.ordinal())); 1429 return EMPTY_BYTE_ARRAY; 1430 } 1431 1432 @Override 1433 public byte[] visit(Throw node) { 1434 node.getThowable().accept(this); 1435 currentMV.visitInsn(Opcodes.ATHROW); 1436 return EMPTY_BYTE_ARRAY; 1437 } 1438 1439 @Override 1440 public byte[] visit(TryCatchBlock node) { 1441 List<? extends IRNode> children = node.getChildren(); 1442 IRNode tryBlock = children.get(0); 1443 IRNode finallyBlock = children.get(1); 1444 Label tryStart = new Label(); 1445 Label tryEnd = new Label(); 1446 Label finallyStart = new Label(); 1447 Label finallyEnd = new Label(); 1448 1449 currentMV.visitLabel(tryStart); 1450 tryBlock.accept(this); 1451 currentMV.visitLabel(tryEnd); 1452 finallyBlock.accept(this); 1453 currentMV.visitJumpInsn(Opcodes.GOTO, finallyEnd); 1454 VariableInfo exInfo = new VariableInfo("ex", currentClass, 1455 new TypeKlass("java.lang.Throwable"), VariableInfo.LOCAL); 1456 int index = locals.addLocal(exInfo); 1457 for (int i = 2; i < children.size(); ++i) { 1458 Label handlerBegin = new Label(); 1459 Label handlerEnd = new Label(); 1460 CatchBlock catchBlock = (CatchBlock) children.get(i); 1461 for (Type t : catchBlock.throwables) { 1462 currentMV.visitTryCatchBlock(tryStart, tryEnd, handlerBegin, asInternalName(t.getName())); 1463 } 1464 currentMV.visitLabel(handlerBegin); 1465 catchBlock.accept(this); 1466 currentMV.visitLabel(handlerEnd); 1467 finallyBlock.accept(this); 1468 currentMV.visitJumpInsn(Opcodes.GOTO, finallyEnd); 1469 currentMV.visitTryCatchBlock(handlerBegin, handlerEnd, finallyStart, null); 1470 } 1471 1472 currentMV.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null); 1473 currentMV.visitLabel(finallyStart); 1474 currentMV.visitVarInsn(Opcodes.ASTORE, index); 1475 finallyBlock.accept(this); 1476 currentMV.visitVarInsn(Opcodes.ALOAD, index); 1477 currentMV.visitInsn(Opcodes.ATHROW); 1478 currentMV.visitLabel(finallyEnd); 1479 return EMPTY_BYTE_ARRAY; 1480 } 1481 1482 @Override 1483 public byte[] visit(Type node) { 1484 String name; 1485 if (TypeList.isBuiltIn(node)) { 1486 switch (node.getName()) { 1487 case "void": 1488 name = "V"; 1489 break; 1490 case "boolean": 1491 name = "Z"; 1492 break; 1493 case "byte": 1494 name = "B"; 1495 break; 1496 case "char": 1497 name = "C"; 1498 break; 1499 case "short": 1500 name = "S"; 1501 break; 1502 case "int": 1503 name = "I"; 1504 break; 1505 case "long": 1506 name = "J"; 1507 break; 1508 case "float": 1509 name = "F"; 1510 break; 1511 case "double": 1512 name = "D"; 1513 break; 1514 default: 1515 throw new IllegalArgumentException("Unknown type '" + node.getName()); 1516 } 1517 } else { 1518 name = "L" + asInternalName(node.getName()) + ";"; 1519 } 1520 return name.getBytes(); 1521 } 1522 1523 @Override 1524 public byte[] visit(TypeArray node) { 1525 String name; 1526 String prefix = Stream.generate(() -> "[") 1527 .limit(node.dimensions) 1528 .collect(Collectors.joining()); 1529 name = prefix + new String(node.getType().accept(this)); 1530 return name.getBytes(); 1531 } 1532 1533 @Override 1534 public byte[] visit(UnaryOperator node) { 1535 OperatorKind opKind = node.getOperationKind(); 1536 IRNode exp = node.getChild(0); 1537 // argument expression is handled separately for inc and dec operators 1538 if (opKind != OperatorKind.POST_DEC && opKind != OperatorKind.POST_INC 1539 && opKind != OperatorKind.PRE_DEC && opKind != OperatorKind.PRE_INC) { 1540 exp.accept(this); 1541 } 1542 Type resultType = exp.getResultType(); 1543 switch (opKind) { 1544 case NOT: 1545 Label retTrueForNot = new Label(); 1546 Label endForNot = new Label(); 1547 currentMV.visitJumpInsn(Opcodes.IFEQ, retTrueForNot); 1548 currentMV.visitInsn(Opcodes.ICONST_0); 1549 currentMV.visitJumpInsn(Opcodes.GOTO, endForNot); 1550 currentMV.visitLabel(retTrueForNot); 1551 currentMV.visitInsn(Opcodes.ICONST_1); 1552 currentMV.visitLabel(endForNot); 1553 break; 1554 case BIT_NOT: 1555 if (resultType.equals(TypeList.LONG)) { 1556 currentMV.visitLdcInsn(-1L); 1557 currentMV.visitInsn(Opcodes.LXOR); 1558 } else { 1559 currentMV.visitInsn(Opcodes.ICONST_M1); 1560 currentMV.visitInsn(Opcodes.IXOR); 1561 } 1562 break; 1563 case UNARY_MINUS: 1564 if (resultType.equals(TypeList.LONG)) { 1565 currentMV.visitInsn(Opcodes.LNEG); 1566 } else if (resultType.equals(TypeList.FLOAT)) { 1567 currentMV.visitInsn(Opcodes.FNEG); 1568 } else if (resultType.equals(TypeList.DOUBLE)) { 1569 currentMV.visitInsn(Opcodes.DNEG); 1570 } else { 1571 currentMV.visitInsn(Opcodes.INEG); 1572 } 1573 break; 1574 case UNARY_PLUS: 1575 break; 1576 case PRE_DEC: 1577 lowerIncDecUnaryOperator(OperatorKind.SUB, true, node); 1578 break; 1579 case POST_DEC: 1580 lowerIncDecUnaryOperator(OperatorKind.SUB, false, node); 1581 break; 1582 case PRE_INC: 1583 lowerIncDecUnaryOperator(OperatorKind.ADD, true, node); 1584 break; 1585 case POST_INC: 1586 lowerIncDecUnaryOperator(OperatorKind.ADD, false, node); 1587 break; 1588 default: 1589 throw new RuntimeException("Incorrect unary operator: " + opKind); 1590 } 1591 return EMPTY_BYTE_ARRAY; 1592 } 1593 1594 private void lowerIncDecUnaryOperator(OperatorKind kind, boolean isPrefix, IRNode node) { 1595 IRNode var = node.getChild(0); 1596 Literal one; 1597 Type resultType = node.getResultType(); 1598 if (resultType.equals(TypeList.LONG)) { 1599 one = new Literal(1L, TypeList.LONG); 1600 } else if (resultType.equals(TypeList.INT)) { 1601 one = new Literal(1, TypeList.INT); 1602 } else if (resultType.equals(TypeList.SHORT)) { 1603 one = new Literal((short) 1, TypeList.SHORT); 1604 } else { 1605 one = new Literal((byte) 1, TypeList.BYTE); 1606 } 1607 if (var instanceof NonStaticMemberVariable) { 1608 IRNode holder = var.getChild(0); 1609 Type type = holder.getResultType(); 1610 VariableInfo tmpInfo = new VariableInfo("tmpObject_" + tmpObject++, 1611 currentClass, type, VariableInfo.LOCAL); 1612 new Statement(new VariableInitialization(tmpInfo, holder), true).accept(this); 1613 var = new NonStaticMemberVariable(new LocalVariable(tmpInfo), 1614 ((NonStaticMemberVariable) var).getVariableInfo()); 1615 } 1616 BinaryOperator calculation = new BinaryOperator(kind, resultType, var, one); 1617 BinaryOperator changeValue = new BinaryOperator(OperatorKind.ASSIGN, resultType, var, calculation); 1618 Statement finalChangeStatement = new Statement(changeValue, true); 1619 if (isPrefix) { 1620 finalChangeStatement.accept(this); 1621 var.accept(this); 1622 } else { 1623 var.accept(this); 1624 finalChangeStatement.accept(this); 1625 } 1626 } 1627 1628 @Override 1629 public byte[] visit(VariableDeclaration node) { 1630 VariableInfo vi = node.getVariableInfo(); 1631 String ownerName = vi.getOwner().getName(); 1632 ContextDependedClassWriter cw = classWriters.get(ownerName); 1633 String typeName = new String(vi.type.accept(this)); 1634 if (vi.isLocal()) { 1635 locals.addLocal(vi); 1636 } else { 1637 FieldVisitor fv = cw.visitField(asAccessFlags(vi), 1638 vi.name, 1639 typeName, 1640 null /* Generic */, 1641 null /* Constant value */); 1642 fv.visitEnd(); // doesn't need visitAnnotation and visitAttribute 1643 } 1644 return EMPTY_BYTE_ARRAY; 1645 } 1646 1647 @Override 1648 public byte[] visit(VariableDeclarationBlock node) { 1649 return iterateBlock(node); 1650 } 1651 1652 @Override 1653 public byte[] visit(While node) { 1654 Loop loop = node.getLoop(); 1655 loop.initialization.accept(this); 1656 node.getChild(While.WhilePart.HEADER.ordinal()).accept(this); 1657 Label currentLoopBegin = new Label(); 1658 beginLabels.push(currentLoopBegin); 1659 currentMV.visitLabel(currentLoopBegin); 1660 loop.condition.accept(this); 1661 assert loop.condition.getResultType() == TypeList.BOOLEAN; 1662 Label currentLoopEnd = new Label(); 1663 endLabels.push(currentLoopEnd); 1664 currentMV.visitJumpInsn(Opcodes.IFEQ, currentLoopEnd); 1665 node.getChild(While.WhilePart.BODY1.ordinal()).accept(this); 1666 loop.manipulator.accept(this); 1667 node.getChild(While.WhilePart.BODY2.ordinal()).accept(this); 1668 node.getChild(While.WhilePart.BODY3.ordinal()).accept(this); 1669 currentMV.visitJumpInsn(Opcodes.GOTO, currentLoopBegin); 1670 currentMV.visitLabel(currentLoopEnd); 1671 Label a = beginLabels.pop(); 1672 assert currentLoopBegin == a; 1673 a = endLabels.pop(); 1674 assert currentLoopEnd == a; 1675 return EMPTY_BYTE_ARRAY; 1676 } 1677 1678 public byte[] getByteCode(String name) { 1679 return context.get(name); 1680 } 1681 1682 private static byte[] concat(byte[] a, byte[] b) { 1683 byte[] r = new byte[a.length + b.length]; 1684 System.arraycopy(a, 0, r, 0, a.length); 1685 System.arraycopy(b, 0, r, a.length, b.length); 1686 return r; 1687 } 1688 1689 private String argTypeToString(ArgumentDeclaration declarations) { 1690 return new String(declarations.variableInfo.type.accept(this)); 1691 } 1692 1693 private byte[] iterateBlock(IRNode node) { 1694 return node.getChildren().stream() 1695 .map(ch -> ch.accept(this)) 1696 .reduce(new byte[0], ByteCodeVisitor::concat); 1697 } 1698 1699 private String getDescriptor(IRNode node, int skipChilds, String returnType) { 1700 return node.getChildren().stream() 1701 .skip(skipChilds) 1702 .map(c -> argTypeToString((ArgumentDeclaration)c)) 1703 .collect(Collectors.joining("", "(", ")" + returnType)); 1704 } 1705 1706 private static String asInternalName(String type) { 1707 return type.replace('.', '/'); 1708 } 1709 1710 private static int asAccessFlags(TypeKlass klass) { 1711 int attr = Opcodes.ACC_SUPER; 1712 attr |= klass.isFinal() ? Opcodes.ACC_FINAL : 0; 1713 attr |= klass.isAbstract() ? Opcodes.ACC_ABSTRACT : 0; 1714 attr |= klass.isInterface() ? Opcodes.ACC_INTERFACE : 0; 1715 1716 return attr; 1717 } 1718 1719 private static int asAccessFlags(FunctionInfo fi) { 1720 int result = asAccessFlags((Symbol) fi); 1721 result |= ProductionParams.enableStrictFP.value() ? Opcodes.ACC_STRICT : 0; 1722 result |= fi.isSynchronized() ? Opcodes.ACC_SYNCHRONIZED : 0; 1723 return result; 1724 } 1725 1726 private static int asAccessFlags(Symbol s) { 1727 int attr = 0; 1728 attr |= s.isPublic() ? Opcodes.ACC_PUBLIC : 0; 1729 attr |= s.isPrivate() ? Opcodes.ACC_PRIVATE : 0; 1730 attr |= s.isProtected() ? Opcodes.ACC_PROTECTED : 0; 1731 attr |= s.isStatic() ? Opcodes.ACC_STATIC : 0; 1732 attr |= s.isFinal() ? Opcodes.ACC_FINAL : 0; 1733 1734 return attr; 1735 } 1736 1737 private static class LocalVariablesTable { 1738 private int nextLocalIndex = 0; 1739 // a map keeping local variable table index for a local variable 1740 private final HashMap<String, Integer> locals = new HashMap<>(); 1741 1742 public int addLocal(VariableInfo vi) { 1743 int indexToReturn = nextLocalIndex; 1744 locals.put(vi.name, nextLocalIndex++); 1745 if (vi.type.equals(TypeList.DOUBLE) || vi.type.equals(TypeList.LONG)) { 1746 nextLocalIndex++; 1747 } 1748 return indexToReturn; 1749 } 1750 1751 public int getLocalIndex(VariableInfo vi) { 1752 if (!locals.containsKey(vi.name)) { 1753 throw new NoSuchElementException(vi.name); 1754 } 1755 return locals.get(vi.name); 1756 } 1757 1758 public void clear() { 1759 locals.clear(); 1760 nextLocalIndex = 0; 1761 } 1762 1763 public void initFunctionArguments(FunctionInfo info) { 1764 initArguments(null, info); 1765 } 1766 1767 public void initConstructorArguments(TypeKlass owner, FunctionInfo info) { 1768 Objects.requireNonNull(owner, "owner is null"); 1769 initArguments(owner, info); 1770 } 1771 1772 private void initArguments(TypeKlass owner, FunctionInfo info) { 1773 clear(); 1774 if (owner != null) { 1775 addLocal(new VariableInfo("this", owner, owner, VariableInfo.LOCAL | VariableInfo.INITIALIZED)); 1776 } 1777 for (VariableInfo vi : info.argTypes) { 1778 addLocal(vi); 1779 } 1780 } 1781 } 1782 1783 private static class GeneratedClassesContext extends java.lang.ClassLoader { 1784 private final HashMap<String, byte[]> byteCodes = new HashMap<>(); 1785 1786 public void register(String name, byte[] bytecode) { 1787 defineClass(name, bytecode, 0, bytecode.length); 1788 byteCodes.put(name, bytecode); 1789 } 1790 1791 public byte[] get(String name) { 1792 return byteCodes.get(name); 1793 } 1794 } 1795 1796 1797 private static class ContextDependedClassWriter extends ClassWriter { 1798 private final GeneratedClassesContext context; 1799 1800 public ContextDependedClassWriter(GeneratedClassesContext context, int flags) { 1801 super(flags); 1802 this.context = context; 1803 } 1804 1805 protected String getCommonSuperClass(String className1, String className2) { 1806 Class<?> klass1; 1807 Class<?> klass2; 1808 try { 1809 klass1 = Class.forName(className1.replace('/', '.'), false, context); 1810 klass2 = Class.forName(className2.replace('/', '.'), false, context); 1811 } catch (ClassNotFoundException e) { 1812 throw new Error("can not get common supper for " + className1 1813 + " and " + className2, e); 1814 } 1815 1816 if (klass1.isAssignableFrom(klass2)) { 1817 return className1; 1818 } else if (klass2.isAssignableFrom(klass1)) { 1819 return className2; 1820 } else if (!klass1.isInterface() && !klass2.isInterface()) { 1821 do { 1822 klass1 = klass1.getSuperclass(); 1823 } while (!klass1.isAssignableFrom(klass2)); 1824 1825 return asInternalName(className1); 1826 } else { 1827 return "java/lang/Object"; 1828 } 1829 } 1830 } 1831 }