Skip to content

Commit

Permalink
Implemented short-circuit of function call arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
andreabergia committed Oct 23, 2024
1 parent b8d5eae commit 2659cba
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 120 deletions.
106 changes: 73 additions & 33 deletions rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,15 @@ private void visitExpression(Node node, int contextFlags) {
{
boolean isOptionalChainingCall =
node.getIntProp(Node.OPTIONAL_CHAINING, 0) == 1;
CompleteOptionalCallJump completeOptionalCallJump = null;
if (type == Token.NEW) {
visitExpression(child, 0);
} else {
generateCallFunAndThis(child, isOptionalChainingCall);
completeOptionalCallJump =
generateCallFunAndThis(child, isOptionalChainingCall);
if (completeOptionalCallJump != null) {
resolveForwardGoto(completeOptionalCallJump.putArgsAndDoCallLabel);
}
}
int argCount = 0;
while ((child = child.getNext()) != null) {
Expand All @@ -617,11 +622,7 @@ private void visitExpression(Node node, int contextFlags) {
int callType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
if (type != Token.REF_CALL && callType != Node.NON_SPECIALCALL) {
// embed line number and source filename
addIndexOp(
isOptionalChainingCall
? Icode_CALLSPECIAL_OPTIONAL
: Icode_CALLSPECIAL,
argCount);
addIndexOp(Icode_CALLSPECIAL, argCount);
addUint8(callType);
addUint8(type == Token.NEW ? 1 : 0);
addUint16(lineNumber & 0xFFFF);
Expand All @@ -635,11 +636,7 @@ private void visitExpression(Node node, int contextFlags) {
&& !itsInTryFlag) {
type = Icode_TAIL_CALL;
}
addIndexOp(
type == Token.CALL && isOptionalChainingCall
? Icode_CALL_OPTIONAL
: type,
argCount);
addIndexOp(type, argCount);
}
// adjust stack
if (type == Token.NEW) {
Expand All @@ -653,6 +650,10 @@ private void visitExpression(Node node, int contextFlags) {
if (argCount > itsData.itsMaxCalleeArgs) {
itsData.itsMaxCalleeArgs = argCount;
}

if (completeOptionalCallJump != null) {
resolveForwardGoto(completeOptionalCallJump.afterLabel);
}
}
break;

Expand Down Expand Up @@ -1158,20 +1159,23 @@ private void finishGetElemGeneration(Node child) {
stackChange(-1);
}

private void generateCallFunAndThis(Node left, boolean isOptionalChainingCall) {
private CompleteOptionalCallJump generateCallFunAndThis(
Node left, boolean isOptionalChainingCall) {
// Generate code to place on stack function and thisObj
int type = left.getType();
switch (type) {
case Token.NAME:
{
String name = left.getString();
// stack: ... -> ... function thisObj
addStringOp(
isOptionalChainingCall
? Icode_NAME_AND_THIS_OPTIONAL
: Icode_NAME_AND_THIS,
name);
stackChange(2);
if (isOptionalChainingCall) {
addStringOp(Icode_NAME_AND_THIS_OPTIONAL, name);
stackChange(2);
return completeOptionalCallJump();
} else {
addStringOp(Icode_NAME_AND_THIS, name);
stackChange(2);
}
break;
}
case Token.GETPROP:
Expand All @@ -1183,33 +1187,59 @@ private void generateCallFunAndThis(Node left, boolean isOptionalChainingCall) {
if (type == Token.GETPROP) {
String property = id.getString();
// stack: ... target -> ... function thisObj
addStringOp(
isOptionalChainingCall
? Icode_PROP_AND_THIS_OPTIONAL
: Icode_PROP_AND_THIS,
property);
stackChange(1);
if (isOptionalChainingCall) {
addStringOp(Icode_PROP_AND_THIS_OPTIONAL, property);
stackChange(1);
return completeOptionalCallJump();
} else {
addStringOp(Icode_PROP_AND_THIS, property);
stackChange(1);
}
} else {
visitExpression(id, 0);
// stack: ... target id -> ... function thisObj
addIcode(
isOptionalChainingCall
? Icode_ELEM_AND_THIS_OPTIONAL
: Icode_ELEM_AND_THIS);
if (isOptionalChainingCall) {
addIcode(Icode_ELEM_AND_THIS_OPTIONAL);
return completeOptionalCallJump();
} else {
addIcode(Icode_ELEM_AND_THIS);
}
}
break;
}
default:
// Including Token.GETVAR
visitExpression(left, 0);
// stack: ... value -> ... function thisObj
addIcode(
isOptionalChainingCall
? Icode_VALUE_AND_THIS_OPTIONAL
: Icode_VALUE_AND_THIS);
stackChange(1);
if (isOptionalChainingCall) {
addIcode(Icode_VALUE_AND_THIS_OPTIONAL);
stackChange(1);
return completeOptionalCallJump();
} else {
addIcode(Icode_VALUE_AND_THIS);
stackChange(1);
}
break;
}
return null;
}

private CompleteOptionalCallJump completeOptionalCallJump() {
// If it's null or undefined, pop undefined and skip the arguments and call
addIcode(Icode_DUP);
stackChange(1);
int putArgsAndDoCallLabel = iCodeTop;
addGotoOp(Icode.Icode_IF_NOT_NULL_UNDEF);
stackChange(-1);

// Put undefined
addIcode(Icode_POP);
addIcode(Icode_POP);
addStringOp(Token.NAME, "undefined");
int afterLabel = iCodeTop;
addGotoOp(Token.GOTO);

return new CompleteOptionalCallJump(putArgsAndDoCallLabel, afterLabel);
}

private void visitIncDec(Node node, Node child) {
Expand Down Expand Up @@ -1719,4 +1749,14 @@ private void releaseLocal(int localSlot) {
--localTop;
if (localSlot != localTop) Kit.codeBug();
}

private static final class CompleteOptionalCallJump {
private final int putArgsAndDoCallLabel;
private final int afterLabel;

public CompleteOptionalCallJump(int putArgsAndDoCallLabel, int afterLabel) {
this.putArgsAndDoCallLabel = putArgsAndDoCallLabel;
this.afterLabel = afterLabel;
}
}
}
5 changes: 1 addition & 4 deletions rhino/src/main/java/org/mozilla/javascript/Icode.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,9 @@ abstract class Icode {
Icode_PROP_AND_THIS_OPTIONAL = Icode_NAME_AND_THIS_OPTIONAL - 1,
Icode_ELEM_AND_THIS_OPTIONAL = Icode_PROP_AND_THIS_OPTIONAL - 1,
Icode_VALUE_AND_THIS_OPTIONAL = Icode_ELEM_AND_THIS_OPTIONAL - 1,
Icode_CALL_OPTIONAL = Icode_VALUE_AND_THIS_OPTIONAL - 1,

// Create closure object for nested functions
Icode_CLOSURE_EXPR = Icode_CALL_OPTIONAL - 1,
Icode_CLOSURE_EXPR = Icode_VALUE_AND_THIS_OPTIONAL - 1,
Icode_CLOSURE_STMT = Icode_CLOSURE_EXPR - 1,

// Special calls
Expand Down Expand Up @@ -213,8 +212,6 @@ static String bytecodeName(int bytecode) {
return "ELEM_AND_THIS_OPTIONAL";
case Icode_VALUE_AND_THIS_OPTIONAL:
return "VALUE_AND_THIS_OPTIONAL";
case Icode_CALL_OPTIONAL:
return "CALL_OPTIONAL";
case Icode_CLOSURE_EXPR:
return "CLOSURE_EXPR";
case Icode_CLOSURE_STMT:
Expand Down
10 changes: 2 additions & 8 deletions rhino/src/main/java/org/mozilla/javascript/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,6 @@ static void dumpICode(InterpreterData idata) {
out.println(tname + " " + idata.itsNestedFunctions[indexReg]);
break;
case Token.CALL:
case Icode_CALL_OPTIONAL:
case Icode_TAIL_CALL:
case Token.REF_CALL:
case Token.NEW:
Expand Down Expand Up @@ -1854,7 +1853,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
continue Loop;
}
case Token.CALL:
case Icode_CALL_OPTIONAL:
case Icode_TAIL_CALL:
case Token.REF_CALL:
{
Expand Down Expand Up @@ -2006,10 +2004,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
cx.newArray(calleeScope, elements);
indexReg = 2;
} else if (fun == null) {
if (op == Icode_CALL_OPTIONAL) {
stack[stackTop] = Undefined.instance;
continue Loop;
}
throw ScriptRuntime.notFunctionError(null, null);
} else {
// Current function is something that we can't reduce
Expand Down Expand Up @@ -3582,7 +3576,7 @@ private static void exitFrame(Context cx, CallFrame frame, Object throwable) {
}

private static void setCallResult(CallFrame frame, Object callResult, double callResultDbl) {
if (frame.savedCallOp == Token.CALL || frame.savedCallOp == Icode_CALL_OPTIONAL) {
if (frame.savedCallOp == Token.CALL) {
frame.stack[frame.savedStackTop] = callResult;
frame.sDbl[frame.savedStackTop] = callResultDbl;
} else if (frame.savedCallOp == Token.NEW) {
Expand Down Expand Up @@ -3621,7 +3615,7 @@ private static NativeContinuation captureContinuation(
x.stack[i] = null;
x.stackAttributes[i] = ScriptableObject.EMPTY;
}
if (x.savedCallOp == Token.CALL || x.savedCallOp == Icode_CALL_OPTIONAL) {
if (x.savedCallOp == Token.CALL) {
// the call will always overwrite the stack top with the result
x.stack[x.savedStackTop] = null;
} else {
Expand Down
Loading

0 comments on commit 2659cba

Please sign in to comment.