mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 00:22:55 +00:00
[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:
parent
5cf401f976
commit
d4c9263fde
|
@ -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') {
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue