This commit is contained in:
Lana Steuck 2015-07-23 15:28:32 -07:00
commit 2f7dd1981b
10 changed files with 231 additions and 52 deletions

View File

@ -48,7 +48,9 @@
<condition property="git.executable" value="/usr/local/bin/git" else="git">
<available file="/usr/local/bin/git"/>
</condition>
<!-- check if testng.jar is avaiable -->
<!-- check if testng.jar is avaiable, and download it if it isn't -->
<available property="testng.already.present" file="${file.reference.testng.jar}"/>
<antcall target="get-testng"/>
<available property="testng.available" file="${file.reference.testng.jar}"/>
<!-- check if Jemmy ang testng.jar are avaiable -->
<condition property="jemmy.jfx.testng.available" value="true">
@ -484,7 +486,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</target>
<target name="test" depends="get-testng, javadocnh, test-pessimistic, test-optimistic"/>
<target name="test" depends="prepare, javadocnh, test-pessimistic, test-optimistic"/>
<target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<echo message="Running test suite in OPTIMISTIC mode..."/>
@ -514,7 +516,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/>
</target>
<target name="testjfx" depends="jar, get-testng, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
<target name="testjfx" depends="jar, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/>
</fileset>
@ -542,7 +544,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</target>
<target name="testmarkdown" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<target name="testmarkdown" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/>
</fileset>
@ -561,7 +563,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</target>
<target name="test262" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<target name="test262" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/>
</fileset>
@ -585,7 +587,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="test262parallel" depends="test262-parallel"/>
<target name="test262-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<target name="test262-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<!-- use just build.test.classes.dir to avoid referring to TestNG -->
<java classname="${parallel.test.runner}" dir="${basedir}" fork="true">
<jvmarg line="${boot.class.path}"/>
@ -604,7 +606,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="testparallel" depends="test-parallel"/>
<target name="test-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<target name="test-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<!-- use just build.test.classes.dir to avoid referring to TestNG -->
<java classname="${parallel.test.runner}" dir="${basedir}"
failonerror="true"
@ -709,7 +711,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</target>
<!-- get all external test scripts -->
<target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider, get-testng">
<target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider">
<!-- make external test dir -->
<mkdir dir="${test.external.dir}"/>
@ -746,7 +748,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="perf" depends="externals, update-externals, sunspider, octane"/>
<!-- download and install testng.jar -->
<target name="get-testng" depends="prepare" unless="testng.available">
<target name="get-testng" unless="testng.already.present">
<get src="http://testng.org/testng-6.8.zip" dest="${test.lib}" skipexisting="true" ignoreerrors="true"/>
<unzip src="${test.lib}${file.separator}testng-6.8.zip" dest="${test.lib}">
<patternset>
@ -758,7 +760,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</target>
<!-- run all tests -->
<target name="alltests" depends="get-testng, externals, update-externals, test, test262parallel, testmarkdown, perf"/>
<target name="alltests" depends="externals, update-externals, test, test262parallel, testmarkdown, perf"/>
<import file="build-benchmark.xml"/>

View File

