Skip to content

Commit be5d4d0

Browse files
aardvark179gbrail
authored andcommitted
Convert ES6Iteratorz to descriptors.
1 parent 9f01f4f commit be5d4d0

10 files changed

Lines changed: 164 additions & 93 deletions

File tree

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

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
package org.mozilla.javascript;
88

9+
import static org.mozilla.javascript.ClassDescriptor.Builder.value;
910
import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
11+
import static org.mozilla.javascript.Symbol.Kind.REGULAR;
1012

1113
import java.io.Serial;
1214
import java.util.EnumSet;
@@ -26,14 +28,16 @@ public class BaseFunction extends ScriptableObject implements Function {
2628

2729
private static final Object FUNCTION_TAG = "Function";
2830
private static final String FUNCTION_CLASS = "Function";
29-
static final String GENERATOR_FUNCTION_CLASS = "__GeneratorFunction";
31+
static final SymbolKey GENERATOR_FUNCTION_CLASS =
32+
new SymbolKey("GeneratorFunctionPrototype", REGULAR);
3033

3134
private static final String APPLY_TAG = "APPLY_TAG";
3235
private static final String CALL_TAG = "CALL_TAG";
3336
private static final String PROTOTYPE_PROPERTY_NAME = "prototype";
3437

3538
private static final ClassDescriptor DESCRIPTOR;
3639
private static final ClassDescriptor ES6_DESCRIPTOR;
40+
private static final ClassDescriptor GENERATOR_DESCRIPTOR;
3741
private static final JSDescriptor<JSFunction> APPLY_DESCRIPTOR;
3842
private static final JSDescriptor<JSFunction> CALL_DESCRIPTOR;
3943

@@ -69,6 +73,19 @@ public class BaseFunction extends ScriptableObject implements Function {
6973

7074
APPLY_DESCRIPTOR = DESCRIPTOR.findProtoDesc("apply");
7175
CALL_DESCRIPTOR = DESCRIPTOR.findProtoDesc("call");
76+
77+
GENERATOR_DESCRIPTOR =
78+
new ClassDescriptor.Builder(
79+
GENERATOR_FUNCTION_CLASS,
80+
"GeneratorFunction",
81+
1,
82+
BaseFunction::js_gen_constructor,
83+
BaseFunction::js_gen_constructor)
84+
.withProp(
85+
PROTO,
86+
SymbolKey.TO_STRING_TAG,
87+
value("GeneratorFunction", READONLY | DONTENUM))
88+
.build();
7289
}
7390

7491
static JSFunction init(Context cx, VarScope scope, boolean sealed) {
@@ -91,41 +108,29 @@ static void init(VarScope scope, boolean sealed) {
91108
init(Context.getContext(), scope, sealed);
92109
}
93110

94-
static Object initAsGeneratorFunction(VarScope scope, boolean sealed) {
111+
static Object initAsGeneratorFunction(Context cx, VarScope scope, boolean sealed) {
95112
var proto = new NativeObject();
96-
VarScope top = ScriptableObject.getTopLevelScope(scope);
97-
98-
var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
99-
var functionProto =
100-
(Scriptable) ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
101-
proto.setPrototype(functionProto);
102113

103-
var iterator = (Scriptable) ScriptableObject.getProperty(scope, "Iterator");
104-
ScriptableObject.putProperty(
114+
return GENERATOR_DESCRIPTOR.buildConstructor(
115+
cx,
116+
scope,
105117
proto,
106-
PROTOTYPE_PROPERTY_NAME,
107-
ScriptableObject.getTopScopeValue(top, ES6Generator.GENERATOR_TAG));
118+
sealed,
119+
(c, ctor) -> {
120+
VarScope top = ScriptableObject.getTopLevelScope(scope);
108121

109-
LambdaConstructor ctor =
110-
new LambdaConstructor(
111-
scope,
112-
GENERATOR_FUNCTION_CLASS,
113-
1,
114-
proto,
115-
BaseFunction::js_gen_constructorCall,
116-
BaseFunction::js_gen_constructor);
122+
var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
123+
var functionProto =
124+
(Scriptable)
125+
ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
126+
proto.setPrototype(functionProto);
117127

118-
proto.defineProperty("constructor", ctor, READONLY | DONTENUM);
128+
var generatorProto =
129+
ScriptableObject.getTopScopeValue(top, ES6Generator.GENERATOR_TAG);
119130

120-
// Function.prototype attributes: see ECMA 15.3.3.1
121-
ctor.setPrototypePropertyAttributes(DONTENUM | READONLY | PERMANENT);
122-
123-
proto.defineProperty(SymbolKey.TO_STRING_TAG, "GeneratorFunction", READONLY | DONTENUM);
124-
ScriptableObject.putProperty(scope, GENERATOR_FUNCTION_CLASS, ctor);
125-
// Function.prototype attributes: see ECMA 15.3.3.1
126-
// The "GeneratorFunction" name actually never appears in the global scope.
127-
// Return it here so it can be cached as a "builtin"
128-
return ctor;
131+
proto.setAttributes("constructor", DONTENUM | READONLY);
132+
proto.defineProperty("prototype", generatorProto, READONLY | DONTENUM);
133+
});
129134
}
130135

131136
public BaseFunction() {
@@ -283,6 +288,11 @@ protected static boolean prototypeDescSetter(
283288
}
284289
}
285290

291+
static DescriptorInfo createThrowingProp(Context cx, VarScope scope, ScriptableObject obj) {
292+
var thrower = ScriptRuntime.typeErrorThrower(scope);
293+
return new DescriptorInfo(false, NOT_FOUND, true, thrower, thrower, null);
294+
}
295+
286296
protected final boolean defaultHas(String name) {
287297
return super.has(name, this);
288298
}
@@ -297,7 +307,7 @@ protected final void defaultPut(String name, Object value) {
297307

298308
@Override
299309
public String getClassName() {
300-
return isGeneratorFunction() ? GENERATOR_FUNCTION_CLASS : FUNCTION_CLASS;
310+
return isGeneratorFunction() ? "GeneratorFunction" : FUNCTION_CLASS;
301311
}
302312

303313
// Generated code will override this
@@ -468,18 +478,14 @@ private static Object js_toString(
468478
return realf.decompile(indent, EnumSet.noneOf(DecompilerFlag.class));
469479
}
470480

471-
private static Scriptable js_gen_constructorCall(
472-
Context cx, VarScope scope, Object thisObj, Object[] args) {
473-
return js_gen_constructor(cx, scope, args);
474-
}
475-
476481
private static Scriptable js_constructor(
477482
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
478483
return jsConstructor(cx, f.getDeclarationScope(), args, false);
479484
}
480485

481-
private static Scriptable js_gen_constructor(Context cx, VarScope scope, Object[] args) {
482-
return jsConstructor(cx, scope, args, true);
486+
private static Scriptable js_gen_constructor(
487+
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
488+
return jsConstructor(cx, f.getDeclarationScope(), args, true);
483489
}
484490

485491
private static BaseFunction realFunction(Object thisObj, String functionName) {

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

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,32 @@
66

77
package org.mozilla.javascript;
88

9+
import static org.mozilla.javascript.ClassDescriptor.Builder.value;
10+
import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
11+
import static org.mozilla.javascript.Symbol.Kind.REGULAR;
12+
913
import java.io.Serial;
1014

1115
public final class ES6Generator extends ScriptableObject {
1216
@Serial private static final long serialVersionUID = -1617667918827493330L;
1317

14-
static final Object GENERATOR_TAG = "Generator";
18+
static final SymbolKey GENERATOR_TAG = new SymbolKey("GeneratorPrototype", REGULAR);
19+
20+
private static final ClassDescriptor DESCRIPTOR;
21+
22+
static {
23+
DESCRIPTOR =
24+
new ClassDescriptor.Builder(GENERATOR_TAG)
25+
.withMethod(CTOR, "next", 1, ES6Generator::js_next)
26+
.withMethod(CTOR, "return", 1, ES6Generator::js_return)
27+
.withMethod(CTOR, "throw", 1, ES6Generator::js_throw)
28+
.withMethod(CTOR, SymbolKey.ITERATOR, 0, ES6Generator::js_iterator)
29+
.withProp(
30+
CTOR,
31+
SymbolKey.TO_STRING_TAG,
32+
value("Generator", DONTENUM | READONLY))
33+
.build();
34+
}
1535

1636
private JSFunction function;
1737
private Object savedState;
@@ -20,33 +40,13 @@ public final class ES6Generator extends ScriptableObject {
2040
private State state = State.SUSPENDED_START;
2141
private Object delegee;
2242

23-
static ES6Generator init(TopLevel scope, boolean sealed) {
24-
25-
ES6Generator prototype = new ES6Generator();
26-
if (scope != null) {
27-
prototype.setParentScope(scope);
28-
prototype.setPrototype(getObjectPrototype(scope));
29-
}
30-
31-
// Define prototype methods using LambdaFunction
32-
LambdaFunction next = new LambdaFunction(scope, "next", 1, ES6Generator::js_next);
33-
ScriptableObject.defineProperty(prototype, "next", next, DONTENUM);
34-
35-
LambdaFunction returnFunc = new LambdaFunction(scope, "return", 1, ES6Generator::js_return);
36-
ScriptableObject.defineProperty(prototype, "return", returnFunc, DONTENUM);
37-
38-
LambdaFunction throwFunc = new LambdaFunction(scope, "throw", 1, ES6Generator::js_throw);
39-
ScriptableObject.defineProperty(prototype, "throw", throwFunc, DONTENUM);
43+
static ScriptableObject init(Context cx, TopLevel scope, boolean sealed) {
4044

41-
LambdaFunction iterator =
42-
new LambdaFunction(scope, "[Symbol.iterator]", 0, ES6Generator::js_iterator);
43-
prototype.defineProperty(SymbolKey.ITERATOR, iterator, DONTENUM);
45+
NativeObject prototype = new NativeObject();
46+
DESCRIPTOR.populateGlobal(cx, scope, prototype, sealed);
4447

45-
prototype.defineProperty(SymbolKey.TO_STRING_TAG, "Generator", DONTENUM | READONLY);
46-
47-
if (sealed) {
48-
prototype.sealObject();
49-
}
48+
var iterCtor = (JSFunction) scope.get("Iterator", scope);
49+
prototype.setPrototype((Scriptable) iterCtor.getPrototypeProperty());
5050

5151
// Need to access Generator prototype when constructing
5252
// Generator instances, but don't have a generator constructor
@@ -77,8 +77,8 @@ public ES6Generator(VarScope scope, JSFunction function, Object savedState) {
7777
// If function.prototype is not an Object, use the intrinsic default prototype
7878
// Ref: Ecma 2026, 10.1.14 GetPrototypeFromConstructor step 4.
7979
// See test262: language/statements/generators/default-proto.js
80-
ES6Generator prototype =
81-
(ES6Generator) ScriptableObject.getTopScopeValue(top, GENERATOR_TAG);
80+
ScriptableObject prototype =
81+
(ScriptableObject) ScriptableObject.getTopScopeValue(top, GENERATOR_TAG);
8282
this.setPrototype(prototype);
8383
}
8484
}
@@ -92,34 +92,38 @@ private static ES6Generator realThis(Object thisObj) {
9292
return LambdaConstructor.convertThisObject(thisObj, ES6Generator.class);
9393
}
9494

95-
private static Object js_return(Context cx, VarScope scope, Object thisObj, Object[] args) {
95+
private static Object js_return(
96+
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
9697
ES6Generator generator = realThis(thisObj);
9798
Object value = args.length >= 1 ? args[0] : Undefined.instance;
9899
if (generator.delegee == null) {
99-
return generator.resumeAbruptLocal(cx, scope, NativeGenerator.GENERATOR_CLOSE, value);
100+
return generator.resumeAbruptLocal(cx, s, NativeGenerator.GENERATOR_CLOSE, value);
100101
}
101-
return generator.resumeDelegeeReturn(cx, scope, value);
102+
return generator.resumeDelegeeReturn(cx, s, value);
102103
}
103104

104-
private static Object js_next(Context cx, VarScope scope, Object thisObj, Object[] args) {
105+
private static Object js_next(
106+
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
105107
ES6Generator generator = realThis(thisObj);
106108
Object value = args.length >= 1 ? args[0] : Undefined.instance;
107109
if (generator.delegee == null) {
108-
return generator.resumeLocal(cx, scope, value);
110+
return generator.resumeLocal(cx, s, value);
109111
}
110-
return generator.resumeDelegee(cx, scope, value);
112+
return generator.resumeDelegee(cx, s, value);
111113
}
112114

113-
private static Object js_throw(Context cx, VarScope scope, Object thisObj, Object[] args) {
115+
private static Object js_throw(
116+
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
114117
ES6Generator generator = realThis(thisObj);
115118
Object value = args.length >= 1 ? args[0] : Undefined.instance;
116119
if (generator.delegee == null) {
117-
return generator.resumeAbruptLocal(cx, scope, NativeGenerator.GENERATOR_THROW, value);
120+
return generator.resumeAbruptLocal(cx, s, NativeGenerator.GENERATOR_THROW, value);
118121
}
119-
return generator.resumeDelegeeThrow(cx, scope, value);
122+
return generator.resumeDelegeeThrow(cx, s, value);
120123
}
121124

122-
private static Object js_iterator(Context cx, VarScope scope, Object thisObj, Object[] args) {
125+
private static Object js_iterator(
126+
Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
123127
return thisObj;
124128
}
125129

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4181,7 +4181,9 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
41814181
state.indexReg += frame.idata.itsMaxVars;
41824182
int enumType =
41834183
op == Token.ENUM_INIT_KEYS
4184-
? ScriptRuntime.ENUMERATE_KEYS
4184+
? cx.getLanguageVersion() <= Context.VERSION_1_8
4185+
? ScriptRuntime.ENUMERATE_KEYS
4186+
: ScriptRuntime.ENUMERATE_KEYS_NO_ITERATOR
41854187
: op == Token.ENUM_INIT_VALUES
41864188
? ScriptRuntime.ENUMERATE_VALUES
41874189
: op == Token.ENUM_INIT_VALUES_IN_ORDER

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ public final class NativeIterator extends ScriptableObject {
4646
}
4747

4848
static void init(Context cx, TopLevel scope, boolean sealed) {
49-
NativeIterator proto = new NativeIterator();
49+
NativeObject proto = new NativeObject();
5050
var ctor = DESCRIPTOR.buildConstructor(cx, scope, proto, sealed);
5151

5252
// Generator
5353
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
54-
ES6Generator.init(scope, sealed);
54+
ES6Generator.init(cx, scope, sealed);
5555
} else {
5656
NativeGenerator.init(cx, scope, sealed);
5757
}

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
package org.mozilla.javascript;
88

9+
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
10+
import static org.mozilla.javascript.ScriptableObject.PERMANENT;
11+
import static org.mozilla.javascript.ScriptableObject.READONLY;
12+
import static org.mozilla.javascript.Symbol.Kind.REGULAR;
13+
import static org.mozilla.javascript.UniqueTag.NOT_FOUND;
14+
915
import java.io.Serializable;
1016
import java.lang.reflect.Constructor;
1117
import java.lang.reflect.Field;
@@ -69,11 +75,19 @@ public static BaseFunction typeErrorThrower() {
6975

7076
/** Returns representation of the [[ThrowTypeError]] object. See ECMA 5 spec, 13.2.3 */
7177
public static BaseFunction typeErrorThrower(Context cx) {
72-
if (cx.typeErrorThrower == null) {
73-
BaseFunction thrower = new ThrowTypeError(cx.topCallScope);
74-
cx.typeErrorThrower = thrower;
78+
return typeErrorThrower(cx.topCallScope);
79+
}
80+
81+
private static final SymbolKey TYPE_ERROR_THROWER = new SymbolKey("TypeErrorThrower", REGULAR);
82+
83+
public static BaseFunction typeErrorThrower(VarScope scope) {
84+
TopLevel top = ScriptableObject.getTopLevelScope(scope);
85+
var thrower = top.get(TYPE_ERROR_THROWER, top);
86+
if (thrower == NOT_FOUND) {
87+
thrower = new ThrowTypeError(top);
88+
top.defineProperty(TYPE_ERROR_THROWER, thrower, DONTENUM | READONLY | PERMANENT);
7589
}
76-
return cx.typeErrorThrower;
90+
return (BaseFunction) thrower;
7791
}
7892

7993
static final class ThrowTypeError extends BaseFunction {
@@ -1639,6 +1653,17 @@ public static Function getExistingCtor(Context cx, VarScope scope, String constr
16391653
throw Context.reportRuntimeErrorById("msg.not.ctor", constructorName);
16401654
}
16411655

1656+
public static Function getExistingCtor(Context cx, VarScope scope, SymbolKey constructorName) {
1657+
Object ctorVal = ScriptableObject.getProperty(scope, constructorName);
1658+
if (ctorVal instanceof Function) {
1659+
return (Function) ctorVal;
1660+
}
1661+
if (ctorVal == Scriptable.NOT_FOUND) {
1662+
throw Context.reportRuntimeErrorById("msg.ctor.not.found", constructorName);
1663+
}
1664+
throw Context.reportRuntimeErrorById("msg.not.ctor", constructorName);
1665+
}
1666+
16421667
/**
16431668
* Return -1L if str is not an index, or the index value as lower 32 bits of the result. Note
16441669
* that the result needs to be cast to an int in order to produce the actual index, which may be

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,24 @@ public static Scriptable getClassPrototype(VarScope scope, String className) {
22152215
return null;
22162216
}
22172217

2218+
public static Scriptable getClassPrototype(VarScope scope, Symbol className) {
2219+
scope = getTopLevelScope(scope);
2220+
Object ctor = getProperty(scope, className);
2221+
Object proto;
2222+
if (ctor instanceof BaseFunction) {
2223+
proto = ((BaseFunction) ctor).getPrototypeProperty();
2224+
} else if (ctor instanceof Scriptable) {
2225+
Scriptable ctorObj = (Scriptable) ctor;
2226+
proto = ctorObj.get("prototype", ctorObj);
2227+
} else {
2228+
return null;
2229+
}
2230+
if (proto instanceof Scriptable) {
2231+
return (Scriptable) proto;
2232+
}
2233+
return null;
2234+
}
2235+
22182236
/**
22192237
* Get the global scope.
22202238
*
@@ -2317,6 +2335,10 @@ public static Object getProperty(VarScope obj, String name) {
23172335
return obj.get(name, obj);
23182336
}
23192337

2338+
public static Object getProperty(VarScope obj, Symbol name) {
2339+
return obj.get(name, obj);
2340+
}
2341+
23202342
/**
23212343
* Gets a named property from super, walking the super's prototype chain, but passing the
23222344
* correct "this" to getter slots.

0 commit comments

Comments
 (0)