8160034: The this
value in the with
is broken by the repetition of a function call
Reviewed-by: attila, sundar
This commit is contained in:
parent
2faec59457
commit
baad0ee85d
@ -3057,6 +3057,7 @@ public final class Global extends Scope {
|
||||
|
||||
LexicalScope(final Global global) {
|
||||
super(global, PropertyMap.newMap());
|
||||
setIsInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,6 +123,9 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
|
||||
/** Is this a builtin object? */
|
||||
public static final int IS_BUILTIN = 1 << 3;
|
||||
|
||||
/** Is this an internal object that should not be visible to scripts? */
|
||||
public static final int IS_INTERNAL = 1 << 4;
|
||||
|
||||
/**
|
||||
* Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
|
||||
* {@link ScriptObject#objectSpill} when full
|
||||
@ -1667,6 +1670,21 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
|
||||
return (flags & IS_BUILTIN) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag this script object as internal object that should not be visible to script code.
|
||||
*/
|
||||
public final void setIsInternal() {
|
||||
flags |= IS_INTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this script object is an internal object that should not be visible to script code.
|
||||
* @return true if internal
|
||||
*/
|
||||
public final boolean isInternal() {
|
||||
return (flags & IS_INTERNAL) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the properties from a ScriptObject
|
||||
* (java.util.Map-like method to help ScriptObjectMirror implementation)
|
||||
@ -2045,7 +2063,13 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
|
||||
private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
|
||||
final FindProperty find = findProperty(key, true, isScope, this);
|
||||
if (find != null) {
|
||||
return find.getObjectValue();
|
||||
// If this is a method invocation, and found property has a different self object then this,
|
||||
// then return a function bound to the self object. This is the case for functions in with expressions.
|
||||
final Object value = find.getObjectValue();
|
||||
if (isMethod && value instanceof ScriptFunction && find.getSelf() != this && !find.getSelf().isInternal()) {
|
||||
return ((ScriptFunction) value).createBound(find.getSelf(), ScriptRuntime.EMPTY_ARRAY);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
return isMethod ? getNoSuchMethod(key, isScope, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, isScope, INVALID_PROGRAM_POINT);
|
||||
|
@ -66,6 +66,7 @@ public final class WithObject extends Scope {
|
||||
WithObject(final ScriptObject scope, final ScriptObject expression) {
|
||||
super(scope, null);
|
||||
this.expression = expression;
|
||||
setIsInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,37 +100,23 @@ public final class WithObject extends Scope {
|
||||
// With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
|
||||
// necessity have a Nashorn descriptor - it is safe to cast.
|
||||
final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
|
||||
FindProperty find = null;
|
||||
GuardedInvocation link = null;
|
||||
ScriptObject self;
|
||||
|
||||
final boolean isNamedOperation;
|
||||
final String name;
|
||||
final Operation op = desc.getOperation();
|
||||
if (op instanceof NamedOperation) {
|
||||
isNamedOperation = true;
|
||||
name = ((NamedOperation)op).getName().toString();
|
||||
} else {
|
||||
isNamedOperation = false;
|
||||
name = null;
|
||||
}
|
||||
|
||||
self = expression;
|
||||
if (isNamedOperation) {
|
||||
find = self.findProperty(name, true);
|
||||
}
|
||||
assert op instanceof NamedOperation; // WithObject is a scope object, access is always named
|
||||
final String name = ((NamedOperation)op).getName().toString();
|
||||
|
||||
FindProperty find = expression.findProperty(name, true);
|
||||
|
||||
if (find != null) {
|
||||
link = self.lookup(desc, request);
|
||||
link = expression.lookup(desc, request);
|
||||
if (link != null) {
|
||||
return fixExpressionCallSite(ndesc, link);
|
||||
}
|
||||
}
|
||||
|
||||
final ScriptObject scope = getProto();
|
||||
if (isNamedOperation) {
|
||||
find = scope.findProperty(name, true);
|
||||
}
|
||||
find = scope.findProperty(name, true);
|
||||
|
||||
if (find != null) {
|
||||
return fixScopeCallSite(scope.lookup(desc, request), name, find.getOwner());
|
||||
@ -137,43 +124,41 @@ public final class WithObject extends Scope {
|
||||
|
||||
// the property is not found - now check for
|
||||
// __noSuchProperty__ and __noSuchMethod__ in expression
|
||||
if (self != null) {
|
||||
final String fallBack;
|
||||
final String fallBack;
|
||||
|
||||
final StandardOperation firstOp = ndesc.getFirstOperation();
|
||||
switch (firstOp) {
|
||||
case GET_METHOD:
|
||||
fallBack = NO_SUCH_METHOD_NAME;
|
||||
break;
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT:
|
||||
fallBack = NO_SUCH_PROPERTY_NAME;
|
||||
break;
|
||||
default:
|
||||
fallBack = null;
|
||||
break;
|
||||
}
|
||||
final StandardOperation firstOp = ndesc.getFirstOperation();
|
||||
switch (firstOp) {
|
||||
case GET_METHOD:
|
||||
fallBack = NO_SUCH_METHOD_NAME;
|
||||
break;
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT:
|
||||
fallBack = NO_SUCH_PROPERTY_NAME;
|
||||
break;
|
||||
default:
|
||||
fallBack = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fallBack != null) {
|
||||
find = self.findProperty(fallBack, true);
|
||||
if (find != null) {
|
||||
switch (firstOp) {
|
||||
case GET_METHOD:
|
||||
link = self.noSuchMethod(desc, request);
|
||||
break;
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT:
|
||||
link = self.noSuchProperty(desc, request);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (fallBack != null) {
|
||||
find = expression.findProperty(fallBack, true);
|
||||
if (find != null) {
|
||||
switch (firstOp) {
|
||||
case GET_METHOD:
|
||||
link = expression.noSuchMethod(desc, request);
|
||||
break;
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT:
|
||||
link = expression.noSuchProperty(desc, request);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (link != null) {
|
||||
return fixExpressionCallSite(ndesc, link);
|
||||
}
|
||||
if (link != null) {
|
||||
return fixExpressionCallSite(ndesc, link);
|
||||
}
|
||||
|
||||
// still not found, may be scope can handle with it's own
|
||||
@ -204,7 +189,7 @@ public final class WithObject extends Scope {
|
||||
// (as opposed from another non-scope object in the proto chain such as Object.prototype).
|
||||
final FindProperty exprProperty = expression.findProperty(key, true, false, expression);
|
||||
if (exprProperty != null) {
|
||||
return exprProperty;
|
||||
return exprProperty;
|
||||
}
|
||||
return super.findProperty(key, deep, isScope, start);
|
||||
}
|
||||
@ -295,14 +280,14 @@ public final class WithObject extends Scope {
|
||||
private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name, final ScriptObject owner) {
|
||||
final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
|
||||
final MethodHandle expressionGuard = expressionGuard(name, owner);
|
||||
final MethodHandle filterGuardReceiver = filterGuardReceiver(newLink, WITHSCOPEFILTER);
|
||||
final MethodHandle filteredGuard = filterGuardReceiver(newLink, WITHSCOPEFILTER);
|
||||
return link.replaceMethods(
|
||||
filterReceiver(
|
||||
newLink.getInvocation(),
|
||||
WITHSCOPEFILTER),
|
||||
NashornGuards.combineGuards(
|
||||
expressionGuard,
|
||||
filterGuardReceiver));
|
||||
filteredGuard));
|
||||
}
|
||||
|
||||
private static MethodHandle filterGuardReceiver(final GuardedInvocation link, final MethodHandle receiverFilter) {
|
||||
|
@ -140,7 +140,7 @@ public final class NashornGuards {
|
||||
if (!needsGuard(property, desc)) {
|
||||
return null;
|
||||
}
|
||||
if (NashornCallSiteDescriptor.isScope(desc)) {
|
||||
if (NashornCallSiteDescriptor.isScope(desc) && sobj.isScope()) {
|
||||
if (property != null && property.isBound() && !property.canChangeType()) {
|
||||
// This is a declared top level variables in main script or eval, use identity guard.
|
||||
return getIdentityGuard(sobj);
|
||||
|
69
nashorn/test/script/basic/JDK-8160034.js
Normal file
69
nashorn/test/script/basic/JDK-8160034.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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-8160034.js: The `this` value in the `with` is broken by the repetition of a function call
|
||||
*
|
||||
* @test
|
||||
* @option --unstable-relink-threshold=4
|
||||
* @run
|
||||
*/
|
||||
|
||||
|
||||
var bar = "BAR";
|
||||
|
||||
function Foo() {
|
||||
this.bar = "bar";
|
||||
this.baz = "baz";
|
||||
}
|
||||
|
||||
function foo_proto_h() {
|
||||
print(this.bar);
|
||||
delete Foo.prototype._h;
|
||||
}
|
||||
|
||||
function foo_proto_e() {
|
||||
print(this.baz);
|
||||
}
|
||||
|
||||
function _h() {
|
||||
print(this.bar);
|
||||
Foo.prototype._h = foo_proto_h;
|
||||
}
|
||||
|
||||
Foo.prototype._e = foo_proto_e;
|
||||
Foo.prototype._h = foo_proto_h;
|
||||
|
||||
|
||||
var fn = new Function("with(this) { _h(); _e(); }");
|
||||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
fn.call(new Foo());
|
||||
}
|
||||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
foo = new Foo();
|
||||
foo['e' + Math.random()] = 1; // force new map
|
||||
fn.call(foo);
|
||||
}
|
||||
|
80
nashorn/test/script/basic/JDK-8160034.js.EXPECTED
Normal file
80
nashorn/test/script/basic/JDK-8160034.js.EXPECTED
Normal file
@ -0,0 +1,80 @@
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
||||
bar
|
||||
baz
|
||||
BAR
|
||||
baz
|
Loading…
Reference in New Issue
Block a user