Skip to content

Commit bf067f8

Browse files
authored
Convert NativeObject from IdScriptableObject to lambda constructor
* Make built-in function source spec compliant. * Pull JS methods out into separate private methods. * Refactor away from `IdFunctionObject`s. * Conversion of `NativeObject` to `LambdaConstructor`. * Update Test262 test properties. * Seal Object prototype when sealing constructor. * Recover performance in nsieve benchmark. * Refactor method declarations for readability.
1 parent c26c929 commit bf067f8

37 files changed

+804
-796
lines changed

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@ public Object execIdCall(
391391
((NativeFunction) ((BoundFunction) thisObj).getTargetFunction())
392392
.getPrototypeProperty();
393393
else protoProp = ScriptableObject.getProperty(thisObj, "prototype");
394-
if (protoProp instanceof IdScriptableObject) {
394+
if (protoProp instanceof NativeObject
395+
|| protoProp instanceof IdScriptableObject) {
395396
return ScriptRuntime.jsDelegatesTo(obj, (Scriptable) protoProp);
396397
}
397398
throw ScriptRuntime.typeErrorById(
@@ -505,9 +506,7 @@ String decompile(int indent, EnumSet<DecompilerFlag> flags) {
505506
sb.append(getFunctionName());
506507
sb.append("() {\n\t");
507508
}
508-
sb.append("[native code, arity=");
509-
sb.append(getArity());
510-
sb.append("]\n");
509+
sb.append("[native code]\n");
511510
if (!justbody) {
512511
sb.append("}\n");
513512
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ protected ES6Iterator(Scriptable scope, String tag) {
4242
this.tag = tag;
4343
Scriptable top = ScriptableObject.getTopLevelScope(scope);
4444
this.setParentScope(top);
45-
IdScriptableObject prototype =
46-
(IdScriptableObject) ScriptableObject.getTopScopeValue(top, tag);
45+
ScriptableObject prototype = (ScriptableObject) ScriptableObject.getTopScopeValue(top, tag);
4746
setPrototype(prototype);
4847
}
4948

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class EmbeddedSlotMap implements SlotMap {
2626
private Slot lastAdded;
2727

2828
private int count;
29+
private boolean hasIndex = false;
2930

3031
// initial slot array size, must be a power of 2
3132
private static final int INITIAL_SLOT_SIZE = 4;
@@ -79,7 +80,7 @@ public Iterator<Slot> iterator() {
7980
/** Locate the slot with the given name or index. */
8081
@Override
8182
public Slot query(Object key, int index) {
82-
if (slots == null) {
83+
if (slots == null || (key == null && !hasIndex)) {
8384
return null;
8485
}
8586

@@ -231,6 +232,7 @@ private void insertNewSlot(Slot newSlot) {
231232
firstAdded = newSlot;
232233
}
233234
lastAdded = newSlot;
235+
if (newSlot.name == null) hasIndex = true;
234236
addKnownAbsentSlot(slots, newSlot);
235237
}
236238

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

-24
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
package org.mozilla.javascript;
1010

11-
import java.util.EnumSet;
12-
1311
public class IdFunctionObject extends BaseFunction {
1412
private static final long serialVersionUID = -5332312783643935019L;
1513

@@ -97,28 +95,6 @@ public Scriptable createObject(Context cx, Scriptable scope) {
9795
throw ScriptRuntime.typeErrorById("msg.not.ctor", functionName);
9896
}
9997

100-
@Override
101-
String decompile(int indent, EnumSet<DecompilerFlag> flags) {
102-
StringBuilder sb = new StringBuilder();
103-
boolean justbody = flags.contains(DecompilerFlag.ONLY_BODY);
104-
if (!justbody) {
105-
sb.append("function ");
106-
sb.append(getFunctionName());
107-
sb.append("() { ");
108-
}
109-
sb.append("[native code for ");
110-
if (idcall instanceof Scriptable) {
111-
Scriptable sobj = (Scriptable) idcall;
112-
sb.append(sobj.getClassName());
113-
sb.append('.');
114-
}
115-
sb.append(getFunctionName());
116-
sb.append(", arity=");
117-
sb.append(getArity());
118-
sb.append(justbody ? "]\n" : "] }\n");
119-
return sb.toString();
120-
}
121-
12298
@Override
12399
public int getArity() {
124100
return arity;

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

+36
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,24 @@ public void definePrototypeMethod(
181181
proto.defineProperty(name, f, attributes);
182182
}
183183

184+
/**
185+
* Define a function property on the prototype of the constructor using a LambdaFunction under
186+
* the covers.
187+
*/
188+
public void definePrototypeMethod(
189+
Scriptable scope,
190+
String name,
191+
int length,
192+
Object prototype,
193+
SerializableCallable target,
194+
int attributes,
195+
int propertyAttributes) {
196+
LambdaFunction f = new LambdaFunction(scope, name, length, prototype, target);
197+
f.setStandardPropertyAttributes(propertyAttributes);
198+
ScriptableObject proto = getPrototypeScriptable();
199+
proto.defineProperty(name, f, attributes);
200+
}
201+
184202
/** Define a property that may be of any type on the prototype of this constructor. */
185203
public void definePrototypeProperty(String name, Object value, int attributes) {
186204
ScriptableObject proto = getPrototypeScriptable();
@@ -306,6 +324,24 @@ public void defineConstructorMethod(
306324
defineProperty(name, f, attributes);
307325
}
308326

327+
/**
328+
* Define a function property directly on the constructor that is implemented under the covers
329+
* by a LambdaFunction, and override the properties of its "name", "length", "arity", and
330+
* "protoyupe" properties.
331+
*/
332+
public void defineConstructorMethod(
333+
Scriptable scope,
334+
String name,
335+
int length,
336+
Object prototype,
337+
SerializableCallable target,
338+
int attributes,
339+
int propertyAttributes) {
340+
LambdaFunction f = new LambdaFunction(scope, name, length, prototype, target);
341+
f.setStandardPropertyAttributes(propertyAttributes);
342+
defineProperty(name, f, attributes);
343+
}
344+
309345
/**
310346
* Replace the default "Object" prototype with a prototype of a specific implementation. This is
311347
* only necessary for a few built-in constructors, like Boolean, that must have their prototype

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

+24
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,30 @@ public LambdaFunction(Scriptable scope, String name, int length, SerializableCal
3838
setupDefaultPrototype();
3939
}
4040

41+
/**
42+
* Create a new function. The new object will have the Function prototype and no parent. The
43+
* caller is responsible for binding this object to the appropriate scope.
44+
*
45+
* @param scope scope of the calling context
46+
* @param name name of the function
47+
* @param length the arity of the function
48+
* @param prototype prototype to set for this function
49+
* @param target an object that implements the function in Java. Since Callable is a
50+
* single-function interface this will typically be implemented as a lambda.
51+
*/
52+
public LambdaFunction(
53+
Scriptable scope,
54+
String name,
55+
int length,
56+
Object prototype,
57+
SerializableCallable target) {
58+
this.target = target;
59+
this.name = name;
60+
this.length = length;
61+
ScriptRuntime.setFunctionProtoAndParent(this, Context.getCurrentContext(), scope);
62+
setPrototypeProperty(prototype);
63+
}
64+
4165
/** Create a new built-in function, with no name, and no default prototype. */
4266
public LambdaFunction(Scriptable scope, int length, SerializableCallable target) {
4367
this.target = target;

0 commit comments

Comments
 (0)