[ddc] Cleanup changes to JSArray prototype

The old runtime type system required prototype manipulations to
correctly capture a type that contained an embedded type argument.
This was achieved by assigning the prototype of the array in the
JSArray factories and connecting the prototype chain so JSArray
"extended" the native JavaScript Array.

In the new runtime type system these special case operations are
not needed.

Remove the error state for `JS_CLASS_REF()` for interface types
with type arguments. The class definitions are now defined outside
of closures so they can be referenced just like classes without
type arguments.

Update debugger API to manually identify the library for JSArray and
remove unnecessary accesses of `.length` via JavaScript.

Cleanup skipped test cases for the old runtime type system.

Change-Id: I57ab0c968ec06437dad0e081f6334268e99dbc69
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385102
Commit-Queue: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Nicholas Shahan 2024-09-13 22:47:15 +00:00 committed by Commit Queue
parent 5cf401f976
commit d4c9263fde
6 changed files with 11 additions and 84 deletions

View file

@ -1083,14 +1083,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
body.addAll(jsCtors);
// Emit things that come after the ES6 `class ... { ... }`.
var jsPeerNames = _extensionTypes.getNativePeers(c);
if (jsPeerNames.length == 1 && c.typeParameters.isNotEmpty) {
// Special handling for JSArray<E>
body.add(_runtimeStatement('setExtensionBaseClass(#, #)', [
className,
_runtimeCall('global.#', [jsPeerNames[0]])
]));
}
/// Collects all implemented types in the ancestry of [cls].
Iterable<Supertype> transitiveImplementedTypes(Class cls) {
@ -1151,7 +1143,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Instead, just assign the identity equals method.
body.add(_runtimeStatement('_installIdentityEquals()'));
} else {
for (var peer in jsPeerNames) {
for (var peer in _extensionTypes.getNativePeers(c)) {
_registerExtensionType(c, peer, body);
}
}
@ -6175,11 +6167,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
'JS_CLASS_REF only supports interface types: found $type '
'(${type.runtimeType}) at ${node.location}');
}
if (type.typeArguments.isNotEmpty) {
throw UnsupportedError(
'JS_CLASS_REF does not support type arguments: found '
'${type.typeArguments} at ${node.location}');
}
return _emitTopLevelName(type.classNode);
}
if (name == 'RAW_DART_FUNCTION_REF') {

View file

@ -1171,14 +1171,6 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
body.addAll(jsCtors);
// Emit things that come after the ES6 `class ... { ... }`.
var jsPeerNames = _extensionTypes.getNativePeers(c);
if (jsPeerNames.length == 1 && c.typeParameters.isNotEmpty) {
// Special handling for JSArray<E>
body.add(_runtimeStatement('setExtensionBaseClass(#, #)', [
className,
_runtimeCall('global.#', [jsPeerNames[0]])
]));
}
/// Collects all implemented types in the ancestry of [cls].
Iterable<Supertype> transitiveImplementedTypes(Class cls) {
@ -1241,7 +1233,7 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Instead, just assign the identity equals method.
body.add(_runtimeStatement('_installIdentityEquals()'));
} else {
for (var peer in jsPeerNames) {
for (var peer in _extensionTypes.getNativePeers(c)) {
_registerExtensionType(c, peer, body);
}
}
@ -6255,11 +6247,6 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
'JS_CLASS_REF only supports interface types: found $type '
'(${type.runtimeType}) at ${node.location}');
}
if (type.typeArguments.isNotEmpty) {
throw UnsupportedError(
'JS_CLASS_REF does not support type arguments: found '
'${type.typeArguments} at ${node.location}');
}
return _emitTopLevelName(type.classNode);
}
if (name == 'RAW_DART_FUNCTION_REF') {

View file

@ -566,44 +566,6 @@ void runSharedTests(
);
});
test('getObjectMetadata (DartType)', () async {
final innerType = 'dart.dloadRepl(object.runtimeType, "_type")';
final typeName = await driver.evaluateJsExpression(
breakpointId: 'BP',
expression: '$innerType.toString()',
);
expect(typeName, startsWith('class Object'));
await driver.checkRuntimeInFrame(
breakpointId: 'BP',
expression: 'dart.getObjectMetadata($innerType)',
expectedResult: {
'className': 'Type',
'libraryId': null,
'runtimeKind': 'function',
'length': 0,
});
}, skip: 'Only applies to old type system');
test('getObjectMetadata (RecordType)', () async {
final innerType = 'dart.dloadRepl(record.runtimeType, "_type")';
final typeName = await driver.evaluateJsExpression(
breakpointId: 'BP',
expression: '$innerType.toString()',
);
expect(typeName, '(int, int, {String name})');
await driver.checkRuntimeInFrame(
breakpointId: 'BP',
expression: 'dart.getObjectMetadata($innerType)',
expectedResult: {
'className': 'Type',
'libraryId': 'dart:core',
'runtimeKind': 'type',
'typeName': '(int, int, {String name})'
});
}, skip: 'Only applies to old type system');
test('getObjectMetadata (Rti)', () async {
final rti = 'dart.dloadRepl(object.runtimeType, "_rti")';
final typeName = await driver.evaluateJsExpression(

View file

@ -481,16 +481,6 @@ void classExtends(@notNull Object cls, @notNull Object superClass) {
JS('', '#.prototype', cls), JS('', '#.prototype', superClass));
}
/// Link the [dartType] to the native [jsType] it is extending as a base class.
///
/// Used for generic extension types such as `JSArray<E>`.
void setExtensionBaseClass(@notNull Object dartType, @notNull Object jsType) {
// Mark the generic type as an extension type and link the prototype objects.
var dartProto = JS<Object>('!', '#.prototype', dartType);
JS('', '#[#] = #', dartProto, _extensionType, dartType);
jsObjectSetPrototypeOf(dartProto, JS('', '#.prototype', jsType));
}
/// A runtime mapping of interface type recipe to the symbol used to tag the
/// class for simple identification in the dart:rti library.
///

View file

@ -287,7 +287,11 @@ Object getObjectMetadata(@notNull Object object) {
var reifiedType = getReifiedType(object);
var className = typeName(reifiedType);
var libraryId = null;
var cls = _get<Object?>(object, 'constructor');
var cls = JS<bool>('!', '#.Array.isArray(#)', global_, object)
// When the object is actually represented by a JavaScript Array use the
// interceptor class that matches the reified type.
? JS_CLASS_REF(JSArray)
: _get<Object?>(object, 'constructor');
if (cls != null) {
libraryId = getLibraryUri(cls);
}
@ -298,16 +302,16 @@ Object getObjectMetadata(@notNull Object object) {
});
if (object is String) {
_set(result, 'length', _get(object, 'length'));
_set(result, 'length', object.length);
} else if (object is List) {
_set(result, 'runtimeKind', RuntimeObjectKind.list);
_set(result, 'length', _get(object, 'length'));
_set(result, 'length', object.length);
} else if (object is Map) {
_set(result, 'runtimeKind', RuntimeObjectKind.map);
_set(result, 'length', _get(object, 'length'));
_set(result, 'length', object.length);
} else if (object is Set) {
_set(result, 'runtimeKind', RuntimeObjectKind.set);
_set(result, 'length', _get(object, 'length'));
_set(result, 'length', object.length);
} else if (object is Function) {
_set(result, 'runtimeKind', RuntimeObjectKind.function);
} else if (object is RecordImpl) {

View file

@ -20,21 +20,18 @@ class JSArray<E> extends JavaScriptObject
/// Array. Used for creating literal lists.
factory JSArray.of(@notNull Object list) {
// TODO(sra): Move this to core.List for better readability.
jsObjectSetPrototypeOf(list, JS('', 'this.prototype'));
JS('', '#.# = #', list, _arrayRtiSymbol, JS_RTI_PARAMETER());
return JS('-dynamic', '#', list);
}
// TODO(jmesserly): consider a fixed array subclass instead.
factory JSArray.fixed(@notNull Object list) {
jsObjectSetPrototypeOf(list, JS('', 'this.prototype'));
JS('', r'#.fixed$length = Array', list);
JS('', '#.# = #', list, _arrayRtiSymbol, JS_RTI_PARAMETER());
return JS('-dynamic', '#', list);
}
factory JSArray.unmodifiable(@notNull Object list) {
jsObjectSetPrototypeOf(list, JS('', 'this.prototype'));
JS('', r'#.fixed$length = Array', list);
JS('', r'#.immutable$list = Array', list);
JS('', '#.# = #', list, _arrayRtiSymbol, JS_RTI_PARAMETER());