8170565: JSObject call() is passed undefined for the argument 'thiz'

Reviewed-by: hannesw, jlaskey, attila
This commit is contained in:
Athijegannathan Sundararajan 2016-12-01 18:53:51 +05:30
parent 7fe5109735
commit fa4bdd39c5
2 changed files with 58 additions and 2 deletions

View File

@ -40,9 +40,13 @@ import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.LinkerServices;
import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.objects.Global;
/**
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
@ -142,9 +146,9 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
}
private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
MethodHandle mh = JSOBJECT_CALL;
MethodHandle mh = NashornCallSiteDescriptor.isScope(desc)? JSOBJECT_SCOPE_CALL : JSOBJECT_CALL;
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, mh);
}
final MethodType type = desc.getMethodType();
mh = type.parameterType(type.parameterCount() - 1) == Object[].class ?
@ -215,6 +219,19 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
}
}
// This is used when a JSObject is called as scope call to do undefined -> Global this translation.
@SuppressWarnings("unused")
private static Object jsObjectScopeCall(final JSObject jsObj, final Object thiz, final Object[] args) {
final Object modifiedThiz;
if (thiz == ScriptRuntime.UNDEFINED && !jsObj.isStrictFunction()) {
final Global global = Context.getGlobal();
modifiedThiz = ScriptObjectMirror.wrap(global, global);
} else {
modifiedThiz = thiz;
}
return jsObj.call(modifiedThiz, args);
}
private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
// method handles of the current class
@ -226,6 +243,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
private static final MethodHandle JSOBJECT_GETMEMBER = findJSObjectMH_V("getMember", Object.class, String.class);
private static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
private static final MethodHandle JSOBJECT_CALL = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_SCOPE_CALL = findOwnMH_S("jsObjectScopeCall", Object.class, JSObject.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_NEW = findJSObjectMH_V("newObject", Object.class, Object[].class);

View File

@ -41,6 +41,7 @@ import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.testng.annotations.Test;
@ -389,4 +390,41 @@ public class ScriptObjectMirrorTest {
assertTrue(func.isFunction());
assertEquals(func.call(e.eval("this"), "hello"), "hello world");
}
// @bug 8170565: JSObject call() is passed undefined for the argument 'thiz'
@Test
public void jsObjectThisTest() throws Exception {
final ScriptEngineManager engineManager = new ScriptEngineManager();
final ScriptEngine e = engineManager.getEngineByName("nashorn");
e.put("func", new AbstractJSObject() {
@Override
public boolean isFunction() { return true; }
@Override
public Object call(Object thiz, Object...args) {
return thiz;
}
});
assertTrue((boolean)e.eval("func() === this"));
// check that there is no blind undefined->Global translation!
assertTrue((boolean)e.eval("typeof(Function.prototype.call.call(func, undefined)) == 'undefined'"));
// make sure that strict functions don't get translated this for scope calls!
e.put("sfunc", new AbstractJSObject() {
@Override
public boolean isFunction() { return true; }
@Override
public boolean isStrictFunction() { return true; }
@Override
public Object call(Object thiz, Object...args) {
return thiz;
}
});
assertTrue((boolean)e.eval("typeof sfunc() == 'undefined'"));
}
}