Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add INDY ops for math operations #1711

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ private void generateExpression(Node node, Node parent) {
{
generateExpression(child, node);
cfw.add(ByteCode.DUP);
addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
addDynamicInvoke("MATH:TOBOOLEAN", Signatures.MATH_TO_BOOLEAN);
int falseTarget = cfw.acquireLabel();
if (type == Token.AND) cfw.add(ByteCode.IFEQ, falseTarget);
else cfw.add(ByteCode.IFNE, falseTarget);
Expand All @@ -1210,7 +1210,7 @@ private void generateExpression(Node node, Node parent) {
Node ifThen = child.getNext();
Node ifElse = ifThen.getNext();
generateExpression(child, node);
addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
addDynamicInvoke("MATH:TOBOOLEAN", Signatures.MATH_TO_BOOLEAN);
int elseTarget = cfw.acquireLabel();
cfw.add(ByteCode.IFEQ, elseTarget);
int stack = cfw.getStackTop();
Expand Down Expand Up @@ -1245,12 +1245,7 @@ private void generateExpression(Node node, Node parent) {
break;
default:
cfw.addALoad(contextLocal);
addScriptRuntimeInvoke(
"add",
"(Ljava/lang/Object;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("MATH:ADD", Signatures.MATH_ADD);
}
}
break;
Expand Down Expand Up @@ -1928,7 +1923,7 @@ private void generateIfJump(Node node, Node parent, int trueLabel, int falseLabe
default:
// Generate generic code for non-optimized jump
generateExpression(node, parent);
addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
addDynamicInvoke("MATH:TOBOOLEAN", Signatures.MATH_TO_BOOLEAN);
cfw.add(ByteCode.IFNE, trueLabel);
cfw.add(ByteCode.GOTO, falseLabel);
}
Expand Down Expand Up @@ -2433,18 +2428,11 @@ private void visitStandardCall(Node node, Node child) {
// there are no checks for it
String name = child.getString();
if (isOptionalChainingCall) { // name?.()
// eval name and this and push name on stack
cfw.addPush(name);
cfw.addALoad(contextLocal);
// eval name and this and put name in dynamic signature just like
// with "GETWITHTHIS".
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getNameFunctionAndThisOptional",
""
+ "("
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Lorg/mozilla/javascript/Callable;");
cfw.addALoad(contextLocal);
addDynamicInvoke("NAME:GETWITHTHISOPTIONAL:" + name, Signatures.NAME_GET_THIS);

// jump to afterLabel is name is not null and not undefined
afterLabel = cfw.acquireLabel();
Expand Down Expand Up @@ -3373,8 +3361,7 @@ private void visitSwitch(Jump switchNode, Node child) {
Node test = caseNode.getFirstChild();
generateExpression(test, caseNode);
cfw.addALoad(selector);
addScriptRuntimeInvoke(
"shallowEq", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + ")Z");
addDynamicInvoke("MATH:SHALLOWEQ", Signatures.MATH_SHALLOW_EQ);
addGoto(caseNode.target, ByteCode.IFNE);
}
releaseWordLocal(selector);
Expand Down Expand Up @@ -3719,9 +3706,9 @@ private void visitBitOp(Node node, int type, Node child) {
// that we can return a 32-bit unsigned value, and call
// toUint32 instead of toInt32.
if (type == Token.URSH) {
addScriptRuntimeInvoke("toUint32", "(Ljava/lang/Object;)J");
addDynamicInvoke("MATH:TOUINT32", Signatures.MATH_TO_UINT32);
generateExpression(child.getNext(), node);
addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
addDynamicInvoke("MATH:TOINT32", Signatures.MATH_TO_INT32);
// Looks like we need to explicitly mask the shift to 5 bits -
// LUSHR takes 6 bits.
cfw.addPush(31);
Expand Down Expand Up @@ -3916,8 +3903,25 @@ private void visitIfJumpRelOp(Node node, Node child, int trueGOTO, int falseGOTO
generateExpression(rChild, node);
}

cfw.addPush(type);
addScriptRuntimeInvoke("compare", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "I)Z");
String compareOp;
switch (type) {
case Token.GT:
compareOp = "MATH:COMPAREGT";
break;
case Token.LT:
compareOp = "MATH:COMPARELT";
break;
case Token.GE:
compareOp = "MATH:COMPAREGE";
break;
case Token.LE:
compareOp = "MATH:COMPARELE";
break;
default:
throw Kit.codeBug();
}

addDynamicInvoke(compareOp, Signatures.MATH_COMPARE);
cfw.add(ByteCode.IFNE, trueGOTO);
cfw.add(ByteCode.GOTO, falseGOTO);
}
Expand Down Expand Up @@ -3986,25 +3990,25 @@ private void visitIfJumpEqOp(Node node, Node child, int trueGOTO, int falseGOTO)
int testCode;
switch (type) {
case Token.EQ:
name = "eq";
name = "MATH:EQ";
testCode = ByteCode.IFNE;
break;
case Token.NE:
name = "eq";
name = "MATH:EQ";
testCode = ByteCode.IFEQ;
break;
case Token.SHEQ:
name = "shallowEq";
name = "MATH:SHALLOWEQ";
testCode = ByteCode.IFNE;
break;
case Token.SHNE:
name = "shallowEq";
name = "MATH:SHALLOWEQ";
testCode = ByteCode.IFEQ;
break;
default:
throw Codegen.badTree();
}
addScriptRuntimeInvoke(name, "(Ljava/lang/Object;" + "Ljava/lang/Object;" + ")Z");
addDynamicInvoke(name, Signatures.MATH_EQ);
cfw.add(testCode, trueGOTO);
cfw.add(ByteCode.GOTO, falseGOTO);
}
Expand Down Expand Up @@ -4269,7 +4273,7 @@ private void visitDotQuery(Node node, Node child) {
cfw.add(ByteCode.POP);

generateExpression(child.getNext(), node);
addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
addDynamicInvoke("MATH:TOBOOLEAN", Signatures.MATH_TO_BOOLEAN);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"updateDotQuery",
Expand Down Expand Up @@ -4326,11 +4330,11 @@ private void addGoto(Node target, int jumpcode) {
}

private void addObjectToDouble() {
addScriptRuntimeInvoke("toNumber", "(Ljava/lang/Object;)D");
addDynamicInvoke("MATH:TONUMBER", Signatures.MATH_TO_NUMBER);
}

private void addObjectToNumeric() {
addScriptRuntimeInvoke("toNumeric", "(Ljava/lang/Object;)Ljava/lang/Number;");
addDynamicInvoke("MATH:TONUMERIC", Signatures.MATH_TO_NUMERIC);
}

private void addNewObjectArray(int size) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,20 @@ public class Bootstrapper {
private static final DynamicLinker linker;

static {
// Set up the linkers that will be invoked whenever a call site needs to be resolved.
// Set up the linkers
DynamicLinkerFactory factory = new DynamicLinkerFactory();
// The const-aware-linker will only bind a few operations, and everything
// else will fall back to the default linker, which will always bind.
factory.setPrioritizedLinkers(new ConstAwareLinker(), new DefaultLinker());
linker = factory.createLinker();
}

/** This is the method called by every call site in the bytecode to map it to a function. */
@SuppressWarnings("unused")
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType mType)
throws NoSuchMethodException, IllegalAccessException {
throws NoSuchMethodException {
Operation op = parseOperation(name);
// For now, use a very simple call site.
// ChainedCallSite lets a call site have a few options for complex situations
return linker.link(new ChainedCallSite(new CallSiteDescriptor(lookup, op, mType)));
}

Expand Down Expand Up @@ -137,6 +139,34 @@ private static Operation parseOperation(String name) throws NoSuchMethodExceptio
.withNamespace(RhinoNamespace.NAME)
.named(getNameSegment(tokens, name, 2));
}

} else if ("MATH".equals(namespaceName)) {
switch (opName) {
case "ADD":
return RhinoOperation.ADD.withNamespace(RhinoNamespace.MATH);
case "TOBOOLEAN":
return RhinoOperation.TOBOOLEAN.withNamespace(RhinoNamespace.MATH);
case "TOINT32":
return RhinoOperation.TOINT32.withNamespace(RhinoNamespace.MATH);
case "TOUINT32":
return RhinoOperation.TOUINT32.withNamespace(RhinoNamespace.MATH);
case "EQ":
return RhinoOperation.EQ.withNamespace(RhinoNamespace.MATH);
case "SHALLOWEQ":
return RhinoOperation.SHALLOWEQ.withNamespace(RhinoNamespace.MATH);
case "TONUMBER":
return RhinoOperation.TONUMBER.withNamespace(RhinoNamespace.MATH);
case "TONUMERIC":
return RhinoOperation.TONUMERIC.withNamespace(RhinoNamespace.MATH);
case "COMPAREGT":
return RhinoOperation.COMPARE_GT.withNamespace(RhinoNamespace.MATH);
case "COMPARELT":
return RhinoOperation.COMPARE_LT.withNamespace(RhinoNamespace.MATH);
case "COMPAREGE":
return RhinoOperation.COMPARE_GE.withNamespace(RhinoNamespace.MATH);
case "COMPARELE":
return RhinoOperation.COMPARE_LE.withNamespace(RhinoNamespace.MATH);
}
}

// Fall through to no match. This should only happen if the name in the bytecode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
Expand All @@ -20,29 +17,19 @@
@SuppressWarnings("AndroidJdkLibsChecker")
class ConstAwareLinker implements GuardingDynamicLinker {
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest req, LinkerServices svc)
throws Exception {
public GuardedInvocation getGuardedInvocation(LinkRequest req, LinkerServices svc) {
if (req.isCallSiteUnstable()) {
if (DefaultLinker.DEBUG) {
System.out.println(
req.getCallSiteDescriptor().getOperation() + ": unstable call site");
}
return null;
}

MethodHandles.Lookup lookup = MethodHandles.lookup();
Operation rootOp = req.getCallSiteDescriptor().getOperation();
MethodType mType = req.getCallSiteDescriptor().getMethodType();
String name = DefaultLinker.getName(rootOp);
Operation op = NamedOperation.getBaseOperation(rootOp);
ParsedOperation op = new ParsedOperation(req.getCallSiteDescriptor().getOperation());
Object target = req.getReceiver();

if (NamespaceOperation.contains(op, StandardOperation.GET, RhinoNamespace.NAME)
|| NamespaceOperation.contains(
op, StandardOperation.GET, StandardNamespace.PROPERTY)
|| NamespaceOperation.contains(
op, RhinoOperation.GETNOWARN, StandardNamespace.PROPERTY)) {
Object constValue = getConstValue(target, name);
if ((op.isNamespace(RhinoNamespace.NAME) && op.isOperation(StandardOperation.GET))
|| (op.isNamespace(StandardNamespace.PROPERTY)
&& op.isOperation(StandardOperation.GET, RhinoOperation.GETNOWARN))) {
Object constValue = getConstValue(target, op.getName());
if (constValue != null) {
// The guard returns boolean and compares the first argument to the
// target here. This works because the target is always our first argument.
Expand All @@ -55,7 +42,7 @@ public GuardedInvocation getGuardedInvocation(LinkRequest req, LinkerServices sv
0,
mType.parameterList());
if (DefaultLinker.DEBUG) {
System.out.println(rootOp + " constant");
System.out.println(op + ": constant");
}
return new GuardedInvocation(mh, guard);
}
Expand Down
Loading
Loading