зеркало из https://github.com/mozilla/rhino.git
make sure, equivalentValues is used if available
This commit is contained in:
Родитель
59eb197681
Коммит
740299852f
|
@ -3737,7 +3737,15 @@ public class ScriptRuntime {
|
|||
if (isSymbol(y) && isObject(x)) {
|
||||
return eq(toPrimitive(x), y);
|
||||
}
|
||||
if (y instanceof Scriptable) {
|
||||
if (y == null || Undefined.isUndefined(y)) {
|
||||
if (x instanceof ScriptableObject) {
|
||||
Object test = ((ScriptableObject) x).equivalentValues(y);
|
||||
if (test != Scriptable.NOT_FOUND) {
|
||||
return ((Boolean) test).booleanValue();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (y instanceof Scriptable) {
|
||||
if (x instanceof ScriptableObject) {
|
||||
Object test = ((ScriptableObject) x).equivalentValues(y);
|
||||
if (test != Scriptable.NOT_FOUND) {
|
||||
|
|
|
@ -3934,34 +3934,18 @@ class BodyCodegen {
|
|||
int type = node.getType();
|
||||
Node rChild = child.getNext();
|
||||
|
||||
// Optimize if one of operands is null
|
||||
if (child.getType() == Token.NULL || rChild.getType() == Token.NULL) {
|
||||
// Optimize if one of operands is null; but we can't do this
|
||||
// for EQ/NEQ because a ScripableObject might overwrite equivalentValues()
|
||||
if (type != Token.EQ
|
||||
&& type != Token.NE
|
||||
&& (child.getType() == Token.NULL || rChild.getType() == Token.NULL)) {
|
||||
// eq is symmetric in this case
|
||||
if (child.getType() == Token.NULL) {
|
||||
child = rChild;
|
||||
}
|
||||
generateExpression(child, node);
|
||||
if (type == Token.SHEQ || type == Token.SHNE) {
|
||||
int testCode = (type == Token.SHEQ) ? ByteCode.IFNULL : ByteCode.IFNONNULL;
|
||||
cfw.add(testCode, trueGOTO);
|
||||
} else {
|
||||
if (type != Token.EQ) {
|
||||
// swap false/true targets for !=
|
||||
if (type != Token.NE) throw Codegen.badTree();
|
||||
int tmp = trueGOTO;
|
||||
trueGOTO = falseGOTO;
|
||||
falseGOTO = tmp;
|
||||
}
|
||||
cfw.add(ByteCode.DUP);
|
||||
int undefCheckLabel = cfw.acquireLabel();
|
||||
cfw.add(ByteCode.IFNONNULL, undefCheckLabel);
|
||||
int stack = cfw.getStackTop();
|
||||
cfw.add(ByteCode.POP);
|
||||
cfw.add(ByteCode.GOTO, trueGOTO);
|
||||
cfw.markLabel(undefCheckLabel, stack);
|
||||
Codegen.pushUndefined(cfw);
|
||||
cfw.add(ByteCode.IF_ACMPEQ, trueGOTO);
|
||||
}
|
||||
int testCode = (type == Token.SHEQ) ? ByteCode.IFNULL : ByteCode.IFNONNULL;
|
||||
cfw.add(testCode, trueGOTO);
|
||||
cfw.add(ByteCode.GOTO, falseGOTO);
|
||||
} else {
|
||||
int child_dcp_register = nodeIsDirectCallParameter(child);
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package org.mozilla.javascript.tests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mozilla.javascript.*;
|
||||
import org.mozilla.javascript.annotations.JSConstructor;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link ScriptRuntime} support for ScriptableObject#equivalentValues(Object)
|
||||
* method.
|
||||
*
|
||||
* @author Ronald Brill
|
||||
*/
|
||||
public class ScriptRuntimeEquivalentValuesTest {
|
||||
|
||||
@Test
|
||||
public void equivalentValuesUndefined() throws Exception {
|
||||
Utils.runWithAllOptimizationLevels(
|
||||
cx -> {
|
||||
final Scriptable scope = cx.initStandardObjects();
|
||||
try {
|
||||
ScriptableObject.defineClass(scope, EquivalentTesterObject.class);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
Object result =
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"var o = new EquivalentTesterObject();"
|
||||
+ "'' + (o == undefined) + ' ' + (undefined == o)",
|
||||
"test",
|
||||
1,
|
||||
null);
|
||||
assertEquals("" + cx.getOptimizationLevel(), "true true", result);
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equivalentValuesNull() throws Exception {
|
||||
Utils.runWithAllOptimizationLevels(
|
||||
cx -> {
|
||||
final Scriptable scope = cx.initStandardObjects();
|
||||
try {
|
||||
ScriptableObject.defineClass(scope, EquivalentTesterObject.class);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
Object result =
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"var o = new EquivalentTesterObject();"
|
||||
+ "'' + (o == null) + ' ' + (null == o)",
|
||||
"test",
|
||||
1,
|
||||
null);
|
||||
assertEquals("" + cx.getOptimizationLevel(), "true true", result);
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static class EquivalentTesterObject extends ScriptableObject {
|
||||
|
||||
public EquivalentTesterObject() {}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return "EquivalentTesterObject";
|
||||
}
|
||||
|
||||
@JSConstructor
|
||||
public void jsConstructorMethod() {}
|
||||
|
||||
@Override
|
||||
protected Object equivalentValues(final Object value) {
|
||||
if (value == null || Undefined.isUndefined(value)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
return super.equivalentValues(value);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче