8019585: Sometimes a var declaration using itself in its init wasn't declared as canBeUndefined, causing erroneous bytecode

Reviewed-by: sundar, attila
This commit is contained in:
Marcus Lagergren 2013-07-03 13:03:36 +02:00
parent 92bcfea39a
commit 62fb002570
22 changed files with 81 additions and 12 deletions

@ -146,7 +146,7 @@ public abstract class NashornException extends RuntimeException {
* @return array of javascript stack frames
*/
public static StackTraceElement[] getScriptFrames(final Throwable exception) {
final StackTraceElement[] frames = ((Throwable)exception).getStackTrace();
final StackTraceElement[] frames = exception.getStackTrace();
final List<StackTraceElement> filtered = new ArrayList<>();
for (final StackTraceElement st : frames) {
if (ECMAErrors.isScriptFrame(st)) {
@ -170,7 +170,7 @@ public abstract class NashornException extends RuntimeException {
*/
public static String getScriptStackString(final Throwable exception) {
final StringBuilder buf = new StringBuilder();
final StackTraceElement[] frames = getScriptFrames((Throwable)exception);
final StackTraceElement[] frames = getScriptFrames(exception);
for (final StackTraceElement st : frames) {
buf.append("\tat ");
buf.append(st.getMethodName());

@ -54,6 +54,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@ -234,10 +235,25 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public boolean enterVarNode(final VarNode varNode) {
final String name = varNode.getName().getName();
//if this is used the var node symbol needs to be tagged as can be undefined
//if this is used before the var node, the var node symbol needs to be tagged as can be undefined
if (uses.contains(name)) {
canBeUndefined.add(name);
}
// all uses of the declared varnode inside the var node are potentially undefined
// however this is a bit conservative as e.g. var x = 17; var x = 1 + x; does work
if (!varNode.isFunctionDeclaration() && varNode.getInit() != null) {
varNode.getInit().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterIdentNode(final IdentNode identNode) {
if (name.equals(identNode.getName())) {
canBeUndefined.add(name);
}
return false;
}
});
}
return true;
}
@ -257,6 +273,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
}
return varNode;
}
});

@ -1847,7 +1847,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// If expression not int see if we can convert, if not use deflt to trigger default.
if (!type.isInteger()) {
method.load(deflt);
final Class exprClass = type.getTypeClass();
final Class<?> exprClass = type.getTypeClass();
method.invoke(staticCallNoLookup(ScriptRuntime.class, "switchTagAsInt", int.class, exprClass.isPrimitive()? exprClass : Object.class, int.class));
}

@ -40,6 +40,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
abstract class ArrayBufferView extends ScriptObject {
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {

@ -382,6 +382,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private final Context context;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
/**

@ -119,6 +119,7 @@ public final class NativeError extends ScriptObject {
* Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided.
*
* @param self self reference
* @param errorObj the error object
* @return undefined
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@ -286,9 +287,9 @@ public final class NativeError extends ScriptObject {
final Object exception = ECMAException.getException(sobj);
if (exception instanceof Throwable) {
return getScriptStackString(sobj, (Throwable)exception);
} else {
return "";
}
return "";
}
/**

@ -48,6 +48,7 @@ public final class NativeFloat32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -48,6 +48,7 @@ public final class NativeFloat64Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 8;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.util.List;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@ -55,6 +56,7 @@ import jdk.nashorn.internal.runtime.Source;
public final class NativeFunction {
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
// do *not* create me!

@ -42,6 +42,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
public final class NativeInt16Array extends ArrayBufferView {
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
/**

@ -47,6 +47,7 @@ public final class NativeInt32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -47,6 +47,7 @@ public final class NativeInt8Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -32,6 +32,7 @@ import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.internal.objects.annotations.Attribute;
@ -54,6 +55,7 @@ import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
public final class NativeJava {
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private NativeJava() {

@ -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 jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@ -55,6 +54,7 @@ public final class NativeObject {
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private NativeObject() {

@ -68,6 +68,7 @@ public final class NativeRegExp extends ScriptObject {
private Global globalObject;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
NativeRegExp(final String input, final String flagString) {

@ -47,6 +47,7 @@ public final class NativeUint16Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 2;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -48,6 +48,7 @@ public final class NativeUint32Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 4;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -47,6 +47,7 @@ public final class NativeUint8Array extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -48,6 +48,7 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
public static final int BYTES_PER_ELEMENT = 1;
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {

@ -149,12 +149,13 @@ public class ScriptFunctionImpl extends ScriptFunction {
return typeErrorThrower;
}
private static PropertyMap createStrictModeMap(PropertyMap map) {
private static PropertyMap createStrictModeMap(final PropertyMap map) {
final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
PropertyMap newMap = map;
// Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
map = map.addProperty(map.newUserAccessors("arguments", flags));
map = map.addProperty(map.newUserAccessors("caller", flags));
return map;
newMap = newMap.addProperty(map.newUserAccessors("arguments", flags));
newMap = newMap.addProperty(map.newUserAccessors("caller", flags));
return newMap;
}
// Choose the map based on strict mode!

@ -146,7 +146,7 @@ final class ObjectArrayData extends ArrayData {
@Override
public ArrayData setEmpty(final long lo, final long hi) {
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, (long)Integer.MAX_VALUE), ScriptRuntime.EMPTY);
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
return this;
}

@ -0,0 +1,34 @@
/*
* Copyright (c) 2010, 2013, 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-8019585 - use before def issues with vars using the declared var
* legal - but needs to set "a" as undefined
*
* @test
* @run
*/
function f() {
var a = b == 17 && (a = toto(b)) && toto2(a);
}