Version 2.10.0-130.0.dev
Merge commit 'acbd51c08d3023a4ffaf3a1a9276edf61c9bbfcf' into 'dev'
diff --git a/DEPS b/DEPS
index dd033f0..973a186 100644
--- a/DEPS
+++ b/DEPS
@@ -97,7 +97,7 @@
"dart_style_tag": "1.3.7", # Please see the note above before updating.
"chromedriver_tag": "83.0.4103.39",
- "dartdoc_rev" : "ab98003fc368f484fcc4c055770adea47bc83fbd",
+ "dartdoc_rev" : "2bef0f260594b822f55c8c8f777d9c4c1ea8f76c",
"ffi_rev": "454ab0f9ea6bd06942a983238d8a6818b1357edb",
"fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
"glob_rev": "e9f4e6b7ae8abe5071461cf8f47191bb19cf7ef6",
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index 989ea2d..e544c4f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -144,45 +144,29 @@
void _lookupInterfaceType(InterfaceType type) {
var isSuper = _receiver is SuperExpression;
- if (_name == '[]') {
- _getterRequested = type.lookUpMethod2(
- '[]',
- _definingLibrary,
- concrete: isSuper,
- inherited: isSuper,
- );
- _needsGetterError = _getterRequested == null;
+ var getterName = Name(_definingLibrary.source.uri, _name);
+ _getterRequested =
+ _resolver.inheritance.getMember(type, getterName, forSuper: isSuper);
+ _needsGetterError = _getterRequested == null;
- _setterRequested = type.lookUpMethod2(
- '[]=',
- _definingLibrary,
- concrete: isSuper,
- inherited: isSuper,
- );
- _needsSetterError = _setterRequested == null;
- } else {
+ if (_getterRequested == null) {
var classElement = type.element as AbstractClassElementImpl;
+ _getterRecovery ??=
+ classElement.lookupStaticGetter(_name, _definingLibrary) ??
+ classElement.lookupStaticMethod(_name, _definingLibrary);
+ _needsGetterError = _getterRecovery == null;
+ }
- var getterName = Name(_definingLibrary.source.uri, _name);
- _getterRequested =
- _resolver.inheritance.getMember(type, getterName, forSuper: isSuper);
- _needsGetterError = _getterRequested == null;
- if (_getterRequested == null) {
- _getterRecovery ??=
- classElement.lookupStaticGetter(_name, _definingLibrary) ??
- classElement.lookupStaticMethod(_name, _definingLibrary);
- _needsGetterError = _getterRecovery == null;
- }
+ var setterName = Name(_definingLibrary.source.uri, '$_name=');
+ _setterRequested =
+ _resolver.inheritance.getMember(type, setterName, forSuper: isSuper);
+ _needsSetterError = _setterRequested == null;
- var setterName = Name(_definingLibrary.source.uri, '$_name=');
- _setterRequested =
- _resolver.inheritance.getMember(type, setterName, forSuper: isSuper);
- _needsSetterError = _setterRequested == null;
- if (_setterRequested == null) {
- _setterRecovery ??=
- classElement.lookupStaticSetter(_name, _definingLibrary);
- _needsSetterError = _setterRecovery == null;
- }
+ if (_setterRequested == null) {
+ var classElement = type.element as AbstractClassElementImpl;
+ _setterRecovery ??=
+ classElement.lookupStaticSetter(_name, _definingLibrary);
+ _needsSetterError = _setterRecovery == null;
}
}
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index 5ea6b54..8050d63 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 1.3.4
+
+- Fixed issue where `isolateId`s were expected to take the form `isolates/123`
+ although this is not required by the VM service specification.
+
# 1.3.3
- Fixed issue where `DartDevelopmentService.sseUri` did not return a URI with a
diff --git a/pkg/dds/lib/src/isolate_manager.dart b/pkg/dds/lib/src/isolate_manager.dart
index 57711bf..50ace65 100644
--- a/pkg/dds/lib/src/isolate_manager.dart
+++ b/pkg/dds/lib/src/isolate_manager.dart
@@ -31,7 +31,7 @@
}
class _RunningIsolate {
- _RunningIsolate(this.isolateManager, this.portId, this.name);
+ _RunningIsolate(this.isolateManager, this.id, this.name);
// State setters.
void pausedOnExit() => _state = _IsolateState.pauseExit;
@@ -52,7 +52,7 @@
if (shouldResume()) {
clearResumeApprovals();
await isolateManager.dds._vmServiceClient.sendRequest('resume', {
- 'isolateId': 'isolates/$portId',
+ 'isolateId': id,
});
}
}
@@ -104,7 +104,7 @@
final _IsolateManager isolateManager;
final String name;
- final String portId;
+ final String id;
final Set<String> _resumeApprovalsByName = {};
_IsolateState _state;
}
@@ -124,7 +124,7 @@
}
final isolateData = event['isolate'];
- final id = isolateData['number'].asString;
+ final id = isolateData['id'].asString;
final name = isolateData['name'].asString;
_updateIsolateState(id, name, eventKind);
}
@@ -165,32 +165,32 @@
// Check the pause event for each isolate to determine whether or not the
// isolate is already paused.
for (final isolateRef in isolateRefs) {
+ final id = isolateRef['id'];
final isolate = await dds._vmServiceClient.sendRequest('getIsolate', {
- 'isolateId': isolateRef['id'],
+ 'isolateId': id,
});
- final portId = isolate['number'];
final name = isolate['name'];
if (isolate.containsKey('pauseEvent')) {
- isolates[portId] = _RunningIsolate(this, portId, name);
+ isolates[id] = _RunningIsolate(this, id, name);
final eventKind = isolate['pauseEvent']['kind'];
- _updateIsolateState(portId, name, eventKind);
+ _updateIsolateState(id, name, eventKind);
} else {
// If the isolate doesn't have a pauseEvent, assume it's running.
- isolateStarted(portId, name);
+ isolateStarted(id, name);
}
}
}
/// Initializes state for a newly started isolate.
- void isolateStarted(String portId, String name) {
- final isolate = _RunningIsolate(this, portId, name);
+ void isolateStarted(String id, String name) {
+ final isolate = _RunningIsolate(this, id, name);
isolate.running();
- isolates[portId] = isolate;
+ isolates[id] = isolate;
}
/// Cleans up state for an isolate that has exited.
- void isolateExited(String portId) {
- isolates.remove(portId);
+ void isolateExited(String id) {
+ isolates.remove(id);
}
/// Handles `resume` RPC requests. If the client requires that approval be
@@ -206,8 +206,7 @@
json_rpc.Parameters parameters,
) async {
final isolateId = parameters['isolateId'].asString;
- final portId = _isolateIdToPortId(isolateId);
- final isolate = isolates[portId];
+ final isolate = isolates[isolateId];
if (isolate == null) {
return _RPCResponses.collectedSentinel;
}
@@ -233,9 +232,6 @@
return resumeResult;
}
- static String _isolateIdToPortId(String isolateId) =>
- isolateId.substring('isolates/'.length);
-
final _DartDevelopmentService dds;
final Map<String, _RunningIsolate> isolates = {};
}
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index 16e8c0b..6fa115b 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -3,7 +3,7 @@
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.
-version: 1.3.3
+version: 1.3.4
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
diff --git a/pkg/front_end/lib/widget_cache.dart b/pkg/front_end/lib/widget_cache.dart
new file mode 100644
index 0000000..9ccfa38
--- /dev/null
+++ b/pkg/front_end/lib/widget_cache.dart
@@ -0,0 +1,191 @@
+// 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.
+
+import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/kernel.dart';
+
+/// Provides support for "single widget reloads" in Flutter, by determining if
+/// a partial component contains single change to the class body of a
+/// StatelessWidget, StatefulWidget, or State subtype.
+class WidgetCache {
+ /// Create a [WidgetCache] from a [Component] containing the flutter
+ /// framework.
+ WidgetCache(Component fullComponent) {
+ Library frameworkLibrary;
+ for (Library library in fullComponent.libraries) {
+ if (library?.importUri?.path == 'flutter/src/widgets/framework.dart') {
+ frameworkLibrary = library;
+ break;
+ }
+ }
+ if (frameworkLibrary == null) {
+ return;
+ }
+ for (Class classDeclaration in frameworkLibrary.classes) {
+ if (classDeclaration.name == _statelessWidgetClassName) {
+ _statelessWidget = classDeclaration;
+ } else if (classDeclaration.name == _statefulWidgetClassName) {
+ _statefulWidget = classDeclaration;
+ } else if (classDeclaration.name == _stateClassName) {
+ _state = classDeclaration;
+ }
+ }
+ _frameworkTypesLocated =
+ _statefulWidget != null && _state != null && _statelessWidget != null;
+ }
+
+ static const String _stateClassName = 'State';
+ static const String _statefulWidgetClassName = 'StatefulWidget';
+ static const String _statelessWidgetClassName = 'StatelessWidget';
+
+ Class _statelessWidget;
+ Class _state;
+ Class _statefulWidget;
+ bool _frameworkTypesLocated = false;
+
+ /// Mark [uri] as invalidated.
+ void invalidate(Uri uri) {
+ _invalidatedLibraries.add(uri);
+ }
+
+ /// Reset the invalidated libraries.
+ void reset() {
+ _invalidatedLibraries.clear();
+ }
+
+ final List<Uri> _invalidatedLibraries = <Uri>[];
+
+ /// Determine if any changes to [partialComponent] were located entirely
+ /// within the class body of a single `StatefulWidget`, `StatelessWidget` or
+ /// `State` subtype.
+ ///
+ /// Returns the class name if located, otherwise `null`.
+ String checkWidgetCache(
+ Component lastGoodComponent,
+ Component partialComponent,
+ ClassHierarchy classHierarchy,
+ ) {
+ if (!_frameworkTypesLocated ||
+ lastGoodComponent == null ||
+ _invalidatedLibraries.length != 1) {
+ return null;
+ }
+ Uri importUri = _invalidatedLibraries[0];
+ Library library;
+ for (Library candidateLibrary in partialComponent.libraries) {
+ if (candidateLibrary.importUri == importUri) {
+ library = candidateLibrary;
+ break;
+ }
+ }
+ if (library == null) {
+ return null;
+ }
+ List<int> oldSource = lastGoodComponent.uriToSource[library.fileUri].source;
+ List<int> newSource = partialComponent.uriToSource[library.fileUri].source;
+ // Library was added and does not exist in the old component.
+ if (oldSource == null) {
+ return null;
+ }
+ int newStartIndex = 0;
+ int newEndIndex = newSource.length - 1;
+ int oldStartIndex = 0;
+ int oldEndIndex = oldSource.length - 1;
+
+ while (newStartIndex < newEndIndex && oldStartIndex < oldEndIndex) {
+ if (newSource[newStartIndex] != oldSource[oldStartIndex]) {
+ break;
+ }
+ newStartIndex += 1;
+ oldStartIndex += 1;
+ }
+ while (newEndIndex > newStartIndex && oldEndIndex > oldStartIndex) {
+ if (newSource[newEndIndex] != oldSource[oldEndIndex]) {
+ break;
+ }
+ newEndIndex -= 1;
+ oldEndIndex -= 1;
+ }
+
+ Class newClass =
+ _locateContainingClass(library, newStartIndex, newEndIndex);
+ if (newClass == null) {
+ return null;
+ }
+
+ Library oldLibrary =
+ lastGoodComponent.libraries.firstWhere((Library library) {
+ return library.importUri == importUri;
+ });
+
+ Class oldClass =
+ _locateContainingClass(oldLibrary, oldStartIndex, oldEndIndex);
+
+ if (oldClass == null || oldClass.name != newClass.name) {
+ return null;
+ }
+
+ if (classHierarchy.isSubclassOf(newClass, _statelessWidget) ||
+ classHierarchy.isSubclassOf(newClass, _statefulWidget)) {
+ if (_hasSubClasses(newClass, partialComponent, classHierarchy)) {
+ return null;
+ }
+ return newClass.name;
+ }
+
+ // For changes to State classes, locate the name of the corresponding
+ // StatefulWidget that is provided as a type parameter. If the bounds are
+ // StatefulWidget itself, fail as that indicates the type was not
+ // specified.
+ Supertype stateSuperType =
+ classHierarchy.getClassAsInstanceOf(newClass, _state);
+ if (stateSuperType != null) {
+ if (stateSuperType.typeArguments.length != 1) {
+ return null;
+ }
+ DartType widgetType = stateSuperType.typeArguments[0];
+ if (widgetType is InterfaceType) {
+ Class statefulWidgetType = widgetType.classNode;
+ if (statefulWidgetType.name == _statefulWidgetClassName) {
+ return null;
+ }
+ if (_hasSubClasses(
+ statefulWidgetType, partialComponent, classHierarchy)) {
+ return null;
+ }
+ return statefulWidgetType.name;
+ }
+ }
+
+ return null;
+ }
+
+ /// Checks whether the class [node] has any subclasses.
+ bool _hasSubClasses(
+ Class node, Component component, ClassHierarchy classHierarchy) {
+ for (Library library in component.libraries) {
+ for (Class otherClass in library.classes) {
+ if (identical(otherClass, node)) {
+ continue;
+ }
+ if (classHierarchy.isSubclassOf(otherClass, node)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Locate the that fully contains the edit range, or null.
+ Class _locateContainingClass(
+ Library library, int startOffset, int endOffset) {
+ for (Class classDeclaration in library.classes) {
+ if (classDeclaration.startFileOffset <= startOffset &&
+ classDeclaration.fileEndOffset >= endOffset) {
+ return classDeclaration;
+ }
+ }
+ return null;
+ }
+}
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 0073a80..0ca4f6d 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -2790,6 +2790,7 @@
startup
state
stateful
+stateless
statement
statement's
statements
diff --git a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
index 73ac5bd..d03bffb 100644
--- a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart
@@ -21,9 +21,13 @@
var target3 = new _TestClass();
var target4 = new _TestClass();
var target5 = new _TestClass();
+@pragma("vm:entry-point") // Prevent obfuscation
var globalObject = new _TestClass();
+@pragma("vm:entry-point") // Prevent obfuscation
var globalList = new List(100);
+@pragma("vm:entry-point") // Prevent obfuscation
var globalMap1 = new Map();
+@pragma("vm:entry-point") // Prevent obfuscation
var globalMap2 = new Map();
void warmup() {
@@ -93,9 +97,9 @@
'limit': 100,
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
- expect(result['gcRootType'], 'static fields table');
- expect(result['elements'].length, equals(1));
- expect(result['elements'][0]['value']['type'], equals('@Instance'));
+ expect(result['gcRootType'], 'user global');
+ expect(result['elements'].length, equals(2));
+ expect(result['elements'][1]['value']['name'], equals('globalObject'));
},
// missing limit.
@@ -125,10 +129,10 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['gcRootType'], 'static fields table');
- expect(result['elements'].length, equals(2));
- expect(result['elements'][0]['value']['type'], equals('@Instance'));
+ expect(result['gcRootType'], 'user global');
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentField'], equals('x'));
+ expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
(Isolate isolate) async {
@@ -139,10 +143,10 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['gcRootType'], 'static fields table');
- expect(result['elements'].length, equals(2));
+ expect(result['gcRootType'], 'user global');
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentField'], equals('y'));
- expect(result['elements'][1]['value']['type'], equals('@Instance'));
+ expect(result['elements'][2]['value']['name'], equals('globalObject'));
},
(Isolate isolate) async {
@@ -153,10 +157,10 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['gcRootType'], 'static fields table');
- expect(result['elements'].length, equals(2));
+ expect(result['gcRootType'], 'user global');
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentListIndex'], equals(12));
- expect(result['elements'][1]['value']['type'], equals('@Instance'));
+ expect(result['elements'][2]['value']['name'], equals('globalList'));
},
(Isolate isolate) async {
@@ -167,11 +171,11 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['gcRootType'], 'static fields table');
- expect(result['elements'].length, equals(2));
+ expect(result['gcRootType'], 'user global');
+ expect(result['elements'].length, equals(3));
expect(
result['elements'][1]['parentMapKey']['valueAsString'], equals('key'));
- expect(result['elements'][1]['value']['type'], equals('@Instance'));
+ expect(result['elements'][2]['value']['name'], equals('globalMap1'));
},
(Isolate isolate) async {
@@ -182,10 +186,10 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'].length, equals(2));
+ expect(result['elements'].length, equals(3));
expect(result['elements'][1]['parentMapKey']['class']['name'],
equals('_TestClass'));
- expect(result['elements'][1]['value']['type'], equals('@Instance'));
+ expect(result['elements'][2]['value']['name'], equals('globalMap2'));
},
// object store
diff --git a/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart
index 9f69aeb..535c882 100644
--- a/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart
@@ -53,9 +53,10 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'].length, equals(1));
+ expect(result['elements'].length, equals(2));
expect(
result['elements'][0]['value']['class']['name'], equals('_TestConst'));
+ expect(result['elements'][1]['value']['name'], equals('x'));
},
// Expect a simple path through variable fn instead of long path filled
@@ -68,8 +69,9 @@
};
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
expect(result['type'], equals('RetainingPath'));
- expect(result['elements'].length, equals(1));
+ expect(result['elements'].length, equals(2));
expect(result['elements'][0]['value']['class']['name'], equals('_Closure'));
+ expect(result['elements'][1]['value']['name'], equals('fn'));
}
];
diff --git a/runtime/observatory/tests/service/inbound_references_test.dart b/runtime/observatory/tests/service/inbound_references_test.dart
index 267f1b1..5c10ae1 100644
--- a/runtime/observatory/tests/service/inbound_references_test.dart
+++ b/runtime/observatory/tests/service/inbound_references_test.dart
@@ -48,6 +48,8 @@
r['source'].clazz.name == 'Node');
hasReferenceSuchThat(
(r) => r['parentListIndex'] == 1 && r['source'].isList);
+ hasReferenceSuchThat(
+ (r) => r['source'] is Field && r['source'].name == 'e');
}
];
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index a973ce7..c31e1a2c 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -4847,10 +4847,8 @@
OneByteStringPtr str = objects_[i];
AutoTraceObject(str);
const intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- s->Write<bool>(str->ptr()->IsCanonical());
- intptr_t hash = String::GetCachedHash(str);
- s->Write<int32_t>(hash);
+ ASSERT(length <= compiler::target::kSmiMax);
+ s->WriteUnsigned((length << 1) | (str->ptr()->IsCanonical() ? 1 : 0));
s->WriteBytes(str->ptr()->data(), length);
}
}
@@ -4880,16 +4878,20 @@
void ReadFill(Deserializer* d) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
OneByteStringPtr str = static_cast<OneByteStringPtr>(d->Ref(id));
- const intptr_t length = d->ReadUnsigned();
- bool is_canonical = d->Read<bool>();
+ const intptr_t combined = d->ReadUnsigned();
+ const intptr_t length = combined >> 1;
+ const bool is_canonical = (combined & 1) != 0;
Deserializer::InitializeHeader(str, kOneByteStringCid,
OneByteString::InstanceSize(length),
is_canonical);
str->ptr()->length_ = Smi::New(length);
- String::SetCachedHash(str, d->Read<int32_t>());
+ uint32_t hash = 0;
for (intptr_t j = 0; j < length; j++) {
- str->ptr()->data()[j] = d->Read<uint8_t>();
+ uint8_t code_point = d->Read<uint8_t>();
+ str->ptr()->data()[j] = code_point;
+ hash = CombineHashes(hash, code_point);
}
+ String::SetCachedHash(str, FinalizeHash(hash, String::kHashBits));
}
}
};
@@ -4924,10 +4926,8 @@
TwoByteStringPtr str = objects_[i];
AutoTraceObject(str);
const intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- s->Write<bool>(str->ptr()->IsCanonical());
- intptr_t hash = String::GetCachedHash(str);
- s->Write<int32_t>(hash);
+ ASSERT(length <= (compiler::target::kSmiMax / 2));
+ s->WriteUnsigned((length << 1) | (str->ptr()->IsCanonical() ? 1 : 0));
s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
}
}
@@ -4957,15 +4957,16 @@
void ReadFill(Deserializer* d) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TwoByteStringPtr str = static_cast<TwoByteStringPtr>(d->Ref(id));
- const intptr_t length = d->ReadUnsigned();
- bool is_canonical = d->Read<bool>();
+ const intptr_t combined = d->ReadUnsigned();
+ const intptr_t length = combined >> 1;
+ const bool is_canonical = (combined & 1) != 0;
Deserializer::InitializeHeader(str, kTwoByteStringCid,
TwoByteString::InstanceSize(length),
is_canonical);
str->ptr()->length_ = Smi::New(length);
- String::SetCachedHash(str, d->Read<int32_t>());
uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
d->ReadBytes(cdata, length * 2);
+ String::SetCachedHash(str, String::Hash(str));
}
}
};
@@ -5622,10 +5623,6 @@
return "CodeSourceMap";
case kCompressedStackMapsCid:
return "CompressedStackMaps";
- case kOneByteStringCid:
- return "OneByteString";
- case kTwoByteStringCid:
- return "TwoByteString";
default:
return nullptr;
}
@@ -6352,8 +6349,6 @@
case kPcDescriptorsCid:
case kCodeSourceMapCid:
case kCompressedStackMapsCid:
- case kOneByteStringCid:
- case kTwoByteStringCid:
return new (Z) RODataDeserializationCluster();
}
}
diff --git a/runtime/vm/compiler/asm_intrinsifier.h b/runtime/vm/compiler/asm_intrinsifier.h
index 01fd20d..58a97e0 100644
--- a/runtime/vm/compiler/asm_intrinsifier.h
+++ b/runtime/vm/compiler/asm_intrinsifier.h
@@ -24,6 +24,7 @@
namespace compiler {
class Assembler;
+class Intrinsifier;
class Label;
class AsmIntrinsifier : public AllStatic {
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 50cba71..f94e466 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2736,7 +2736,9 @@
}
// Visit objects in the field table.
- field_table()->VisitObjectPointers(visitor);
+ if (!visitor->trace_values_through_fields()) {
+ field_table()->VisitObjectPointers(visitor);
+ }
visitor->clear_gc_root_type();
// Visit the objects directly referenced from the isolate structure.
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index e127267..2cd2590 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -48,6 +48,8 @@
object_ids_ = nullptr;
}
+ virtual bool trace_values_through_fields() const { return true; }
+
// Marks and pushes. Used to initialize this stack with roots.
// We can use ObjectIdTable normally used by serializers because it
// won't be in use while handling a service request (ObjectGraph's only use).
@@ -472,6 +474,8 @@
ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
}
+ virtual bool trace_values_through_fields() const { return true; }
+
intptr_t length() const { return length_; }
virtual void VisitObject(ObjectPtr raw_obj) {
@@ -765,6 +769,8 @@
HandleVisitor(Thread::Current()),
writer_(writer) {}
+ virtual bool trace_values_through_fields() const { return true; }
+
void VisitObject(ObjectPtr obj) {
if (obj->IsPseudoObject()) return;
@@ -819,6 +825,8 @@
isolate_(thread()->isolate()),
writer_(writer) {}
+ virtual bool trace_values_through_fields() const { return true; }
+
void VisitObject(ObjectPtr obj) {
if (obj->IsPseudoObject()) return;
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 9797fc2..3dfd910 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -516,7 +516,6 @@
REGULAR_VISITOR(SignatureData)
REGULAR_VISITOR(RedirectionData)
REGULAR_VISITOR(FfiTrampolineData)
-REGULAR_VISITOR(Field)
REGULAR_VISITOR(Script)
REGULAR_VISITOR(Library)
REGULAR_VISITOR(LibraryPrefix)
@@ -592,6 +591,26 @@
REGULAR_VISITOR(WeakSerializationReference)
#endif
+intptr_t FieldLayout::VisitFieldPointers(FieldPtr raw_obj,
+ ObjectPointerVisitor* visitor) {
+ ASSERT(raw_obj->IsHeapObject());
+ ASSERT_UNCOMPRESSED(Field);
+ visitor->VisitPointers(raw_obj->ptr()->from(), raw_obj->ptr()->to());
+
+ if (visitor->trace_values_through_fields()) {
+ if (Field::StaticBit::decode(raw_obj->ptr()->kind_bits_)) {
+ visitor->isolate_group()->ForEachIsolate(
+ [&](Isolate* isolate) {
+ intptr_t index =
+ Smi::Value(raw_obj->ptr()->host_offset_or_field_id_);
+ visitor->VisitPointer(&isolate->field_table()->table()[index]);
+ },
+ /*at_safepoint=*/true);
+ }
+ }
+ return Field::InstanceSize();
+}
+
bool CodeLayout::ContainsPC(const ObjectPtr raw_obj, uword pc) {
if (!raw_obj->IsCode()) return false;
auto const raw_code = static_cast<const CodePtr>(raw_obj);
diff --git a/runtime/vm/visitor.h b/runtime/vm/visitor.h
index 93baf0d..eb9d343 100644
--- a/runtime/vm/visitor.h
+++ b/runtime/vm/visitor.h
@@ -52,6 +52,11 @@
virtual bool visit_weak_persistent_handles() const { return false; }
+ // When visiting objects to build retaining paths, trace field values
+ // through fields.
+ // Otherwise trace field values through isolate's field_table.
+ virtual bool trace_values_through_fields() const { return false; }
+
const SharedClassTable* shared_class_table() const {
return shared_class_table_;
}
diff --git a/tools/VERSION b/tools/VERSION
index 14a7a99..38b781d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 129
+PRERELEASE 130
PRERELEASE_PATCH 0
\ No newline at end of file