Skip to content

Commit 05c2f3b

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Hook interpreter to the standalone VM
When dynamic modules are enabled, standalone VM can now run bytecode binaries directly. Also, if --interpreter flag is specified, Dart source is compiled to bytecode and interpreter is used to run it. This will allow us to test VM service capabilities including debugging and hot reload against the interpreter. TEST=manual Change-Id: Ibb5a67f4844485c4ed90b8a7568dc42fa552fcac Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436421 Reviewed-by: Ryan Macnak <[email protected]> Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 0ba9781 commit 05c2f3b

File tree

15 files changed

+257
-30
lines changed

15 files changed

+257
-30
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:typed_data' show Uint8List;
6+
7+
import 'package:dart2bytecode/bytecode_generator.dart' show generateBytecode;
8+
import 'package:dart2bytecode/options.dart' show BytecodeOptions;
9+
import 'package:kernel/ast.dart' show Component, Library;
10+
import 'package:kernel/binary/ast_to_binary.dart' show BytesSink;
11+
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
12+
import 'package:kernel/core_types.dart' show CoreTypes;
13+
import 'package:kernel/target/targets.dart' show Target;
14+
15+
import '../../vm/bin/kernel_service.dart' as kernel_service;
16+
17+
Uint8List _generateBytecode(
18+
Component component,
19+
List<Library> libraries,
20+
CoreTypes coreTypes,
21+
ClassHierarchy hierarchy,
22+
Target target,
23+
bool enableAsserts,
24+
) {
25+
final byteSink = new BytesSink();
26+
generateBytecode(component, byteSink,
27+
libraries: libraries,
28+
coreTypes: coreTypes,
29+
hierarchy: hierarchy,
30+
target: target,
31+
options: BytecodeOptions(
32+
enableAsserts: enableAsserts, emitSourcePositions: true));
33+
return byteSink.builder.takeBytes();
34+
}
35+
36+
// Wire up bytecode generator to the kernel service to avoid
37+
// circular dependency between package:vm and package:dart2bytecode.
38+
main([args]) {
39+
kernel_service.bytecodeGenerator = _generateBytecode;
40+
return kernel_service.main(args);
41+
}

pkg/vm/bin/kernel_service.dart

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ const int kRejectTag = 7;
7777

7878
bool allowDartInternalImport = false;
7979

