mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:41:19 +00:00
[js_runtime] Faster List.of copying a JSArray
Improved inferrer to handle some cases of JS-fragments. The JS-fragment to copy the array caused the inferrer to be too pessimistic about list-tracing into List.of. Change-Id: I0cb4f7610d971d7927d973bd2b0b532d4cef9a7e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/173883 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
This commit is contained in:
parent
0d145f836b
commit
f0be731480
|
@ -6,6 +6,7 @@ library compiler.src.inferrer.list_tracer;
|
|||
|
||||
import '../common/names.dart';
|
||||
import '../elements/entities.dart';
|
||||
import '../native/behavior.dart';
|
||||
import '../universe/selector.dart' show Selector;
|
||||
import '../util/util.dart' show Setlet;
|
||||
import 'node_tracer.dart';
|
||||
|
@ -162,10 +163,16 @@ class ListTracerVisitor extends TracerVisitor {
|
|||
@override
|
||||
visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
|
||||
super.visitStaticCallSiteTypeInformation(info);
|
||||
final commonElements = inferrer.closedWorld.commonElements;
|
||||
MemberEntity called = info.calledElement;
|
||||
if (inferrer.closedWorld.commonElements.isForeign(called) &&
|
||||
called.name == Identifiers.JS) {
|
||||
bailout('Used in JS ${info.debugName}');
|
||||
if (commonElements.isForeign(called) && called.name == Identifiers.JS) {
|
||||
NativeBehavior nativeBehavior = inferrer.closedWorld.elementMap
|
||||
.getNativeBehaviorForJsCall(info.invocationNode);
|
||||
// Assume side-effects means that the list has escaped to some unknown
|
||||
// location.
|
||||
if (nativeBehavior.sideEffects.hasSideEffects()) {
|
||||
bailout('Used in JS ${info.debugName}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -968,6 +968,8 @@ class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
|
|||
: super(abstractValueDomain, context, call, enclosing, selector,
|
||||
arguments, inLoop);
|
||||
|
||||
ir.StaticInvocation get invocationNode => _call as ir.StaticInvocation;
|
||||
|
||||
MemberTypeInformation _getCalledTypeInfo(InferrerEngine inferrer) {
|
||||
return inferrer.types.getInferredTypeOfMember(calledElement);
|
||||
}
|
||||
|
|
|
@ -51,22 +51,22 @@ testStoredInInstance() {
|
|||
return res;
|
||||
}
|
||||
|
||||
/*member: testStoredInMapOfList:[null|subclass=Object]*/
|
||||
/*member: testStoredInMapOfList:[null|exact=JSUInt31]*/
|
||||
testStoredInMapOfList() {
|
||||
var res;
|
||||
/*[null|subclass=Object]*/ closure(/*[null|subclass=Object]*/ a) => res = a;
|
||||
/*[exact=JSUInt31]*/ closure(/*[exact=JSUInt31]*/ a) => res = a;
|
||||
dynamic a = <dynamic>[closure];
|
||||
dynamic b = <dynamic, dynamic>{'foo': 1};
|
||||
|
||||
b
|
||||
/*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/
|
||||
/*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
['bar'] = a;
|
||||
|
||||
b
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
['bar']
|
||||
|
||||
/*Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
|
||||
/*Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)*/
|
||||
[0](42);
|
||||
return res;
|
||||
}
|
||||
|
|
60
pkg/compiler/test/inference/data/list_js.dart
Normal file
60
pkg/compiler/test/inference/data/list_js.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Test effect of NativeBehavior on list tracing.
|
||||
|
||||
/// ignore: IMPORT_INTERNAL_LIBRARY
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
|
||||
/*member: main:[null]*/
|
||||
main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
}
|
||||
|
||||
/*member: test1:[null]*/
|
||||
test1() {
|
||||
var list = [42];
|
||||
JS('', '#', list); // '#' is by default a no-op.
|
||||
witness1(list);
|
||||
}
|
||||
|
||||
/*member: witness1:[null]*/
|
||||
witness1(
|
||||
/*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) {}
|
||||
|
||||
/*member: test2:[null]*/
|
||||
test2() {
|
||||
var list = [42];
|
||||
JS('effects:all;depends:all', '#', list);
|
||||
witness2(list);
|
||||
}
|
||||
|
||||
/*member: witness2:[null]*/
|
||||
witness2(
|
||||
/*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) {}
|
||||
|
||||
/*member: test3:[null]*/
|
||||
test3() {
|
||||
var list = [42];
|
||||
JS('', '#.slice(0)', list);
|
||||
witness3(list);
|
||||
}
|
||||
|
||||
/*member: witness3:[null]*/
|
||||
witness3(
|
||||
/*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) {}
|
||||
|
||||
/*member: test4:[null]*/
|
||||
test4() {
|
||||
var list = [42];
|
||||
JS('effects:none;depends:all', '#.slice(0)', list);
|
||||
witness4(list);
|
||||
}
|
||||
|
||||
/*member: witness4:[null]*/
|
||||
witness4(
|
||||
/*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) {}
|
|
@ -79,28 +79,28 @@ test2() {
|
|||
/*member: aDouble3:Union(null, [exact=JSDouble], [exact=JSExtendableArray])*/
|
||||
dynamic aDouble3 = 42.5;
|
||||
|
||||
/*member: aList3:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
|
||||
/*member: aList3:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/
|
||||
dynamic aList3 = [42];
|
||||
|
||||
/*member: consume3:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
|
||||
/*member: consume3:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/
|
||||
consume3(
|
||||
/*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) =>
|
||||
/*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) =>
|
||||
x;
|
||||
|
||||
/*member: test3:[null]*/
|
||||
test3() {
|
||||
dynamic theMap = <dynamic, dynamic>{'a': 2.2, 'b': 3.3, 'c': 4.4};
|
||||
theMap
|
||||
/*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/
|
||||
/*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/
|
||||
['d'] = aList3;
|
||||
/*iterator: [exact=LinkedHashMapKeyIterable]*/
|
||||
/*current: [exact=LinkedHashMapKeyIterator]*/
|
||||
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
|
||||
for (var key in theMap.
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/
|
||||
keys) {
|
||||
aDouble3 = theMap
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSDouble], [exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/
|
||||
[key];
|
||||
}
|
||||
// We have to reference it somewhere, so that it always gets resolved.
|
||||
|
|
|
@ -237,9 +237,7 @@ doTest(String allocation, {bool nullify}) async {
|
|||
checkType('listEscapingInSetterValue', commonMasks.numType);
|
||||
checkType('listEscapingInIndex', commonMasks.numType);
|
||||
checkType('listEscapingInIndexSet', commonMasks.uint31Type);
|
||||
// TODO(johnniwinther): Since Iterable.iterableToString is part of the closed
|
||||
// world we find the `dynamicType` instead of `numType`.
|
||||
checkType('listEscapingTwiceInIndexSet', commonMasks.dynamicType);
|
||||
checkType('listEscapingTwiceInIndexSet', commonMasks.numType);
|
||||
checkType('listSetInNonFinalField', commonMasks.numType);
|
||||
checkType('listWithChangedLength', commonMasks.uint31Type.nullable());
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import 'dart:_js_helper'
|
|||
getTraceFromException,
|
||||
RuntimeError;
|
||||
|
||||
import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_native_typed_data' show NativeUint8List;
|
||||
import 'dart:_rti' show getRuntimeType;
|
||||
|
||||
|
@ -459,9 +459,15 @@ class List<E> {
|
|||
assertUnreachable();
|
||||
}
|
||||
|
||||
factory List._ofArray(Iterable<E> elements) {
|
||||
return JSArray<E>.markGrowable(
|
||||
JS('effects:none;depends:no-static', '#.slice(0)', elements));
|
||||
}
|
||||
|
||||
factory List._of(Iterable<E> elements) {
|
||||
// This is essentially `addAll`, but without a check for modifiability or
|
||||
// ConcurrentModificationError on the receiver.
|
||||
if (elements is JSArray) return List._ofArray(elements);
|
||||
// This is essentially `<E>[]..addAll(elements)`, but without a check for
|
||||
// modifiability or ConcurrentModificationError on the receiver.
|
||||
List<E> list = <E>[];
|
||||
for (final e in elements) {
|
||||
list.add(e);
|
||||
|
|
Loading…
Reference in a new issue