package jdk.nashorn.internal.codegen;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
static final long FUNCTION_WEIGHT = 40;
static final long AASTORE_WEIGHT = 2;
static final long ACCESS_WEIGHT = 4;
static final long ADD_WEIGHT = 10;
static final long BREAK_WEIGHT = 1;
static final long CALL_WEIGHT = 10;
static final long CATCH_WEIGHT = 10;
static final long COMPARE_WEIGHT = 6;
static final long CONTINUE_WEIGHT = 1;
static final long IF_WEIGHT = 2;
static final long LITERAL_WEIGHT = 10;
static final long LOOP_WEIGHT = 4;
static final long NEW_WEIGHT = 6;
static final long FUNC_EXPR_WEIGHT = 20;
static final long RETURN_WEIGHT = 2;
static final long SPLIT_WEIGHT = 40;
static final long SWITCH_WEIGHT = 8;
static final long THROW_WEIGHT = 2;
static final long VAR_WEIGHT = 40;
static final long WITH_WEIGHT = 8;
static final long OBJECT_WEIGHT = 16;
static final long SETPROP_WEIGHT = 5;
private long weight;
private final Map<Node, Long> weightCache;
private final FunctionNode topFunction;
private WeighNodes(final FunctionNode topFunction, final Map<Node, Long> weightCache) {
super(new LexicalContext());
this.topFunction = topFunction;
this.weightCache = weightCache;
}
static long weigh(final Node node) {
return weigh(node, null);
}
static long weigh(final Node node, final Map<Node, Long> weightCache) {
final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
node.accept(weighNodes);
return weighNodes.weight;
}
@Override
public Node leaveAccessNode(final AccessNode accessNode) {
weight += ACCESS_WEIGHT;
return accessNode;
}
@Override
public boolean enterBlock(final Block block) {
if (weightCache != null && weightCache.containsKey(block)) {
weight += weightCache.get(block);
return false;
}
return true;
}
@Override
public Node leaveBreakNode(final BreakNode breakNode) {
weight += BREAK_WEIGHT;
return breakNode;
}
@Override
public Node leaveCallNode(final CallNode callNode) {
weight += CALL_WEIGHT;
return callNode;
}
@Override
public Node leaveCatchNode(final CatchNode catchNode) {
weight += CATCH_WEIGHT;
return catchNode;
}
@Override
public Node leaveContinueNode(final ContinueNode continueNode) {
weight += CONTINUE_WEIGHT;
return continueNode;
}
@Override
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
return expressionStatement;
}
@Override
public Node leaveForNode(final ForNode forNode) {
weight += LOOP_WEIGHT;
return forNode;
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (functionNode == topFunction) {
return true;
}
weight += FUNC_EXPR_WEIGHT;
return false;
}
@Override
public Node leaveIdentNode(final IdentNode identNode) {
weight += ACCESS_WEIGHT;
return identNode;
}
@Override
public Node leaveIfNode(final IfNode ifNode) {
weight += IF_WEIGHT;
return ifNode;
}
@Override
public Node leaveIndexNode(final IndexNode indexNode) {
weight += ACCESS_WEIGHT;
return indexNode;
}
@Override
public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
weight += BREAK_WEIGHT;
return jumpToInlinedFinally;
}
@SuppressWarnings("rawtypes")
@Override
public boolean enterLiteralNode(final LiteralNode literalNode) {
weight += LITERAL_WEIGHT;
if (literalNode instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] value = arrayLiteralNode.getValue();
final int[] postsets = arrayLiteralNode.getPostsets();
final List<Splittable.SplitRange> units = arrayLiteralNode.getSplitRanges();
if (units == null) {
for (final int postset : postsets) {
weight += AASTORE_WEIGHT;
final Node element = value[postset];
if (element != null) {
element.accept(this);
}
}
}
return false;
}
return true;
}
@Override
public boolean enterObjectNode(final ObjectNode objectNode) {
weight += OBJECT_WEIGHT;
final List<PropertyNode> properties = objectNode.getElements();
final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
for (final PropertyNode property : properties) {
if (!LiteralNode.isConstant(property.getValue())) {
weight += SETPROP_WEIGHT;
property.getValue().accept(this);
} else if (!isSpillObject) {
weight += SETPROP_WEIGHT;
}
}
return false;
}
@Override
public Node leavePropertyNode(final PropertyNode propertyNode) {
weight += LITERAL_WEIGHT;
return propertyNode;
}
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
weight += RETURN_WEIGHT;
return returnNode;
}
@Override
public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
weight += CALL_WEIGHT;
return runtimeNode;
}
@Override
public boolean enterSplitNode(final SplitNode splitNode) {
weight += SPLIT_WEIGHT;
return false;
}
@Override
public Node leaveSwitchNode(final SwitchNode switchNode) {
weight += SWITCH_WEIGHT;
return switchNode;
}
@Override
public Node leaveThrowNode(final ThrowNode throwNode) {
weight += THROW_WEIGHT;
return throwNode;
}
@Override
public Node leaveTryNode(final TryNode tryNode) {
weight += THROW_WEIGHT;
return tryNode;
}
@Override
public Node leaveVarNode(final VarNode varNode) {
weight += VAR_WEIGHT;
return varNode;
}
@Override
public Node leaveWhileNode(final WhileNode whileNode) {
weight += LOOP_WEIGHT;
return whileNode;
}
@Override
public Node leaveWithNode(final WithNode withNode) {
weight += WITH_WEIGHT;
return withNode;
}
@Override
public Node leavePOS(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveBIT_NOT(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveDELETE(final UnaryNode unaryNode) {
return runtimeNodeWeight(unaryNode);
}
@Override
public Node leaveNEW(final UnaryNode unaryNode) {
weight += NEW_WEIGHT;
return unaryNode;
}
@Override
public Node leaveNOT(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveNEG(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveTYPEOF(final UnaryNode unaryNode) {
return runtimeNodeWeight(unaryNode);
}
@Override
public Node leaveVOID(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
@Override
public Node leaveADD(final BinaryNode binaryNode) {
weight += ADD_WEIGHT;
return binaryNode;
}
@Override
public Node leaveAND(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
weight += ADD_WEIGHT;
return binaryNode;
}
@Override
public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveARROW(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveBIT_AND(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveBIT_OR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveBIT_XOR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveDIV(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveEQ(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveGE(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveGT(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveIN(final BinaryNode binaryNode) {
weight += CALL_WEIGHT;
return binaryNode;
}
@Override
public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
weight += CALL_WEIGHT;
return binaryNode;
}
@Override
public Node leaveLE(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveLT(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveMOD(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveMUL(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveNE(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveNE_STRICT(final BinaryNode binaryNode) {
return compareWeight(binaryNode);
}
@Override
public Node leaveOR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveSAR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveSHL(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveSHR(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
@Override
public Node leaveSUB(final BinaryNode binaryNode) {
return binaryNodeWeight(binaryNode);
}
private Node unaryNodeWeight(final UnaryNode unaryNode) {
weight += 1;
return unaryNode;
}
private Node binaryNodeWeight(final BinaryNode binaryNode) {
weight += 1;
return binaryNode;
}
private Node runtimeNodeWeight(final UnaryNode unaryNode) {
weight += CALL_WEIGHT;
return unaryNode;
}
private Node compareWeight(final BinaryNode binaryNode) {
weight += COMPARE_WEIGHT;
return binaryNode;
}
}