Skip to content

Commit b455392

Browse files
committed
make arguments a function prototype property
1 parent e326961 commit b455392

File tree

8 files changed

+257
-64
lines changed

8 files changed

+257
-64
lines changed

rhino/src/main/java/org/mozilla/javascript/BaseFunction.java

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ static LambdaConstructor init(Context cx, Scriptable scope, boolean sealed) {
6969
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
7070
ctor.setStandardPropertyAttributes(READONLY | DONTENUM);
7171
}
72+
73+
if (!cx.isStrictMode() && cx.getLanguageVersion() >= Context.VERSION_ES6) {
74+
ctor.definePrototypeProperty(
75+
cx,
76+
"arguments",
77+
BaseFunction::js_protoArgumentsGetter,
78+
BaseFunction::js_protoArgumentsSetter,
79+
DONTENUM | READONLY);
80+
}
81+
7282
ScriptableObject.defineProperty(scope, FUNCTION_CLASS, ctor, DONTENUM);
7383
if (sealed) {
7484
ctor.sealObject();
@@ -177,20 +187,21 @@ protected void createProperties() {
177187
DONTENUM | READONLY,
178188
BaseFunction::nameGetter,
179189
BaseFunction::nameSetter);
180-
if (includeNonStandardProps()) {
190+
191+
Context cx = Context.getCurrentContext();
192+
if (cx == null || !cx.isStrictMode()) {
181193
ScriptableObject.defineBuiltInProperty(
182194
this, "arity", PERMANENT | DONTENUM | READONLY, BaseFunction::arityGetter);
183-
ScriptableObject.defineBuiltInProperty(
184-
this,
185-
"arguments",
186-
PERMANENT | DONTENUM,
187-
BaseFunction::argumentsGetter,
188-
BaseFunction::argumentsSetter);
189-
}
190-
}
191195

192-
protected boolean includeNonStandardProps() {
193-
return !Context.isCurrentContextStrict();
196+
if (cx == null || cx.getLanguageVersion() < Context.VERSION_ES6) {
197+
ScriptableObject.defineBuiltInProperty(
198+
this,
199+
"arguments",
200+
PERMANENT | DONTENUM,
201+
BaseFunction::argumentsGetter,
202+
BaseFunction::argumentsSetter);
203+
}
204+
}
194205
}
195206

