Skip to content

Commit

Permalink
Begin to use invokedynamic in the bytecode (#1645)
Browse files Browse the repository at this point in the history
This replaces some of the key operations on object properties and on names with invokedynamic scopes. Each call site is resolved using the "jdk.dynalink" package. Right now there is only a single linker, so all operations are linked to the same ScriptRuntime operations that were previously invoked directly from the bytecode, but this will gradually change as we find opportunities to optimize the code more.
  • Loading branch information
gbrail authored Oct 5, 2024
1 parent 7eac09a commit 776fdb3
Show file tree
Hide file tree
Showing 7 changed files with 573 additions and 182 deletions.
1 change: 1 addition & 0 deletions rhino/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
exports org.mozilla.javascript.xml;

requires java.compiler;
requires jdk.dynalink;
requires transitive java.desktop;
}
217 changes: 35 additions & 182 deletions rhino/src/main/java/org/mozilla/javascript/optimizer/BodyCodegen.java
Original file line number Diff line number Diff line change
Expand Up @@ -984,15 +984,9 @@ private void generateExpression(Node node, Node parent) {

case Token.NAME:
{
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(node.getString());
addScriptRuntimeInvoke(
"name",
"(Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ ")Ljava/lang/Object;");
cfw.addALoad(contextLocal);
addDynamicInvoke("NAME:GET:" + node.getString(), Signatures.NAME_GET);
}
break;

Expand Down Expand Up @@ -1368,21 +1362,11 @@ private void generateExpression(Node node, Node parent) {
generateExpression(child, node); // object
generateExpression(child.getNext(), node); // id
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
addScriptRuntimeInvoke(
"getObjectIndex",
"(Ljava/lang/Object;D"
+ "Lorg/mozilla/javascript/Context;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GETINDEX", Signatures.PROP_GET_INDEX);
} else {
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectElem",
"(Ljava/lang/Object;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GETELEMENT", Signatures.PROP_GET_ELEMENT);
}
break;

Expand Down Expand Up @@ -1489,15 +1473,9 @@ private void generateExpression(Node node, Node parent) {
child = child.getNext();
}
// Generate code for "ScriptRuntime.bind(varObj, "s")"
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(node.getString());
addScriptRuntimeInvoke(
"bind",
"(Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ ")Lorg/mozilla/javascript/Scriptable;");
cfw.addALoad(contextLocal);
addDynamicInvoke("NAME:BIND:" + node.getString(), Signatures.NAME_BIND);
}
break;

