Skip to content

Commit

Permalink
adding few new rhino ByteCodes to handle Optional property get and op…
Browse files Browse the repository at this point in the history
…tional method call for `?.` operator
  • Loading branch information
nabacg committed Sep 5, 2024
1 parent dff3ecc commit e1727ce
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 117 deletions.
12 changes: 12 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ private void visitExpression(Node node, int contextFlags) {

case Token.REF_CALL:
case Token.CALL:
case Token.CALL_OPTIONAL:
case Token.NEW:
{
if (type == Token.NEW) {
Expand Down Expand Up @@ -686,6 +687,11 @@ private void visitExpression(Node node, int contextFlags) {
resolveForwardGoto(afterElseJumpStart);
}
break;
case Token.GETPROP_OPTIONAL:
visitExpression(child, 0);
child = child.getNext();
addStringOp(type, child.getString());
break;

case Token.GETPROP:
case Token.GETPROPNOWARN:
Expand Down Expand Up @@ -1057,6 +1063,7 @@ private void generateCallFunAndThis(Node left) {
stackChange(2);
break;
}
case Token.GETPROP_OPTIONAL:
case Token.GETPROP:
case Token.GETELEM:
{
Expand All @@ -1068,6 +1075,11 @@ private void generateCallFunAndThis(Node left) {
// stack: ... target -> ... function thisObj
addStringOp(Icode_PROP_AND_THIS, property);
stackChange(1);
} else if (type == Token.GETPROP_OPTIONAL) {
String property = id.getString();
// stack: ... target -> ... function thisObj
addStringOp(Icode_PROP_AND_THIS_OPTIONAL, property);
stackChange(1);
} else {
visitExpression(id, 0);
// stack: ... target id -> ... function thisObj
Expand Down
29 changes: 22 additions & 7 deletions rhino/src/main/java/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ private Node transform(AstNode node) {
return transformBlock(node);
case Token.BREAK:
return transformBreak((BreakStatement) node);
case Token.CALL_OPTIONAL:
case Token.CALL:
return transformFunctionCall((FunctionCall) node);
case Token.CONTINUE:
Expand All @@ -161,6 +162,7 @@ private Node transform(AstNode node) {
return transformGenExpr((GeneratorExpression) node);
case Token.GETELEM:
return transformElementGet((ElementGet) node);
case Token.QUESTION_DOT:
case Token.GETPROP:
return transformPropertyGet((PropertyGet) node);
case Token.HOOK:
Expand Down Expand Up @@ -347,7 +349,8 @@ private Node arrayCompTransformHelper(ArrayComprehension node, String arrayName)
Node call =
createCallOrNew(
Token.CALL,
createPropertyGet(parser.createName(arrayName), null, "push", 0));
createPropertyGet(
parser.createName(arrayName), null, "push", 0, node.type));

Node body = new Node(Token.EXPR_VOID, call, lineno);

Expand Down Expand Up @@ -603,7 +606,10 @@ private Node transformFunction(FunctionNode fn) {
}

private Node transformFunctionCall(FunctionCall node) {
Node call = createCallOrNew(Token.CALL, transform(node.getTarget()));
Node call =
createCallOrNew(
node.type == Token.CALL_OPTIONAL ? Token.CALL_OPTIONAL : Token.CALL,
transform(node.getTarget()));
call.setLineno(node.getLineno());
List<AstNode> args = node.getArguments();
for (int i = 0; i < args.size(); i++) {
Expand Down Expand Up @@ -889,7 +895,7 @@ private Node transformComputedPropertyKey(ComputedPropertyKey node) {
private Node transformPropertyGet(PropertyGet node) {
Node target = transform(node.getTarget());
String name = node.getProperty().getIdentifier();
return createPropertyGet(target, null, name, 0);
return createPropertyGet(target, null, name, 0, node.type);
}

private Node transformTemplateLiteral(TemplateLiteral node) {
Expand Down Expand Up @@ -1211,7 +1217,7 @@ private Node transformXmlRef(Node pn, XmlRef node, int memberTypeFlags) {
String ns = namespace != null ? namespace.getIdentifier() : null;
if (node instanceof XmlPropRef) {
String name = ((XmlPropRef) node).getPropName().getIdentifier();
return createPropertyGet(pn, ns, name, memberTypeFlags);
return createPropertyGet(pn, ns, name, memberTypeFlags, node.type);
}
Node expr = transform(((XmlElemRef) node).getExpression());
return createElementGet(pn, ns, expr, memberTypeFlags);
Expand Down Expand Up @@ -1847,18 +1853,27 @@ private static Node createIncDec(int nodeType, boolean post, Node child) {
}

private Node createPropertyGet(
Node target, String namespace, String name, int memberTypeFlags) {
Node target, String namespace, String name, int memberTypeFlags, int type) {
if (namespace == null && memberTypeFlags == 0) {
if (target == null) {
return parser.createName(name);
}
parser.checkActivationName(name, Token.GETPROP);
if (ScriptRuntime.isSpecialProperty(name)) {
Node ref = new Node(Token.REF_SPECIAL, target);
Node ref =
new Node(
type == Token.QUESTION_DOT
? Token.REF_SPECIAL_OPTIONAL
: Token.REF_SPECIAL,
target);
ref.putProp(Node.NAME_PROP, name);
return new Node(Token.GET_REF, ref);
}
return new Node(Token.GETPROP, target, Node.newString(name));

return new Node(
type == Token.QUESTION_DOT ? Token.GETPROP_OPTIONAL : Token.GETPROP,
target,
Node.newString(name));
}
Node elem = Node.newString(name);
memberTypeFlags |= Node.PROPERTY_FLAG;
Expand Down
6 changes: 4 additions & 2 deletions rhino/src/main/java/org/mozilla/javascript/Icode.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ abstract class Icode {
Icode_TEMPLATE_LITERAL_CALLSITE = -74,
Icode_LITERAL_KEYS = -75,
Icode_LITERAL_KEY_SET = -76,

Icode_PROP_AND_THIS_OPTIONAL = -77,
// Last icode
MIN_ICODE = -76;
MIN_ICODE = -77;

static String bytecodeName(int bytecode) {
if (!validBytecode(bytecode)) {
Expand Down Expand Up @@ -190,6 +190,8 @@ static String bytecodeName(int bytecode) {
return "NAME_AND_THIS";
case Icode_PROP_AND_THIS:
return "PROP_AND_THIS";
case Icode_PROP_AND_THIS_OPTIONAL:
return "PROP_AND_THIS_OPTIONAL";
case Icode_ELEM_AND_THIS:
return "ELEM_AND_THIS";
case Icode_VALUE_AND_THIS:
Expand Down
24 changes: 24 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,16 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
lhs, stringReg, cx, frame.scope);
continue Loop;
}
case Token.GETPROP_OPTIONAL:
{
Object lhs = stack[stackTop];
if (lhs == DBL_MRK)
lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
stack[stackTop] =
ScriptRuntime.getObjectPropOptional(
lhs, stringReg, cx, frame.scope);
continue Loop;
}
case Token.SETPROP:
{
Object rhs = stack[stackTop];
Expand Down Expand Up @@ -1694,6 +1704,19 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
++stackTop;
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
continue Loop;
case Icode_PROP_AND_THIS_OPTIONAL:
{
Object obj = stack[stackTop];
if (obj == DBL_MRK)
obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
// stringReg: property
stack[stackTop] =
ScriptRuntime.getPropFunctionAndThisOptional(
obj, stringReg, cx, frame.scope);
++stackTop;
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
continue Loop;
}
case Icode_PROP_AND_THIS:
{
Object obj = stack[stackTop];
Expand Down Expand Up @@ -1744,6 +1767,7 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
continue Loop;
}
case Token.CALL:
case Token.CALL_OPTIONAL:
case Icode_TAIL_CALL:
case Token.REF_CALL:
{
Expand Down
9 changes: 5 additions & 4 deletions rhino/src/main/java/org/mozilla/javascript/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2908,8 +2908,9 @@ private AstNode propertyAccess(int tt, AstNode pn) throws IOException {
AstNode ref = null; // right side of . or .. operator
int token = nextToken();
if (token == Token.LP && tt == Token.QUESTION_DOT) {
// optional chaining operator method call, o.func.?()
// optional chaining operator method call, o.func?.()
var pos = pn.getPosition();
pn.setType(Token.QUESTION_DOT);
consumeToken();
checkCallRequiresActivation(pn);
FunctionCall f = new FunctionCall(pos);
Expand All @@ -2923,8 +2924,8 @@ private AstNode propertyAccess(int tt, AstNode pn) throws IOException {
f.setArguments(args);
f.setRp(ts.tokenBeg - pos);
f.setLength(ts.tokenEnd - pos);

return conditionalPropertyAccess(pn, f);
f.setType(Token.CALL_OPTIONAL);
return f;
}

switch (token) {
Expand Down Expand Up @@ -2984,7 +2985,7 @@ private AstNode propertyAccess(int tt, AstNode pn) throws IOException {
result.setRight(ref);

if (tt == Token.QUESTION_DOT && result instanceof PropertyGet) {
return conditionalPropertyAccess(pn, result);
result.setType(Token.QUESTION_DOT);
}
return result;
}
Expand Down
22 changes: 22 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,14 @@ public static Object getObjectProp(Object obj, String property, Context cx, Scri
return getObjectProp(sobj, property, cx);
}

public static Object getObjectPropOptional(
Object obj, String property, Context cx, Scriptable scope) {
if (obj == null || Undefined.isUndefined(obj)) {
return Undefined.instance;
}
return getObjectProp(obj, property, cx, scope);
}

public static Object getObjectProp(Scriptable obj, String property, Context cx) {

Object result = ScriptableObject.getProperty(obj, property);
Expand Down Expand Up @@ -2617,6 +2625,20 @@ public static Callable getElemFunctionAndThis(
return (Callable) value;
}

public static Callable getPropFunctionAndThisOptional(
Object obj, String property, Context cx, Scriptable scope) {

Scriptable thisObj = toObjectOrNull(cx, obj, scope);
if (thisObj == null) {
throw undefCallError(obj, property);
}

Object value = ScriptableObject.getProperty(thisObj, property);
if (Scriptable.NOT_FOUND == value || Undefined.isUndefined(value) || value == null)
return (cx1, scope1, thisObj2, args) -> Undefined.instance;
return getPropFunctionAndThisHelper(obj, property, cx, thisObj);
}

/**
* Prepare for calling obj.property(...): return function corresponding to obj.property and make
* obj properly converted to Scriptable available as ScriptRuntime.lastStoredScriptable() for
Expand Down
Loading

0 comments on commit e1727ce

Please sign in to comment.