80+
// Bytecode generator, optionally injected in
81+
// pkg/dart2bytecode/bin/kernel_service.dart.
82+
Uint8List Function(
83+
Component component,
84+
List<Library> libraries,
85+
CoreTypes coreTypes,
86+
ClassHierarchy hierarchy,
87+
Target target,
88+
bool enableAsserts,
89+
)?
90+
bytecodeGenerator;
91+
8092
CompilerOptions setupCompilerOptions(
8193
FileSystem fileSystem,
8294
Uri? platformKernelPath,
@@ -165,6 +177,7 @@ abstract class Compiler {
165177
final String invocationModes;
166178
final String verbosityLevel;
167179
final bool enableMirrors;
180+
final bool generateBytecode;
168181

169182
// Code coverage and hot reload are only supported by incremental compiler,
170183
// which is used if vm-service is enabled.
@@ -189,6 +202,7 @@ abstract class Compiler {
189202
this.invocationModes = '',
190203
this.verbosityLevel = Verbosity.defaultValue,
191204
required this.enableMirrors,
205+
required this.generateBytecode,
192206
}) {
193207
Uri? packagesUri = null;
194208
final packageConfig = this.packageConfig ?? Platform.packageConfig;
@@ -309,6 +323,7 @@ class IncrementalCompilerWrapper extends Compiler {
309323
String invocationModes = '',
310324
String verbosityLevel = Verbosity.defaultValue,
311325
required bool enableMirrors,
326+
required super.generateBytecode,
312327
}) : super(
313328
isolateGroupId,
314329
fileSystem,
@@ -333,6 +348,7 @@ class IncrementalCompilerWrapper extends Compiler {
333348
String? packageConfig,
334349
String invocationModes = '',
335350
required bool enableMirrors,
351+
required bool generateBytecode,
336352
}) {
337353
IncrementalCompilerWrapper result = IncrementalCompilerWrapper(
338354
isolateGroupId,
@@ -343,6 +359,7 @@ class IncrementalCompilerWrapper extends Compiler {
343359
packageConfig: packageConfig,
344360
invocationModes: invocationModes,
345361
enableMirrors: enableMirrors,
362+
generateBytecode: generateBytecode,
346363
);
347364
result.generator = new IncrementalCompiler.forExpressionCompilationOnly(
348365
component,
@@ -381,6 +398,7 @@ class IncrementalCompilerWrapper extends Compiler {
381398
packageConfig: packageConfig,
382399
invocationModes: invocationModes,
383400
enableMirrors: enableMirrors,
401+
generateBytecode: generateBytecode,
384402
);
385403
final generator = this.generator!;
386404
// TODO(VM TEAM): This does not seem safe. What if cloning while having
@@ -424,6 +442,7 @@ class SingleShotCompilerWrapper extends Compiler {
424442
String invocationModes = '',
425443
String verbosityLevel = Verbosity.defaultValue,
426444
required bool enableMirrors,
445+
required super.generateBytecode,
427446
}) : super(
428447
isolateGroupId,
429448
fileSystem,
@@ -483,6 +502,7 @@ Future<Compiler> lookupOrBuildNewIncrementalCompiler(
483502
String invocationModes = '',
484503
String verbosityLevel = Verbosity.defaultValue,
485504
required bool enableMirrors,
505+
required bool generateBytecode,
486506
}) async {
487507
IncrementalCompilerWrapper? compiler = lookupIncrementalCompiler(
488508
isolateGroupId,
@@ -520,6 +540,7 @@ Future<Compiler> lookupOrBuildNewIncrementalCompiler(
520540
invocationModes: invocationModes,
521541
verbosityLevel: verbosityLevel,
522542
enableMirrors: enableMirrors,
543+
generateBytecode: generateBytecode,
523544
);
524545
}
525546
isolateCompilers[isolateGroupId] = compiler;
@@ -578,6 +599,7 @@ Future _processExpressionCompilationRequest(request) async {
578599
final List<String>? experimentalFlags =
579600
request[19] != null ? request[19].cast<String>() : null;
580601
final bool enableMirrors = request[20];
602+
final bool generateBytecode = request[21];
581603

582604
IncrementalCompilerWrapper? compiler = isolateCompilers[isolateGroupId];
583605

@@ -676,6 +698,7 @@ Future _processExpressionCompilationRequest(request) async {
676698
experimentalFlags: experimentalFlags,
677699
packageConfig: packageConfigFile,
678700
enableMirrors: enableMirrors,
701+
generateBytecode: generateBytecode,
679702
);
680703
isolateCompilers[isolateGroupId] = compiler;
681704
await compiler.compile(
@@ -737,7 +760,20 @@ Future _processExpressionCompilationRequest(request) async {
737760
result = new CompilationResult.errors(compiler.errorsPlain);
738761
} else {
739762
Component component = createExpressionEvaluationComponent(procedure);
740-
result = new CompilationResult.ok(serializeComponent(component));
763+
Uint8List bytes;
764+
if (compiler.generateBytecode) {
765+
bytes = bytecodeGenerator!.call(
766+
component,
767+
component.libraries,
768+
compiler.generator!.lastKnownGoodResult!.coreTypes,
769+
compiler.generator!.lastKnownGoodResult!.classHierarchy,
770+
compiler.options.target!,
771+
compiler.enableAsserts,
772+
);
773+
} else {
774+
bytes = serializeComponent(component);
775+
}
776+
result = new CompilationResult.ok(bytes);
741777
}
742778
} catch (error, stack) {
743779
result = new CompilationResult.crash(error, stack);
@@ -867,6 +903,7 @@ Future _processLoadRequest(request) async {
867903
final String? multirootScheme = request[13];
868904
final String verbosityLevel = request[14];
869905
final bool enableMirrors = request[15];
906+
final bool generateBytecode = request[16];
870907
Uri platformKernelPath;
871908
List<int>? platformKernel = null;
872909
if (request[3] is String) {
@@ -952,6 +989,7 @@ Future _processLoadRequest(request) async {
952989
invocationModes: invocationModes,
953990
verbosityLevel: verbosityLevel,
954991
enableMirrors: enableMirrors,
992+
generateBytecode: generateBytecode,
955993
);
956994
fileSystem = compiler.fileSystem;
957995
} else {
@@ -973,6 +1011,7 @@ Future _processLoadRequest(request) async {
9731011
invocationModes: invocationModes,
9741012
verbosityLevel: verbosityLevel,
9751013
enableMirrors: enableMirrors,
1014+
generateBytecode: generateBytecode,
9761015
);
9771016
}
9781017

@@ -1028,13 +1067,30 @@ Future _processLoadRequest(request) async {
10281067
// these sources built-in. Everything loaded as a summary in
10291068
// [kernelForProgram] is marked `external`, so we can use that bit to
10301069
// decide what to exclude.
1031-
result = new CompilationResult.ok(
1032-
serializeComponent(
1070+
Uint8List bytes;
1071+
if (compiler.generateBytecode) {
1072+
final generator = bytecodeGenerator;
1073+
if (generator == null) {
1074+
throw 'Cannot generate bytecode as dynamic modules are disabled.';
1075+
}
1076+
bytes = generator(
1077+
compilerResult.component!,
1078+
compilerResult.component!.libraries
1079+
.where((lib) => !loadedLibraries.contains(lib))
1080+
.toList(),
1081+
compilerResult.coreTypes!,
1082+
compilerResult.classHierarchy!,
1083+
compiler.options.target!,
1084+
compiler.enableAsserts,
1085+
);
1086+
} else {
1087+
bytes = serializeComponent(
10331088
compilerResult.component!,
10341089
filter: (lib) => !loadedLibraries.contains(lib),
10351090
nativeAssetsComponent: nativeAssetsComponent,
1036-
),
1037-
);
1091+
);
1092+
}
1093+
result = new CompilationResult.ok(bytes);
10381094
}
10391095
} catch (error, stack) {
10401096
result = new CompilationResult.crash(error, stack);
@@ -1232,7 +1288,7 @@ Future trainInternal(String scriptUri, String? platformKernelPath) async {
12321288
null /* multirootScheme */,
12331289
'all' /* CFE logging mode */,
12341290
true /* enableMirrors */,
1235-
null /* native assets yaml */,
1291+
false /* generateBytecode */,
12361292
];
12371293
await _processLoadRequest(request);
12381294
}

pkg/vm/test/kernel_service_test.dart

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,16 @@ Future<kernel_service.Status> singleShotCompile(
139139
/* [4] = bool = incremental = */ false,
140140
/* [5] = bool = for_snapshot = */ false,
141141
/* [6] = bool = embed_sources = */ true,
142-
/* [8] = int = isolateGroupId = */ 42,
143-
/* [9] = List = sourceFiles = */ sourceFiles,
144-
/* [10] = bool = enableAsserts = */ true,
145-
/* [11] = List<String>? = experimentalFlags = */ [],
146-
/* [12] = String? = packageConfig = */ packageConfig,
147-
/* [13] = String? = multirootFilepaths = */ null,
148-
/* [14] = String? = multirootScheme = */ null,
149-
/* [16] = String = verbosityLevel = */ Verbosity.all.name,
150-
/* [17] = bool = enableMirrors = */ false,
142+
/* [7] = int = isolateGroupId = */ 42,
143+
/* [8] = List = sourceFiles = */ sourceFiles,
144+
/* [9] = bool = enableAsserts = */ true,
145+
/* [10] = List<String>? = experimentalFlags = */ [],
146+
/* [11] = String? = packageConfig = */ packageConfig,
147+
/* [12] = String? = multirootFilepaths = */ null,
148+
/* [13] = String? = multirootScheme = */ null,
149+
/* [14] = String = verbosityLevel = */ Verbosity.all.name,
150+
/* [15] = bool = enableMirrors = */ false,
151+
/* [16] = bool = generateBytecode = */ false,
151152
]);
152153

153154
// Wait for kernel-service response.

runtime/bin/dart_api_win.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ typedef void (*Dart_ExitIsolateType)();
111111
typedef Dart_Handle (
112112
*Dart_CreateSnapshotType)(uint8_t**, intptr_t*, uint8_t**, intptr_t*, bool);
113113
typedef bool (*Dart_IsKernelType)(const uint8_t*, intptr_t);
114+
typedef bool (*Dart_IsBytecodeType)(const uint8_t*, intptr_t);
114115
typedef char* (*Dart_IsolateMakeRunnableType)(Dart_Isolate);
115116
typedef void (*Dart_SetMessageNotifyCallbackType)(Dart_MessageNotifyCallback);
116117
typedef Dart_MessageNotifyCallback (*Dart_GetMessageNotifyCallbackType)();
@@ -347,6 +348,8 @@ typedef Dart_Handle (*Dart_DeferredLoadCompleteErrorType)(intptr_t,
347348
const char*,
348349
bool);
349350
typedef Dart_Handle (*Dart_LoadScriptFromKernelType)(const uint8_t*, intptr_t);
351+
typedef Dart_Handle (*Dart_LoadScriptFromBytecodeType)(const uint8_t*,
352+
intptr_t);
350353
typedef Dart_Handle (*Dart_RootLibraryType)();
351354
typedef Dart_Handle (*Dart_SetRootLibraryType)(Dart_Handle);
352355
typedef Dart_Handle (*Dart_GetTypeType)(Dart_Handle,
@@ -528,6 +531,7 @@ static Dart_AddSymbolsType Dart_AddSymbolsFn = NULL;
528531
static Dart_ExitIsolateType Dart_ExitIsolateFn = NULL;
529532
static Dart_CreateSnapshotType Dart_CreateSnapshotFn = NULL;
530533
static Dart_IsKernelType Dart_IsKernelFn = NULL;
534+
static Dart_IsBytecodeType Dart_IsBytecodeFn = NULL;
531535
static Dart_IsolateMakeRunnableType Dart_IsolateMakeRunnableFn = NULL;
532536
static Dart_SetMessageNotifyCallbackType Dart_SetMessageNotifyCallbackFn = NULL;
533537
static Dart_GetMessageNotifyCallbackType Dart_GetMessageNotifyCallbackFn = NULL;
@@ -692,6 +696,7 @@ static Dart_DeferredLoadCompleteType Dart_DeferredLoadCompleteFn = NULL;
692696
static Dart_DeferredLoadCompleteErrorType Dart_DeferredLoadCompleteErrorFn =
693697
NULL;
694698
static Dart_LoadScriptFromKernelType Dart_LoadScriptFromKernelFn = NULL;
699+
static Dart_LoadScriptFromBytecodeType Dart_LoadScriptFromBytecodeFn = NULL;
695700
static Dart_RootLibraryType Dart_RootLibraryFn = NULL;
696701
static Dart_SetRootLibraryType Dart_SetRootLibraryFn = NULL;
697702
static Dart_GetTypeType Dart_GetTypeFn = NULL;
@@ -898,6 +903,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
898903
(Dart_CreateSnapshotType)GetProcAddress(process, "Dart_CreateSnapshot");
899904
Dart_IsKernelFn =
900905
(Dart_IsKernelType)GetProcAddress(process, "Dart_IsKernel");
906+
Dart_IsBytecodeFn =
907+
(Dart_IsBytecodeType)GetProcAddress(process, "Dart_IsBytecode");
901908
Dart_IsolateMakeRunnableFn = (Dart_IsolateMakeRunnableType)GetProcAddress(
902909
process, "Dart_IsolateMakeRunnable");
903910
Dart_SetMessageNotifyCallbackFn =
@@ -1225,6 +1232,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
12251232
process, "Dart_DeferredLoadCompleteError");
12261233
Dart_LoadScriptFromKernelFn = (Dart_LoadScriptFromKernelType)GetProcAddress(
12271234
process, "Dart_LoadScriptFromKernel");
1235+
Dart_LoadScriptFromBytecodeFn =
1236+
(Dart_LoadScriptFromBytecodeType)GetProcAddress(
1237+
process, "Dart_LoadScriptFromBytecode");
12281238
Dart_RootLibraryFn =
12291239
(Dart_RootLibraryType)GetProcAddress(process, "Dart_RootLibrary");
12301240
Dart_SetRootLibraryFn =
@@ -1648,6 +1658,10 @@ bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size) {
16481658
return Dart_IsKernelFn(buffer, buffer_size);
16491659
}
16501660

1661+
bool Dart_IsBytecode(const uint8_t* buffer, intptr_t buffer_size) {
1662+
return Dart_IsBytecodeFn(buffer, buffer_size);
1663+
}
1664+
16511665
char* Dart_IsolateMakeRunnable(Dart_Isolate isolate) {
16521666
return Dart_IsolateMakeRunnableFn(isolate);
16531667
}
@@ -2369,6 +2383,11 @@ Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer,
23692383
return Dart_LoadScriptFromKernelFn(kernel_buffer, kernel_size);
23702384
}
23712385

2386+
Dart_Handle Dart_LoadScriptFromBytecode(const uint8_t* kernel_buffer,
2387+
intptr_t kernel_size) {
2388+
return Dart_LoadScriptFromBytecodeFn(kernel_buffer, kernel_size);
2389+
}
2390+
23722391
Dart_Handle Dart_RootLibrary() {
23732392
return Dart_RootLibraryFn();
23742393
}

runtime/bin/dartutils.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ MagicNumberData kernel_magic_number = {4, {0x90, 0xab, 0xcd, 0xef}};
4444
MagicNumberData kernel_list_magic_number = {
4545
7,
4646
{0x23, 0x40, 0x64, 0x69, 0x6c, 0x6c, 0x0a}}; // #@dill\n
47+
MagicNumberData bytecode_magic_number = {4, {0x33, 0x43, 0x42, 0x44}};
4748
MagicNumberData gzip_magic_number = {2, {0x1f, 0x8b, 0, 0}};
4849

4950
static bool IsWindowsHost() {
@@ -398,6 +399,7 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const char* filename) {
398399
ASSERT(aotcoff_riscv64_magic_number.length <= appjit_magic_number.length);
399400
ASSERT(kernel_magic_number.length <= appjit_magic_number.length);
400401
ASSERT(kernel_list_magic_number.length <= appjit_magic_number.length);
402+
ASSERT(bytecode_magic_number.length <= appjit_magic_number.length);
401403
ASSERT(gzip_magic_number.length <= appjit_magic_number.length);
402404
if (File::GetType(nullptr, filename, true) == File::kIsFile) {
403405
File* file = File::Open(nullptr, filename, File::kRead);
@@ -426,8 +428,8 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const uint8_t* buffer,
426428
return kKernelListMagicNumber;
427429
}
428430

429-
if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) {
430-
return kGzipMagicNumber;
431+
if (CheckMagicNumber(buffer, buffer_length, bytecode_magic_number)) {
432+
return kBytecodeMagicNumber;
431433
}
432434

433435
if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) {

runtime/bin/dartutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ class DartUtils {
256256
kAppJITMagicNumber,
257257
kKernelMagicNumber,
258258
kKernelListMagicNumber,
259+
kBytecodeMagicNumber,
259260
kGzipMagicNumber,
260261
kAotELFMagicNumber,
261262
// Only the host-endian magic numbers are recognized, not the reverse-endian

0 commit comments

Comments
 (0)