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

Handle super.__proto__, which has a special implementation #1737

Closed
wants to merge 2 commits into from
Closed
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
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
96 changes: 79 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 @@ -1930,6 +1964,22 @@ private Node createPropertyGet(
}
parser.checkActivationName(name, Token.GETPROP);
if (ScriptRuntime.isSpecialProperty(name)) {
if (target.getType() == Token.SUPER) {
// We have an access to super.__proto__ or super.__parent__.
// This needs to behave in the same way as this.__proto__ - it really is not
// obvious why, but you can test it in v8 or any other engine. So, we just
// replace SUPER with THIS in the AST. It's a bit hacky, but it works - see the
// test cases in SuperTest!
if (!(target instanceof KeywordLiteral)) {
throw Kit.codeBug();
}
KeywordLiteral oldTarget = (KeywordLiteral) target;
target =
new KeywordLiteral(
oldTarget.getPosition(), oldTarget.getLength(), Token.THIS);
target.setLineColumnNumber(oldTarget.getLineno(), oldTarget.getColumn());
}

Node ref = new Node(Token.REF_SPECIAL, target);
ref.putProp(Node.NAME_PROP, name);
Node getRef = new Node(Token.GET_REF, ref);
Expand All @@ -1944,6 +1994,9 @@ private Node createPropertyGet(
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 +2200,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 +2258,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 +2270,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
Loading