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.x++ and similar #1738

Closed
wants to merge 7 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
108 changes: 105 additions & 3 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 All @@ -728,7 +737,9 @@ private void visitExpression(Node node, int contextFlags) {
visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
if (isName) {
if (node.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
addIcode(Icode_DELPROP_SUPER);
} else if (isName) {
// special handling for delete name
addIcode(Icode_DELNAME);
} else {
Expand Down Expand Up @@ -757,6 +768,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 +858,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 +882,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 +1018,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 Expand Up @@ -1245,6 +1268,12 @@ private CompleteOptionalCallJump completeOptionalCallJump() {
private void visitIncDec(Node node, Node child) {
int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
int childType = child.getType();

if (child.getIntProp(Node.SUPER_PROPERTY_ACCESS, 0) == 1) {
visitSuperIncDec(node, child, childType, incrDecrMask);
return;
}

switch (childType) {
case Token.GETVAR:
{
Expand Down Expand Up @@ -1298,6 +1327,79 @@ private void visitIncDec(Node node, Node child) {
}
}

// Handles super.x++ and variants thereof. We don't want to create new icode in the interpreter
// for this edge case, so we will transform this into something like super.x = super.x + 1
private void visitSuperIncDec(Node node, Node child, int childType, int incrDecrMask) {
Node object = child.getFirstChild();

// Push the old value on the stack
visitExpression(object, 0); // stack: [super]
switch (childType) {
case Token.GETPROP:
addStringOp(Token.GETPROP_SUPER, object.getNext().getString()); // stack: [p]
break;

case Token.GETELEM:
{
Node index = object.getNext();
visitExpression(index, 0); // stack: [super, elem]
addToken(Token.GETELEM_SUPER); // stack: [p]
stackChange(-1);
break;
}

default:
throw badTree(node);
}

// If it's a postfix expression, we copy the old value
// If it's postfix, we only need the _new_ value on the stack
if ((incrDecrMask & Node.POST_FLAG) != 0) {
addIcode(Icode_DUP); // stack: postfix [p, p], prefix: [p]
stackChange(+1);
}

// We need, in order, super and then the new value
addToken(Token.SUPER); // stack: postfix [p, p, super], prefix: [p, super]
stackChange(+1);
addIcode(Icode_SWAP); // stack: postfix [p, super, p], prefix: [super, p]

// Increment or decrement the new value
addIcode(Icode_ONE); // stack: prefix [p, super, p, 1], postfix: [super, p, 1]
stackChange(+1);
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
addToken(Token.ADD); // stack: prefix [p, super, p+1], postfix: [super, p+1]
} else {
addToken(Token.SUB); // stack: prefix [p, super, p-1], postfix: [super, p-1]
}
stackChange(-1);

// Assign the new value to the property
switch (childType) {
case Token.GETPROP:
addStringOp(Token.SETPROP_SUPER, object.getNext().getString());
// stack: prefix [p, p+-1], postfix: [p+-1]
stackChange(-1);
break;

case Token.GETELEM:
{
Node index = object.getNext();
visitExpression(index, 0);
// stack: prefix [p, super, p+-1, elem], postfix: [super, p+-1, elem]
addToken(Token.SETELEM_SUPER); // stack: prefix [p, p+-1], postfix: [p+-1]
stackChange(-2);
break;
}
}

// If it was a postfix, just drop the new value
if ((incrDecrMask & Node.POST_FLAG) != 0) {
addIcode(Icode_POP); // stack: [p]
stackChange(-1);
}
}

private void visitLiteral(Node node, Node child) {
int type = node.getType();
if (type == Token.ARRAYLIT) {
Expand Down
10 changes: 10 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/CompilerEnvirons.java
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ public boolean getAllowSharpComments() {
return allowSharpComments;
}

/** Allows usage of "super" everywhere, simulating that we are inside a method. */
public void setAllowSuper(boolean allowSuper) {
this.allowSuper = allowSuper;
}

public boolean isAllowSuper() {
return allowSuper;
}

/**
* Returns a {@code CompilerEnvirons} suitable for using Rhino in an IDE environment. Most
* features are enabled by default. The {@link ErrorReporter} is set to an {@link
Expand Down Expand Up @@ -257,5 +266,6 @@ public static CompilerEnvirons ideEnvirons() {
private boolean warnTrailingComma;
private boolean ideMode;
private boolean allowSharpComments;
private boolean allowSuper;
Set<String> activationNames;
}
34 changes: 27 additions & 7 deletions rhino/src/main/java/org/mozilla/javascript/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import org.mozilla.classfile.ClassFileWriter.ClassFileFormatException;
import org.mozilla.javascript.ast.AstRoot;
Expand Down Expand Up @@ -1367,6 +1368,16 @@ public final Script compileReader(
*/
public final Script compileReader(
Reader in, String sourceName, int lineno, Object securityDomain) throws IOException {
return compileReader(in, sourceName, lineno, securityDomain, null);
}

public Script compileReader(
Reader in,
String sourceName,
int lineno,
Object securityDomain,
Consumer<CompilerEnvirons> compilerEnvironsProcessor)
throws IOException {
if (lineno < 0) {
// For compatibility IllegalArgumentException can not be thrown here
lineno = 0;
Expand All @@ -1381,7 +1392,8 @@ public final Script compileReader(
securityDomain,
false,
null,
null);
null,
compilerEnvironsProcessor);
}

/**
Expand All @@ -1405,7 +1417,7 @@ public final Script compileString(
// For compatibility IllegalArgumentException can not be thrown here
lineno = 0;
}
return compileString(source, null, null, sourceName, lineno, securityDomain);
return compileString(source, null, null, sourceName, lineno, securityDomain, null);
}

final Script compileString(
Expand All @@ -1414,7 +1426,8 @@ final Script compileString(
ErrorReporter compilationErrorReporter,
String sourceName,
int lineno,
Object securityDomain) {
Object securityDomain,
Consumer<CompilerEnvirons> compilerEnvironsProcessor) {
return (Script)
compileImpl(
null,
Expand All @@ -1424,7 +1437,8 @@ final Script compileString(
securityDomain,
false,
compiler,
compilationErrorReporter);
compilationErrorReporter,
compilerEnvironsProcessor);
}

/**
Expand Down Expand Up @@ -1465,7 +1479,8 @@ final Function compileFunction(
securityDomain,
true,
compiler,
compilationErrorReporter);
compilationErrorReporter,
null);
}

/**
Expand Down Expand Up @@ -2424,7 +2439,8 @@ protected Object compileImpl(
Object securityDomain,
boolean returnFunction,
Evaluator compiler,
ErrorReporter compilationErrorReporter) {
ErrorReporter compilationErrorReporter,
Consumer<CompilerEnvirons> compilerEnvironProcessor) {
if (sourceName == null) {
sourceName = "unnamed script";
}
Expand All @@ -2441,6 +2457,9 @@ protected Object compileImpl(
if (compilationErrorReporter == null) {
compilationErrorReporter = compilerEnv.getErrorReporter();
}
if (compilerEnvironProcessor != null) {
compilerEnvironProcessor.accept(compilerEnv);
}

ScriptNode tree =
parse(
Expand Down Expand Up @@ -2524,7 +2543,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
Loading
Loading