8012518: Reengineer Parser.java to make it play well with the copy-on-write IR

Remove the kludges introduced to make the parser work with the copy on write IR. Now everything is done bottom up, finshing node children completely before node parents. The repeated non-functional pattern 'node = node.setSomething(something);' is gone. Resulting code is much more readable, and extensible for future work. The parser is now also consistent with the rest of the stateless copy-on-write world in code generation.

Reviewed-by: lagergren, attila, hannesw, shade
This commit is contained in:
Andreas Gabrielsson 2014-10-14 15:28:24 +02:00 committed by Marcus Lagergren
parent a891de3114
commit fab85d4210
24 changed files with 1466 additions and 370 deletions

@ -26,3 +26,5 @@ jcov2/*
test/lib/testng.jar
test/script/external/*
.project
.externalToolBuilders/*
.settings/*

137
nashorn/bin/runopt.sh Normal file

@ -0,0 +1,137 @@
#!/bin/sh
#
# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
###########################################################################################
# This is a helper script to evaluate nashorn with optimistic types
# it produces a flight recording for every run, and uses the best
# known flags for performance for the current configration
###########################################################################################
# Flags to enable assertions, we need the system assertions too, since
# this script runs Nashorn in the BCP to override any nashorn.jar that might
# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
#
ENABLE_ASSERTIONS_FLAGS="-ea -esa"
# Flags to instrument lambdaform computation, caching, interpretation and compilation
# Default compile threshold for lambdaforms is 30
#
#LAMBDAFORM_FLAGS="\
# -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
# -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
# -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
# -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
# Flags to run trusted tests from the Nashorn test suite
#
#TRUSTED_TEST_FLAGS="\
#-Djava.security.manager \
#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
# Testing out new code optimizations using the generic hotspot "new code" parameter
#
#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
#
#-Dnashorn.typeInfo.disabled=false \
# and for Nashorn options:
# --class-cache-size=0 --persistent-code-cache=false
# Unique timestamped file name for JFR recordings. For JFR, we also have to
# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
# stack traces.
#
# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
# set the "method-sampling-interval" Normal and Maximum sample time as low as you
# can go (10 ms on most platforms). The default is normally higher. The increased
# sampling overhead is usually negligible for Nashorn runs, but the data is better
if [ -z $JFR_FILENAME ]; then
JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
echo "Using default JFR filename: ${JFR_FILENAME}..."
fi
# Flight recorder
#
# see above - already in place, copy the flags down here to disable
ENABLE_FLIGHT_RECORDER_FLAGS="\
-XX:+UnlockCommercialFeatures \
-XX:+FlightRecorder \
-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
# keeping this flag around for experimental reasons. Replace + with - to switch it off
#
#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
# this disables them if needed
#
#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
# Add timing to time the compilation phases.
#ENABLE_TIME_FLAGS=--log=time
# Add ShowHiddenFrames to get lambda form internals on the stack traces
#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
# That tired compilation is switched off, for C2 only output and that the number of
# compiler threads is set to 1 for determinsm.
#
#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
# that we run the script from the make dir
DIR=..
NASHORN_JAR=$DIR/dist/nashorn.jar
# The built Nashorn jar is placed first in the bootclasspath to override the JDK
# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
# nashorn count as system assertions in this configuration
# Type profiling default level is 111, 222 adds some compile time, but is faster
$JAVA_HOME/bin/java \
$ENABLE_ASSERTIONS_FLAGS \
$LAMBDAFORM_FLAGS \
$TRUSTED_FLAGS \
$USE_NEW_CODE_FLAGS \
$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
$ENABLE_FLIGHT_RECORDER_FLAGS \
$ENABLE_TYPE_SPECIALIZATION_FLAGS \
$TIERED_COMPILATION_THRESOLD_FLAGS \
$DISABLE_MATH_INTRINSICS_FLAGS \
$PRINT_ASM_FLAGS \
-Xbootclasspath/p:$NASHORN_JAR \
-Xms2G -Xmx2G \
-XX:TypeProfileLevel=222 \
-cp $CLASSPATH:../build/test/classes/ \
jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}

@ -25,8 +25,6 @@
package jdk.nashorn.api.scripting;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.LinkerServices;

@ -80,11 +80,12 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
/**
* Constructor
*
* @param token token
* @param finish finish
* @param statements statements
* @param token The first token of the block
* @param finish The index of the last character
* @param flags The flags of the block
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final Statement... statements) {
public Block(final long token, final int finish, final int flags, final Statement... statements) {
super(token, finish);
this.statements = Arrays.asList(statements);
@ -92,29 +93,52 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
this.entryLabel = new Label("block_entry");
this.breakLabel = new Label("block_break");
final int len = statements.length;
this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
final int terminalFlags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
this.flags = terminalFlags | flags;
this.conversion = null;
}
/**
* Constructs a new block
*
* @param token The first token of the block
* @param finish The index of the last character
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final Statement...statements){
this(token, finish, 0, statements);
}
/**
* Constructs a new block
*
* @param token The first token of the block
* @param finish The index of the last character
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final List<Statement> statements){
this(token, finish, 0, statements);
}
/**
* Constructor
*
* @param token token
* @param finish finish
* @param statements statements
* @param token The first token of the block
* @param finish The index of the last character
* @param flags The flags of the block
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final List<Statement> statements) {
this(token, finish, statements.toArray(new Statement[statements.size()]));
public Block(final long token, final int finish, final int flags, final List<Statement> statements) {
this(token, finish, flags, statements.toArray(new Statement[statements.size()]));
}
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols, final LocalVariableConversion conversion) {
super(block);
super(block, finish);
this.statements = statements;
this.flags = flags;
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
this.entryLabel = new Label(block.entryLabel);
this.breakLabel = new Label(block.breakLabel);
this.finish = finish;
this.conversion = conversion;
}

@ -54,20 +54,37 @@ public final class ForNode extends LoopNode {
private final int flags;
/**
* Constructs a ForNode
*
* @param lineNumber The line number of header
* @param token The for token
* @param finish The last character of the for node
* @param body The body of the for node
* @param flags The flags
*/
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
this(lineNumber, token, finish, body, flags, null, null, null);
}
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param body body
* @param flags flags
* @param lineNumber The line number of header
* @param token The for token
* @param finish The last character of the for node
* @param body The body of the for node
* @param flags The flags
* @param init The initial expression
* @param test The test expression
* @param modify The modify expression
*/
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags) {
super(lineNumber, token, finish, body, false);
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags, final Expression init, final JoinPredecessorExpression test, final JoinPredecessorExpression modify) {
super(lineNumber, token, finish, body, test, false);
this.flags = flags;
this.init = null;
this.modify = null;
this.init = init;
this.modify = modify;
}
private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
@ -166,16 +183,6 @@ public final class ForNode extends LoopNode {
public boolean isForIn() {
return (flags & IS_FOR_IN) != 0;
}
/**
* Flag this to be a for in construct
* @param lc lexical context
* @return new for node if changed or existing if not
*/
public ForNode setIsForIn(final LexicalContext lc) {
return setFlags(lc, flags | IS_FOR_IN);
}
/**
* Is this a for each construct, known from e.g. Rhino. This will be a for of construct
* in ECMAScript 6
@ -185,15 +192,6 @@ public final class ForNode extends LoopNode {
return (flags & IS_FOR_EACH) != 0;
}
/**
* Flag this to be a for each construct
* @param lc lexical context
* @return new for node if changed or existing if not
*/
public ForNode setIsForEach(final LexicalContext lc) {
return setFlags(lc, flags | IS_FOR_EACH);
}
/**
* If this is a for in or for each construct, there is an iterator symbol
* @return the symbol for the iterator to be used, or null if none exists
@ -260,13 +258,6 @@ public final class ForNode extends LoopNode {
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
}
private ForNode setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));

@ -31,7 +31,6 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
@ -46,6 +45,7 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
@ -299,12 +299,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @param token token
* @param finish finish
* @param firstToken first token of the function node (including the function declaration)
* @param lastToken lastToken
* @param namespace the namespace
* @param ident the identifier
* @param name the name of the function
* @param parameters parameter list
* @param kind kind of function as in {@link FunctionNode.Kind}
* @param flags initial flags
* @param body body of the function
* @param state The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
* @param endParserState The parser state at the end of the parsing.
*/
public FunctionNode(
final Source source,
@ -312,12 +316,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final long token,
final int finish,
final long firstToken,
final long lastToken,
final Namespace namespace,
final IdentNode ident,
final String name,
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
final int flags) {
final int flags,
final Block body,
final CompilationState state,
final Object endParserState) {
super(token, finish);
this.source = source;
@ -327,15 +335,15 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
this.kind = kind;
this.parameters = parameters;
this.firstToken = firstToken;
this.lastToken = token;
this.lastToken = lastToken;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
this.flags = flags;
this.compileUnit = null;
this.body = null;
this.body = body;
this.thisProperties = 0;
this.rootClass = null;
this.endParserState = null;
this.endParserState = endParserState;
}
private FunctionNode(
@ -439,7 +447,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @return the id
*/
public int getId() {
return position();
return isProgram() ? -1: Token.descPosition(firstToken);
}
/**
@ -902,34 +910,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return lastToken;
}
/**
* Set the last token for this function's code
* @param lc lexical context
* @param lastToken the last token
* @return function node or a new one if state was changed
*/
public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
if (this.lastToken == lastToken) {
return this;
}
return Node.replaceInLexicalContext(
lc,
this,
new FunctionNode(
this,
lastToken,
endParserState,
flags,
name,
returnType,
compileUnit,
compilationState,
body,
parameters,
thisProperties,
rootClass));
}
/**
* Returns the end parser state for this function.
* @return the end parser state for this function.
@ -938,33 +918,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return endParserState;
}
/**
* Set the end parser state for this function.
* @param lc lexical context
* @param endParserState the parser state to set
* @return function node or a new one if state was changed
*/
public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
if (this.endParserState == endParserState) {
return this;
}
return Node.replaceInLexicalContext(
lc,
this,
new FunctionNode(
this,
lastToken,
endParserState,
flags,
name,
returnType,
compileUnit,
compilationState,
body,
parameters,
thisProperties, rootClass));
}
/**
* Get the name of this function
* @return the name

@ -53,14 +53,15 @@ public abstract class LoopNode extends BreakableStatement {
* @param token token
* @param finish finish
* @param body loop body
* @param test test
* @param controlFlowEscapes controlFlowEscapes
*/
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final boolean controlFlowEscapes) {
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = null;
this.body = body;
this.controlFlowEscapes = controlFlowEscapes;
this.test = test;
}
/**

@ -39,7 +39,7 @@ public abstract class Node implements Cloneable {
protected final int start;
/** End of source range. */
protected int finish;
protected final int finish;
/** Token descriptor. */
private final long token;
@ -80,6 +80,18 @@ public abstract class Node implements Cloneable {
this.finish = node.finish;
}
/**
* Copy constructor that overrides finish
*
* @param node source node
* @param finish Last character
*/
protected Node(final Node node, final int finish) {
this.token = node.token;
this.start = node.start;
this.finish = finish;
}
/**
* Is this a loop node?
*
@ -151,14 +163,6 @@ public abstract class Node implements Cloneable {
return finish;
}
/**
* Set finish position for this node in the source string
* @param finish finish
*/
public void setFinish(final int finish) {
this.finish = finish;
}
/**
* Get start position for node
* @return start position

@ -45,9 +45,11 @@ public final class WhileNode extends LoopNode {
* @param token token
* @param finish finish
* @param isDoWhile is this a do while loop?
* @param test test expression
* @param body body of the while loop
*/
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
super(lineNumber, token, finish, null, false);
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile, final JoinPredecessorExpression test, final Block body) {
super(lineNumber, token, finish, body, test, false);
this.isDoWhile = isDoWhile;
}
@ -55,10 +57,10 @@ public final class WhileNode extends LoopNode {
* Internal copy constructor
*
* @param whileNode while node
* @param test test
* @param body body
* @param test Test expression
* @param body body of the while loop
* @param controlFlowEscapes control flow escapes?
* @param conversion TODO
* @param conversion local variable conversion info
*/
private WhileNode(final WhileNode whileNode, final JoinPredecessorExpression test, final Block body, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
super(whileNode, test, body, controlFlowEscapes, conversion);

@ -42,14 +42,16 @@ public final class WithNode extends LexicalContextStatement {
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param lineNumber Line number of the header
* @param token First token
* @param finish Character index of the last token
* @param expression With expression
* @param body Body of with node
*/
public WithNode(final int lineNumber, final long token, final int finish) {
public WithNode(final int lineNumber, final long token, final int finish, final Expression expression, final Block body) {
super(lineNumber, token, finish);
this.expression = null;
this.body = null;
this.expression = expression;
this.body = body;
}
private WithNode(final WithNode node, final Expression expression, final Block body) {

@ -561,7 +561,6 @@ public final class Global extends ScriptObject implements Scope {
*
* @param engine ScriptEngine to initialize
*/
@SuppressWarnings("hiding")
public void initBuiltinObjects(final ScriptEngine engine) {
if (this.builtinObject != null) {
// already initialized, just return
@ -1718,7 +1717,6 @@ public final class Global extends ScriptObject implements Scope {
return func;
}
@SuppressWarnings("hiding")
private void init(final ScriptEngine engine) {
assert Context.getGlobal() == this : "this global is not set as current";

@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.nashorn.api.scripting.NashornException;
@ -131,7 +130,6 @@ public final class NativeError extends ScriptObject {
// This is called NativeError, NativeTypeError etc. to
// associate a ECMAException with the ECMA Error object.
@SuppressWarnings("unused")
static void initException(final ScriptObject self) {
// ECMAException constructor has side effects
new ECMAException(self, null);

@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.util.Collection;
@ -36,7 +35,6 @@ import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;

@ -0,0 +1,334 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.Iterator;
import java.util.NoSuchElementException;
import jdk.nashorn.internal.ir.Statement;
/**
* A class that tracks the current lexical context of node visitation as a stack of {@code ParserContextNode} nodes. Has special
* methods to retrieve useful subsets of the context.
*
* This is implemented with a primitive array and a stack pointer, because it really makes a difference
* performance wise. None of the collection classes were optimal
*/
class ParserContext {
private ParserContextNode[] stack;
private int sp;
private static final int INITIAL_DEPTH = 16;
/**
* Constructs a ParserContext,
* initializes the stack
*/
public ParserContext(){
this.sp = 0;
this.stack = new ParserContextNode[INITIAL_DEPTH];
}
/**
* Pushes a new block on top of the context, making it the innermost open block.
* @param node the new node
* @return The node that was pushed
*/
public <T extends ParserContextNode> T push(final T node) {
assert !contains(node);
if (sp == stack.length) {
final ParserContextNode[] newStack = new ParserContextNode[sp * 2];
System.arraycopy(stack, 0, newStack, 0, sp);
stack = newStack;
}
stack[sp] = node;
sp++;
return node;
}
/**
* The topmost node on the stack
* @return The topmost node on the stack
*/
public ParserContextNode peek() {
return stack[sp - 1];
}
/**
* Removes and returns the topmost Node from the stack.
* @param node The node expected to be popped, used for sanity check
* @return The removed node
*/
public <T extends ParserContextNode> T pop(final T node) {
--sp;
@SuppressWarnings("unchecked")
final T popped = (T)stack[sp];
stack[sp] = null;
assert node == popped;
return popped;
}
/**
* Tests if a node is on the stack.
* @param node The node to test
* @return true if stack contains node, false otherwise
*/
public boolean contains(final ParserContextNode node) {
for (int i = 0; i < sp; i++) {
if (stack[i] == node) {
return true;
}
}
return false;
}
/**
* Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
* @return Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
*/
private ParserContextBreakableNode getBreakable() {
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
final ParserContextBreakableNode next = iter.next();
if (next.isBreakableWithoutLabel()) {
return next;
}
}
return null;
}
/**
* Find the breakable node corresponding to this label.
* @param labelName name of the label to search for. If null, the closest breakable node will be returned
* unconditionally, e.g. a while loop with no label
* @return closest breakable node
*/
public ParserContextBreakableNode getBreakable(final String labelName) {
if (labelName != null) {
final ParserContextLabelNode foundLabel = findLabel(labelName);
if (foundLabel != null) {
// iterate to the nearest breakable to the foundLabel
ParserContextBreakableNode breakable = null;
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, foundLabel); iter.hasNext(); ) {
breakable = iter.next();
}
return breakable;
}
return null;
} else {
return getBreakable();
}
}
/**
* Returns the loop node of the current loop, or null if not inside a loop
* @return loop noder
*/
public ParserContextLoopNode getCurrentLoop() {
final Iterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, getCurrentFunction());
return iter.hasNext() ? iter.next() : null;
}
private ParserContextLoopNode getContinueTo() {
return getCurrentLoop();
}
/**
* Find the continue target node corresponding to this label.
* @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a
* while loop with no label
* @return closest continue target node
*/
public ParserContextLoopNode getContinueTo(final String labelName) {
if (labelName != null) {
final ParserContextLabelNode foundLabel = findLabel(labelName);
if (foundLabel != null) {
// iterate to the nearest loop to the foundLabel
ParserContextLoopNode loop = null;
for (final NodeIterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, foundLabel); iter.hasNext(); ) {
loop = iter.next();
}
return loop;
}
return null;
}
return getContinueTo();
}
/**
* Get the function body of a function node on the stack.
* This will trigger an assertion if node isn't present
* @param functionNode function node
* @return body of function node
*/
public ParserContextBlockNode getFunctionBody(final ParserContextFunctionNode functionNode) {
for (int i = sp - 1; i >= 0 ; i--) {
if (stack[i] == functionNode) {
return (ParserContextBlockNode)stack[i + 1];
}
}
throw new AssertionError(functionNode.getName() + " not on context stack");
}
/**
* Check the stack for a given label node by name
* @param name name of the label
* @return LabelNode if found, null otherwise
*/
public ParserContextLabelNode findLabel(final String name) {
for (final Iterator<ParserContextLabelNode> iter = new NodeIterator<>(ParserContextLabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
final ParserContextLabelNode next = iter.next();
if (next.getLabelName().equals(name)) {
return next;
}
}
return null;
}
/**
* Prepends a statement to the current node.
* @param statement The statement to prepend
*/
public void prependStatementToCurrentNode(final Statement statement) {
assert statement != null;
stack[sp - 1].prependStatement(statement);
}
/**
* Appends a statement to the current Node.
* @param statement The statement to append
*/
public void appendStatementToCurrentNode(final Statement statement) {
assert statement != null;
stack[sp - 1].appendStatement(statement);
}
/**
* Returns the innermost function in the context.
* @return the innermost function in the context.
*/
public ParserContextFunctionNode getCurrentFunction() {
for (int i = sp - 1; i >= 0; i--) {
if (stack[i] instanceof ParserContextFunctionNode) {
return (ParserContextFunctionNode) stack[i];
}
}
return null;
}
/**
* Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
* @return an iterator over all blocks in the context.
*/
public Iterator<ParserContextBlockNode> getBlocks() {
return new NodeIterator<>(ParserContextBlockNode.class);
}
/**
* Returns the innermost block in the context.
* @return the innermost block in the context.
*/
public ParserContextBlockNode getCurrentBlock() {
return getBlocks().next();
}
/**
* The last statement added to the context
* @return The last statement added to the context
*/
public Statement getLastStatement() {
if (sp == 0) {
return null;
}
final ParserContextNode top = stack[sp - 1];
final int s = top.getStatements().size();
return s == 0 ? null : top.getStatements().get(s - 1);
}
/**
* Returns an iterator over all functions in the context, with the top (innermost open) function first.
* @return an iterator over all functions in the context.
*/
public Iterator<ParserContextFunctionNode> getFunctions() {
return new NodeIterator<>(ParserContextFunctionNode.class);
}
private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
private int index;
private T next;
private final Class<T> clazz;
private ParserContextNode until;
NodeIterator(final Class<T> clazz) {
this(clazz, null);
}
NodeIterator(final Class<T> clazz, final ParserContextNode until) {
this.index = sp - 1;
this.clazz = clazz;
this.until = until;
this.next = findNext();
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public T next() {
if (next == null) {
throw new NoSuchElementException();
}
final T lnext = next;
next = findNext();
return lnext;
}
@SuppressWarnings("unchecked")
private T findNext() {
for (int i = index; i >= 0; i--) {
final Object node = stack[i];
if (node == until) {
return null;
}
if (clazz.isAssignableFrom(node.getClass())) {
index = i - 1;
return (T)node;
}
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

@ -0,0 +1,109 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.ir.Statement;
/**
* Base class for parser context nodes
*/
abstract class ParserContextBaseNode implements ParserContextNode {
/**
* Flags for this node
*/
protected int flags;
private List<Statement> statements;
/**
* Constructor
*/
public ParserContextBaseNode() {
this.statements = new ArrayList<>();
}
/**
* @return The flags for this node
*/
@Override
public int getFlags() {
return flags;
}
/**
* Returns a single flag
* @param flag
* @return A single flag
*/
protected int getFlag(final int flag) {
return (flags & flag);
}
/**
* @param flag
* @return the new flags
*/
@Override
public int setFlag(final int flag) {
flags |= flag;
return flags;
}
/**
* @return The list of statements that belongs to this node
*/
@Override
public List<Statement> getStatements() {
return statements;
}
/**
* @param statements
*/
@Override
public void setStatements(final List<Statement> statements) {
this.statements = statements;
}
/**
* Adds a Statement at the end of the Statementlist
* @param statement The statement to add
*/
@Override
public void appendStatement(final Statement statement) {
this.statements.add(statement);
}
/**
* Adds a statement at the begining of the statementlist
* @param statement The statement to add
*/
@Override
public void prependStatement(final Statement statement) {
this.statements.add(0, statement);
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a block that is currently being parsed
*/
class ParserContextBlockNode extends ParserContextBaseNode implements ParserContextBreakableNode {
private final long token;
/**
* Constructs a ParserContextBlockNode
*
* @param token The first token of the block
*/
public ParserContextBlockNode(final long token) {
this.token = token;
}
@Override
public boolean isBreakableWithoutLabel() {
return false;
}
/**
* Get token
* @return The first token of the block
*/
public long getToken() {
return token;
}
}

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import jdk.nashorn.internal.ir.BreakNode;
/**
* An interface that is implemented by ParserContextNodes that can
* contain a {@link BreakNode}
*/
interface ParserContextBreakableNode extends ParserContextNode {
/**
* Returns true if not i breakable without label, false otherwise
* @return Returns true if not i breakable without label, false otherwise
*/
boolean isBreakableWithoutLabel();
}

@ -0,0 +1,197 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.List;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
/**
* ParserContextNode that represents a function that is currently being parsed
*/
class ParserContextFunctionNode extends ParserContextBaseNode {
/** Function name */
private final String name;
/** Function identifier node */
private final IdentNode ident;
/** Name space for function */
private final Namespace namespace;
/** Line number for function declaration */
private final int line;
/** Function node kind, see {@link FunctionNode#Kind} */
private final FunctionNode.Kind kind;
/** List of parameter identifiers for function */
private final List<IdentNode> parameters;
/** Token for function start */
private final long token;
/** Last function token */
private long lastToken;
/** Opaque node for parser end state, see {@link Parser} */
private Object endParserState;
/**
* @param token The token for the function
* @param ident External function name
* @param name Internal name of the function
* @param namespace Function's namespace
* @param line The source line of the function
* @param kind Function kind
* @param parameters The parameters of the function
*/
public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
this.ident = ident;
this.namespace = namespace;
this.line = line;
this.kind = kind;
this.name = name;
this.parameters = parameters;
this.token = token;
}
/**
* @return Internal name of the function
*/
public String getName() {
return name;
}
/**
* @return The external identifier for the function
*/
public IdentNode getIdent() {
return ident;
}
/**
*
* @return true if function is the program function
*/
public boolean isProgram() {
return getFlag(FunctionNode.IS_PROGRAM) != 0;
}
/**
* @return if function in strict mode
*/
public boolean isStrict() {
return getFlag(FunctionNode.IS_STRICT) != 0;
}
/**
* @return true if the function has nested evals
*/
public boolean hasNestedEval() {
return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
}
/**
* Returns true if any of the blocks in this function create their own scope.
* @return true if any of the blocks in this function create their own scope.
*/
public boolean hasScopeBlock() {
return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
}
/**
* Create a unique name in the namespace of this FunctionNode
* @param base prefix for name
* @return base if no collision exists, otherwise a name prefix with base
*/
public String uniqueName(final String base) {
return namespace.uniqueName(base);
}
/**
* @return line number of the function
*/
public int getLineNumber() {
return line;
}
/**
* @return The kind if function
*/
public FunctionNode.Kind getKind() {
return kind;
}
/**
* Get parameters
* @return The parameters of the function
*/
public List<IdentNode> getParameters() {
return parameters;
}
/**
* Set last token
* @param token New last token
*/
public void setLastToken(final long token) {
this.lastToken = token;
}
/**
* @return lastToken Function's last token
*/
public long getLastToken() {
return lastToken;
}
/**
* Returns the ParserState of when the parsing of this function was ended
* @return endParserState The end parser state
*/
public Object getEndParserState() {
return endParserState;
}
/**
* Sets the ParserState of when the parsing of this function was ended
* @param endParserState The end parser state
*/
public void setEndParserState(final Object endParserState) {
this.endParserState = endParserState;
}
/**
* Returns the if of this function
* @return The function id
*/
public int getId() {
return isProgram() ? -1 : Token.descPosition(token);
}
}

@ -0,0 +1,52 @@
/**
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* ParserContextNode that represents a LabelNode
*/
class ParserContextLabelNode extends ParserContextBaseNode {
/** Name for label */
private final String name;
/**
* Constructor
*
* @param name The name of the label
*/
public ParserContextLabelNode(final String name) {
this.name = name;
}
/**
* Returns the name of the label
* @return name of label
*/
public String getLabelName() {
return name;
}
}

@ -0,0 +1,37 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a loop that is being parsed
*/
class ParserContextLoopNode extends ParserContextBaseNode implements ParserContextBreakableNode {
@Override
public boolean isBreakableWithoutLabel() {
return true;
}
}

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.List;
import jdk.nashorn.internal.ir.Statement;
/**
* Used for keeping state when needed in the parser.
*/
interface ParserContextNode {
/**
* @return The flags for this node
*/
public int getFlags();
/**
* @param flag The flag to set
* @return All current flags after update
*/
public int setFlag(final int flag);
/**
* @return The list of statements that belongs to this node
*/
public List<Statement> getStatements();
/**
* @param statements The statement list
*/
public void setStatements(final List<Statement> statements);
/**
* Adds a Statement at the end of the Statementlist
* @param statement The statement to add
*/
public void appendStatement(final Statement statement);
/**
* Adds a statement at the begining of the statementlist
* @param statement The statement to add
*/
public void prependStatement(final Statement statement);
}

@ -0,0 +1,36 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a SwithcNode that is currently being parsed
*/
class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
@Override
public boolean isBreakableWithoutLabel() {
return true;
}
}

@ -483,7 +483,7 @@ public final class Context {
final int cacheSize = env._class_cache_size;
if (cacheSize > 0) {
classCache = new ClassCache(cacheSize);
classCache = new ClassCache(this, cacheSize);
}
if (env._persistent_cache) {
@ -1261,17 +1261,23 @@ public final class Context {
* Cache for compiled script classes.
*/
@SuppressWarnings("serial")
private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
@Logger(name="classcache")
private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
private final int size;
private final ReferenceQueue<Class<?>> queue;
private final DebugLogger log;
ClassCache(final int size) {
ClassCache(final Context context, final int size) {
super(size, 0.75f, true);
this.size = size;
this.queue = new ReferenceQueue<>();
this.log = initLogger(context);
}
void cache(final Source source, final Class<?> clazz) {
if (log.isEnabled()) {
log.info("Caching ", source, " in class cache");
}
put(source, new ClassReference(clazz, queue, source));
}
@ -1283,9 +1289,28 @@ public final class Context {
@Override
public ClassReference get(final Object key) {
for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
remove(ref.source);
final Source source = ref.source;
if (log.isEnabled()) {
log.info("Evicting ", source, " from class cache.");
}
remove(source);
}
return super.get(key);
final ClassReference ref = super.get(key);
if (ref != null && log.isEnabled()) {
log.info("Retrieved class reference for ", ref.source, " from class cache");
}
return ref;
}
@Override
public DebugLogger initLogger(final Context context) {
return context.getLogger(getClass());
}
@Override
public DebugLogger getLogger() {
return log;
}
}