@ -783,12 +783,13 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
// If this is a declared variable or a function parameter, delete always fails (except for globals).
final String name = ident.getName();
final Symbol symbol = ident.getSymbol();
final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
if (failDelete && symbol.isThis()) {
if (symbol.isThis()) {
// Can't delete "this", ignore and return true
return LiteralNode.newInstance(unaryNode, true).accept(this);
}
final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
if (!failDelete) {
args.add(compilerConstantIdentifier(SCOPE));
@ -798,6 +799,8 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
if (failDelete) {
request = Request.FAIL_DELETE;
} else if (symbol.isGlobal() && !symbol.isFunctionDeclaration()) {
request = Request.SLOW_DELETE;
}
} else if (rhs instanceof AccessNode) {
final Expression base = ((AccessNode)rhs).getBase();

View File

@ -56,6 +56,8 @@ public class RuntimeNode extends Expression {
REFERENCE_ERROR,
/** Delete operator */
DELETE(TokenType.DELETE, Type.BOOLEAN, 1),
/** Delete operator for slow scopes */
SLOW_DELETE(TokenType.DELETE, Type.BOOLEAN, 1, false),
/** Delete operator that always fails -- see Lower */
FAIL_DELETE(TokenType.DELETE, Type.BOOLEAN, 1, false),
/** === operator with at least one object */

View File

@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.Collection;
import java.util.List;
/**
@ -71,11 +72,6 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
}
}
@Override
boolean isRecompilable() {
return false;
}
@Override
protected boolean needsCallee() {
final boolean needsCallee = code.getFirst().needsCallee();
@ -92,6 +88,20 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
return true;
}
@Override
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
assert isValidCallSite(callSiteType) : callSiteType;
CompiledFunction best = null;
for (final CompiledFunction candidate: code) {
if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
best = candidate;
}
}
return best;
}
@Override
MethodType getGenericType() {
// We need to ask the code for its generic type. We can't just rely on this function data's arity, as it's not

View File

@ -617,6 +617,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
private CompiledFunction addCode(final MethodHandle target, final Map<Integer, Type> invalidatedProgramPoints,
final MethodType callSiteType, final int fnFlags) {
final CompiledFunction cfn = new CompiledFunction(target, this, invalidatedProgramPoints, callSiteType, fnFlags);
assert noDuplicateCode(cfn) : "duplicate code";
code.add(cfn);
return cfn;
}
@ -683,14 +684,17 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
@Override
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
assert isValidCallSite(callSiteType) : callSiteType;
CompiledFunction existingBest = pickFunction(callSiteType, false);
if (existingBest == null) {
existingBest = pickFunction(callSiteType, true); // try vararg last
}
if (existingBest == null) {
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
}
assert existingBest != null;
//we are calling a vararg method with real args
boolean varArgWithRealArgs = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType);
//if the best one is an apply to call, it has to match the callsite exactly
//or we need to regenerate
@ -699,26 +703,17 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (best != null) {
return best;
}
varArgWithRealArgs = true;
}
if (varArgWithRealArgs) {
// special case: we had an apply to call, but we failed to make it fit.
// Try to generate a specialized one for this callsite. It may
// be another apply to call specialization, or it may not, but whatever
// it is, it is a specialization that is guaranteed to fit
final FunctionInitializer fnInit = compileTypeSpecialization(callSiteType, runtimeScope, false);
existingBest = addCode(fnInit, callSiteType);
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, false), callSiteType);
}
return existingBest;
}
@Override
boolean isRecompilable() {
return true;
}
@Override
public boolean needsCallee() {
return getFunctionFlag(FunctionNode.NEEDS_CALLEE);
@ -827,6 +822,16 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return newFn;
}
// Make sure code does not contain a compiled function with the same signature as compiledFunction
private boolean noDuplicateCode(final CompiledFunction compiledFunction) {
for (final CompiledFunction cf : code) {
if (cf.type().equals(compiledFunction.type())) {
return false;
}
}
return true;
}
private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
createLogger();

View File

@ -359,31 +359,13 @@ public abstract class ScriptFunctionData implements Serializable {
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
* @return the best function for the specified call site type.
*/
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
abstract CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden);
if (isRecompilable()) {
final CompiledFunction candidate = pickFunction(callSiteType, false);
if (candidate != null) {
return candidate;
}
return pickFunction(callSiteType, true); //try vararg last
}
CompiledFunction best = null;
for (final CompiledFunction candidate: code) {
if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
best = candidate;
}
}
return best;
boolean isValidCallSite(final MethodType callSiteType) {
return callSiteType.parameterCount() >= 2 && // Must have at least (callee, this)
callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class); // Callee must be assignable from script function
}
abstract boolean isRecompilable();
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
}

View File

@ -684,6 +684,33 @@ public final class ScriptRuntime {
return true;
}
/**
* ECMA 11.4.1 - delete operator, implementation for slow scopes
*
* This implementation of 'delete' walks the scope chain to find the scope that contains the
* property to be deleted, then invokes delete on it.
*
* @param obj top scope object
* @param property property to delete
* @param strict are we in strict mode
*
* @return true if property was successfully found and deleted
*/
public static boolean SLOW_DELETE(final Object obj, final Object property, final Object strict) {
if (obj instanceof ScriptObject) {
ScriptObject sobj = (ScriptObject) obj;
final String key = property.toString();
while (sobj != null && sobj.isScope()) {
final FindProperty find = sobj.findProperty(key, false);
if (find != null) {
return sobj.delete(key, Boolean.TRUE.equals(strict));
}
sobj = sobj.getProto();
}
}
return DELETE(obj, property, strict);
}
/**
* ECMA 11.4.1 - delete operator, special case
*

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2015, 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.
*/
/**
* JDK-8131340: Varargs function is recompiled each time it is linked
*
* @test
* @run
*/
// This is an indirect test. If repeated calls were to cause recompilation
// this would trigger an assertion in RecompilableScriptFunctionData.
function varargs() {
return arguments;
}
varargs(1);
varargs(2);
varargs(3);
varargs(4);
varargs(5);
varargs(6);

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, 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.
*/
/**
* JDK-8131683: Delete fails over multiple scopes
*
* @test
* @run
*/
a = 1;
b = 2;
c = 3;
var A = 1;
var B = 2;
var C = 3;
function D() {}
print((function() {
var x; // force creation of scope
(function() { x; })();
return delete a;
})());
print((function() {
eval("");
return delete b;
})());
print((function() {
return eval("delete c");
})());
print((function() {
eval("d = 4");
return eval("delete d");
})());
print(typeof a);
print(typeof b);
print(typeof c);
print(typeof d);
print((function() {
var x; // force creation of scope
(function() { x; })();
return delete A;
})());
print((function() {
eval("");
return delete B;
})());
print((function() {
return eval("delete C");
})());
print((function() {
eval("");
return delete D;
})());
print(typeof A);
print(typeof B);
print(typeof C);
print(typeof D);

View File

@ -0,0 +1,16 @@
true
true
true
true
undefined
undefined
undefined
undefined
false
false
false
false
number
number
number
function