Skip to content

Commit 48c8ffa

Browse files
committed
Initial isolate reload support
This is a cut of the work that Todd and I collaborated on in the reload branch. In this CL, we've dropped the loader port hacks, in other words, on stack reloading in the standalone embedder does not work yet. - [x] Support for hot reloading of isolate source code - [x] Unit test harness and many tests - [x] Service protocol and Observatory support - [x] Product build does not include support for hot reloading. [email protected] Review URL: https://codereview.chromium.org/1965823002 .
1 parent 39d184f commit 48c8ffa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+5573
-309
lines changed

runtime/include/dart_api.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2658,7 +2658,8 @@ DART_EXPORT Dart_Handle Dart_SetNativeResolver(
26582658
typedef enum {
26592659
Dart_kImportTag = 0,
26602660
Dart_kSourceTag,
2661-
Dart_kCanonicalizeUrl
2661+
Dart_kCanonicalizeUrl,
2662+
Dart_kScriptTag,
26622663
} Dart_LibraryTag;
26632664

26642665
/* TODO(turnidge): Document. */

runtime/lib/developer.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
namespace dart {
1919

2020
// Native implementations for the dart:developer library.
21-
2221
DEFINE_NATIVE_ENTRY(Developer_debugger, 2) {
2322
GET_NON_NULL_NATIVE_ARGUMENT(Bool, when, arguments->NativeArgAt(0));
2423
GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));

runtime/observatory/lib/src/app/application.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ class ObservatoryApplication extends Observable {
101101
// Ignore for now.
102102
break;
103103

104+
case ServiceEvent.kIsolateReload:
105+
notifications.add(new Notification.fromEvent(event));
106+
break;
107+
104108
case ServiceEvent.kIsolateExit:
105109
case ServiceEvent.kResume:
106110
removePauseEvents(event.isolate);

runtime/observatory/lib/src/elements/debugger.dart

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ class IsolateCommand extends DebuggerCommand {
902902
IsolateCommand(Debugger debugger) : super(debugger, 'isolate', [
903903
new IsolateListCommand(debugger),
904904
new IsolateNameCommand(debugger),
905+
new IsolateReloadCommand(debugger),
905906
]) {
906907
alias = 'i';
907908
}
@@ -962,10 +963,10 @@ class IsolateCommand extends DebuggerCommand {
962963
}
963964
return new Future.value(result);
964965
}
965-
String helpShort = 'Switch the current isolate';
966+
String helpShort = 'Switch, list, rename, or reload isolates';
966967

967968
String helpLong =
968-
'Switch, list, or rename isolates.\n'
969+
'Switch the current isolate.\n'
969970
'\n'
970971
'Syntax: isolate <number>\n'
971972
' isolate <name>\n';
@@ -1042,14 +1043,36 @@ class IsolateNameCommand extends DebuggerCommand {
10421043
return debugger.isolate.setName(args[0]);
10431044
}
10441045

1045-
String helpShort = 'Rename an isolate';
1046+
String helpShort = 'Rename the current isolate';
10461047

10471048
String helpLong =
1048-
'Rename an isolate.\n'
1049+
'Rename the current isolate.\n'
10491050
'\n'
10501051
'Syntax: isolate name <name>\n';
10511052
}
10521053

1054+
class IsolateReloadCommand extends DebuggerCommand {
1055+
IsolateReloadCommand(Debugger debugger) : super(debugger, 'reload', []);
1056+
1057+
Future run(List<String> args) async {
1058+
if (debugger.isolate == null) {
1059+
debugger.console.print('There is no current vm');
1060+
return;
1061+
}
1062+
1063+
await debugger.isolate.reloadSources();
1064+
1065+
debugger.console.print('Isolate reloading....');
1066+
}
1067+
1068+
String helpShort = 'Reload the sources for the current isolate.';
1069+
1070+
String helpLong =
1071+
'Reload the sources for the current isolate.\n'
1072+
'\n'
1073+
'Syntax: reload\n';
1074+
}
1075+
10531076
class InfoCommand extends DebuggerCommand {
10541077
InfoCommand(Debugger debugger) : super(debugger, 'info', [
10551078
new InfoBreakpointsCommand(debugger),
@@ -1650,6 +1673,15 @@ class ObservatoryDebugger extends Debugger {
16501673
console.print("Isolate ${iso.number} renamed to '${iso.name}'");
16511674
break;
16521675

1676+
case ServiceEvent.kIsolateReload:
1677+
var reloadError = event.reloadError;
1678+
if (reloadError != null) {
1679+
console.print('Isolate reload failed: ${event.reloadError}');
1680+
} else {
1681+
console.print('Isolate reloaded.');
1682+
}
1683+
break;
1684+
16531685
case ServiceEvent.kPauseStart:
16541686
case ServiceEvent.kPauseExit:
16551687
case ServiceEvent.kPauseBreakpoint:

runtime/observatory/lib/src/elements/isolate_view.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ class IsolateViewElement extends ObservatoryElement {
3333
await isolate.topFrame.function.load();
3434
}
3535
}
36+
37+
Future reloadSources() {
38+
return isolate.reloadSources();
39+
}
3640
}

runtime/observatory/lib/src/elements/isolate_view.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,16 @@ <h1>isolate '{{ isolate.name }}'</h1>
9494
<div class="memberName">service protocol extensions</div>
9595
<div class="memberValue">{{ isolate.extensionRPCs }}</div>
9696
</div>
97+
98+
<div class="memberItem">
99+
<div class="memberName">
100+
<action-link callback="{{ reloadSources }}"
101+
label="reload sources">
102+
</action-link>
103+
</div>
104+
</div>
97105
</div>
106+
98107
</div>
99108
</div>
100109
</div>

runtime/observatory/lib/src/elements/nav_bar.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@
298298
animation: fadein 1s;
299299
}
300300

301+
.wide-item {
302+
width: 50vw;
303+
}
304+
301305
@keyframes fadein {
302306
from { opacity: 0; }
303307
to { opacity: 1; }
@@ -328,6 +332,9 @@
328332
a.boxclose:hover {
329333
background: rgba(255,255,255,0.5);
330334
}
335+
.error {
336+
white-space: pre;
337+
}
331338
</style>
332339
<template if="{{ event != null }}">
333340
<template if="{{ notifyOnPause && event.isPauseEvent }}">
@@ -372,6 +379,21 @@
372379
<a class="boxclose" on-click="{{ closeItem }}">&times;</a>
373380
</div>
374381
</template>
382+
<template if="{{ event.kind == 'IsolateReload' }}">
383+
<div class="wide-item item">
384+
Isolate reload
385+
<template if="{{ event.reloadError != null }}">
386+
failed:
387+
<br>
388+
<br>
389+
<div class="indent error">{{ event.reloadError.message.toString() }}</div><br>
390+
</template>
391+
<template if="{{ event.reloadError == null }}">
392+
succeeded
393+
</template>
394+
<a class="boxclose" on-click="{{ closeItem }}">&times;</a>
395+
</div>
396+
</template>
375397
</template>
376398
</template>
377399
</polymer-element>

runtime/observatory/lib/src/elements/script_view.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ <h1>script {{ script.name }}</h1>
2121
<object-common object="{{ script }}"></object-common>
2222
<br>
2323

24+
<div class="memberList">
25+
<div class="memberItem">
26+
<div class="memberName">loaded at</div>
27+
<div class="memberValue">{{ script.loadTime.toString() }}</div>
28+
</div>
29+
</div>
30+
2431
<hr>
2532
<script-inset id="scriptInset" script="{{ script }}"
2633
currentPos="{{ app.locationManager.internalArguments['pos'] | parseInt }}">

runtime/observatory/lib/src/service/object.dart

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class ServerRpcException extends RpcException {
4242
static const kStreamNotSubscribed = 104;
4343
static const kIsolateMustBeRunnable = 105;
4444
static const kIsolateMustBePaused = 106;
45+
static const kIsolateIsReloading = 107;
4546

4647
int code;
4748
Map data;
@@ -1149,6 +1150,7 @@ class Isolate extends ServiceObjectOwner {
11491150
@observable bool loading = true;
11501151
@observable bool runnable = false;
11511152
@observable bool ioEnabled = false;
1153+
@observable bool reloading = false;
11521154

11531155
final List<String> extensionRPCs = new List<String>();
11541156

@@ -1192,6 +1194,22 @@ class Isolate extends ServiceObjectOwner {
11921194
return invokeRpc('getSourceReport', params);
11931195
}
11941196

1197+
Future<ServiceMap> reloadSources() {
1198+
return invokeRpc('_reloadSources', {}).then((_) {
1199+
reloading = true;
1200+
});
1201+
}
1202+
1203+
void _handleIsolateReloadEvent(ServiceEvent event) {
1204+
reloading = false;
1205+
if (event.reloadError != null) {
1206+
// Failure.
1207+
print('Reload failed: ${event.reloadError}');
1208+
} else {
1209+
_cache.clear();
1210+
}
1211+
}
1212+
11951213
/// Fetches and builds the class hierarchy for this isolate. Returns the
11961214
/// Object class object.
11971215
Future<Class> getClassHierarchy() {
@@ -1499,7 +1517,9 @@ class Isolate extends ServiceObjectOwner {
14991517
case ServiceEvent.kInspect:
15001518
// Handled elsewhere.
15011519
break;
1502-
1520+
case ServiceEvent.kIsolateReload:
1521+
_handleIsolateReloadEvent(event);
1522+
break;
15031523
case ServiceEvent.kBreakpointAdded:
15041524
_addBreakpoint(event.breakpoint);
15051525
break;
@@ -1823,6 +1843,7 @@ class ServiceEvent extends ServiceObject {
18231843
static const kIsolateRunnable = 'IsolateRunnable';
18241844
static const kIsolateExit = 'IsolateExit';
18251845
static const kIsolateUpdate = 'IsolateUpdate';
1846+
static const kIsolateReload = 'IsolateReload';
18261847
static const kServiceExtensionAdded = 'ServiceExtensionAdded';
18271848
static const kPauseStart = 'PauseStart';
18281849
static const kPauseExit = 'PauseExit';
@@ -1854,6 +1875,7 @@ class ServiceEvent extends ServiceObject {
18541875
@observable Frame topFrame;
18551876
@observable String extensionRPC;
18561877
@observable Instance exception;
1878+
@observable Instance reloadError;
18571879
@observable bool atAsyncSuspension;
18581880
@observable ServiceObject inspectee;
18591881
@observable ByteData data;
@@ -1925,6 +1947,7 @@ class ServiceEvent extends ServiceObject {
19251947
if (map['count'] != null) {
19261948
count = map['count'];
19271949
}
1950+
reloadError = map['reloadError'];
19281951
if (map['_debuggerSettings'] != null &&
19291952
map['_debuggerSettings']['_exceptions'] != null) {
19301953
exceptions = map['_debuggerSettings']['_exceptions'];
@@ -2857,6 +2880,7 @@ class Script extends HeapObject {
28572880
final lines = new ObservableList<ScriptLine>();
28582881
@observable String uri;
28592882
@observable String kind;
2883+
@observable DateTime loadTime;
28602884
@observable int firstTokenPos;
28612885
@observable int lastTokenPos;
28622886
@observable int lineOffset;
@@ -2959,6 +2983,8 @@ class Script extends HeapObject {
29592983
return;
29602984
}
29612985
_loaded = true;
2986+
int loadTimeMillis = map['_loadTime'];
2987+
loadTime = new DateTime.fromMillisecondsSinceEpoch(loadTimeMillis);
29622988
lineOffset = map['lineOffset'];
29632989
columnOffset = map['columnOffset'];
29642990
_parseTokenPosTable(map['tokenPosTable']);

runtime/tests/vm/vm.status

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
# for details. All rights reserved. Use of this source code is governed by a
33
# BSD-style license that can be found in the LICENSE file.
44

5+
cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail, Crash
6+
cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: Fail, Crash
7+
cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash
8+
cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash
9+
cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail, Crash
10+
cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash
11+
512
# These tests are expected to crash on all platforms.
613
cc/ArrayNew_Overflow_Crash: Crash, Timeout
714
cc/AllocGeneric_Overflow: Crash, Timeout

0 commit comments

Comments
 (0)