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

Strict mode in runtime #227

Merged
merged 10 commits into from
Sep 1, 2015
51 changes: 51 additions & 0 deletions src/org/mozilla/javascript/Arguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ public Object get(int index, Scriptable start)

private boolean sharedWithActivation(int index)
{
Context cx = Context.getContext();
if (cx.isStrictMode()) {
return false;
}
NativeFunction f = activation.function;
int definedCount = f.getParamCount();
if (index < definedCount) {
Expand Down Expand Up @@ -148,6 +152,12 @@ public void put(int index, Scriptable start, Object value)
}
}

@Override
public void put(String name, Scriptable start, Object value)
{
super.put(name, start, value);
}

@Override
public void delete(int index)
{
Expand Down Expand Up @@ -189,6 +199,13 @@ protected int findInstanceIdInfo(String s)
break L0;
}
// #/generated#
Context cx = Context.getContext();
if (cx.isStrictMode()) {
if (id == Id_callee || id == Id_caller) {
return super.findInstanceIdInfo(s);
}
}


if (id == 0) return super.findInstanceIdInfo(s);

Expand Down Expand Up @@ -363,6 +380,27 @@ protected void defineOwnProperty(Context cx, Object id,
}
}

// ECMAScript2015
// 9.4.4.6 CreateUnmappedArgumentsObject(argumentsList)
// 8. Perform DefinePropertyOrThrow(obj, "caller", PropertyDescriptor {[[Get]]: %ThrowTypeError%,
// [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}).
// 9. Perform DefinePropertyOrThrow(obj, "callee", PropertyDescriptor {[[Get]]: %ThrowTypeError%,
// [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}).
void defineAttributesForStrictMode() {
Context cx = Context.getContext();
if (!cx.isStrictMode()) {
return;
}
setGetterOrSetter("caller", 0, new ThrowTypeError("caller"), true);
setGetterOrSetter("caller", 0, new ThrowTypeError("caller"), false);
setGetterOrSetter("callee", 0, new ThrowTypeError("callee"), true);
setGetterOrSetter("callee", 0, new ThrowTypeError("callee"), false);
setAttributes("caller", DONTENUM | PERMANENT);
setAttributes("callee", DONTENUM | PERMANENT);
callerObj = null;
calleeObj = null;
}

private static BaseFunction iteratorMethod = new BaseFunction() {
@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Expand All @@ -375,6 +413,19 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj,
}
};

private static class ThrowTypeError extends BaseFunction {
private String propertyName;

ThrowTypeError(String propertyName) {
this.propertyName = propertyName;
}

@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
throw ScriptRuntime.typeError1("msg.arguments.not.access.strict", propertyName);
}
}

// Fields to hold caller, callee and length properties,
// where NOT_FOUND value tags deleted properties.
// In addition if callerObj == NULL_VALUE, it tags null for scripts, as
Expand Down
6 changes: 5 additions & 1 deletion src/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ public InterpreterData compile(CompilerEnvirons compilerEnv,
} else {
scriptOrFn = tree;
}

itsData = new InterpreterData(compilerEnv.getLanguageVersion(),
scriptOrFn.getSourceName(),
encodedSource,
((AstRoot)tree).isInStrictMode());
scriptOrFn.isInStrictMode());
itsData.topLevel = true;

if (returnFunction) {
Expand All @@ -100,6 +101,9 @@ private void generateFunctionICode()
addIcode(Icode_GENERATOR);
addUint16(theFunction.getBaseLineno() & 0xFFFF);
}
if (theFunction.isInStrictMode()) {
itsData.isStrict = true;
}

generateICodeFromTree(theFunction.getLastChild());
}
Expand Down
11 changes: 10 additions & 1 deletion src/org/mozilla/javascript/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ public Object callFunctionWithContinuations(Callable function,
// Annotate so we can check later to ensure no java code in
// intervening frames
isContinuationsTopCall = true;
return ScriptRuntime.doTopCall(function, this, scope, scope, args);
return ScriptRuntime.doTopCall(function, this, scope, scope, args, isTopLevelStrict);
}

