aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/runtime/WithObject.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/WithObject.java')
-rw-r--r--src/jdk/nashorn/internal/runtime/WithObject.java113
1 files changed, 87 insertions, 26 deletions
diff --git a/src/jdk/nashorn/internal/runtime/WithObject.java b/src/jdk/nashorn/internal/runtime/WithObject.java
index dc48d727..20510dfd 100644
--- a/src/jdk/nashorn/internal/runtime/WithObject.java
+++ b/src/jdk/nashorn/internal/runtime/WithObject.java
@@ -35,6 +35,8 @@ import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
+import jdk.nashorn.api.scripting.AbstractJSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -64,7 +66,6 @@ public final class WithObject extends ScriptObject implements Scope {
this.expression = expression;
}
-
/**
* Delete a property based on a key.
* @param key Any valid JavaScript value.
@@ -98,11 +99,11 @@ public final class WithObject extends ScriptObject implements Scope {
final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
FindProperty find = null;
GuardedInvocation link = null;
- ScriptObject self = null;
+ ScriptObject self;
final boolean isNamedOperation;
final String name;
- if(desc.getNameTokenCount() > 2) {
+ if (desc.getNameTokenCount() > 2) {
isNamedOperation = true;
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
} else {
@@ -117,7 +118,6 @@ public final class WithObject extends ScriptObject implements Scope {
if (find != null) {
link = self.lookup(desc, request);
-
if (link != null) {
return fixExpressionCallSite(ndesc, link);
}
@@ -193,18 +193,33 @@ public final class WithObject extends ScriptObject implements Scope {
*
* @param key Property key.
* @param deep Whether the search should look up proto chain.
- * @param stopOnNonScope should a deep search stop on the first non-scope object?
* @param start the object on which the lookup was originally initiated
*
* @return FindPropertyData or null if not found.
*/
@Override
- FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) {
- final FindProperty exprProperty = expression.findProperty(key, deep, stopOnNonScope, start);
+ FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+ // We call findProperty on 'expression' with 'expression' itself as start parameter.
+ // This way in ScriptObject.setObject we can tell the property is from a 'with' expression
+ // (as opposed from another non-scope object in the proto chain such as Object.prototype).
+ final FindProperty exprProperty = expression.findProperty(key, true, expression);
if (exprProperty != null) {
return exprProperty;
}
- return super.findProperty(key, deep, stopOnNonScope, start);
+ return super.findProperty(key, deep, start);
+ }
+
+ @Override
+ protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+ FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
+ if (find != null) {
+ final Object func = find.getObjectValue();
+ if (func instanceof ScriptFunction) {
+ return ScriptRuntime.apply((ScriptFunction)func, expression, name);
+ }
+ }
+
+ return getProto().invokeNoSuchProperty(name, programPoint);
}
@Override
@@ -242,35 +257,65 @@ public final class WithObject extends ScriptObject implements Scope {
private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
// If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
// expression.
- if(!"getMethod".equals(desc.getFirstOperator())) {
+ if (!"getMethod".equals(desc.getFirstOperator())) {
return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
}
- final MethodHandle linkInvocation = link.getInvocation();
- final MethodType linkType = linkInvocation.type();
- final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
+ final MethodHandle linkInvocation = link.getInvocation();
+ final MethodType linkType = linkInvocation.type();
+ final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
+
return link.replaceMethods(
// Make sure getMethod will bind the script functions it receives to WithObject.expression
- MH.foldArguments(linkReturnsFunction ? BIND_TO_EXPRESSION_FN : BIND_TO_EXPRESSION_OBJ,
- filter(linkInvocation.asType(linkType.changeReturnType(
- linkReturnsFunction ? ScriptFunction.class : Object.class)), WITHEXPRESSIONFILTER)),
- // No clever things for the guard -- it is still identically filtered.
- filterGuard(link, WITHEXPRESSIONFILTER));
+ MH.foldArguments(
+ linkReturnsFunction ?
+ BIND_TO_EXPRESSION_FN :
+ BIND_TO_EXPRESSION_OBJ,
+ filterReceiver(
+ linkInvocation.asType(
+ linkType.changeReturnType(
+ linkReturnsFunction ?
+ ScriptFunction.class :
+ Object.class).
+ changeParameterType(
+ 0,
+ Object.class)),
+ WITHEXPRESSIONFILTER)),
+ filterGuardReceiver(link, WITHEXPRESSIONFILTER));
+ // No clever things for the guard -- it is still identically filtered.
+
}
private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name, final ScriptObject owner) {
- final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
- return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER),
- NashornGuards.combineGuards(expressionGuard(name, owner), filterGuard(newLink, WITHSCOPEFILTER)));
+ final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
+ final MethodHandle expressionGuard = expressionGuard(name, owner);
+ final MethodHandle filterGuardReceiver = filterGuardReceiver(newLink, WITHSCOPEFILTER);
+ return link.replaceMethods(
+ filterReceiver(
+ newLink.getInvocation(),
+ WITHSCOPEFILTER),
+ NashornGuards.combineGuards(
+ expressionGuard,
+ filterGuardReceiver));
}
- private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) {
+ private static MethodHandle filterGuardReceiver(final GuardedInvocation link, final MethodHandle receiverFilter) {
final MethodHandle test = link.getGuard();
- return test == null ? null : filter(test, filter);
+ if (test == null) {
+ return null;
+ }
+
+ final Class<?> receiverType = test.type().parameterType(0);
+ final MethodHandle filter = MH.asType(receiverFilter,
+ receiverFilter.type().changeParameterType(0, receiverType).
+ changeReturnType(receiverType));
+
+ return filterReceiver(test, filter);
}
- private static MethodHandle filter(final MethodHandle mh, final MethodHandle filter) {
- return MH.filterArguments(mh, 0, filter.asType(filter.type().changeReturnType(mh.type().parameterType(0))));
+ private static MethodHandle filterReceiver(final MethodHandle mh, final MethodHandle receiverFilter) {
+ //With expression filter == receiverFilter, i.e. receiver is cast to withobject and its expression returned
+ return MH.filterArguments(mh, 0, receiverFilter.asType(receiverFilter.type().changeReturnType(mh.type().parameterType(0))));
}
/**
@@ -284,11 +329,27 @@ public final class WithObject extends ScriptObject implements Scope {
@SuppressWarnings("unused")
private static Object bindToExpression(final Object fn, final Object receiver) {
- return fn instanceof ScriptFunction ? bindToExpression((ScriptFunction) fn, receiver) : fn;
+ if (fn instanceof ScriptFunction) {
+ return bindToExpression((ScriptFunction) fn, receiver);
+ } else if (fn instanceof ScriptObjectMirror) {
+ final ScriptObjectMirror mirror = (ScriptObjectMirror)fn;
+ if (mirror.isFunction()) {
+ // We need to make sure correct 'this' is used for calls with Ident call
+ // expressions. We do so here using an AbstractJSObject instance.
+ return new AbstractJSObject() {
+ @Override
+ public Object call(final Object thiz, final Object... args) {
+ return mirror.call(withFilterExpression(receiver), args);
+ }
+ };
+ }
+ }
+
+ return fn;
}
private static Object bindToExpression(final ScriptFunction fn, final Object receiver) {
- return fn.makeBoundFunction(withFilterExpression(receiver), new Object[0]);
+ return fn.makeBoundFunction(withFilterExpression(receiver), ScriptRuntime.EMPTY_ARRAY);
}
private MethodHandle expressionGuard(final String name, final ScriptObject owner) {