Expand Down Expand Up @@ -1686,14 +1664,11 @@ private void generateYieldPoint(Node node, boolean exprContext) {
if (unnestedYields.containsKey(node)) {
// Yield was previously moved up via the "nestedYield" code below.
if (exprContext) {
String name = unnestedYields.get(node);
cfw.addALoad(variableObjectLocal);
cfw.addLoadConstant(unnestedYields.get(node));
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectPropNoWarn",
"(Ljava/lang/Object;Ljava/lang/String;Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;)Ljava/lang/Object;");
addDynamicInvoke("PROP:GETNOWARN:" + name, Signatures.PROP_GET_NOWARN);
}
return;
}
Expand All @@ -1711,14 +1686,9 @@ private void generateYieldPoint(Node node, boolean exprContext) {
unnestedYieldCount++;
cfw.addALoad(variableObjectLocal);
cfw.add(ByteCode.SWAP);
cfw.addLoadConstant(nn);
cfw.add(ByteCode.SWAP);
cfw.addALoad(contextLocal);

addScriptRuntimeInvoke(
"setObjectProp",
"(Lorg/mozilla/javascript/Scriptable;Ljava/lang/String;Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;)Ljava/lang/Object;");
cfw.addALoad(variableObjectLocal);
addDynamicInvoke("PROP:SET:" + nn, Signatures.PROP_SET);
cfw.add(ByteCode.POP);

unnestedYields.put(nestedYield, nn);
Expand Down Expand Up @@ -2652,16 +2622,9 @@ private void generateFunctionAndThisObj(Node node, Node parent) {
Node id = target.getNext();
if (type == Token.GETPROP) {
String property = id.getString();
cfw.addPush(property);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getPropFunctionAndThis",
"(Ljava/lang/Object;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Lorg/mozilla/javascript/Callable;");
addDynamicInvoke("PROP:GETWITHTHIS:" + property, Signatures.PROP_GET_THIS);
} else {
generateExpression(id, node); // id
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) addDoubleWrap();
Expand All @@ -2681,15 +2644,9 @@ private void generateFunctionAndThisObj(Node node, Node parent) {
case Token.NAME:
{
String name = node.getString();
cfw.addPush(name);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getNameFunctionAndThis",
"(Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Lorg/mozilla/javascript/Callable;");
cfw.addALoad(contextLocal);
addDynamicInvoke("NAME:GETWITHTHIS:" + name, Signatures.NAME_GET_THIS);
break;
}

Expand Down Expand Up @@ -3895,15 +3852,7 @@ private void visitSetName(Node node, Node child) {
}
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(name);
addScriptRuntimeInvoke(
"setName",
"(Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("NAME:SET:" + name, Signatures.NAME_SET);
}

private void visitStrictSetName(Node node, Node child) {
Expand All @@ -3914,15 +3863,7 @@ private void visitStrictSetName(Node node, Node child) {
}
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(name);
addScriptRuntimeInvoke(
"strictSetName",
"(Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("NAME:SETSTRICT:" + name, Signatures.NAME_SET_STRICT);
}

private void visitSetConst(Node node, Node child) {
Expand All @@ -3932,14 +3873,7 @@ private void visitSetConst(Node node, Node child) {
child = child.getNext();
}
cfw.addALoad(contextLocal);
cfw.addPush(name);
addScriptRuntimeInvoke(
"setConst",
"(Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Ljava/lang/String;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("NAME:SETCONST:" + name, Signatures.NAME_SET_CONST);
}

private void visitGetVar(Node node) {
Expand Down Expand Up @@ -4060,42 +3994,13 @@ private void visitSetConstVar(Node node, Node child, boolean needValue) {
private void visitGetProp(Node node, Node child) {
generateExpression(child, node); // object
Node nameChild = child.getNext();
generateExpression(nameChild, node); // the name
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);

if (node.getType() == Token.GETPROPNOWARN) {
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectPropNoWarn",
"(Ljava/lang/Object;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
return;
}
/*
for 'this.foo' we call getObjectProp(Scriptable...) which can
skip some casting overhead.
*/
int childType = child.getType();
if (childType == Token.THIS && nameChild.getType() == Token.STRING) {
cfw.addALoad(contextLocal);
addScriptRuntimeInvoke(
"getObjectProp",
"(Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GETNOWARN:" + nameChild.getString(), Signatures.PROP_GET_NOWARN);
} else {
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectProp",
"(Ljava/lang/Object;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GET:" + nameChild.getString(), Signatures.PROP_GET);
}
}

Expand Down Expand Up @@ -4130,51 +4035,20 @@ private void visitGetPropOptional(Node node, Node child) {
}

private void visitSetProp(int type, Node node, Node child) {
Node objectChild = child;
generateExpression(child, node);
child = child.getNext();
Node nameChild = child;
if (type == Token.SETPROP_OP) {
cfw.add(ByteCode.DUP);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addDynamicInvoke("PROP:GET:" + nameChild.getString(), Signatures.PROP_GET);
}
Node nameChild = child;
generateExpression(child, node);
child = child.getNext();
if (type == Token.SETPROP_OP) {
// stack: ... object object name -> ... object name object name
cfw.add(ByteCode.DUP_X1);
// for 'this.foo += ...' we call thisGet which can skip some
// casting overhead.
if (objectChild.getType() == Token.THIS && nameChild.getType() == Token.STRING) {
cfw.addALoad(contextLocal);
addScriptRuntimeInvoke(
"getObjectProp",
"(Lorg/mozilla/javascript/Scriptable;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ ")Ljava/lang/Object;");
} else {
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectProp",
"(Ljava/lang/Object;"
+ "Ljava/lang/String;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
}
}
generateExpression(child, node);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"setObjectProp",
"(Ljava/lang/Object;"
+ "Ljava/lang/String;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:SET:" + nameChild.getString(), Signatures.PROP_SET);
}

private void visitSetElem(int type, Node node, Node child) {
Expand All @@ -4193,48 +4067,23 @@ private void visitSetElem(int type, Node node, Node child) {
cfw.add(ByteCode.DUP2_X1);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectIndex",
"(Ljava/lang/Object;D"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GETINDEX", Signatures.PROP_GET_INDEX);
} else {
// stack: ... object object indexObject
// -> ... object indexObject object indexObject
cfw.add(ByteCode.DUP_X1);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"getObjectElem",
"(Ljava/lang/Object;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:GETELEMENT", Signatures.PROP_GET_ELEMENT);
}
}
generateExpression(child, node);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
if (indexIsNumber) {
addScriptRuntimeInvoke(
"setObjectIndex",
"(Ljava/lang/Object;"
+ "D"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:SETINDEX", Signatures.PROP_SET_INDEX);
} else {
addScriptRuntimeInvoke(
"setObjectElem",
"(Ljava/lang/Object;"
+ "Ljava/lang/Object;"
+ "Ljava/lang/Object;"
+ "Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ ")Ljava/lang/Object;");
addDynamicInvoke("PROP:SETELEMENT", Signatures.PROP_SET_ELEMENT);
}
}

Expand Down Expand Up @@ -4355,6 +4204,10 @@ private void addOptRuntimeInvoke(String methodName, String methodSignature) {
methodSignature);
}

private void addDynamicInvoke(String operation, String signature) {
cfw.addInvokeDynamic(operation, signature, Bootstrapper.BOOTSTRAP_HANDLE);
}

private void addJumpedBooleanWrap(int trueLabel, int falseLabel) {
cfw.markLabel(falseLabel);
int skip = cfw.acquireLabel();
Expand Down
Loading

0 comments on commit 776fdb3

Please sign in to comment.