src/jdk/nashorn/internal/ir/RuntimeNode.java

Thu, 23 May 2013 15:51:08 +0200

author
lagergren
date
Thu, 23 May 2013 15:51:08 +0200
changeset 290
6fc7b51e83d6
parent 254
d28180d97c61
child 401
313bdcd2fd22
permissions
-rw-r--r--

8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
Reviewed-by: attila, jlaskey

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.ir;
jlaskey@3 27
jlaskey@3 28 import java.util.ArrayList;
jlaskey@3 29 import java.util.Arrays;
jlaskey@3 30 import java.util.Collections;
jlaskey@3 31 import java.util.List;
lagergren@290 32
jlaskey@3 33 import jdk.nashorn.internal.codegen.types.Type;
lagergren@211 34 import jdk.nashorn.internal.ir.annotations.Immutable;
jlaskey@3 35 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
jlaskey@3 36 import jdk.nashorn.internal.parser.TokenType;
jlaskey@3 37
jlaskey@3 38 /**
jlaskey@3 39 * IR representation for a runtime call.
jlaskey@3 40 */
lagergren@211 41 @Immutable
attila@144 42 public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
jlaskey@3 43
jlaskey@3 44 /**
jlaskey@3 45 * Request enum used for meta-information about the runtime request
jlaskey@3 46 */
jlaskey@3 47 public enum Request {
jlaskey@3 48 /** An addition with at least one object */
jlaskey@3 49 ADD(TokenType.ADD, Type.OBJECT, 2, true),
jlaskey@3 50 /** Request to enter debugger */
jlaskey@3 51 DEBUGGER,
jlaskey@3 52 /** New operator */
jlaskey@3 53 NEW,
jlaskey@3 54 /** Typeof operator */
jlaskey@3 55 TYPEOF,
jlaskey@3 56 /** void type */
jlaskey@3 57 VOID,
jlaskey@3 58 /** Reference error type */
jlaskey@3 59 REFERENCE_ERROR,
jlaskey@3 60 /** Delete operator */
jlaskey@3 61 DELETE(TokenType.DELETE, Type.BOOLEAN, 1),
jlaskey@3 62 /** Delete operator that always fails -- see Lower */
jlaskey@3 63 FAIL_DELETE(TokenType.DELETE, Type.BOOLEAN, 1, false),
jlaskey@3 64 /** === operator with at least one object */
jlaskey@3 65 EQ_STRICT(TokenType.EQ_STRICT, Type.BOOLEAN, 2, true),
jlaskey@3 66 /** == operator with at least one object */
jlaskey@3 67 EQ(TokenType.EQ, Type.BOOLEAN, 2, true),
sundar@128 68 /** {@literal >=} operator with at least one object */
jlaskey@3 69 GE(TokenType.GE, Type.BOOLEAN, 2, true),
sundar@128 70 /** {@literal >} operator with at least one object */
jlaskey@3 71 GT(TokenType.GT, Type.BOOLEAN, 2, true),
jlaskey@3 72 /** in operator */
jlaskey@3 73 IN(TokenType.IN, Type.BOOLEAN, 2),
jlaskey@3 74 /** instanceof operator */
jlaskey@3 75 INSTANCEOF(TokenType.INSTANCEOF, Type.BOOLEAN, 2),
sundar@128 76 /** {@literal <=} operator with at least one object */
jlaskey@3 77 LE(TokenType.LE, Type.BOOLEAN, 2, true),
sundar@128 78 /** {@literal <} operator with at least one object */
jlaskey@3 79 LT(TokenType.LT, Type.BOOLEAN, 2, true),
jlaskey@3 80 /** !== operator with at least one object */
jlaskey@3 81 NE_STRICT(TokenType.NE_STRICT, Type.BOOLEAN, 2, true),
jlaskey@3 82 /** != operator with at least one object */
jlaskey@3 83 NE(TokenType.NE, Type.BOOLEAN, 2, true);
jlaskey@3 84
jlaskey@3 85 /** token type */
jlaskey@3 86 private final TokenType tokenType;
jlaskey@3 87
jlaskey@3 88 /** return type for request */
jlaskey@3 89 private final Type returnType;
jlaskey@3 90
jlaskey@3 91 /** arity of request */
jlaskey@3 92 private final int arity;
jlaskey@3 93
jlaskey@3 94 /** Can the specializer turn this into something that works with 1 or more primitives? */
jlaskey@3 95 private final boolean canSpecialize;
jlaskey@3 96
jlaskey@3 97 private Request() {
jlaskey@3 98 this(TokenType.VOID, Type.OBJECT, 0);
jlaskey@3 99 }
jlaskey@3 100
jlaskey@3 101 private Request(final TokenType tokenType, final Type returnType, final int arity) {
jlaskey@3 102 this(tokenType, returnType, arity, false);
jlaskey@3 103 }
jlaskey@3 104
jlaskey@3 105 private Request(final TokenType tokenType, final Type returnType, final int arity, final boolean canSpecialize) {
jlaskey@3 106 this.tokenType = tokenType;
jlaskey@3 107 this.returnType = returnType;
jlaskey@3 108 this.arity = arity;
jlaskey@3 109 this.canSpecialize = canSpecialize;
jlaskey@3 110 }
jlaskey@3 111
jlaskey@3 112 /**
jlaskey@3 113 * Can this request type be specialized?
jlaskey@3 114 *
jlaskey@3 115 * @return true if request can be specialized
jlaskey@3 116 */
jlaskey@3 117 public boolean canSpecialize() {
jlaskey@3 118 return canSpecialize;
jlaskey@3 119 }
jlaskey@3 120
jlaskey@3 121 /**
jlaskey@3 122 * Get arity
jlaskey@3 123 *
jlaskey@3 124 * @return the arity of the request
jlaskey@3 125 */
jlaskey@3 126 public int getArity() {
jlaskey@3 127 return arity;
jlaskey@3 128 }
jlaskey@3 129
jlaskey@3 130 /**
jlaskey@3 131 * Get the return type
jlaskey@3 132 *
jlaskey@3 133 * @return return type for request
jlaskey@3 134 */
jlaskey@3 135 public Type getReturnType() {
jlaskey@3 136 return returnType;
jlaskey@3 137 }
jlaskey@3 138
jlaskey@3 139 /**
jlaskey@3 140 * Get token type
jlaskey@3 141 *
jlaskey@3 142 * @return token type for request
jlaskey@3 143 */
jlaskey@3 144 public TokenType getTokenType() {
jlaskey@3 145 return tokenType;
jlaskey@3 146 }
jlaskey@3 147
jlaskey@3 148 /**
hannesw@100 149 * Get the non-strict name for this request.
hannesw@100 150 *
hannesw@100 151 * @return the name without _STRICT suffix
hannesw@100 152 */
hannesw@100 153 public String nonStrictName() {
hannesw@100 154 switch(this) {
hannesw@100 155 case NE_STRICT:
hannesw@100 156 return NE.name();
hannesw@100 157 case EQ_STRICT:
hannesw@100 158 return EQ.name();
hannesw@100 159 default:
hannesw@100 160 return name();
hannesw@100 161 }
hannesw@100 162 }
hannesw@100 163
hannesw@100 164 /**
jlaskey@3 165 * Is this an EQ or EQ_STRICT?
jlaskey@3 166 *
jlaskey@3 167 * @param request a request
jlaskey@3 168 *
jlaskey@3 169 * @return true if EQ or EQ_STRICT
jlaskey@3 170 */
jlaskey@3 171 public static boolean isEQ(final Request request) {
jlaskey@3 172 return request == EQ || request == EQ_STRICT;
jlaskey@3 173 }
jlaskey@3 174
jlaskey@3 175 /**
jlaskey@3 176 * Is this an NE or NE_STRICT?
jlaskey@3 177 *
jlaskey@3 178 * @param request a request
jlaskey@3 179 *
jlaskey@3 180 * @return true if NE or NE_STRICT
jlaskey@3 181 */
jlaskey@3 182 public static boolean isNE(final Request request) {
jlaskey@3 183 return request == NE || request == NE_STRICT;
jlaskey@3 184 }
jlaskey@3 185
jlaskey@3 186 /**
jlaskey@3 187 * If this request can be reversed, return the reverse request
sundar@128 188 * Eq EQ {@literal ->} NE.
jlaskey@3 189 *
jlaskey@3 190 * @param request request to reverse
jlaskey@3 191 *
jlaskey@3 192 * @return reversed request or null if not applicable
jlaskey@3 193 */
jlaskey@3 194 public static Request reverse(final Request request) {
jlaskey@3 195 switch (request) {
jlaskey@3 196 case EQ:
jlaskey@3 197 case EQ_STRICT:
jlaskey@3 198 case NE:
jlaskey@3 199 case NE_STRICT:
jlaskey@3 200 return request;
jlaskey@3 201 case LE:
jlaskey@3 202 return GE;
jlaskey@3 203 case LT:
jlaskey@3 204 return GT;
jlaskey@3 205 case GE:
jlaskey@3 206 return LE;
jlaskey@3 207 case GT:
jlaskey@3 208 return LT;
jlaskey@3 209 default:
jlaskey@3 210 return null;
jlaskey@3 211 }
jlaskey@3 212 }
jlaskey@3 213
jlaskey@3 214 /**
jlaskey@3 215 * Invert the request, only for non equals comparisons.
jlaskey@3 216 *
jlaskey@3 217 * @param request a request
jlaskey@3 218 *
jlaskey@3 219 * @return the inverted rquest, or null if not applicable
jlaskey@3 220 */
jlaskey@3 221 public static Request invert(final Request request) {
jlaskey@3 222 switch (request) {
jlaskey@3 223 case EQ:
jlaskey@3 224 return NE;
jlaskey@3 225 case EQ_STRICT:
jlaskey@3 226 return NE_STRICT;
jlaskey@3 227 case NE:
jlaskey@3 228 return EQ;
jlaskey@3 229 case NE_STRICT:
jlaskey@3 230 return EQ_STRICT;
jlaskey@3 231 case LE:
jlaskey@3 232 return GT;
jlaskey@3 233 case LT:
jlaskey@3 234 return GE;
jlaskey@3 235 case GE:
jlaskey@3 236 return LT;
jlaskey@3 237 case GT:
jlaskey@3 238 return LE;
jlaskey@3 239 default:
jlaskey@3 240 return null;
jlaskey@3 241 }
jlaskey@3 242 }
jlaskey@3 243
jlaskey@3 244 /**
jlaskey@3 245 * Check if this is a comparison
jlaskey@3 246 *
jlaskey@3 247 * @param request a request
jlaskey@3 248 *
jlaskey@3 249 * @return true if this is a comparison, null otherwise
jlaskey@3 250 */
jlaskey@3 251 public static boolean isComparison(final Request request) {
jlaskey@3 252 switch (request) {
jlaskey@3 253 case EQ:
jlaskey@3 254 case EQ_STRICT:
jlaskey@3 255 case NE:
jlaskey@3 256 case NE_STRICT:
jlaskey@3 257 case LE:
jlaskey@3 258 case LT:
jlaskey@3 259 case GE:
jlaskey@3 260 case GT:
jlaskey@3 261 return true;
jlaskey@3 262 default:
jlaskey@3 263 return false;
jlaskey@3 264 }
jlaskey@3 265 }
jlaskey@3 266 }
jlaskey@3 267
jlaskey@3 268 /** Runtime request. */
jlaskey@3 269 private final Request request;
jlaskey@3 270
jlaskey@3 271 /** Call arguments. */
jlaskey@3 272 private final List<Node> args;
jlaskey@3 273
jlaskey@3 274 /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
lagergren@211 275 private final Type callSiteType;
jlaskey@3 276
lagergren@57 277 /** is final - i.e. may not be removed again, lower in the code pipeline */
lagergren@211 278 private final boolean isFinal;
lagergren@57 279
jlaskey@3 280 /**
jlaskey@3 281 * Constructor
jlaskey@3 282 *
jlaskey@3 283 * @param token token
jlaskey@3 284 * @param finish finish
jlaskey@3 285 * @param request the request
jlaskey@3 286 * @param args arguments to request
jlaskey@3 287 */
lagergren@252 288 public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
lagergren@252 289 super(token, finish);
jlaskey@3 290
jlaskey@3 291 this.request = request;
jlaskey@3 292 this.args = args;
lagergren@211 293 this.callSiteType = null;
lagergren@211 294 this.isFinal = false;
lagergren@211 295 }
lagergren@211 296
lagergren@211 297 private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Node> args) {
lagergren@211 298 super(runtimeNode);
lagergren@211 299
lagergren@211 300 this.request = request;
lagergren@211 301 this.args = args;
lagergren@211 302 this.callSiteType = callSiteType;
lagergren@211 303 this.isFinal = isFinal;
jlaskey@3 304 }
jlaskey@3 305
jlaskey@3 306 /**
jlaskey@3 307 * Constructor
jlaskey@3 308 *
jlaskey@3 309 * @param token token
jlaskey@3 310 * @param finish finish
jlaskey@3 311 * @param request the request
jlaskey@3 312 * @param args arguments to request
jlaskey@3 313 */
lagergren@252 314 public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
lagergren@252 315 this(token, finish, request, Arrays.asList(args));
jlaskey@3 316 }
jlaskey@3 317
lagergren@57 318 /**
lagergren@57 319 * Constructor
lagergren@57 320 *
lagergren@57 321 * @param parent parent node from which to inherit source, token, finish
lagergren@57 322 * @param request the request
lagergren@57 323 * @param args arguments to request
lagergren@57 324 */
lagergren@57 325 public RuntimeNode(final Node parent, final Request request, final Node... args) {
lagergren@57 326 this(parent, request, Arrays.asList(args));
lagergren@57 327 }
lagergren@57 328
lagergren@57 329 /**
lagergren@57 330 * Constructor
lagergren@57 331 *
lagergren@57 332 * @param parent parent node from which to inherit source, token, finish
lagergren@57 333 * @param request the request
lagergren@57 334 * @param args arguments to request
lagergren@57 335 */
lagergren@57 336 public RuntimeNode(final Node parent, final Request request, final List<Node> args) {
lagergren@57 337 super(parent);
lagergren@57 338
lagergren@211 339 this.request = request;
lagergren@211 340 this.args = args;
lagergren@211 341 this.callSiteType = null;
lagergren@211 342 this.isFinal = false;
lagergren@57 343 }
lagergren@57 344
lagergren@57 345 /**
lagergren@57 346 * Constructor
lagergren@57 347 *
lagergren@57 348 * @param parent parent node from which to inherit source, token, finish and arguments
lagergren@57 349 * @param request the request
lagergren@57 350 */
lagergren@57 351 public RuntimeNode(final UnaryNode parent, final Request request) {
lagergren@57 352 this(parent, request, parent.rhs());
lagergren@57 353 }
lagergren@57 354
lagergren@57 355 /**
lagergren@57 356 * Constructor
lagergren@57 357 *
lagergren@57 358 * @param parent parent node from which to inherit source, token, finish and arguments
lagergren@57 359 * @param request the request
lagergren@57 360 */
lagergren@57 361 public RuntimeNode(final BinaryNode parent, final Request request) {
lagergren@57 362 this(parent, request, parent.lhs(), parent.rhs());
lagergren@57 363 }
lagergren@57 364
lagergren@57 365 /**
lagergren@57 366 * Is this node final - i.e. it can never be replaced with other nodes again
lagergren@57 367 * @return true if final
lagergren@57 368 */
lagergren@57 369 public boolean isFinal() {
lagergren@57 370 return isFinal;
lagergren@57 371 }
lagergren@57 372
lagergren@57 373 /**
lagergren@57 374 * Flag this node as final - i.e it may never be replaced with other nodes again
lagergren@211 375 * @param isFinal is the node final, i.e. can not be removed and replaced by a less generic one later in codegen
lagergren@211 376 * @return same runtime node if already final, otherwise a new one
lagergren@57 377 */
lagergren@211 378 public RuntimeNode setIsFinal(final boolean isFinal) {
lagergren@211 379 if (this.isFinal == isFinal) {
lagergren@211 380 return this;
lagergren@211 381 }
lagergren@211 382 return new RuntimeNode(this, request, callSiteType, isFinal, args);
jlaskey@3 383 }
jlaskey@3 384
jlaskey@3 385 /**
jlaskey@3 386 * Return type for the ReferenceNode
jlaskey@3 387 */
jlaskey@3 388 @Override
jlaskey@3 389 public Type getType() {
jlaskey@3 390 return hasCallSiteType() ? callSiteType : request.getReturnType();
jlaskey@3 391 }
jlaskey@3 392
jlaskey@3 393 @Override
attila@254 394 public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
lagergren@211 395 if (this.callSiteType == type) {
lagergren@211 396 return this;
lagergren@211 397 }
lagergren@211 398 return new RuntimeNode(this, request, type, isFinal, args);
jlaskey@3 399 }
jlaskey@3 400
jlaskey@3 401 @Override
jlaskey@3 402 public boolean canHaveCallSiteType() {
jlaskey@3 403 return request == Request.ADD;
jlaskey@3 404 }
jlaskey@3 405
jlaskey@3 406 private boolean hasCallSiteType() {
jlaskey@3 407 return callSiteType != null;
jlaskey@3 408 }
jlaskey@3 409
jlaskey@3 410 @Override
lagergren@290 411 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
lagergren@211 412 if (visitor.enterRuntimeNode(this)) {
lagergren@211 413 final List<Node> newArgs = new ArrayList<>();
lagergren@211 414 for (final Node arg : args) {
lagergren@211 415 newArgs.add(arg.accept(visitor));
jlaskey@3 416 }
lagergren@211 417 return visitor.leaveRuntimeNode(setArgs(newArgs));
jlaskey@3 418 }
jlaskey@3 419
jlaskey@3 420 return this;
jlaskey@3 421 }
jlaskey@3 422
jlaskey@3 423 @Override
jlaskey@3 424 public void toString(final StringBuilder sb) {
jlaskey@3 425 sb.append("ScriptRuntime.");
jlaskey@3 426 sb.append(request);
jlaskey@3 427 sb.append('(');
jlaskey@3 428
jlaskey@3 429 boolean first = true;
jlaskey@3 430
jlaskey@3 431 for (final Node arg : args) {
jlaskey@3 432 if (!first) {
jlaskey@3 433 sb.append(", ");
jlaskey@3 434 } else {
jlaskey@3 435 first = false;
jlaskey@3 436 }
jlaskey@3 437
jlaskey@3 438 arg.toString(sb);
jlaskey@3 439 }
jlaskey@3 440
jlaskey@3 441 sb.append(')');
jlaskey@3 442 }
jlaskey@3 443
jlaskey@3 444 /**
jlaskey@3 445 * Get the arguments for this runtime node
jlaskey@3 446 * @return argument list
jlaskey@3 447 */
jlaskey@3 448 public List<Node> getArgs() {
jlaskey@3 449 return Collections.unmodifiableList(args);
jlaskey@3 450 }
jlaskey@3 451
lagergren@211 452 private RuntimeNode setArgs(final List<Node> args) {
lagergren@211 453 if (this.args == args) {
lagergren@211 454 return this;
lagergren@211 455 }
lagergren@211 456 return new RuntimeNode(this, request, callSiteType, isFinal, args);
lagergren@211 457 }
lagergren@211 458
jlaskey@3 459 /**
jlaskey@3 460 * Get the request that this runtime node implements
jlaskey@3 461 * @return the request
jlaskey@3 462 */
jlaskey@3 463 public Request getRequest() {
jlaskey@3 464 return request;
jlaskey@3 465 }
jlaskey@3 466
jlaskey@3 467 /**
jlaskey@3 468 * Is this runtime node, engineered to handle the "at least one object" case of the defined
jlaskey@3 469 * requests and specialize on demand, really primitive. This can happen e.g. after AccessSpecializer
jlaskey@3 470 * In that case it can be turned into a simpler primitive form in CodeGenerator
jlaskey@3 471 *
jlaskey@3 472 * @return true if all arguments now are primitive
jlaskey@3 473 */
jlaskey@3 474 public boolean isPrimitive() {
jlaskey@3 475 for (final Node arg : args) {
jlaskey@3 476 if (arg.getType().isObject()) {
jlaskey@3 477 return false;
jlaskey@3 478 }
jlaskey@3 479 }
jlaskey@3 480 return true;
jlaskey@3 481 }
jlaskey@3 482 }

mercurial