196207
private static Object lengthGetter(BaseFunction function, Scriptable start) {
@@ -627,6 +638,14 @@ public int getLength() {
627638
return 0;
628639
}
629640

641+
private static Object js_protoArgumentsGetter(Scriptable thisObj) {
642+
return LambdaConstructor.convertThisObject(thisObj, BaseFunction.class).getArguments();
643+
}
644+
645+
private static void js_protoArgumentsSetter(Scriptable thisObj, Object value) {
646+
LambdaConstructor.convertThisObject(thisObj, BaseFunction.class).setArguments(value);
647+
}
648+
630649
public String getFunctionName() {
631650
return "";
632651
}
@@ -713,7 +732,7 @@ protected synchronized Object setupDefaultPrototype(Scriptable scope) {
713732
return obj;
714733
}
715734

716-
private Object getArguments() {
735+
Object getArguments() {
717736
// <Function name>.arguments is deprecated, so we use a slow
718737
// way of getting it that doesn't add to the invocation cost.
719738
// TODO: add warning, error based on version
@@ -731,13 +750,18 @@ private Object getArguments() {
731750
if (activation == null) {
732751
return null;
733752
}
753+
if (activation.isStrict && cx.getLanguageVersion() >= Context.VERSION_ES6) {
754+
throw ScriptRuntime.typeErrorById("msg.op.not.allowed");
755+
}
734756
Object arguments = activation.get("arguments", activation);
735757
if (arguments instanceof Arguments && cx.getLanguageVersion() >= Context.VERSION_ES6) {
736758
return new Arguments.ReadonlyArguments((Arguments) arguments, cx);
737759
}
738760
return arguments;
739761
}
740762

763+
void setArguments(Object caller) {}
764+
741765
private static Scriptable jsConstructor(
742766
Context cx, Scriptable scope, Object[] args, boolean isGeneratorFunction) {
743767
int arglen = args.length;

rhino/src/main/java/org/mozilla/javascript/BoundFunction.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,21 @@ public BoundFunction(
4040
Function thrower = ScriptRuntime.typeErrorThrower(cx);
4141
var throwing = new DescriptorInfo(false, NOT_FOUND, false, thrower, thrower, NOT_FOUND);
4242

43-
this.defineOwnProperty(cx, "caller", throwing, false);
44-
this.defineOwnProperty(cx, "arguments", throwing, false);
43+
defineOwnProperty(cx, "caller", throwing, false);
44+
if (cx.getLanguageVersion() < Context.VERSION_ES6) {
45+
defineOwnProperty(cx, "arguments", throwing, false);
46+
}
47+
}
48+
49+
@Override
50+
Object getArguments() {
51+
throw ScriptRuntime.typeErrorById("msg.op.not.allowed");
52+
}
53+
54+
@Override
55+
void setArguments(Object caller) {
56+
// todo
57+
throw ScriptRuntime.typeErrorById("msg.op.not.allowed");
4558
}
4659

4760
@Override

tests/src/test/java/org/mozilla/javascript/tests/es6/ArgumentsTest.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public void argumentsShouldBeNullOutsideFunctionStrict() {
238238
+ "res";
239239

240240
// Utils.assertWithAllModes_ES6("ex [object Arguments] ex ex", code);
241-
Utils.assertWithAllModes_ES6("null [object Arguments] null null", code);
241+
Utils.assertWithAllModes_ES6("null [object Arguments] ex null", code);
242242
Utils.assertWithAllModes_1_8("null [object Arguments] null null", code);
243243
}
244244

@@ -255,7 +255,7 @@ public void argumentsOutsideFunction() {
255255
+ "res";
256256

257257
// Utils.assertWithAllModes_ES6("undefined length,name,prototype", code);
258-
Utils.assertWithAllModes_ES6("[object Object] arguments,arity,length,name,prototype", code);
258+
Utils.assertWithAllModes_ES6("undefined arity,length,name,prototype", code);
259259
Utils.assertWithAllModes_1_8("[object Object] arguments,arity,length,name,prototype", code);
260260
}
261261

@@ -340,8 +340,7 @@ public void passedCountDifferentFromDeclaredStrict() {
340340
+ "test('hi', 'there');\n"
341341
+ "res";
342342

343-
// Utils.assertWithAllModes_ES6("2 ex", code);
344-
Utils.assertWithAllModes_ES6("2 null", code);
343+
Utils.assertWithAllModes_ES6("2 ex", code);
345344
Utils.assertWithAllModes_1_8("2 null", code);
346345
}
347346

@@ -636,7 +635,7 @@ public void argumentsEqualsFnArgumentsStrict() {
636635
+ "function test() {\n"
637636
+ " try {\n"
638637
+ " res += ' ' + (arguments == test.arguments);\n"
639-
+ " } catch(e) { res += 'ex'; }"
638+
+ " } catch(e) { res += ' ex'; }"
640639
+ " try {\n"
641640
+ " res += ' ' + (arguments === test.arguments);\n"
642641
+ " } catch(e) { res += ' ex'; }"
@@ -645,8 +644,7 @@ public void argumentsEqualsFnArgumentsStrict() {
645644
+ "test('hello', 'world');\n"
646645
+ "res";
647646

648-
// Utils.assertWithAllModes_ES6("ex ex", code);
649-
Utils.assertWithAllModes_ES6("null false false", code);
647+
Utils.assertWithAllModes_ES6("null ex ex", code);
650648
Utils.assertWithAllModes_1_8("null false false", code);
651649
}
652650

tests/src/test/java/org/mozilla/javascript/tests/es6/BoundFunctionTest.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
/*
6-
* Tests for the Object.getOwnPropertyDescriptor(obj, prop) method
7-
*/
85
package org.mozilla.javascript.tests.es6;
96

107
import org.junit.Test;
118
import org.mozilla.javascript.testutils.Utils;
129

10+
/*
11+
* Tests for BoundFunction
12+
*/
1313
public class BoundFunctionTest {
1414

1515
@Test
@@ -20,7 +20,7 @@ public void name() {
2020
}
2121

2222
@Test
23-
public void lenght() {
23+
public void length() {
2424
Utils.assertWithAllModes_ES6(0, "function foo() {}; foo.bind({}).length;");
2525

2626
Utils.assertWithAllModes_ES6(1, "function foo(a) {}; foo.bind({}).length;");
@@ -39,6 +39,30 @@ public void lenght() {
3939
Utils.assertWithAllModes_ES6(1, "function foo(a, b, c) {}; foo.bind({}, 'x', 'y').length;");
4040
}
4141

42+
@Test
43+
public void arguments() {
44+
String code =
45+
"function foo() { return 'Hello!'; };\n"
46+
+ "var boundFoo = foo.bind({});\n"
47+
+ "'' + Object.getOwnPropertyDescriptor(boundFoo, 'arguments');";
48+
Utils.assertWithAllModes_ES6("undefined", code);
49+
Utils.assertWithAllModes_1_8("[object Object]", code);
50+
}
51+
52+
@Test
53+
public void argumentsAccess() {
54+
String code =
55+
"function foo() { return 'Hello!'; };\n"
56+
+ "var boundFoo = foo.bind({});\n"
57+
+ "let res = '';\n"
58+
+ "try { boundFoo.arguments; res += 'no ex'; } catch (e) { res += e.message; };\n"
59+
+ "try { boundFoo.arguments = 7; res += ' no ex'; } catch (e) { res += ' ' + e.message; };";
60+
Utils.assertWithAllModes_ES6(
61+
"This operation is not allowed. This operation is not allowed.", code);
62+
Utils.assertWithAllModes_1_8(
63+
"This operation is not allowed. This operation is not allowed.", code);
64+
}
65+
4266
@Test
4367
public void fooArgs0_boundArgs0_invokeArgs0() {
4468
Utils.assertWithAllModes_ES6("boundThis []", constructCode(0, 0, "(", 0, false));
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package org.mozilla.javascript.tests.es6;
6+
7+
import org.junit.jupiter.api.Test;
8+
import org.mozilla.javascript.testutils.Utils;
9+
10+
class FunctionArityTest {
11+
12+
@Test
13+
void simple() {
14+
// todo Utils.assertWithAllModes_ES6("undefined", "function f(a,b) {}; '' + f.arity");
15+
// todo Utils.assertWithAllModes_ES6("undefined", "function f() {}; '' + f.arity");
16+
Utils.assertWithAllModes_ES6("2", "function f(a,b) {}; '' + f.arity");
17+
Utils.assertWithAllModes_ES6("0", "function f() {}; '' + f.arity");
18+
19+
Utils.assertWithAllModes_1_8("2", "function f(a,b) {}; '' + f.arity");
20+
Utils.assertWithAllModes_1_8("0", "function f() {}; '' + f.arity");
21+
}
22+
23+
@Test
24+
void arrow() {
25+
// todo Utils.assertWithAllModes_ES6("undefined", "'' + ((a,b) => {}).arity");
26+
// todo Utils.assertWithAllModes_ES6("undefined", "'' + (() => {}).arity");
27+
Utils.assertWithAllModes_ES6("2", "'' + ((a,b) => {}).arity");
28+
Utils.assertWithAllModes_ES6("0", "'' + (() => {}).arity");
29+
30+
Utils.assertWithAllModes_1_8("2", "'' + ((a,b) => {}).arity");
31+
Utils.assertWithAllModes_1_8("0", "'' + (() => {}).arity");
32+
}
33+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package org.mozilla.javascript.tests.es6;
6+
7+
import org.junit.Test;
8+
import org.mozilla.javascript.testutils.Utils;
9+
10+
/*
11+
* Tests for GeneratorFunction
12+
*/
13+
public class GeneratorFunctionTest {
14+
15+
@Test
16+
public void arguments() {
17+
String code =
18+
"function* foo() { yield 'Hello!'; };\n"
19+
+ "'' + Object.getOwnPropertyDescriptor(foo, 'arguments');";
20+
Utils.assertWithAllModes_ES6("undefined", code);
21+
}
22+
23+
@Test
24+
public void argumentsAccess() {
25+
String code =
26+
"function* foo() { yield 'Hello!'; };\n"
27+
+ "let res = '';\n"
28+
+ "try { foo.arguments; res += 'no ex'; } catch (e) { res += e.message; };\n"
29+
+ "try { foo.arguments = 7; res += ' no ex'; } catch (e) { res += ' ' + e.message; };";
30+
// todo Utils.assertWithAllModes_ES6("This operation is not allowed. This operation is not
31+
// allowed.", code);
32+
Utils.assertWithAllModes_ES6("no ex no ex", code);
33+
}
34+
}

0 commit comments

Comments
 (0)