/**
Expand Down Expand Up @@ -2486,6 +2486,9 @@ private Object compileImpl(Scriptable scope,
if (returnFunction) {
p.calledByCompileFunction = true;
}
if (isStrictMode()) {
p.setDefaultUseStrictDirective(true);
}
AstRoot ast;
if (sourceString != null) {
ast = p.parse(sourceString, sourceName, lineno);
Expand Down Expand Up @@ -2672,6 +2675,10 @@ public void removeActivationName(String name)
activationNames.remove(name);
}

public final boolean isStrictMode() {
return isTopLevelStrict || (currentActivationCall != null && currentActivationCall.isStrict);
}

private static String implementationVersion;

private final ContextFactory factory;
Expand Down Expand Up @@ -2741,4 +2748,6 @@ public void removeActivationName(String name)

// Generate an observer count on compiled code
public boolean generateObserverCount = false;

boolean isTopLevelStrict;
}
18 changes: 16 additions & 2 deletions src/org/mozilla/javascript/IdScriptableObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,15 @@ final void delete(int id)
{
ensureId(id);
int attr = attributeArray[id - 1];
if ((attr & PERMANENT) == 0) {
// non-configurable
if ((attr & PERMANENT) != 0) {
Context cx = Context.getContext();
if (cx.isStrictMode()) {
int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
String name = (String)valueArray[nameSlot];
throw ScriptRuntime.typeError1("msg.delete.property.with.configurable.false", name);
}
} else {
int valueSlot = (id - 1) * SLOT_SPAN;
synchronized (this) {
valueArray[valueSlot] = NOT_FOUND;
Expand Down Expand Up @@ -394,7 +402,13 @@ public void delete(String name)
// Let the super class to throw exceptions for sealed objects
if (!isSealed()) {
int attr = (info >>> 16);
if ((attr & PERMANENT) == 0) {
// non-configurable
if ((attr & PERMANENT) != 0) {
Context cx = Context.getContext();
if (cx.isStrictMode()) {
throw ScriptRuntime.typeError1("msg.delete.property.with.configurable.false", name);
}
} else {
int id = (info & 0xFFFF);
setInstanceIdValue(id, NOT_FOUND);
}
Expand Down
6 changes: 3 additions & 3 deletions src/org/mozilla/javascript/InterpretedFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static InterpretedFunction createFunction(Context cx,Scriptable scope,
* Create function embedded in script or another function.
*/
static InterpretedFunction createFunction(Context cx, Scriptable scope,
InterpretedFunction parent,
InterpretedFunction parent,
int index)
{
InterpretedFunction f = new InterpretedFunction(parent, index);
Expand Down Expand Up @@ -104,7 +104,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
{
if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args, idata.isStrict);
}
return Interpreter.interpret(this, cx, scope, thisObj, args);
}
Expand All @@ -118,7 +118,7 @@ public Object exec(Context cx, Scriptable scope)
if (!ScriptRuntime.hasTopCall(cx)) {
// It will go through "call" path. but they are equivalent
return ScriptRuntime.doTopCall(
this, cx, scope, scope, ScriptRuntime.emptyArgs);
this, cx, scope, scope, ScriptRuntime.emptyArgs, idata.isStrict);
}
return Interpreter.interpret(
this, cx, scope, scope, ScriptRuntime.emptyArgs);
Expand Down
6 changes: 3 additions & 3 deletions src/org/mozilla/javascript/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ public static Object restartContinuation(NativeContinuation c, Context cx,
Scriptable scope, Object[] args)
{
if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(c, cx, scope, null, args);
return ScriptRuntime.doTopCall(c, cx, scope, null, args, cx.isTopLevelStrict);
}

Object arg;
Expand Down Expand Up @@ -2759,9 +2759,9 @@ private static void initFrame(Context cx, Scriptable callerScope,

if (useActivation) {
if (idata.itsFunctionType == FunctionNode.ARROW_FUNCTION) {
scope = ScriptRuntime.createArrowFunctionActivation(fnOrScript, scope, args);
scope = ScriptRuntime.createArrowFunctionActivation(fnOrScript, scope, args, idata.isStrict);
} else {
scope = ScriptRuntime.createFunctionActivation(fnOrScript, scope, args);
scope = ScriptRuntime.createFunctionActivation(fnOrScript, scope, args, idata.isStrict);
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/org/mozilla/javascript/InterpreterData.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class InterpreterData implements Serializable, DebuggableScript
this.languageVersion = parent.languageVersion;
this.itsSourceFile = parent.itsSourceFile;
this.encodedSource = parent.encodedSource;

this.isStrict = parent.isStrict;
init();
}

Expand Down
19 changes: 12 additions & 7 deletions src/org/mozilla/javascript/NativeCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,15 @@ static void init(Scriptable scope, boolean sealed)

NativeCall() { }

NativeCall(NativeFunction function, Scriptable scope, Object[] args)
{
this(function, scope, args, false);
}

NativeCall(NativeFunction function, Scriptable scope, Object[] args, boolean isArrow)
NativeCall(NativeFunction function, Scriptable scope, Object[] args, boolean isArrow, boolean isStrict)
{
this.function = function;

setParentScope(scope);
// leave prototype null

this.originalArgs = (args == null) ? ScriptRuntime.emptyArgs : args;
this.isStrict = isStrict;

// initialize values of arguments
int paramAndVarCount = function.getParamAndVarCount();
Expand All @@ -57,7 +53,8 @@ static void init(Scriptable scope, boolean sealed)
// initialize "arguments" property but only if it was not overridden by
// the parameter with the same name
if (!super.has("arguments", this) && !isArrow) {
defineProperty("arguments", new Arguments(this), PERMANENT);
arguments = new Arguments(this);
defineProperty("arguments", arguments, PERMANENT);
}

if (paramAndVarCount != 0) {
Expand Down Expand Up @@ -118,12 +115,20 @@ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
throw new IllegalArgumentException(String.valueOf(id));
}

public void defineAttributesForArguments() {
if (arguments != null) {
arguments.defineAttributesForStrictMode();
}
}

private static final int
Id_constructor = 1,
MAX_PROTOTYPE_ID = 1;

NativeFunction function;
Object[] originalArgs;
boolean isStrict;
private Arguments arguments;

transient NativeCall parentActivationCall;
}
Expand Down
21 changes: 0 additions & 21 deletions src/org/mozilla/javascript/NativeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,6 @@ public String getClassName() {
return "Generator";
}

private static class CloseGeneratorAction implements ContextAction {
private NativeGenerator generator;

CloseGeneratorAction(NativeGenerator generator) {
this.generator = generator;
}

public Object run(Context cx) {
Scriptable scope = ScriptableObject.getTopLevelScope(generator);
Callable closeGenerator = new Callable() {
public Object call(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args) {
return ((NativeGenerator)thisObj).resume(cx, scope,
GENERATOR_CLOSE, new GeneratorClosedException());
}
};
return ScriptRuntime.doTopCall(closeGenerator, cx, scope,
generator, null);
}
}

@Override
protected void initPrototypeId(int id) {
String s;
Expand Down
Loading