Skip to content

Commit

Permalink
Implement super
Browse files Browse the repository at this point in the history
Co-authored-by: Satish Srinivasan <[email protected]>
  • Loading branch information
andreabergia and 0xe committed Nov 27, 2024
1 parent 8406632 commit b5a3170
Show file tree
Hide file tree
Showing 27 changed files with 2,076 additions and 205 deletions.
12 changes: 11 additions & 1 deletion rhino/src/main/java/org/mozilla/javascript/ArrowFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ public class ArrowFunction extends BaseFunction {

private final Callable targetFunction;
private final Scriptable boundThis;
private final Scriptable boundHomeObject;

public ArrowFunction(
Context cx, Scriptable scope, Callable targetFunction, Scriptable boundThis) {
Context cx,
Scriptable scope,
Callable targetFunction,
Scriptable boundThis,
Scriptable boundHomeObject) {
this.targetFunction = targetFunction;
this.boundThis = boundThis;
this.boundHomeObject = boundHomeObject;

ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, false);

Expand Down Expand Up @@ -80,6 +86,10 @@ Scriptable getCallThis(Context cx) {
return boundThis != null ? boundThis : ScriptRuntime.getTopCallScope(cx);
}

Scriptable getBoundHomeObject() {
return this.boundHomeObject;
}

Callable getTargetFunction() {
return targetFunction;
}
Expand Down
9 changes: 9 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/BaseFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,14 @@ protected int findPrototypeId(String s) {
return id;
}

public void setHomeObject(Scriptable homeObject) {
this.homeObject = homeObject;
}

public Scriptable getHomeObject() {
return homeObject;
}

private static final int Id_constructor = 1,
Id_toString = 2,
Id_toSource = 3,
Expand All @@ -668,6 +676,7 @@ protected int findPrototypeId(String s) {
private Object argumentsObj = NOT_FOUND;
private String nameValue = null;
private boolean isGeneratorFunction = false;
private Scriptable homeObject = null;

// For function object instances, attributes are
// {configurable:false, enumerable:false};
Expand Down
25 changes: 23 additions & 2 deletions rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,9 @@ private void visitExpression(Node node, int contextFlags) {
throw Kit.codeBug();
}
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
if (fn.isMethodDefinition()) {
addIcode(ICode_FN_STORE_HOME_OBJECT);
}
stackChange(1);
}
break;
Expand Down Expand Up @@ -626,6 +629,8 @@ private void visitExpression(Node node, int contextFlags) {
addUint8(callType);
addUint8(type == Token.NEW ? 1 : 0);
addUint16(lineNumber & 0xFFFF);
} else if (node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
addIndexOp(Icode_CALL_ON_SUPER, argCount);
} else {
// Only use the tail call optimization if we're not in a try
// or we're not generating debug info (since the
Expand Down Expand Up @@ -718,6 +723,10 @@ private void visitExpression(Node node, int contextFlags) {
addIcode(Icode_POP);
addStringOp(Token.NAME, "undefined");
resolveForwardGoto(afterLabel);
} else if (node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
addStringOp(
type == Token.GETPROP ? Token.GETPROP_SUPER : Token.GETPROPNOWARN_SUPER,
child.getString());
} else {
addStringOp(type, child.getString());
}
Expand Down Expand Up @@ -757,6 +766,10 @@ private void visitExpression(Node node, int contextFlags) {
addIcode(Icode_POP);
addStringOp(Token.NAME, "undefined");
resolveForwardGoto(afterLabel);
} else if (node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
visitExpression(child, 0);
addToken(Token.GETELEM_SUPER);
stackChange(-1);
} else {
finishGetElemGeneration(child);
}
Expand Down Expand Up @@ -843,7 +856,11 @@ private void visitExpression(Node node, int contextFlags) {
stackChange(-1);
}
visitExpression(child, 0);
addStringOp(Token.SETPROP, property);
addStringOp(
node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1
? Token.SETPROP_SUPER
: Token.SETPROP,
property);
stackChange(-1);
}
break;
Expand All @@ -863,7 +880,10 @@ private void visitExpression(Node node, int contextFlags) {
stackChange(-1);
}
visitExpression(child, 0);
addToken(Token.SETELEM);
addToken(
node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1
? Token.SETELEM_SUPER
: Token.SETELEM);
stackChange(-2);
break;

Expand Down Expand Up @@ -996,6 +1016,7 @@ private void visitExpression(Node node, int contextFlags) {

case Token.NULL:
case Token.THIS:
case Token.SUPER:
case Token.THISFN:
case Token.FALSE:
case Token.TRUE:
Expand Down
3 changes: 2 additions & 1 deletion rhino/src/main/java/org/mozilla/javascript/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -2524,7 +2524,8 @@ private ScriptNode parse(
}
}

IRFactory irf = new IRFactory(compilerEnv, sourceString, compilationErrorReporter);
IRFactory irf =
new IRFactory(compilerEnv, sourceName, sourceString, compilationErrorReporter);
ScriptNode tree = irf.transformTree(ast);

if (compilerEnv.isGeneratingSource()) {
Expand Down
83 changes: 66 additions & 17 deletions rhino/src/main/java/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,24 @@ public final class IRFactory {
private AstNodePosition astNodePos;

public IRFactory(CompilerEnvirons env, String sourceString) {
this(env, sourceString, env.getErrorReporter());
this(env, null, sourceString, env.getErrorReporter());
}

/** Use {@link #IRFactory(CompilerEnvirons, String, String, ErrorReporter)} */
@Deprecated
public IRFactory(CompilerEnvirons env, String sourceString, ErrorReporter errorReporter) {
this(env, null, sourceString, errorReporter);
}

public IRFactory(
CompilerEnvirons env,
String sourceName,
String sourceString,
ErrorReporter errorReporter) {
parser = new Parser(env, errorReporter);
astNodePos = new AstNodePosition(sourceString);
parser.currentPos = astNodePos;
parser.setSourceURI(sourceName);
}

/** Transforms the tree into a lower-level IR suitable for codegen. */
Expand Down Expand Up @@ -180,7 +191,9 @@ private Node transform(AstNode node) {
case Token.NULL:
case Token.DEBUGGER:
return transformLiteral(node);

case Token.SUPER:
parser.setRequiresActivation();
return transformLiteral(node);
case Token.NAME:
return transformName((Name) node);
case Token.NUMBER:
Expand Down Expand Up @@ -533,6 +546,9 @@ private Node transformElementGet(ElementGet node) {
if (node.type == Token.QUESTION_DOT) {
getElem.putIntProp(Node.OPTIONAL_CHAINING, 1);
}
if (target.getType() == Token.SUPER) {
getElem.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return getElem;
}

Expand Down Expand Up @@ -660,17 +676,26 @@ private Node transformFunction(FunctionNode fn) {
}

private Node transformFunctionCall(FunctionCall node) {
Node call = createCallOrNew(Token.CALL, transform(node.getTarget()));
call.setLineColumnNumber(node.getLineno(), node.getColumn());
List<AstNode> args = node.getArguments();
for (int i = 0; i < args.size(); i++) {
AstNode arg = args.get(i);
call.addChildToBack(transform(arg));
}
if (node.isOptionalCall()) {
call.putIntProp(Node.OPTIONAL_CHAINING, 1);
astNodePos.push(node);
try {
Node transformedTarget = transform(node.getTarget());
Node call = createCallOrNew(Token.CALL, transformedTarget);
call.setLineColumnNumber(node.getLineno(), node.getColumn());
List<AstNode> args = node.getArguments();
for (int i = 0; i < args.size(); i++) {
AstNode arg = args.get(i);
call.addChildToBack(transform(arg));
}
if (node.isOptionalCall()) {
call.putIntProp(Node.OPTIONAL_CHAINING, 1);
}
if (transformedTarget.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
call.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return call;
} finally {
astNodePos.pop();
}
return call;
}

private Node transformGenExpr(GeneratorExpression node) {
Expand Down Expand Up @@ -863,6 +888,11 @@ private Node transformLetNode(LetNode node) {
}

private Node transformLiteral(AstNode node) {
// Trying to call super as a function. See 15.4.2 Static Semantics: HasDirectSuper
if (node.getParent() instanceof FunctionCall
&& node.getType() == Token.SUPER
&& parser.currentScriptOrFn.isMethodDefinition())
parser.reportError("msg.super.shorthand.function");
return node;
}

Expand Down Expand Up @@ -969,8 +999,12 @@ private Node transformTemplateLiteral(TemplateLiteral node) {
}

private Node transformTemplateLiteralCall(TaggedTemplateLiteral node) {
Node call = createCallOrNew(Token.CALL, transform(node.getTarget()));
Node transformedTarget = transform(node.getTarget());
Node call = createCallOrNew(Token.CALL, transformedTarget);
call.setLineColumnNumber(node.getLineno(), node.getColumn());
if (transformedTarget.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
call.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
TemplateLiteral templateLiteral = (TemplateLiteral) node.getTemplateLiteral();
List<AstNode> elems = templateLiteral.getElements();
call.addChildToBack(templateLiteral);
Expand Down Expand Up @@ -1937,13 +1971,19 @@ private Node createPropertyGet(
ref.putIntProp(Node.OPTIONAL_CHAINING, 1);
getRef.putIntProp(Node.OPTIONAL_CHAINING, 1);
}
if (target.getType() == Token.SUPER) {
getRef.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return getRef;
}

Node node = new Node(Token.GETPROP, target, Node.newString(name));
if (type == Token.QUESTION_DOT) {
node.putIntProp(Node.OPTIONAL_CHAINING, 1);
}
if (target.getType() == Token.SUPER) {
node.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return node;
}
Node elem = Node.newString(name);
Expand Down Expand Up @@ -2147,7 +2187,9 @@ private Node createAssignment(int assignType, Node left, Node right) {
int assignOp;
switch (assignType) {
case Token.ASSIGN:
return parser.simpleAssignment(left, right);
{
return propagateSuperFromLhs(parser.simpleAssignment(left, right), left);
}
case Token.ASSIGN_BITOR:
assignOp = Token.BITOR;
break;
Expand Down Expand Up @@ -2203,7 +2245,7 @@ private Node createAssignment(int assignType, Node left, Node right) {
{
Node op = new Node(assignOp, left, right);
Node lvalueLeft = Node.newString(Token.BINDNAME, left.getString());
return new Node(Token.SETNAME, lvalueLeft, op);
return propagateSuperFromLhs(new Node(Token.SETNAME, lvalueLeft, op), left);
}
case Token.GETPROP:
case Token.GETELEM:
Expand All @@ -2215,21 +2257,28 @@ private Node createAssignment(int assignType, Node left, Node right) {

Node opLeft = new Node(Token.USE_STACK);
Node op = new Node(assignOp, opLeft, right);
return new Node(type, obj, id, op);
return propagateSuperFromLhs(new Node(type, obj, id, op), left);
}
case Token.GET_REF:
{
ref = left.getFirstChild();
parser.checkMutableReference(ref);
Node opLeft = new Node(Token.USE_STACK);
Node op = new Node(assignOp, opLeft, right);
return new Node(Token.SET_REF_OP, ref, op);
return propagateSuperFromLhs(new Node(Token.SET_REF_OP, ref, op), left);
}
}

throw Kit.codeBug();
}

private Node propagateSuperFromLhs(Node result, Node left) {
if (left.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
result.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return result;
}

private static Node createUseLocal(Node localBlock) {
if (Token.LOCAL_BLOCK != localBlock.getType()) throw Kit.codeBug();
Node result = new Node(Token.LOCAL_LOAD);
Expand Down
13 changes: 11 additions & 2 deletions rhino/src/main/java/org/mozilla/javascript/Icode.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ abstract class Icode {
Icode_LITERAL_NEW_OBJECT = Icode_INTNUMBER - 1,
Icode_LITERAL_NEW_ARRAY = Icode_LITERAL_NEW_OBJECT - 1,
Icode_LITERAL_SET = Icode_LITERAL_NEW_ARRAY - 1,
ICode_FN_STORE_HOME_OBJECT = Icode_LITERAL_SET - 1,

// Array literal with skipped index like [1,,2]
Icode_SPARE_ARRAYLIT = Icode_LITERAL_SET - 1,
Icode_SPARE_ARRAYLIT = ICode_FN_STORE_HOME_OBJECT - 1,

// Load index register to prepare for the following index operation
Icode_REG_IND_C0 = Icode_SPARE_ARRAYLIT - 1,
Expand Down Expand Up @@ -151,8 +152,12 @@ abstract class Icode {
// Jump if stack head is null or undefined
Icode_IF_NULL_UNDEF = Icode_LITERAL_KEY_SET - 1,
Icode_IF_NOT_NULL_UNDEF = Icode_IF_NULL_UNDEF - 1,

// Call a method on the super object, i.e. super.foo()
Icode_CALL_ON_SUPER = Icode_IF_NOT_NULL_UNDEF - 1,

// Last icode
MIN_ICODE = Icode_IF_NOT_NULL_UNDEF;
MIN_ICODE = Icode_CALL_ON_SUPER;

static String bytecodeName(int bytecode) {
if (!validBytecode(bytecode)) {
Expand Down Expand Up @@ -240,6 +245,8 @@ static String bytecodeName(int bytecode) {
return "LITERAL_NEW_ARRAY";
case Icode_LITERAL_SET:
return "LITERAL_SET";
case ICode_FN_STORE_HOME_OBJECT:
return "FN_STORE_HOME_OBJECT";
case Icode_SPARE_ARRAYLIT:
return "SPARE_ARRAYLIT";
case Icode_REG_IND_C0:
Expand Down Expand Up @@ -334,6 +341,8 @@ static String bytecodeName(int bytecode) {
return "IF_NULL_UNDEF";
case Icode_IF_NOT_NULL_UNDEF:
return "IF_NOT_NULL_UNDEF";
case Icode_CALL_ON_SUPER:
return "CALL_ON_SUPER";
}

// icode without name
Expand Down
Loading

0 comments on commit b5a3170

Please sign in to comment.