src/jdk/nashorn/internal/codegen/MethodEmitter.java

Wed, 27 Apr 2016 01:36:41 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:36:41 +0800
changeset 0
b1a7da25b547
child 952
6d5471a497fb
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/nashorn/
changeset: 1034:4b9cc65dd24d
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package jdk.nashorn.internal.codegen;
aoqi@0 27
aoqi@0 28 import static jdk.internal.org.objectweb.asm.Opcodes.ATHROW;
aoqi@0 29 import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
aoqi@0 30 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
aoqi@0 31 import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
aoqi@0 32 import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
aoqi@0 33 import static jdk.internal.org.objectweb.asm.Opcodes.GOTO;
aoqi@0 34 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
aoqi@0 35 import static jdk.internal.org.objectweb.asm.Opcodes.IFEQ;
aoqi@0 36 import static jdk.internal.org.objectweb.asm.Opcodes.IFGE;
aoqi@0 37 import static jdk.internal.org.objectweb.asm.Opcodes.IFGT;
aoqi@0 38 import static jdk.internal.org.objectweb.asm.Opcodes.IFLE;
aoqi@0 39 import static jdk.internal.org.objectweb.asm.Opcodes.IFLT;
aoqi@0 40 import static jdk.internal.org.objectweb.asm.Opcodes.IFNE;
aoqi@0 41 import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL;
aoqi@0 42 import static jdk.internal.org.objectweb.asm.Opcodes.IFNULL;
aoqi@0 43 import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ;
aoqi@0 44 import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE;
aoqi@0 45 import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ;
aoqi@0 46 import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE;
aoqi@0 47 import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF;
aoqi@0 48 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
aoqi@0 49 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
aoqi@0 50 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
aoqi@0 51 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
aoqi@0 52 import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
aoqi@0 53 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
aoqi@0 54 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
aoqi@0 55 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
aoqi@0 56 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
aoqi@0 57 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
aoqi@0 58 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
aoqi@0 59 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
aoqi@0 60 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
aoqi@0 61 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
aoqi@0 62 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
aoqi@0 63 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
aoqi@0 64 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
aoqi@0 65 import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
aoqi@0 66 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
aoqi@0 67
aoqi@0 68 import java.io.PrintStream;
aoqi@0 69 import java.lang.reflect.Array;
aoqi@0 70 import java.util.EnumSet;
aoqi@0 71 import java.util.List;
aoqi@0 72 import jdk.internal.dynalink.support.NameCodec;
aoqi@0 73 import jdk.internal.org.objectweb.asm.Handle;
aoqi@0 74 import jdk.internal.org.objectweb.asm.MethodVisitor;
aoqi@0 75 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
aoqi@0 76 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
aoqi@0 77 import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
aoqi@0 78 import jdk.nashorn.internal.codegen.types.ArrayType;
aoqi@0 79 import jdk.nashorn.internal.codegen.types.BitwiseType;
aoqi@0 80 import jdk.nashorn.internal.codegen.types.NumericType;
aoqi@0 81 import jdk.nashorn.internal.codegen.types.Type;
aoqi@0 82 import jdk.nashorn.internal.ir.FunctionNode;
aoqi@0 83 import jdk.nashorn.internal.ir.IdentNode;
aoqi@0 84 import jdk.nashorn.internal.ir.LexicalContext;
aoqi@0 85 import jdk.nashorn.internal.ir.LiteralNode;
aoqi@0 86 import jdk.nashorn.internal.ir.RuntimeNode;
aoqi@0 87 import jdk.nashorn.internal.ir.Symbol;
aoqi@0 88 import jdk.nashorn.internal.runtime.ArgumentSetter;
aoqi@0 89 import jdk.nashorn.internal.runtime.Debug;
aoqi@0 90 import jdk.nashorn.internal.runtime.DebugLogger;
aoqi@0 91 import jdk.nashorn.internal.runtime.JSType;
aoqi@0 92 import jdk.nashorn.internal.runtime.ScriptEnvironment;
aoqi@0 93 import jdk.nashorn.internal.runtime.ScriptObject;
aoqi@0 94 import jdk.nashorn.internal.runtime.linker.Bootstrap;
aoqi@0 95 import jdk.nashorn.internal.runtime.options.Options;
aoqi@0 96
aoqi@0 97 /**
aoqi@0 98 * This is the main function responsible for emitting method code
aoqi@0 99 * in a class. It maintains a type stack and keeps track of control
aoqi@0 100 * flow to make sure that the registered instructions don't violate
aoqi@0 101 * byte code verification.
aoqi@0 102 *
aoqi@0 103 * Running Nashorn with -ea will assert as soon as a type stack
aoqi@0 104 * becomes corrupt, for easier debugging
aoqi@0 105 *
aoqi@0 106 * Running Nashorn with -Dnashorn.codegen.debug=true will print
aoqi@0 107 * all generated bytecode and labels to stderr, for easier debugging,
aoqi@0 108 * including bytecode stack contents
aoqi@0 109 */
aoqi@0 110 public class MethodEmitter implements Emitter {
aoqi@0 111 /** The ASM MethodVisitor we are plugged into */
aoqi@0 112 private final MethodVisitor method;
aoqi@0 113
aoqi@0 114 /** Current type stack for current evaluation */
aoqi@0 115 private Label.Stack stack;
aoqi@0 116
aoqi@0 117 /** Parent classEmitter representing the class of this method */
aoqi@0 118 private final ClassEmitter classEmitter;
aoqi@0 119
aoqi@0 120 /** FunctionNode representing this method, or null if none exists */
aoqi@0 121 protected FunctionNode functionNode;
aoqi@0 122
aoqi@0 123 /** Check whether this emitter ever has a function return point */
aoqi@0 124 private boolean hasReturn;
aoqi@0 125
aoqi@0 126 /** The script environment */
aoqi@0 127 private final ScriptEnvironment env;
aoqi@0 128
aoqi@0 129 /** Threshold in chars for when string constants should be split */
aoqi@0 130 static final int LARGE_STRING_THRESHOLD = 32 * 1024;
aoqi@0 131
aoqi@0 132 /** Debug flag, should we dump all generated bytecode along with stacks? */
aoqi@0 133 private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug");
aoqi@0 134 private static final boolean DEBUG = LOG.isEnabled();
aoqi@0 135
aoqi@0 136 /** dump stack on a particular line, or -1 if disabled */
aoqi@0 137 private static final int DEBUG_TRACE_LINE;
aoqi@0 138
aoqi@0 139 static {
aoqi@0 140 final String tl = Options.getStringProperty("nashorn.codegen.debug.trace", "-1");
aoqi@0 141 int line = -1;
aoqi@0 142 try {
aoqi@0 143 line = Integer.parseInt(tl);
aoqi@0 144 } catch (final NumberFormatException e) {
aoqi@0 145 //fallthru
aoqi@0 146 }
aoqi@0 147 DEBUG_TRACE_LINE = line;
aoqi@0 148 }
aoqi@0 149
aoqi@0 150 /** Bootstrap for normal indy:s */
aoqi@0 151 private static final Handle LINKERBOOTSTRAP = new Handle(H_INVOKESTATIC, Bootstrap.BOOTSTRAP.className(), Bootstrap.BOOTSTRAP.name(), Bootstrap.BOOTSTRAP.descriptor());
aoqi@0 152
aoqi@0 153 /** Bootstrap for runtime node indy:s */
aoqi@0 154 private static final Handle RUNTIMEBOOTSTRAP = new Handle(H_INVOKESTATIC, RuntimeCallSite.BOOTSTRAP.className(), RuntimeCallSite.BOOTSTRAP.name(), RuntimeCallSite.BOOTSTRAP.descriptor());
aoqi@0 155
aoqi@0 156 /**
aoqi@0 157 * Constructor - internal use from ClassEmitter only
aoqi@0 158 * @see ClassEmitter#method
aoqi@0 159 *
aoqi@0 160 * @param classEmitter the class emitter weaving the class this method is in
aoqi@0 161 * @param method a method visitor
aoqi@0 162 */
aoqi@0 163 MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method) {
aoqi@0 164 this(classEmitter, method, null);
aoqi@0 165 }
aoqi@0 166
aoqi@0 167 /**
aoqi@0 168 * Constructor - internal use from ClassEmitter only
aoqi@0 169 * @see ClassEmitter#method
aoqi@0 170 *
aoqi@0 171 * @param classEmitter the class emitter weaving the class this method is in
aoqi@0 172 * @param method a method visitor
aoqi@0 173 * @param functionNode a function node representing this method
aoqi@0 174 */
aoqi@0 175 MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method, final FunctionNode functionNode) {
aoqi@0 176 this.env = classEmitter.getEnv();
aoqi@0 177 this.classEmitter = classEmitter;
aoqi@0 178 this.method = method;
aoqi@0 179 this.functionNode = functionNode;
aoqi@0 180 this.stack = null;
aoqi@0 181 }
aoqi@0 182
aoqi@0 183 /**
aoqi@0 184 * Begin a method
aoqi@0 185 * @see Emitter
aoqi@0 186 */
aoqi@0 187 @Override
aoqi@0 188 public void begin() {
aoqi@0 189 classEmitter.beginMethod(this);
aoqi@0 190 newStack();
aoqi@0 191 method.visitCode();
aoqi@0 192 }
aoqi@0 193
aoqi@0 194 /**
aoqi@0 195 * End a method
aoqi@0 196 * @see Emitter
aoqi@0 197 */
aoqi@0 198 @Override
aoqi@0 199 public void end() {
aoqi@0 200 method.visitMaxs(0, 0);
aoqi@0 201 method.visitEnd();
aoqi@0 202
aoqi@0 203 classEmitter.endMethod(this);
aoqi@0 204 }
aoqi@0 205
aoqi@0 206 private void newStack() {
aoqi@0 207 stack = new Label.Stack();
aoqi@0 208 }
aoqi@0 209
aoqi@0 210 @Override
aoqi@0 211 public String toString() {
aoqi@0 212 return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
aoqi@0 213 }
aoqi@0 214
aoqi@0 215 /**
aoqi@0 216 * Push a type to the existing stack
aoqi@0 217 * @param type the type
aoqi@0 218 */
aoqi@0 219 private void pushType(final Type type) {
aoqi@0 220 if (type != null) {
aoqi@0 221 stack.push(type);
aoqi@0 222 }
aoqi@0 223 }
aoqi@0 224
aoqi@0 225 /**
aoqi@0 226 * Pop a type from the existing stack
aoqi@0 227 *
aoqi@0 228 * @param expected expected type - will assert if wrong
aoqi@0 229 *
aoqi@0 230 * @return the type that was retrieved
aoqi@0 231 */
aoqi@0 232 private Type popType(final Type expected) {
aoqi@0 233 final Type type = stack.pop();
aoqi@0 234 assert type.isObject() && expected.isObject() ||
aoqi@0 235 type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
aoqi@0 236 return type;
aoqi@0 237 }
aoqi@0 238
aoqi@0 239 /**
aoqi@0 240 * Pop a type from the existing stack, no matter what it is.
aoqi@0 241 *
aoqi@0 242 * @return the type
aoqi@0 243 */
aoqi@0 244 private Type popType() {
aoqi@0 245 return stack.pop();
aoqi@0 246 }
aoqi@0 247
aoqi@0 248 /**
aoqi@0 249 * Pop a type from the existing stack, ensuring that it is numeric,
aoqi@0 250 * assert if not
aoqi@0 251 *
aoqi@0 252 * @return the type
aoqi@0 253 */
aoqi@0 254 private NumericType popNumeric() {
aoqi@0 255 final Type type = stack.pop();
aoqi@0 256 assert type.isNumeric() : type + " is not numeric";
aoqi@0 257 return (NumericType)type;
aoqi@0 258 }
aoqi@0 259
aoqi@0 260 /**
aoqi@0 261 * Pop a type from the existing stack, ensuring that it is an integer type
aoqi@0 262 * (integer or long), assert if not
aoqi@0 263 *
aoqi@0 264 * @return the type
aoqi@0 265 */
aoqi@0 266 private BitwiseType popInteger() {
aoqi@0 267 final Type type = stack.pop();
aoqi@0 268 assert type.isInteger() || type.isLong() : type + " is not an integer or long";
aoqi@0 269 return (BitwiseType)type;
aoqi@0 270 }
aoqi@0 271
aoqi@0 272 /**
aoqi@0 273 * Pop a type from the existing stack, ensuring that it is an array type,
aoqi@0 274 * assert if not
aoqi@0 275 *
aoqi@0 276 * @return the type
aoqi@0 277 */
aoqi@0 278 private ArrayType popArray() {
aoqi@0 279 final Type type = stack.pop();
aoqi@0 280 assert type.isArray() : type;
aoqi@0 281 return (ArrayType)type;
aoqi@0 282 }
aoqi@0 283
aoqi@0 284 /**
aoqi@0 285 * Peek a given number of slots from the top of the stack and return the
aoqi@0 286 * type in that slot
aoqi@0 287 *
aoqi@0 288 * @param pos the number of positions from the top, 0 is the top element
aoqi@0 289 *
aoqi@0 290 * @return the type at position "pos" on the stack
aoqi@0 291 */
aoqi@0 292 final Type peekType(final int pos) {
aoqi@0 293 return stack.peek(pos);
aoqi@0 294 }
aoqi@0 295
aoqi@0 296 /**
aoqi@0 297 * Peek at the type at the top of the stack
aoqi@0 298 *
aoqi@0 299 * @return the type at the top of the stack
aoqi@0 300 */
aoqi@0 301 final Type peekType() {
aoqi@0 302 return stack.peek();
aoqi@0 303 }
aoqi@0 304
aoqi@0 305 /**
aoqi@0 306 * Generate code a for instantiating a new object and push the
aoqi@0 307 * object type on the stack
aoqi@0 308 *
aoqi@0 309 * @param classDescriptor class descriptor for the object type
aoqi@0 310 *
aoqi@0 311 * @return the method emitter
aoqi@0 312 */
aoqi@0 313 MethodEmitter _new(final String classDescriptor) {
aoqi@0 314 debug("new", classDescriptor);
aoqi@0 315 method.visitTypeInsn(NEW, classDescriptor);
aoqi@0 316 pushType(Type.OBJECT);
aoqi@0 317 return this;
aoqi@0 318 }
aoqi@0 319
aoqi@0 320 /**
aoqi@0 321 * Generate code a for instantiating a new object and push the
aoqi@0 322 * object type on the stack
aoqi@0 323 *
aoqi@0 324 * @param clazz class type to instatiate
aoqi@0 325 *
aoqi@0 326 * @return the method emitter
aoqi@0 327 */
aoqi@0 328 MethodEmitter _new(final Class<?> clazz) {
aoqi@0 329 return _new(className(clazz));
aoqi@0 330 }
aoqi@0 331
aoqi@0 332 /**
aoqi@0 333 * Generate code to call the empty constructor for a class
aoqi@0 334 *
aoqi@0 335 * @param clazz class type to instatiate
aoqi@0 336 *
aoqi@0 337 * @return the method emitter
aoqi@0 338 */
aoqi@0 339 MethodEmitter newInstance(final Class<?> clazz) {
aoqi@0 340 return invoke(constructorNoLookup(clazz));
aoqi@0 341 }
aoqi@0 342
aoqi@0 343 /**
aoqi@0 344 * Perform a dup, that is, duplicate the top element and
aoqi@0 345 * push the duplicate down a given number of positions
aoqi@0 346 * on the stack. This is totally type agnostic.
aoqi@0 347 *
aoqi@0 348 * @param depth the depth on which to put the copy
aoqi@0 349 *
aoqi@0 350 * @return the method emitter, or null if depth is illegal and
aoqi@0 351 * has no instruction equivalent.
aoqi@0 352 */
aoqi@0 353 MethodEmitter dup(final int depth) {
aoqi@0 354 if (peekType().dup(method, depth) == null) {
aoqi@0 355 return null;
aoqi@0 356 }
aoqi@0 357
aoqi@0 358 debug("dup", depth);
aoqi@0 359
aoqi@0 360 switch (depth) {
aoqi@0 361 case 0:
aoqi@0 362 pushType(peekType());
aoqi@0 363 break;
aoqi@0 364 case 1: {
aoqi@0 365 final Type p0 = popType();
aoqi@0 366 final Type p1 = popType();
aoqi@0 367 pushType(p0);
aoqi@0 368 pushType(p1);
aoqi@0 369 pushType(p0);
aoqi@0 370 break;
aoqi@0 371 }
aoqi@0 372 case 2: {
aoqi@0 373 final Type p0 = popType();
aoqi@0 374 final Type p1 = popType();
aoqi@0 375 final Type p2 = popType();
aoqi@0 376 pushType(p0);
aoqi@0 377 pushType(p2);
aoqi@0 378 pushType(p1);
aoqi@0 379 pushType(p0);
aoqi@0 380 break;
aoqi@0 381 }
aoqi@0 382 default:
aoqi@0 383 assert false : "illegal dup depth = " + depth;
aoqi@0 384 return null;
aoqi@0 385 }
aoqi@0 386
aoqi@0 387 return this;
aoqi@0 388 }
aoqi@0 389
aoqi@0 390 /**
aoqi@0 391 * Perform a dup2, that is, duplicate the top element if it
aoqi@0 392 * is a category 2 type, or two top elements if they are category
aoqi@0 393 * 1 types, and push them on top of the stack
aoqi@0 394 *
aoqi@0 395 * @return the method emitter
aoqi@0 396 */
aoqi@0 397 MethodEmitter dup2() {
aoqi@0 398 debug("dup2");
aoqi@0 399
aoqi@0 400 if (peekType().isCategory2()) {
aoqi@0 401 pushType(peekType());
aoqi@0 402 } else {
aoqi@0 403 final Type type = get2();
aoqi@0 404 pushType(type);
aoqi@0 405 pushType(type);
aoqi@0 406 pushType(type);
aoqi@0 407 pushType(type);
aoqi@0 408 }
aoqi@0 409 method.visitInsn(DUP2);
aoqi@0 410 return this;
aoqi@0 411 }
aoqi@0 412
aoqi@0 413 /**
aoqi@0 414 * Duplicate the top element on the stack and push it
aoqi@0 415 *
aoqi@0 416 * @return the method emitter
aoqi@0 417 */
aoqi@0 418 MethodEmitter dup() {
aoqi@0 419 return dup(0);
aoqi@0 420 }
aoqi@0 421
aoqi@0 422 /**
aoqi@0 423 * Pop the top element of the stack and throw it away
aoqi@0 424 *
aoqi@0 425 * @return the method emitter
aoqi@0 426 */
aoqi@0 427 MethodEmitter pop() {
aoqi@0 428 debug("pop", peekType());
aoqi@0 429 popType().pop(method);
aoqi@0 430 return this;
aoqi@0 431 }
aoqi@0 432
aoqi@0 433 /**
aoqi@0 434 * Pop the top element of the stack if category 2 type, or the two
aoqi@0 435 * top elements of the stack if category 1 types
aoqi@0 436 *
aoqi@0 437 * @return the method emitter
aoqi@0 438 */
aoqi@0 439 MethodEmitter pop2() {
aoqi@0 440 if (peekType().isCategory2()) {
aoqi@0 441 popType();
aoqi@0 442 } else {
aoqi@0 443 get2n();
aoqi@0 444 }
aoqi@0 445 return this;
aoqi@0 446 }
aoqi@0 447
aoqi@0 448 /**
aoqi@0 449 * Swap the top two elements of the stack. This is totally
aoqi@0 450 * type agnostic and works for all types
aoqi@0 451 *
aoqi@0 452 * @return the method emitter
aoqi@0 453 */
aoqi@0 454 MethodEmitter swap() {
aoqi@0 455 debug("swap");
aoqi@0 456
aoqi@0 457 final Type p0 = popType();
aoqi@0 458 final Type p1 = popType();
aoqi@0 459 p0.swap(method, p1);
aoqi@0 460
aoqi@0 461 pushType(p0);
aoqi@0 462 pushType(p1);
aoqi@0 463 debug("after ", p0, p1);
aoqi@0 464 return this;
aoqi@0 465 }
aoqi@0 466
aoqi@0 467 /**
aoqi@0 468 * Add a local variable. This is a nop if the symbol has no slot
aoqi@0 469 *
aoqi@0 470 * @param symbol symbol for the local variable
aoqi@0 471 * @param start start of scope
aoqi@0 472 * @param end end of scope
aoqi@0 473 */
aoqi@0 474 void localVariable(final Symbol symbol, final Label start, final Label end) {
aoqi@0 475 if (!symbol.hasSlot()) {
aoqi@0 476 return;
aoqi@0 477 }
aoqi@0 478
aoqi@0 479 String name = symbol.getName();
aoqi@0 480
aoqi@0 481 if (name.equals(THIS.symbolName())) {
aoqi@0 482 name = THIS_DEBUGGER.symbolName();
aoqi@0 483 }
aoqi@0 484
aoqi@0 485 method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
aoqi@0 486 }
aoqi@0 487
aoqi@0 488 /**
aoqi@0 489 * Create a new string builder, call the constructor and push the instance to the stack.
aoqi@0 490 *
aoqi@0 491 * @return the method emitter
aoqi@0 492 */
aoqi@0 493 MethodEmitter newStringBuilder() {
aoqi@0 494 return invoke(constructorNoLookup(StringBuilder.class)).dup();
aoqi@0 495 }
aoqi@0 496
aoqi@0 497 /**
aoqi@0 498 * Pop a string and a StringBuilder from the top of the stack and call the append
aoqi@0 499 * function of the StringBuilder, appending the string. Pushes the StringBuilder to
aoqi@0 500 * the stack when finished.
aoqi@0 501 *
aoqi@0 502 * @return the method emitter
aoqi@0 503 */
aoqi@0 504 MethodEmitter stringBuilderAppend() {
aoqi@0 505 convert(Type.STRING);
aoqi@0 506 return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
aoqi@0 507 }
aoqi@0 508
aoqi@0 509 /**
aoqi@0 510 * Pops two integer types from the stack, performs a bitwise and and pushes
aoqi@0 511 * the result
aoqi@0 512 *
aoqi@0 513 * @return the method emitter
aoqi@0 514 */
aoqi@0 515 MethodEmitter and() {
aoqi@0 516 debug("and");
aoqi@0 517 pushType(get2i().and(method));
aoqi@0 518 return this;
aoqi@0 519 }
aoqi@0 520
aoqi@0 521 /**
aoqi@0 522 * Pops two integer types from the stack, performs a bitwise or and pushes
aoqi@0 523 * the result
aoqi@0 524 *
aoqi@0 525 * @return the method emitter
aoqi@0 526 */
aoqi@0 527 MethodEmitter or() {
aoqi@0 528 debug("or");
aoqi@0 529 pushType(get2i().or(method));
aoqi@0 530 return this;
aoqi@0 531 }
aoqi@0 532
aoqi@0 533 /**
aoqi@0 534 * Pops two integer types from the stack, performs a bitwise xor and pushes
aoqi@0 535 * the result
aoqi@0 536 *
aoqi@0 537 * @return the method emitter
aoqi@0 538 */
aoqi@0 539 MethodEmitter xor() {
aoqi@0 540 debug("xor");
aoqi@0 541 pushType(get2i().xor(method));
aoqi@0 542 return this;
aoqi@0 543 }
aoqi@0 544
aoqi@0 545 /**
aoqi@0 546 * Pops two integer types from the stack, performs a bitwise logic shift right and pushes
aoqi@0 547 * the result. The shift count, the first element, must be INT.
aoqi@0 548 *
aoqi@0 549 * @return the method emitter
aoqi@0 550 */
aoqi@0 551 MethodEmitter shr() {
aoqi@0 552 debug("shr");
aoqi@0 553 popType(Type.INT);
aoqi@0 554 pushType(popInteger().shr(method));
aoqi@0 555 return this;
aoqi@0 556 }
aoqi@0 557
aoqi@0 558 /**
aoqi@0 559 * Pops two integer types from the stack, performs a bitwise shift left and and pushes
aoqi@0 560 * the result. The shift count, the first element, must be INT.
aoqi@0 561 *
aoqi@0 562 * @return the method emitter
aoqi@0 563 */
aoqi@0 564 MethodEmitter shl() {
aoqi@0 565 debug("shl");
aoqi@0 566 popType(Type.INT);
aoqi@0 567 pushType(popInteger().shl(method));
aoqi@0 568 return this;
aoqi@0 569 }
aoqi@0 570
aoqi@0 571 /**
aoqi@0 572 * Pops two integer types from the stack, performs a bitwise arithetic shift right and pushes
aoqi@0 573 * the result. The shift count, the first element, must be INT.
aoqi@0 574 *
aoqi@0 575 * @return the method emitter
aoqi@0 576 */
aoqi@0 577 MethodEmitter sar() {
aoqi@0 578 debug("sar");
aoqi@0 579 popType(Type.INT);
aoqi@0 580 pushType(popInteger().sar(method));
aoqi@0 581 return this;
aoqi@0 582 }
aoqi@0 583
aoqi@0 584 /**
aoqi@0 585 * Pops a numeric type from the stack, negates it and pushes the result
aoqi@0 586 *
aoqi@0 587 * @return the method emitter
aoqi@0 588 */
aoqi@0 589 MethodEmitter neg() {
aoqi@0 590 debug("neg");
aoqi@0 591 pushType(popNumeric().neg(method));
aoqi@0 592 return this;
aoqi@0 593 }
aoqi@0 594
aoqi@0 595 /**
aoqi@0 596 * Add label for the start of a catch block and push the exception to the
aoqi@0 597 * stack
aoqi@0 598 *
aoqi@0 599 * @param recovery label pointing to start of catch block
aoqi@0 600 */
aoqi@0 601 void _catch(final Label recovery) {
aoqi@0 602 stack.clear();
aoqi@0 603 stack.push(Type.OBJECT);
aoqi@0 604 label(recovery);
aoqi@0 605 }
aoqi@0 606
aoqi@0 607 /**
aoqi@0 608 * Start a try/catch block.
aoqi@0 609 *
aoqi@0 610 * @param entry start label for try
aoqi@0 611 * @param exit end label for try
aoqi@0 612 * @param recovery start label for catch
aoqi@0 613 * @param typeDescriptor type descriptor for exception
aoqi@0 614 */
aoqi@0 615 void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
aoqi@0 616 method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
aoqi@0 617 }
aoqi@0 618
aoqi@0 619 /**
aoqi@0 620 * Start a try/catch block.
aoqi@0 621 *
aoqi@0 622 * @param entry start label for try
aoqi@0 623 * @param exit end label for try
aoqi@0 624 * @param recovery start label for catch
aoqi@0 625 * @param clazz exception class
aoqi@0 626 */
aoqi@0 627 void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
aoqi@0 628 method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
aoqi@0 629 }
aoqi@0 630
aoqi@0 631 /**
aoqi@0 632 * Start a try/catch block. The catch is "Throwable" - i.e. catch-all
aoqi@0 633 *
aoqi@0 634 * @param entry start label for try
aoqi@0 635 * @param exit end label for try
aoqi@0 636 * @param recovery start label for catch
aoqi@0 637 */
aoqi@0 638 void _try(final Label entry, final Label exit, final Label recovery) {
aoqi@0 639 _try(entry, exit, recovery, (String)null);
aoqi@0 640 }
aoqi@0 641
aoqi@0 642
aoqi@0 643 /**
aoqi@0 644 * Load the constants array
aoqi@0 645 * @return this method emitter
aoqi@0 646 */
aoqi@0 647 MethodEmitter loadConstants() {
aoqi@0 648 getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
aoqi@0 649 assert peekType().isArray() : peekType();
aoqi@0 650 return this;
aoqi@0 651 }
aoqi@0 652
aoqi@0 653 /**
aoqi@0 654 * Push the undefined value for the given type, i.e.
aoqi@0 655 * UNDEFINED or UNDEFINEDNUMBER. Currently we have no way of
aoqi@0 656 * representing UNDEFINED for INTs and LONGs, so they are not
aoqi@0 657 * allowed to be local variables (yet)
aoqi@0 658 *
aoqi@0 659 * @param type the type for which to push UNDEFINED
aoqi@0 660 * @return the method emitter
aoqi@0 661 */
aoqi@0 662 MethodEmitter loadUndefined(final Type type) {
aoqi@0 663 debug("load undefined ", type);
aoqi@0 664 pushType(type.loadUndefined(method));
aoqi@0 665 return this;
aoqi@0 666 }
aoqi@0 667
aoqi@0 668 /**
aoqi@0 669 * Push the empty value for the given type, i.e. EMPTY.
aoqi@0 670 *
aoqi@0 671 * @param type the type
aoqi@0 672 * @return the method emitter
aoqi@0 673 */
aoqi@0 674 MethodEmitter loadEmpty(final Type type) {
aoqi@0 675 debug("load empty ", type);
aoqi@0 676 pushType(type.loadEmpty(method));
aoqi@0 677 return this;
aoqi@0 678 }
aoqi@0 679
aoqi@0 680 /**
aoqi@0 681 * Push null to stack
aoqi@0 682 *
aoqi@0 683 * @return the method emitter
aoqi@0 684 */
aoqi@0 685 MethodEmitter loadNull() {
aoqi@0 686 debug("aconst_null");
aoqi@0 687 pushType(Type.OBJECT.ldc(method, null));
aoqi@0 688 return this;
aoqi@0 689 }
aoqi@0 690
aoqi@0 691 /**
aoqi@0 692 * Push a handle representing this class top stack
aoqi@0 693 *
aoqi@0 694 * @param className name of the class
aoqi@0 695 *
aoqi@0 696 * @return the method emitter
aoqi@0 697 */
aoqi@0 698 MethodEmitter loadType(final String className) {
aoqi@0 699 debug("load type", className);
aoqi@0 700 method.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(className));
aoqi@0 701 pushType(Type.OBJECT);
aoqi@0 702 return this;
aoqi@0 703 }
aoqi@0 704
aoqi@0 705 /**
aoqi@0 706 * Push a boolean constant to the stack.
aoqi@0 707 *
aoqi@0 708 * @param b value of boolean
aoqi@0 709 *
aoqi@0 710 * @return the method emitter
aoqi@0 711 */
aoqi@0 712 MethodEmitter load(final boolean b) {
aoqi@0 713 debug("load boolean", b);
aoqi@0 714 pushType(Type.BOOLEAN.ldc(method, b));
aoqi@0 715 return this;
aoqi@0 716 }
aoqi@0 717
aoqi@0 718 /**
aoqi@0 719 * Push an int constant to the stack
aoqi@0 720 *
aoqi@0 721 * @param i value of the int
aoqi@0 722 *
aoqi@0 723 * @return the method emitter
aoqi@0 724 */
aoqi@0 725 MethodEmitter load(final int i) {
aoqi@0 726 debug("load int", i);
aoqi@0 727 pushType(Type.INT.ldc(method, i));
aoqi@0 728 return this;
aoqi@0 729 }
aoqi@0 730
aoqi@0 731 /**
aoqi@0 732 * Push a double constant to the stack
aoqi@0 733 *
aoqi@0 734 * @param d value of the double
aoqi@0 735 *
aoqi@0 736 * @return the method emitter
aoqi@0 737 */
aoqi@0 738 MethodEmitter load(final double d) {
aoqi@0 739 debug("load double", d);
aoqi@0 740 pushType(Type.NUMBER.ldc(method, d));
aoqi@0 741 return this;
aoqi@0 742 }
aoqi@0 743
aoqi@0 744 /**
aoqi@0 745 * Push an long constant to the stack
aoqi@0 746 *
aoqi@0 747 * @param l value of the long
aoqi@0 748 *
aoqi@0 749 * @return the method emitter
aoqi@0 750 */
aoqi@0 751 MethodEmitter load(final long l) {
aoqi@0 752 debug("load long", l);
aoqi@0 753 pushType(Type.LONG.ldc(method, l));
aoqi@0 754 return this;
aoqi@0 755 }
aoqi@0 756
aoqi@0 757 /**
aoqi@0 758 * Fetch the length of an array.
aoqi@0 759 * @return Array length.
aoqi@0 760 */
aoqi@0 761 MethodEmitter arraylength() {
aoqi@0 762 debug("arraylength");
aoqi@0 763 popType(Type.OBJECT);
aoqi@0 764 pushType(Type.OBJECT_ARRAY.arraylength(method));
aoqi@0 765 return this;
aoqi@0 766 }
aoqi@0 767
aoqi@0 768 /**
aoqi@0 769 * Push a String constant to the stack
aoqi@0 770 *
aoqi@0 771 * @param s value of the String
aoqi@0 772 *
aoqi@0 773 * @return the method emitter
aoqi@0 774 */
aoqi@0 775 MethodEmitter load(final String s) {
aoqi@0 776 debug("load string", s);
aoqi@0 777
aoqi@0 778 if (s == null) {
aoqi@0 779 loadNull();
aoqi@0 780 return this;
aoqi@0 781 }
aoqi@0 782
aoqi@0 783 //NASHORN-142 - split too large string
aoqi@0 784 final int length = s.length();
aoqi@0 785 if (length > LARGE_STRING_THRESHOLD) {
aoqi@0 786
aoqi@0 787 _new(StringBuilder.class);
aoqi@0 788 dup();
aoqi@0 789 load(length);
aoqi@0 790 invoke(constructorNoLookup(StringBuilder.class, int.class));
aoqi@0 791
aoqi@0 792 for (int n = 0; n < length; n += LARGE_STRING_THRESHOLD) {
aoqi@0 793 final String part = s.substring(n, Math.min(n + LARGE_STRING_THRESHOLD, length));
aoqi@0 794 load(part);
aoqi@0 795 stringBuilderAppend();
aoqi@0 796 }
aoqi@0 797
aoqi@0 798 invoke(virtualCallNoLookup(StringBuilder.class, "toString", String.class));
aoqi@0 799
aoqi@0 800 return this;
aoqi@0 801 }
aoqi@0 802
aoqi@0 803 pushType(Type.OBJECT.ldc(method, s));
aoqi@0 804 return this;
aoqi@0 805 }
aoqi@0 806
aoqi@0 807 /**
aoqi@0 808 * Push a local variable to the stack. If the symbol representing
aoqi@0 809 * the local variable doesn't have a slot, this is a NOP
aoqi@0 810 *
aoqi@0 811 * @param symbol the symbol representing the local variable.
aoqi@0 812 *
aoqi@0 813 * @return the method emitter
aoqi@0 814 */
aoqi@0 815 MethodEmitter load(final Symbol symbol) {
aoqi@0 816 assert symbol != null;
aoqi@0 817 if (symbol.hasSlot()) {
aoqi@0 818 final int slot = symbol.getSlot();
aoqi@0 819 debug("load symbol", symbol.getName(), " slot=", slot);
aoqi@0 820 final Type type = symbol.getSymbolType().load(method, slot);
aoqi@0 821 pushType(type == Type.OBJECT && symbol.isThis() ? Type.THIS : type);
aoqi@0 822 } else if (symbol.isParam()) {
aoqi@0 823 assert !symbol.isScope();
aoqi@0 824 assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
aoqi@0 825 final int index = symbol.getFieldIndex();
aoqi@0 826 if (functionNode.needsArguments()) {
aoqi@0 827 // ScriptObject.getArgument(int) on arguments
aoqi@0 828 debug("load symbol", symbol.getName(), " arguments index=", index);
aoqi@0 829 loadCompilerConstant(ARGUMENTS);
aoqi@0 830 load(index);
aoqi@0 831 ScriptObject.GET_ARGUMENT.invoke(this);
aoqi@0 832 } else {
aoqi@0 833 // array load from __varargs__
aoqi@0 834 debug("load symbol", symbol.getName(), " array index=", index);
aoqi@0 835 loadCompilerConstant(VARARGS);
aoqi@0 836 load(symbol.getFieldIndex());
aoqi@0 837 arrayload();
aoqi@0 838 }
aoqi@0 839 }
aoqi@0 840 return this;
aoqi@0 841 }
aoqi@0 842
aoqi@0 843 /**
aoqi@0 844 * Push a local variable to the stack, given an explicit bytecode slot
aoqi@0 845 * This is used e.g. for stub generation where we know where items like
aoqi@0 846 * "this" and "scope" reside.
aoqi@0 847 *
aoqi@0 848 * @param type the type of the variable
aoqi@0 849 * @param slot the slot the variable is in
aoqi@0 850 *
aoqi@0 851 * @return the method emitter
aoqi@0 852 */
aoqi@0 853 MethodEmitter load(final Type type, final int slot) {
aoqi@0 854 debug("explicit load", type, slot);
aoqi@0 855 final Type loadType = type.load(method, slot);
aoqi@0 856 pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType);
aoqi@0 857 return this;
aoqi@0 858 }
aoqi@0 859
aoqi@0 860 private boolean isThisSlot(final int slot) {
aoqi@0 861 if (functionNode == null) {
aoqi@0 862 return slot == CompilerConstants.JAVA_THIS.slot();
aoqi@0 863 }
aoqi@0 864 final int thisSlot = compilerConstant(THIS).getSlot();
aoqi@0 865 assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
aoqi@0 866 assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
aoqi@0 867 return slot == thisSlot;
aoqi@0 868 }
aoqi@0 869
aoqi@0 870 /**
aoqi@0 871 * Push a method handle to the stack
aoqi@0 872 *
aoqi@0 873 * @param className class name
aoqi@0 874 * @param methodName method name
aoqi@0 875 * @param descName descriptor
aoqi@0 876 * @param flags flags that describe this handle, e.g. invokespecial new, or invoke virtual
aoqi@0 877 *
aoqi@0 878 * @return the method emitter
aoqi@0 879 */
aoqi@0 880 MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet<Flag> flags) {
aoqi@0 881 debug("load handle ");
aoqi@0 882 pushType(Type.OBJECT.ldc(method, new Handle(Flag.getValue(flags), className, methodName, descName)));
aoqi@0 883 return this;
aoqi@0 884 }
aoqi@0 885
aoqi@0 886 private Symbol compilerConstant(final CompilerConstants cc) {
aoqi@0 887 return functionNode.getBody().getExistingSymbol(cc.symbolName());
aoqi@0 888 }
aoqi@0 889
aoqi@0 890 /**
aoqi@0 891 * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
aoqi@0 892 * the scope).
aoqi@0 893 * @return if this method has a slot allocated for the scope variable.
aoqi@0 894 */
aoqi@0 895 boolean hasScope() {
aoqi@0 896 return compilerConstant(SCOPE).hasSlot();
aoqi@0 897 }
aoqi@0 898
aoqi@0 899 MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
aoqi@0 900 final Symbol symbol = compilerConstant(cc);
aoqi@0 901 if (cc == SCOPE && peekType() == Type.SCOPE) {
aoqi@0 902 dup();
aoqi@0 903 return this;
aoqi@0 904 }
aoqi@0 905 return load(symbol);
aoqi@0 906 }
aoqi@0 907
aoqi@0 908 void storeCompilerConstant(final CompilerConstants cc) {
aoqi@0 909 final Symbol symbol = compilerConstant(cc);
aoqi@0 910 debug("store compiler constant ", symbol);
aoqi@0 911 store(symbol);
aoqi@0 912 }
aoqi@0 913
aoqi@0 914 /**
aoqi@0 915 * Load an element from an array, determining type automatically
aoqi@0 916 * @return the method emitter
aoqi@0 917 */
aoqi@0 918 MethodEmitter arrayload() {
aoqi@0 919 debug("Xaload");
aoqi@0 920 popType(Type.INT);
aoqi@0 921 pushType(popArray().aload(method));
aoqi@0 922 return this;
aoqi@0 923 }
aoqi@0 924
aoqi@0 925 /**
aoqi@0 926 * Pop a value, an index and an array from the stack and store
aoqi@0 927 * the value at the given index in the array.
aoqi@0 928 */
aoqi@0 929 void arraystore() {
aoqi@0 930 debug("Xastore");
aoqi@0 931 final Type value = popType();
aoqi@0 932 final Type index = popType(Type.INT);
aoqi@0 933 assert index.isInteger() : "array index is not integer, but " + index;
aoqi@0 934 final ArrayType array = popArray();
aoqi@0 935
aoqi@0 936 assert value.isEquivalentTo(array.getElementType()) : "Storing "+value+" into "+array;
aoqi@0 937 assert array.isObject();
aoqi@0 938 array.astore(method);
aoqi@0 939 }
aoqi@0 940
aoqi@0 941 /**
aoqi@0 942 * Pop a value from the stack and store it in a local variable represented
aoqi@0 943 * by the given symbol. If the symbol has no slot, this is a NOP
aoqi@0 944 *
aoqi@0 945 * @param symbol symbol to store stack to
aoqi@0 946 */
aoqi@0 947 void store(final Symbol symbol) {
aoqi@0 948 assert symbol != null : "No symbol to store";
aoqi@0 949 if (symbol.hasSlot()) {
aoqi@0 950 final int slot = symbol.getSlot();
aoqi@0 951 debug("store symbol", symbol.getName(), " slot=", slot);
aoqi@0 952 popType(symbol.getSymbolType()).store(method, slot);
aoqi@0 953 } else if (symbol.isParam()) {
aoqi@0 954 assert !symbol.isScope();
aoqi@0 955 assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
aoqi@0 956 final int index = symbol.getFieldIndex();
aoqi@0 957 if (functionNode.needsArguments()) {
aoqi@0 958 debug("store symbol", symbol.getName(), " arguments index=", index);
aoqi@0 959 loadCompilerConstant(ARGUMENTS);
aoqi@0 960 load(index);
aoqi@0 961 ArgumentSetter.SET_ARGUMENT.invoke(this);
aoqi@0 962 } else {
aoqi@0 963 // varargs without arguments object - just do array store to __varargs__
aoqi@0 964 debug("store symbol", symbol.getName(), " array index=", index);
aoqi@0 965 loadCompilerConstant(VARARGS);
aoqi@0 966 load(index);
aoqi@0 967 ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this);
aoqi@0 968 }
aoqi@0 969 }
aoqi@0 970 }
aoqi@0 971
aoqi@0 972 /**
aoqi@0 973 * Pop a value from the stack and store it in a given local variable
aoqi@0 974 * slot.
aoqi@0 975 *
aoqi@0 976 * @param type the type to pop
aoqi@0 977 * @param slot the slot
aoqi@0 978 */
aoqi@0 979 void store(final Type type, final int slot) {
aoqi@0 980 popType(type);
aoqi@0 981 type.store(method, slot);
aoqi@0 982 }
aoqi@0 983
aoqi@0 984 /**
aoqi@0 985 * Increment/Decrement a local integer by the given value.
aoqi@0 986 *
aoqi@0 987 * @param slot the int slot
aoqi@0 988 * @param increment the amount to increment
aoqi@0 989 */
aoqi@0 990 void iinc(final int slot, final int increment) {
aoqi@0 991 debug("iinc");
aoqi@0 992 method.visitIincInsn(slot, increment);
aoqi@0 993 }
aoqi@0 994
aoqi@0 995 /**
aoqi@0 996 * Pop an exception object from the stack and generate code
aoqi@0 997 * for throwing it
aoqi@0 998 */
aoqi@0 999 public void athrow() {
aoqi@0 1000 debug("athrow");
aoqi@0 1001 final Type receiver = popType(Type.OBJECT);
aoqi@0 1002 assert receiver.isObject();
aoqi@0 1003 method.visitInsn(ATHROW);
aoqi@0 1004 stack = null;
aoqi@0 1005 }
aoqi@0 1006
aoqi@0 1007 /**
aoqi@0 1008 * Pop an object from the stack and perform an instanceof
aoqi@0 1009 * operation, given a classDescriptor to compare it to.
aoqi@0 1010 * Push the boolean result 1/0 as an int to the stack
aoqi@0 1011 *
aoqi@0 1012 * @param classDescriptor descriptor of the class to type check against
aoqi@0 1013 *
aoqi@0 1014 * @return the method emitter
aoqi@0 1015 */
aoqi@0 1016 MethodEmitter _instanceof(final String classDescriptor) {
aoqi@0 1017 debug("instanceof", classDescriptor);
aoqi@0 1018 popType(Type.OBJECT);
aoqi@0 1019 method.visitTypeInsn(INSTANCEOF, classDescriptor);
aoqi@0 1020 pushType(Type.INT);
aoqi@0 1021 return this;
aoqi@0 1022 }
aoqi@0 1023
aoqi@0 1024 /**
aoqi@0 1025 * Pop an object from the stack and perform an instanceof
aoqi@0 1026 * operation, given a classDescriptor to compare it to.
aoqi@0 1027 * Push the boolean result 1/0 as an int to the stack
aoqi@0 1028 *
aoqi@0 1029 * @param clazz the type to check instanceof against
aoqi@0 1030 *
aoqi@0 1031 * @return the method emitter
aoqi@0 1032 */
aoqi@0 1033 MethodEmitter _instanceof(final Class<?> clazz) {
aoqi@0 1034 return _instanceof(CompilerConstants.className(clazz));
aoqi@0 1035 }
aoqi@0 1036
aoqi@0 1037 /**
aoqi@0 1038 * Perform a checkcast operation on the object at the top of the
aoqi@0 1039 * stack.
aoqi@0 1040 *
aoqi@0 1041 * @param classDescriptor descriptor of the class to type check against
aoqi@0 1042 *
aoqi@0 1043 * @return the method emitter
aoqi@0 1044 */
aoqi@0 1045 MethodEmitter checkcast(final String classDescriptor) {
aoqi@0 1046 debug("checkcast", classDescriptor);
aoqi@0 1047 assert peekType().isObject();
aoqi@0 1048 method.visitTypeInsn(CHECKCAST, classDescriptor);
aoqi@0 1049 return this;
aoqi@0 1050 }
aoqi@0 1051
aoqi@0 1052 /**
aoqi@0 1053 * Perform a checkcast operation on the object at the top of the
aoqi@0 1054 * stack.
aoqi@0 1055 *
aoqi@0 1056 * @param clazz class to checkcast against
aoqi@0 1057 *
aoqi@0 1058 * @return the method emitter
aoqi@0 1059 */
aoqi@0 1060 MethodEmitter checkcast(final Class<?> clazz) {
aoqi@0 1061 return checkcast(CompilerConstants.className(clazz));
aoqi@0 1062 }
aoqi@0 1063
aoqi@0 1064 /**
aoqi@0 1065 * Instantiate a new array given a length that is popped
aoqi@0 1066 * from the stack and the array type
aoqi@0 1067 *
aoqi@0 1068 * @param arrayType the type of the array
aoqi@0 1069 *
aoqi@0 1070 * @return the method emitter
aoqi@0 1071 */
aoqi@0 1072 MethodEmitter newarray(final ArrayType arrayType) {
aoqi@0 1073 debug("newarray ", "arrayType=", arrayType);
aoqi@0 1074 popType(Type.INT); //LENGTH
aoqi@0 1075 pushType(arrayType.newarray(method));
aoqi@0 1076 return this;
aoqi@0 1077 }
aoqi@0 1078
aoqi@0 1079 /**
aoqi@0 1080 * Instantiate a multidimensional array with a given number of dimensions.
aoqi@0 1081 * On the stack are dim lengths of the sub arrays.
aoqi@0 1082 *
aoqi@0 1083 * @param arrayType type of the array
aoqi@0 1084 * @param dims number of dimensions
aoqi@0 1085 *
aoqi@0 1086 * @return the method emitter
aoqi@0 1087 */
aoqi@0 1088 MethodEmitter multinewarray(final ArrayType arrayType, final int dims) {
aoqi@0 1089 debug("multianewarray ", arrayType, dims);
aoqi@0 1090 for (int i = 0; i < dims; i++) {
aoqi@0 1091 popType(Type.INT); //LENGTH
aoqi@0 1092 }
aoqi@0 1093 pushType(arrayType.newarray(method, dims));
aoqi@0 1094 return this;
aoqi@0 1095 }
aoqi@0 1096
aoqi@0 1097 /**
aoqi@0 1098 * Helper function to pop and type check the appropriate arguments
aoqi@0 1099 * from the stack given a method signature
aoqi@0 1100 *
aoqi@0 1101 * @param signature method signature
aoqi@0 1102 *
aoqi@0 1103 * @return return type of method
aoqi@0 1104 */
aoqi@0 1105 private Type fixParamStack(final String signature) {
aoqi@0 1106 final Type[] params = Type.getMethodArguments(signature);
aoqi@0 1107 for (int i = params.length - 1; i >= 0; i--) {
aoqi@0 1108 popType(params[i]);
aoqi@0 1109 }
aoqi@0 1110 final Type returnType = Type.getMethodReturnType(signature);
aoqi@0 1111 return returnType;
aoqi@0 1112 }
aoqi@0 1113
aoqi@0 1114 /**
aoqi@0 1115 * Generate an invocation to a Call structure
aoqi@0 1116 * @see CompilerConstants
aoqi@0 1117 *
aoqi@0 1118 * @param call the call object
aoqi@0 1119 *
aoqi@0 1120 * @return the method emitter
aoqi@0 1121 */
aoqi@0 1122 MethodEmitter invoke(final Call call) {
aoqi@0 1123 return call.invoke(this);
aoqi@0 1124 }
aoqi@0 1125
aoqi@0 1126 private MethodEmitter invoke(final int opcode, final String className, final String methodName, final String methodDescriptor, final boolean hasReceiver) {
aoqi@0 1127 final Type returnType = fixParamStack(methodDescriptor);
aoqi@0 1128
aoqi@0 1129 if (hasReceiver) {
aoqi@0 1130 popType(Type.OBJECT);
aoqi@0 1131 }
aoqi@0 1132
aoqi@0 1133 if (opcode == INVOKEINTERFACE) {
aoqi@0 1134 method.visitMethodInsn(opcode, className, methodName, methodDescriptor, true);
aoqi@0 1135 } else {
aoqi@0 1136 method.visitMethodInsn(opcode, className, methodName, methodDescriptor, false);
aoqi@0 1137 }
aoqi@0 1138
aoqi@0 1139 if (returnType != null) {
aoqi@0 1140 pushType(returnType);
aoqi@0 1141 }
aoqi@0 1142
aoqi@0 1143 return this;
aoqi@0 1144 }
aoqi@0 1145
aoqi@0 1146 /**
aoqi@0 1147 * Pop receiver from stack, perform an invoke special
aoqi@0 1148 *
aoqi@0 1149 * @param className class name
aoqi@0 1150 * @param methodName method name
aoqi@0 1151 * @param methodDescriptor descriptor
aoqi@0 1152 *
aoqi@0 1153 * @return the method emitter
aoqi@0 1154 */
aoqi@0 1155 MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
aoqi@0 1156 debug("invokespecial", className, ".", methodName, methodDescriptor);
aoqi@0 1157 return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
aoqi@0 1158 }
aoqi@0 1159
aoqi@0 1160 /**
aoqi@0 1161 * Pop receiver from stack, perform an invoke virtual, push return value if any
aoqi@0 1162 *
aoqi@0 1163 * @param className class name
aoqi@0 1164 * @param methodName method name
aoqi@0 1165 * @param methodDescriptor descriptor
aoqi@0 1166 *
aoqi@0 1167 * @return the method emitter
aoqi@0 1168 */
aoqi@0 1169 MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
aoqi@0 1170 debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
aoqi@0 1171 return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
aoqi@0 1172 }
aoqi@0 1173
aoqi@0 1174 /**
aoqi@0 1175 * Perform an invoke static and push the return value if any
aoqi@0 1176 *
aoqi@0 1177 * @param className class name
aoqi@0 1178 * @param methodName method name
aoqi@0 1179 * @param methodDescriptor descriptor
aoqi@0 1180 *
aoqi@0 1181 * @return the method emitter
aoqi@0 1182 */
aoqi@0 1183 MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
aoqi@0 1184 debug("invokestatic", className, ".", methodName, methodDescriptor);
aoqi@0 1185 invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
aoqi@0 1186 return this;
aoqi@0 1187 }
aoqi@0 1188
aoqi@0 1189 /**
aoqi@0 1190 * Perform an invoke static and replace the return type if we know better, e.g. Global.allocate
aoqi@0 1191 * that allocates an array should return an ObjectArray type as a NativeArray counts as that
aoqi@0 1192 *
aoqi@0 1193 * @param className class name
aoqi@0 1194 * @param methodName method name
aoqi@0 1195 * @param methodDescriptor descriptor
aoqi@0 1196 * @param returnType return type override
aoqi@0 1197 *
aoqi@0 1198 * @return the method emitter
aoqi@0 1199 */
aoqi@0 1200 MethodEmitter invokeStatic(final String className, final String methodName, final String methodDescriptor, final Type returnType) {
aoqi@0 1201 invokestatic(className, methodName, methodDescriptor);
aoqi@0 1202 popType();
aoqi@0 1203 pushType(returnType);
aoqi@0 1204 return this;
aoqi@0 1205 }
aoqi@0 1206
aoqi@0 1207 /**
aoqi@0 1208 * Pop receiver from stack, perform an invoke interface and push return value if any
aoqi@0 1209 *
aoqi@0 1210 * @param className class name
aoqi@0 1211 * @param methodName method name
aoqi@0 1212 * @param methodDescriptor descriptor
aoqi@0 1213 *
aoqi@0 1214 * @return the method emitter
aoqi@0 1215 */
aoqi@0 1216 MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
aoqi@0 1217 debug("invokeinterface", className, ".", methodName, methodDescriptor);
aoqi@0 1218 return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
aoqi@0 1219 }
aoqi@0 1220
aoqi@0 1221 static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
aoqi@0 1222 final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
aoqi@0 1223 for (int i = 0; i < table.length; i++) {
aoqi@0 1224 internalLabels[i] = table[i].getLabel();
aoqi@0 1225 }
aoqi@0 1226 return internalLabels;
aoqi@0 1227 }
aoqi@0 1228
aoqi@0 1229 /**
aoqi@0 1230 * Generate a lookup switch, popping the switch value from the stack
aoqi@0 1231 *
aoqi@0 1232 * @param defaultLabel default label
aoqi@0 1233 * @param values case values for the table
aoqi@0 1234 * @param table default label
aoqi@0 1235 */
aoqi@0 1236 void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
aoqi@0 1237 debug("lookupswitch", peekType());
aoqi@0 1238 popType(Type.INT);
aoqi@0 1239 method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
aoqi@0 1240 }
aoqi@0 1241
aoqi@0 1242 /**
aoqi@0 1243 * Generate a table switch
aoqi@0 1244 * @param lo low value
aoqi@0 1245 * @param hi high value
aoqi@0 1246 * @param defaultLabel default label
aoqi@0 1247 * @param table label table
aoqi@0 1248 */
aoqi@0 1249 void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
aoqi@0 1250 debug("tableswitch", peekType());
aoqi@0 1251 popType(Type.INT);
aoqi@0 1252 method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
aoqi@0 1253 }
aoqi@0 1254
aoqi@0 1255 /**
aoqi@0 1256 * Abstraction for performing a conditional jump of any type
aoqi@0 1257 *
aoqi@0 1258 * @see MethodEmitter.Condition
aoqi@0 1259 *
aoqi@0 1260 * @param cond the condition to test
aoqi@0 1261 * @param trueLabel the destination label is condition is true
aoqi@0 1262 */
aoqi@0 1263 void conditionalJump(final Condition cond, final Label trueLabel) {
aoqi@0 1264 conditionalJump(cond, cond != Condition.GT && cond != Condition.GE, trueLabel);
aoqi@0 1265 }
aoqi@0 1266
aoqi@0 1267 /**
aoqi@0 1268 * Abstraction for performing a conditional jump of any type,
aoqi@0 1269 * including a dcmpg/dcmpl semantic for doubles.
aoqi@0 1270 *
aoqi@0 1271 * @param cond the condition to test
aoqi@0 1272 * @param isCmpG is this a dcmpg for numbers, false if it's a dcmpl
aoqi@0 1273 * @param trueLabel the destination label if condition is true
aoqi@0 1274 */
aoqi@0 1275 void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
aoqi@0 1276 if (peekType().isCategory2()) {
aoqi@0 1277 debug("[ld]cmp isCmpG=", isCmpG);
aoqi@0 1278 pushType(get2n().cmp(method, isCmpG));
aoqi@0 1279 jump(Condition.toUnary(cond), trueLabel, 1);
aoqi@0 1280 } else {
aoqi@0 1281 debug("if", cond);
aoqi@0 1282 jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
aoqi@0 1283 }
aoqi@0 1284 }
aoqi@0 1285
aoqi@0 1286 MethodEmitter registerReturn() {
aoqi@0 1287 setHasReturn();
aoqi@0 1288 return this;
aoqi@0 1289 }
aoqi@0 1290
aoqi@0 1291 void setHasReturn() {
aoqi@0 1292 this.hasReturn = true;
aoqi@0 1293 }
aoqi@0 1294
aoqi@0 1295 /**
aoqi@0 1296 * Perform a non void return, popping the type from the stack
aoqi@0 1297 *
aoqi@0 1298 * @param type the type for the return
aoqi@0 1299 */
aoqi@0 1300 void _return(final Type type) {
aoqi@0 1301 debug("return", type);
aoqi@0 1302 assert stack.size() == 1 : "Only return value on stack allowed at return point - depth=" + stack.size() + " stack = " + stack;
aoqi@0 1303 final Type stackType = peekType();
aoqi@0 1304 if (!Type.areEquivalent(type, stackType)) {
aoqi@0 1305 convert(type);
aoqi@0 1306 }
aoqi@0 1307 popType(type)._return(method);
aoqi@0 1308 stack = null;
aoqi@0 1309 }
aoqi@0 1310
aoqi@0 1311 /**
aoqi@0 1312 * Perform a return using the stack top value as the guide for the type
aoqi@0 1313 */
aoqi@0 1314 void _return() {
aoqi@0 1315 _return(peekType());
aoqi@0 1316 }
aoqi@0 1317
aoqi@0 1318 /**
aoqi@0 1319 * Perform a void return.
aoqi@0 1320 */
aoqi@0 1321 void returnVoid() {
aoqi@0 1322 debug("return [void]");
aoqi@0 1323 assert stack.isEmpty() : stack;
aoqi@0 1324 method.visitInsn(RETURN);
aoqi@0 1325 stack = null;
aoqi@0 1326 }
aoqi@0 1327
aoqi@0 1328 /**
aoqi@0 1329 * Goto, possibly when splitting is taking place. If
aoqi@0 1330 * a splitNode exists, we need to handle the case that the
aoqi@0 1331 * jump target is another method
aoqi@0 1332 *
aoqi@0 1333 * @param label destination label
aoqi@0 1334 */
aoqi@0 1335 void splitAwareGoto(final LexicalContext lc, final Label label) {
aoqi@0 1336 _goto(label);
aoqi@0 1337 }
aoqi@0 1338
aoqi@0 1339 /**
aoqi@0 1340 * Perform a comparison of two number types that are popped from the stack
aoqi@0 1341 *
aoqi@0 1342 * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
aoqi@0 1343 *
aoqi@0 1344 * @return the method emitter
aoqi@0 1345 */
aoqi@0 1346 MethodEmitter cmp(final boolean isCmpG) {
aoqi@0 1347 pushType(get2n().cmp(method, isCmpG));
aoqi@0 1348 return this;
aoqi@0 1349 }
aoqi@0 1350
aoqi@0 1351 /**
aoqi@0 1352 * Helper function for jumps, conditional or not
aoqi@0 1353 * @param opcode opcode for jump
aoqi@0 1354 * @param label destination
aoqi@0 1355 * @param n elements on stack to compare, 0-2
aoqi@0 1356 */
aoqi@0 1357 private void jump(final int opcode, final Label label, final int n) {
aoqi@0 1358 for (int i = 0; i < n; i++) {
aoqi@0 1359 assert peekType().isInteger() || peekType().isBoolean() || peekType().isObject() : "expecting integer type or object for jump, but found " + peekType();
aoqi@0 1360 popType();
aoqi@0 1361 }
aoqi@0 1362 mergeStackTo(label);
aoqi@0 1363 method.visitJumpInsn(opcode, label.getLabel());
aoqi@0 1364 }
aoqi@0 1365
aoqi@0 1366 /**
aoqi@0 1367 * Generate an if_acmpeq
aoqi@0 1368 *
aoqi@0 1369 * @param label label to true case
aoqi@0 1370 */
aoqi@0 1371 void if_acmpeq(final Label label) {
aoqi@0 1372 debug("if_acmpeq", label);
aoqi@0 1373 jump(IF_ACMPEQ, label, 2);
aoqi@0 1374 }
aoqi@0 1375
aoqi@0 1376 /**
aoqi@0 1377 * Generate an if_acmpne
aoqi@0 1378 *
aoqi@0 1379 * @param label label to true case
aoqi@0 1380 */
aoqi@0 1381 void if_acmpne(final Label label) {
aoqi@0 1382 debug("if_acmpne", label);
aoqi@0 1383 jump(IF_ACMPNE, label, 2);
aoqi@0 1384 }
aoqi@0 1385
aoqi@0 1386 /**
aoqi@0 1387 * Generate an ifnull
aoqi@0 1388 *
aoqi@0 1389 * @param label label to true case
aoqi@0 1390 */
aoqi@0 1391 void ifnull(final Label label) {
aoqi@0 1392 debug("ifnull", label);
aoqi@0 1393 jump(IFNULL, label, 1);
aoqi@0 1394 }
aoqi@0 1395
aoqi@0 1396 /**
aoqi@0 1397 * Generate an ifnonnull
aoqi@0 1398 *
aoqi@0 1399 * @param label label to true case
aoqi@0 1400 */
aoqi@0 1401 void ifnonnull(final Label label) {
aoqi@0 1402 debug("ifnonnull", label);
aoqi@0 1403 jump(IFNONNULL, label, 1);
aoqi@0 1404 }
aoqi@0 1405
aoqi@0 1406 /**
aoqi@0 1407 * Generate an ifeq
aoqi@0 1408 *
aoqi@0 1409 * @param label label to true case
aoqi@0 1410 */
aoqi@0 1411 void ifeq(final Label label) {
aoqi@0 1412 debug("ifeq ", label);
aoqi@0 1413 jump(IFEQ, label, 1);
aoqi@0 1414 }
aoqi@0 1415
aoqi@0 1416 /**
aoqi@0 1417 * Generate an if_icmpeq
aoqi@0 1418 *
aoqi@0 1419 * @param label label to true case
aoqi@0 1420 */
aoqi@0 1421 void if_icmpeq(final Label label) {
aoqi@0 1422 debug("if_icmpeq", label);
aoqi@0 1423 jump(IF_ICMPEQ, label, 2);
aoqi@0 1424 }
aoqi@0 1425
aoqi@0 1426 /**
aoqi@0 1427 * Generate an if_ne
aoqi@0 1428 *
aoqi@0 1429 * @param label label to true case
aoqi@0 1430 */
aoqi@0 1431 void ifne(final Label label) {
aoqi@0 1432 debug("ifne", label);
aoqi@0 1433 jump(IFNE, label, 1);
aoqi@0 1434 }
aoqi@0 1435
aoqi@0 1436 /**
aoqi@0 1437 * Generate an if_icmpne
aoqi@0 1438 *
aoqi@0 1439 * @param label label to true case
aoqi@0 1440 */
aoqi@0 1441 void if_icmpne(final Label label) {
aoqi@0 1442 debug("if_icmpne", label);
aoqi@0 1443 jump(IF_ICMPNE, label, 2);
aoqi@0 1444 }
aoqi@0 1445
aoqi@0 1446 /**
aoqi@0 1447 * Generate an iflt
aoqi@0 1448 *
aoqi@0 1449 * @param label label to true case
aoqi@0 1450 */
aoqi@0 1451 void iflt(final Label label) {
aoqi@0 1452 debug("iflt", label);
aoqi@0 1453 jump(IFLT, label, 1);
aoqi@0 1454 }
aoqi@0 1455
aoqi@0 1456 /**
aoqi@0 1457 * Generate an ifle
aoqi@0 1458 *
aoqi@0 1459 * @param label label to true case
aoqi@0 1460 */
aoqi@0 1461 void ifle(final Label label) {
aoqi@0 1462 debug("ifle", label);
aoqi@0 1463 jump(IFLE, label, 1);
aoqi@0 1464 }
aoqi@0 1465
aoqi@0 1466 /**
aoqi@0 1467 * Generate an ifgt
aoqi@0 1468 *
aoqi@0 1469 * @param label label to true case
aoqi@0 1470 */
aoqi@0 1471 void ifgt(final Label label) {
aoqi@0 1472 debug("ifgt", label);
aoqi@0 1473 jump(IFGT, label, 1);
aoqi@0 1474 }
aoqi@0 1475
aoqi@0 1476 /**
aoqi@0 1477 * Generate an ifge
aoqi@0 1478 *
aoqi@0 1479 * @param label label to true case
aoqi@0 1480 */
aoqi@0 1481 void ifge(final Label label) {
aoqi@0 1482 debug("ifge", label);
aoqi@0 1483 jump(IFGE, label, 1);
aoqi@0 1484 }
aoqi@0 1485
aoqi@0 1486 /**
aoqi@0 1487 * Unconditional jump to a label
aoqi@0 1488 *
aoqi@0 1489 * @param label destination label
aoqi@0 1490 */
aoqi@0 1491 void _goto(final Label label) {
aoqi@0 1492 //debug("goto", label);
aoqi@0 1493 jump(GOTO, label, 0);
aoqi@0 1494 stack = null; //whoever reaches the point after us provides the stack, because we don't
aoqi@0 1495 }
aoqi@0 1496
aoqi@0 1497 /**
aoqi@0 1498 * Examine two stacks and make sure they are of the same size and their
aoqi@0 1499 * contents are equivalent to each other
aoqi@0 1500 * @param s0 first stack
aoqi@0 1501 * @param s1 second stack
aoqi@0 1502 *
aoqi@0 1503 * @return true if stacks are equivalent, false otherwise
aoqi@0 1504 */
aoqi@0 1505 /**
aoqi@0 1506 * A join in control flow - helper function that makes sure all entry stacks
aoqi@0 1507 * discovered for the join point so far are equivalent
aoqi@0 1508 *
aoqi@0 1509 * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
aoqi@0 1510 * we have never been here before. Then we are expected to carry a stack with us.
aoqi@0 1511 *
aoqi@0 1512 * @param label label
aoqi@0 1513 */
aoqi@0 1514 private void mergeStackTo(final Label label) {
aoqi@0 1515 //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
aoqi@0 1516 //see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
aoqi@0 1517 //by Lower removing everything after an unconditionally executed terminating statement OR a break
aoqi@0 1518 //or continue in a block. Previously code left over after breaks and continues was still there
aoqi@0 1519 //and caused bytecode to be generated - which crashed on stack not being there, as the merge
aoqi@0 1520 //was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
aoqi@0 1521 //ATHROW sequences instead of no code being generated at all. This should now be fixed.
aoqi@0 1522 assert stack != null : label + " entered with no stack. deadcode that remains?";
aoqi@0 1523
aoqi@0 1524 final Label.Stack labelStack = label.getStack();
aoqi@0 1525 if (labelStack == null) {
aoqi@0 1526 label.setStack(stack.copy());
aoqi@0 1527 return;
aoqi@0 1528 }
aoqi@0 1529 assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
aoqi@0 1530 }
aoqi@0 1531
aoqi@0 1532 /**
aoqi@0 1533 * Register a new label, enter it here.
aoqi@0 1534 *
aoqi@0 1535 * @param label the label
aoqi@0 1536 */
aoqi@0 1537 void label(final Label label) {
aoqi@0 1538 /*
aoqi@0 1539 * If stack == null, this means that we came here not through a fallthrough.
aoqi@0 1540 * E.g. a label after an athrow. Then we create a new stack if one doesn't exist
aoqi@0 1541 * for this location already.
aoqi@0 1542 */
aoqi@0 1543 if (stack == null) {
aoqi@0 1544 stack = label.getStack();
aoqi@0 1545 if (stack == null) {
aoqi@0 1546 newStack();
aoqi@0 1547 }
aoqi@0 1548 }
aoqi@0 1549 debug_label(label);
aoqi@0 1550
aoqi@0 1551 mergeStackTo(label); //we have to merge our stack to whatever is in the label
aoqi@0 1552
aoqi@0 1553 method.visitLabel(label.getLabel());
aoqi@0 1554 }
aoqi@0 1555
aoqi@0 1556 /**
aoqi@0 1557 * Pop element from stack, convert to given type
aoqi@0 1558 *
aoqi@0 1559 * @param to type to convert to
aoqi@0 1560 *
aoqi@0 1561 * @return the method emitter
aoqi@0 1562 */
aoqi@0 1563 MethodEmitter convert(final Type to) {
aoqi@0 1564 final Type type = peekType().convert(method, to);
aoqi@0 1565 if (type != null) {
aoqi@0 1566 if (!peekType().isEquivalentTo(to)) {
aoqi@0 1567 debug("convert", peekType(), "->", to);
aoqi@0 1568 }
aoqi@0 1569 popType();
aoqi@0 1570 pushType(type);
aoqi@0 1571 }
aoqi@0 1572 return this;
aoqi@0 1573 }
aoqi@0 1574
aoqi@0 1575 /**
aoqi@0 1576 * Helper function - expect two types that are equivalent
aoqi@0 1577 *
aoqi@0 1578 * @return common type
aoqi@0 1579 */
aoqi@0 1580 private Type get2() {
aoqi@0 1581 final Type p0 = popType();
aoqi@0 1582 final Type p1 = popType();
aoqi@0 1583 assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
aoqi@0 1584 return p0;
aoqi@0 1585 }
aoqi@0 1586
aoqi@0 1587 /**
aoqi@0 1588 * Helper function - expect two types that are integer types and equivalent
aoqi@0 1589 *
aoqi@0 1590 * @return common type
aoqi@0 1591 */
aoqi@0 1592 private BitwiseType get2i() {
aoqi@0 1593 final BitwiseType p0 = popInteger();
aoqi@0 1594 final BitwiseType p1 = popInteger();
aoqi@0 1595 assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
aoqi@0 1596 return p0;
aoqi@0 1597 }
aoqi@0 1598
aoqi@0 1599 /**
aoqi@0 1600 * Helper function - expect two types that are numbers and equivalent
aoqi@0 1601 *
aoqi@0 1602 * @return common type
aoqi@0 1603 */
aoqi@0 1604 private NumericType get2n() {
aoqi@0 1605 final NumericType p0 = popNumeric();
aoqi@0 1606 final NumericType p1 = popNumeric();
aoqi@0 1607 assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
aoqi@0 1608 return p0;
aoqi@0 1609 }
aoqi@0 1610
aoqi@0 1611 /**
aoqi@0 1612 * Pop two numbers, perform addition and push result
aoqi@0 1613 *
aoqi@0 1614 * @return the method emitter
aoqi@0 1615 */
aoqi@0 1616 MethodEmitter add() {
aoqi@0 1617 debug("add");
aoqi@0 1618 pushType(get2().add(method));
aoqi@0 1619 return this;
aoqi@0 1620 }
aoqi@0 1621
aoqi@0 1622 /**
aoqi@0 1623 * Pop two numbers, perform subtraction and push result
aoqi@0 1624 *
aoqi@0 1625 * @return the method emitter
aoqi@0 1626 */
aoqi@0 1627 MethodEmitter sub() {
aoqi@0 1628 debug("sub");
aoqi@0 1629 pushType(get2n().sub(method));
aoqi@0 1630 return this;
aoqi@0 1631 }
aoqi@0 1632
aoqi@0 1633 /**
aoqi@0 1634 * Pop two numbers, perform multiplication and push result
aoqi@0 1635 *
aoqi@0 1636 * @return the method emitter
aoqi@0 1637 */
aoqi@0 1638 MethodEmitter mul() {
aoqi@0 1639 debug("mul ");
aoqi@0 1640 pushType(get2n().mul(method));
aoqi@0 1641 return this;
aoqi@0 1642 }
aoqi@0 1643
aoqi@0 1644 /**
aoqi@0 1645 * Pop two numbers, perform division and push result
aoqi@0 1646 *
aoqi@0 1647 * @return the method emitter
aoqi@0 1648 */
aoqi@0 1649 MethodEmitter div() {
aoqi@0 1650 debug("div");
aoqi@0 1651 pushType(get2n().div(method));
aoqi@0 1652 return this;
aoqi@0 1653 }
aoqi@0 1654
aoqi@0 1655 /**
aoqi@0 1656 * Pop two numbers, calculate remainder and push result
aoqi@0 1657 *
aoqi@0 1658 * @return the method emitter
aoqi@0 1659 */
aoqi@0 1660 MethodEmitter rem() {
aoqi@0 1661 debug("rem");
aoqi@0 1662 pushType(get2n().rem(method));
aoqi@0 1663 return this;
aoqi@0 1664 }
aoqi@0 1665
aoqi@0 1666 /**
aoqi@0 1667 * Retrieve the top <tt>count</tt> types on the stack without modifying it.
aoqi@0 1668 *
aoqi@0 1669 * @param count number of types to return
aoqi@0 1670 * @return array of Types
aoqi@0 1671 */
aoqi@0 1672 protected Type[] getTypesFromStack(final int count) {
aoqi@0 1673 final Type[] types = new Type[count];
aoqi@0 1674 int pos = 0;
aoqi@0 1675 for (int i = count - 1; i >= 0; i--) {
aoqi@0 1676 types[i] = stack.peek(pos++);
aoqi@0 1677 }
aoqi@0 1678
aoqi@0 1679 return types;
aoqi@0 1680 }
aoqi@0 1681
aoqi@0 1682 /**
aoqi@0 1683 * Helper function to generate a function signature based on stack contents
aoqi@0 1684 * and argument count and return type
aoqi@0 1685 *
aoqi@0 1686 * @param returnType return type
aoqi@0 1687 * @param argCount argument count
aoqi@0 1688 *
aoqi@0 1689 * @return function signature for stack contents
aoqi@0 1690 */
aoqi@0 1691 private String getDynamicSignature(final Type returnType, final int argCount) {
aoqi@0 1692 final Type[] paramTypes = new Type[argCount];
aoqi@0 1693
aoqi@0 1694 int pos = 0;
aoqi@0 1695 for (int i = argCount - 1; i >= 0; i--) {
aoqi@0 1696 paramTypes[i] = stack.peek(pos++);
aoqi@0 1697 }
aoqi@0 1698 final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
aoqi@0 1699 for (int i = 0; i < argCount; i++) {
aoqi@0 1700 popType(paramTypes[argCount - i - 1]);
aoqi@0 1701 }
aoqi@0 1702
aoqi@0 1703 return descriptor;
aoqi@0 1704 }
aoqi@0 1705
aoqi@0 1706 /**
aoqi@0 1707 * Generate a dynamic new
aoqi@0 1708 *
aoqi@0 1709 * @param argCount number of arguments
aoqi@0 1710 * @param flags callsite flags
aoqi@0 1711 *
aoqi@0 1712 * @return the method emitter
aoqi@0 1713 */
aoqi@0 1714 MethodEmitter dynamicNew(final int argCount, final int flags) {
aoqi@0 1715 debug("dynamic_new", "argcount=", argCount);
aoqi@0 1716 final String signature = getDynamicSignature(Type.OBJECT, argCount);
aoqi@0 1717 method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
aoqi@0 1718 pushType(Type.OBJECT); //TODO fix result type
aoqi@0 1719 return this;
aoqi@0 1720 }
aoqi@0 1721
aoqi@0 1722 /**
aoqi@0 1723 * Generate a dynamic call
aoqi@0 1724 *
aoqi@0 1725 * @param returnType return type
aoqi@0 1726 * @param argCount number of arguments
aoqi@0 1727 * @param flags callsite flags
aoqi@0 1728 *
aoqi@0 1729 * @return the method emitter
aoqi@0 1730 */
aoqi@0 1731 MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
aoqi@0 1732 debug("dynamic_call", "args=", argCount, "returnType=", returnType);
aoqi@0 1733 final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
aoqi@0 1734 debug(" signature", signature);
aoqi@0 1735 method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
aoqi@0 1736 pushType(returnType);
aoqi@0 1737
aoqi@0 1738 return this;
aoqi@0 1739 }
aoqi@0 1740
aoqi@0 1741 /**
aoqi@0 1742 * Generate a dynamic call for a runtime node
aoqi@0 1743 *
aoqi@0 1744 * @param name tag for the invoke dynamic for this runtime node
aoqi@0 1745 * @param returnType return type
aoqi@0 1746 * @param request RuntimeNode request
aoqi@0 1747 *
aoqi@0 1748 * @return the method emitter
aoqi@0 1749 */
aoqi@0 1750 MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
aoqi@0 1751 debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
aoqi@0 1752 final String signature = getDynamicSignature(returnType, request.getArity());
aoqi@0 1753 debug(" signature", signature);
aoqi@0 1754 method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
aoqi@0 1755 pushType(returnType);
aoqi@0 1756
aoqi@0 1757 return this;
aoqi@0 1758 }
aoqi@0 1759
aoqi@0 1760 /**
aoqi@0 1761 * Generate dynamic getter. Pop scope from stack. Push result
aoqi@0 1762 *
aoqi@0 1763 * @param valueType type of the value to set
aoqi@0 1764 * @param name name of property
aoqi@0 1765 * @param flags call site flags
aoqi@0 1766 * @param isMethod should it prefer retrieving methods
aoqi@0 1767 *
aoqi@0 1768 * @return the method emitter
aoqi@0 1769 */
aoqi@0 1770 MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
aoqi@0 1771 debug("dynamic_get", name, valueType);
aoqi@0 1772
aoqi@0 1773 Type type = valueType;
aoqi@0 1774 if (type.isObject() || type.isBoolean()) {
aoqi@0 1775 type = Type.OBJECT; //promote e.g strings to object generic setter
aoqi@0 1776 }
aoqi@0 1777
aoqi@0 1778 popType(Type.SCOPE);
aoqi@0 1779 method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
aoqi@0 1780 NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
aoqi@0 1781
aoqi@0 1782 pushType(type);
aoqi@0 1783
aoqi@0 1784 convert(valueType); //most probably a nop
aoqi@0 1785
aoqi@0 1786 return this;
aoqi@0 1787 }
aoqi@0 1788
aoqi@0 1789 /**
aoqi@0 1790 * Generate dynamic setter. Pop receiver and property from stack.
aoqi@0 1791 *
aoqi@0 1792 * @param valueType the type of the value to set
aoqi@0 1793 * @param name name of property
aoqi@0 1794 * @param flags call site flags
aoqi@0 1795 */
aoqi@0 1796 void dynamicSet(final String name, final int flags) {
aoqi@0 1797 debug("dynamic_set", name, peekType());
aoqi@0 1798
aoqi@0 1799 Type type = peekType();
aoqi@0 1800 if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
aoqi@0 1801 type = Type.OBJECT;
aoqi@0 1802 convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
aoqi@0 1803 }
aoqi@0 1804 popType(type);
aoqi@0 1805 popType(Type.SCOPE);
aoqi@0 1806
aoqi@0 1807 method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
aoqi@0 1808 }
aoqi@0 1809
aoqi@0 1810 /**
aoqi@0 1811 * Dynamic getter for indexed structures. Pop index and receiver from stack,
aoqi@0 1812 * generate appropriate signatures based on types
aoqi@0 1813 *
aoqi@0 1814 * @param result result type for getter
aoqi@0 1815 * @param flags call site flags for getter
aoqi@0 1816 * @param isMethod should it prefer retrieving methods
aoqi@0 1817 *
aoqi@0 1818 * @return the method emitter
aoqi@0 1819 */
aoqi@0 1820 MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
aoqi@0 1821 debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
aoqi@0 1822
aoqi@0 1823 Type resultType = result;
aoqi@0 1824 if (result.isBoolean()) {
aoqi@0 1825 resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
aoqi@0 1826 }
aoqi@0 1827
aoqi@0 1828 Type index = peekType();
aoqi@0 1829 if (index.isObject() || index.isBoolean()) {
aoqi@0 1830 index = Type.OBJECT; //e.g. string->object
aoqi@0 1831 convert(Type.OBJECT);
aoqi@0 1832 }
aoqi@0 1833 popType();
aoqi@0 1834
aoqi@0 1835 popType(Type.OBJECT);
aoqi@0 1836
aoqi@0 1837 final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
aoqi@0 1838
aoqi@0 1839 method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod",
aoqi@0 1840 signature, LINKERBOOTSTRAP, flags);
aoqi@0 1841 pushType(resultType);
aoqi@0 1842
aoqi@0 1843 if (result.isBoolean()) {
aoqi@0 1844 convert(Type.BOOLEAN);
aoqi@0 1845 }
aoqi@0 1846
aoqi@0 1847 return this;
aoqi@0 1848 }
aoqi@0 1849
aoqi@0 1850 /**
aoqi@0 1851 * Dynamic setter for indexed structures. Pop value, index and receiver from
aoqi@0 1852 * stack, generate appropriate signature based on types
aoqi@0 1853 *
aoqi@0 1854 * @param flags call site flags for setter
aoqi@0 1855 */
aoqi@0 1856 void dynamicSetIndex(final int flags) {
aoqi@0 1857 debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
aoqi@0 1858
aoqi@0 1859 Type value = peekType();
aoqi@0 1860 if (value.isObject() || value.isBoolean()) {
aoqi@0 1861 value = Type.OBJECT; //e.g. STRING->OBJECT - one descriptor for all object types
aoqi@0 1862 convert(Type.OBJECT);
aoqi@0 1863 }
aoqi@0 1864 popType();
aoqi@0 1865
aoqi@0 1866 Type index = peekType();
aoqi@0 1867 if (index.isObject() || index.isBoolean()) {
aoqi@0 1868 index = Type.OBJECT; //e.g. string->object
aoqi@0 1869 convert(Type.OBJECT);
aoqi@0 1870 }
aoqi@0 1871 popType(index);
aoqi@0 1872
aoqi@0 1873 final Type receiver = popType(Type.OBJECT);
aoqi@0 1874 assert receiver.isObject();
aoqi@0 1875
aoqi@0 1876 method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags);
aoqi@0 1877 }
aoqi@0 1878
aoqi@0 1879 /**
aoqi@0 1880 * Load a key value in the proper form.
aoqi@0 1881 *
aoqi@0 1882 * @param key
aoqi@0 1883 */
aoqi@0 1884 //TODO move this and break it apart
aoqi@0 1885 MethodEmitter loadKey(final Object key) {
aoqi@0 1886 if (key instanceof IdentNode) {
aoqi@0 1887 method.visitLdcInsn(((IdentNode) key).getName());
aoqi@0 1888 } else if (key instanceof LiteralNode) {
aoqi@0 1889 method.visitLdcInsn(((LiteralNode<?>)key).getString());
aoqi@0 1890 } else {
aoqi@0 1891 method.visitLdcInsn(JSType.toString(key));
aoqi@0 1892 }
aoqi@0 1893 pushType(Type.OBJECT); //STRING
aoqi@0 1894 return this;
aoqi@0 1895 }
aoqi@0 1896
aoqi@0 1897 @SuppressWarnings("fallthrough")
aoqi@0 1898 private static Type fieldType(final String desc) {
aoqi@0 1899 switch (desc) {
aoqi@0 1900 case "Z":
aoqi@0 1901 case "B":
aoqi@0 1902 case "C":
aoqi@0 1903 case "S":
aoqi@0 1904 case "I":
aoqi@0 1905 return Type.INT;
aoqi@0 1906 case "F":
aoqi@0 1907 assert false;
aoqi@0 1908 case "D":
aoqi@0 1909 return Type.NUMBER;
aoqi@0 1910 case "J":
aoqi@0 1911 return Type.LONG;
aoqi@0 1912 default:
aoqi@0 1913 assert desc.startsWith("[") || desc.startsWith("L") : desc + " is not an object type";
aoqi@0 1914 switch (desc.charAt(0)) {
aoqi@0 1915 case 'L':
aoqi@0 1916 return Type.OBJECT;
aoqi@0 1917 case '[':
aoqi@0 1918 return Type.typeFor(Array.newInstance(fieldType(desc.substring(1)).getTypeClass(), 0).getClass());
aoqi@0 1919 default:
aoqi@0 1920 assert false;
aoqi@0 1921 }
aoqi@0 1922 return Type.OBJECT;
aoqi@0 1923 }
aoqi@0 1924 }
aoqi@0 1925
aoqi@0 1926 /**
aoqi@0 1927 * Generate get for a field access
aoqi@0 1928 *
aoqi@0 1929 * @param fa the field access
aoqi@0 1930 *
aoqi@0 1931 * @return the method emitter
aoqi@0 1932 */
aoqi@0 1933 MethodEmitter getField(final FieldAccess fa) {
aoqi@0 1934 return fa.get(this);
aoqi@0 1935 }
aoqi@0 1936
aoqi@0 1937 /**
aoqi@0 1938 * Generate set for a field access
aoqi@0 1939 *
aoqi@0 1940 * @param fa the field access
aoqi@0 1941 */
aoqi@0 1942 void putField(final FieldAccess fa) {
aoqi@0 1943 fa.put(this);
aoqi@0 1944 }
aoqi@0 1945
aoqi@0 1946 /**
aoqi@0 1947 * Get the value of a non-static field, pop the receiver from the stack,
aoqi@0 1948 * push value to the stack
aoqi@0 1949 *
aoqi@0 1950 * @param className class
aoqi@0 1951 * @param fieldName field name
aoqi@0 1952 * @param fieldDescriptor field descriptor
aoqi@0 1953 *
aoqi@0 1954 * @return the method emitter
aoqi@0 1955 */
aoqi@0 1956 MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
aoqi@0 1957 debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
aoqi@0 1958 final Type receiver = popType();
aoqi@0 1959 assert receiver.isObject();
aoqi@0 1960 method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
aoqi@0 1961 pushType(fieldType(fieldDescriptor));
aoqi@0 1962 return this;
aoqi@0 1963 }
aoqi@0 1964
aoqi@0 1965 /**
aoqi@0 1966 * Get the value of a static field, push it to the stack
aoqi@0 1967 *
aoqi@0 1968 * @param className class
aoqi@0 1969 * @param fieldName field name
aoqi@0 1970 * @param fieldDescriptor field descriptor
aoqi@0 1971 *
aoqi@0 1972 * @return the method emitter
aoqi@0 1973 */
aoqi@0 1974 MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
aoqi@0 1975 debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
aoqi@0 1976 method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
aoqi@0 1977 pushType(fieldType(fieldDescriptor));
aoqi@0 1978 return this;
aoqi@0 1979 }
aoqi@0 1980
aoqi@0 1981 /**
aoqi@0 1982 * Pop value and field from stack and write to a non-static field
aoqi@0 1983 *
aoqi@0 1984 * @param className class
aoqi@0 1985 * @param fieldName field name
aoqi@0 1986 * @param fieldDescriptor field descriptor
aoqi@0 1987 */
aoqi@0 1988 void putField(final String className, final String fieldName, final String fieldDescriptor) {
aoqi@0 1989 debug("putfield", "receiver=", peekType(1), "value=", peekType());
aoqi@0 1990 popType(fieldType(fieldDescriptor));
aoqi@0 1991 popType(Type.OBJECT);
aoqi@0 1992 method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
aoqi@0 1993 }
aoqi@0 1994
aoqi@0 1995 /**
aoqi@0 1996 * Pop value from stack and write to a static field
aoqi@0 1997 *
aoqi@0 1998 * @param className class
aoqi@0 1999 * @param fieldName field name
aoqi@0 2000 * @param fieldDescriptor field descriptor
aoqi@0 2001 */
aoqi@0 2002 void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
aoqi@0 2003 debug("putfield", "value=", peekType());
aoqi@0 2004 popType(fieldType(fieldDescriptor));
aoqi@0 2005 method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
aoqi@0 2006 }
aoqi@0 2007
aoqi@0 2008 /**
aoqi@0 2009 * Register line number at a label
aoqi@0 2010 *
aoqi@0 2011 * @param line line number
aoqi@0 2012 * @param label label
aoqi@0 2013 */
aoqi@0 2014 void lineNumber(final int line) {
aoqi@0 2015 if (env._debug_lines) {
aoqi@0 2016 debug_label("[LINE]", line);
aoqi@0 2017 final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
aoqi@0 2018 method.visitLabel(l);
aoqi@0 2019 method.visitLineNumber(line, l);
aoqi@0 2020 }
aoqi@0 2021 }
aoqi@0 2022
aoqi@0 2023 /*
aoqi@0 2024 * Debugging below
aoqi@0 2025 */
aoqi@0 2026
aoqi@0 2027 private final FieldAccess ERR_STREAM = staticField(System.class, "err", PrintStream.class);
aoqi@0 2028 private final Call PRINT = virtualCallNoLookup(PrintStream.class, "print", void.class, Object.class);
aoqi@0 2029 private final Call PRINTLN = virtualCallNoLookup(PrintStream.class, "println", void.class, Object.class);
aoqi@0 2030 private final Call PRINT_STACKTRACE = virtualCallNoLookup(Throwable.class, "printStackTrace", void.class);
aoqi@0 2031
aoqi@0 2032 /**
aoqi@0 2033 * Emit a System.err.print statement of whatever is on top of the bytecode stack
aoqi@0 2034 */
aoqi@0 2035 void print() {
aoqi@0 2036 getField(ERR_STREAM);
aoqi@0 2037 swap();
aoqi@0 2038 convert(Type.OBJECT);
aoqi@0 2039 invoke(PRINT);
aoqi@0 2040 }
aoqi@0 2041
aoqi@0 2042 /**
aoqi@0 2043 * Emit a System.err.println statement of whatever is on top of the bytecode stack
aoqi@0 2044 */
aoqi@0 2045 void println() {
aoqi@0 2046 getField(ERR_STREAM);
aoqi@0 2047 swap();
aoqi@0 2048 convert(Type.OBJECT);
aoqi@0 2049 invoke(PRINTLN);
aoqi@0 2050 }
aoqi@0 2051
aoqi@0 2052 /**
aoqi@0 2053 * Emit a System.err.print statement
aoqi@0 2054 * @param string string to print
aoqi@0 2055 */
aoqi@0 2056 void print(final String string) {
aoqi@0 2057 getField(ERR_STREAM);
aoqi@0 2058 load(string);
aoqi@0 2059 invoke(PRINT);
aoqi@0 2060 }
aoqi@0 2061
aoqi@0 2062 /**
aoqi@0 2063 * Emit a System.err.println statement
aoqi@0 2064 * @param string string to print
aoqi@0 2065 */
aoqi@0 2066 void println(final String string) {
aoqi@0 2067 getField(ERR_STREAM);
aoqi@0 2068 load(string);
aoqi@0 2069 invoke(PRINTLN);
aoqi@0 2070 }
aoqi@0 2071
aoqi@0 2072 /**
aoqi@0 2073 * Print a stacktrace to S
aoqi@0 2074 */
aoqi@0 2075 void stacktrace() {
aoqi@0 2076 _new(Throwable.class);
aoqi@0 2077 dup();
aoqi@0 2078 invoke(constructorNoLookup(Throwable.class));
aoqi@0 2079 invoke(PRINT_STACKTRACE);
aoqi@0 2080 }
aoqi@0 2081
aoqi@0 2082 private static int linePrefix = 0;
aoqi@0 2083
aoqi@0 2084 /**
aoqi@0 2085 * Debug function that outputs generated bytecode and stack contents
aoqi@0 2086 *
aoqi@0 2087 * @param args debug information to print
aoqi@0 2088 */
aoqi@0 2089 private void debug(final Object... args) {
aoqi@0 2090 if (DEBUG) {
aoqi@0 2091 debug(30, args);
aoqi@0 2092 }
aoqi@0 2093 }
aoqi@0 2094
aoqi@0 2095 /**
aoqi@0 2096 * Debug function that outputs generated bytecode and stack contents
aoqi@0 2097 * for a label - indentation is currently the only thing that differs
aoqi@0 2098 *
aoqi@0 2099 * @param args debug information to print
aoqi@0 2100 */
aoqi@0 2101 private void debug_label(final Object... args) {
aoqi@0 2102 if (DEBUG) {
aoqi@0 2103 debug(22, args);
aoqi@0 2104 }
aoqi@0 2105 }
aoqi@0 2106
aoqi@0 2107 private void debug(final int padConstant, final Object... args) {
aoqi@0 2108 if (DEBUG) {
aoqi@0 2109 final StringBuilder sb = new StringBuilder();
aoqi@0 2110 int pad;
aoqi@0 2111
aoqi@0 2112 sb.append('#');
aoqi@0 2113 sb.append(++linePrefix);
aoqi@0 2114
aoqi@0 2115 pad = 5 - sb.length();
aoqi@0 2116 while (pad > 0) {
aoqi@0 2117 sb.append(' ');
aoqi@0 2118 pad--;
aoqi@0 2119 }
aoqi@0 2120
aoqi@0 2121 if (stack != null && !stack.isEmpty()) {
aoqi@0 2122 sb.append("{");
aoqi@0 2123 sb.append(stack.size());
aoqi@0 2124 sb.append(":");
aoqi@0 2125 for (int pos = 0; pos < stack.size(); pos++) {
aoqi@0 2126 final Type t = stack.peek(pos);
aoqi@0 2127
aoqi@0 2128 if (t == Type.SCOPE) {
aoqi@0 2129 sb.append("scope");
aoqi@0 2130 } else if (t == Type.THIS) {
aoqi@0 2131 sb.append("this");
aoqi@0 2132 } else if (t.isObject()) {
aoqi@0 2133 String desc = t.getDescriptor();
aoqi@0 2134 int i;
aoqi@0 2135 for (i = 0; desc.charAt(i) == '[' && i < desc.length(); i++) {
aoqi@0 2136 sb.append('[');
aoqi@0 2137 }
aoqi@0 2138 desc = desc.substring(i);
aoqi@0 2139 final int slash = desc.lastIndexOf('/');
aoqi@0 2140 if (slash != -1) {
aoqi@0 2141 desc = desc.substring(slash + 1, desc.length() - 1);
aoqi@0 2142 }
aoqi@0 2143 if ("Object".equals(desc)) {
aoqi@0 2144 sb.append('O');
aoqi@0 2145 } else {
aoqi@0 2146 sb.append(desc);
aoqi@0 2147 }
aoqi@0 2148 } else {
aoqi@0 2149 sb.append(t.getDescriptor());
aoqi@0 2150 }
aoqi@0 2151
aoqi@0 2152 if (pos + 1 < stack.size()) {
aoqi@0 2153 sb.append(' ');
aoqi@0 2154 }
aoqi@0 2155 }
aoqi@0 2156 sb.append('}');
aoqi@0 2157 sb.append(' ');
aoqi@0 2158 }
aoqi@0 2159
aoqi@0 2160 pad = padConstant - sb.length();
aoqi@0 2161 while (pad > 0) {
aoqi@0 2162 sb.append(' ');
aoqi@0 2163 pad--;
aoqi@0 2164 }
aoqi@0 2165
aoqi@0 2166 for (final Object arg : args) {
aoqi@0 2167 sb.append(arg);
aoqi@0 2168 sb.append(' ');
aoqi@0 2169 }
aoqi@0 2170
aoqi@0 2171 if (env != null) { //early bootstrap code doesn't have inited context yet
aoqi@0 2172 LOG.info(sb);
aoqi@0 2173 if (DEBUG_TRACE_LINE == linePrefix) {
aoqi@0 2174 new Throwable().printStackTrace(LOG.getOutputStream());
aoqi@0 2175 }
aoqi@0 2176 }
aoqi@0 2177 }
aoqi@0 2178 }
aoqi@0 2179
aoqi@0 2180 /**
aoqi@0 2181 * Set the current function node being emitted
aoqi@0 2182 * @param functionNode the function node
aoqi@0 2183 */
aoqi@0 2184 void setFunctionNode(final FunctionNode functionNode) {
aoqi@0 2185 this.functionNode = functionNode;
aoqi@0 2186 }
aoqi@0 2187
aoqi@0 2188 boolean hasReturn() {
aoqi@0 2189 return hasReturn;
aoqi@0 2190 }
aoqi@0 2191
aoqi@0 2192 List<Label> getExternalTargets() {
aoqi@0 2193 return null;
aoqi@0 2194 }
aoqi@0 2195
aoqi@0 2196 }

mercurial