[vm/kernel] Expression execution through Kernel.
Change-Id: Id90c91cb3b71f9ce703e21fe48147b86a7764d34
Reviewed-on: https://dart-review.googlesource.com/42562
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
diff --git a/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart b/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
index 76e4075..768cb71 100644
--- a/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
+++ b/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
@@ -61,6 +61,7 @@
String expression,
Map<String, DartType> definitions,
List<TypeParameter> typeDefinitions,
+ String syntheticProcedureName,
Uri libraryUri,
[String className,
bool isStatic = false]);
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index f23b510..bbd98f8 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -360,6 +360,7 @@
String expression,
Map<String, DartType> definitions,
List<TypeParameter> typeDefinitions,
+ String syntheticProcedureName,
Uri libraryUri,
[String className,
bool isStatic = false]) async {
@@ -440,7 +441,7 @@
debugLibrary, className, className != null && !isStatic, parameters);
Procedure procedure = new Procedure(
- new Name("debugExpr"), ProcedureKind.Method, parameters,
+ new Name(syntheticProcedureName), ProcedureKind.Method, parameters,
isStatic: isStatic);
parameters.body = new ReturnStatement(compiledExpression)
diff --git a/pkg/front_end/lib/src/fasta/kernel/utils.dart b/pkg/front_end/lib/src/fasta/kernel/utils.dart
index 8bcda60..d95f852 100644
--- a/pkg/front_end/lib/src/fasta/kernel/utils.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/utils.dart
@@ -6,7 +6,10 @@
import 'dart:io' show BytesBuilder, File, IOSink;
-import 'package:kernel/ast.dart' show Library, Component;
+import 'package:kernel/clone.dart' show CloneVisitor;
+
+import 'package:kernel/ast.dart'
+ show Library, Component, Procedure, Class, TypeParameter, Supertype;
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
@@ -58,6 +61,39 @@
return byteSink.builder.takeBytes();
}
+List<int> serializeProcedure(Procedure procedure) {
+ Library fakeLibrary =
+ new Library(new Uri(scheme: 'evaluate', path: 'source'));
+
+ if (procedure.parent is Class) {
+ Class realClass = procedure.parent;
+
+ CloneVisitor cloner = new CloneVisitor();
+
+ Class fakeClass = new Class(name: realClass.name);
+ for (TypeParameter typeParam in realClass.typeParameters) {
+ fakeClass.typeParameters.add(typeParam.accept(cloner));
+ }
+
+ fakeClass.parent = fakeLibrary;
+ fakeClass.supertype = new Supertype.byReference(
+ realClass.supertype.className,
+ realClass.supertype.typeArguments.map(cloner.visitType).toList());
+
+ // Rebind the type parameters in the procedure.
+ procedure = procedure.accept(cloner);
+ procedure.parent = fakeClass;
+ fakeClass.procedures.add(procedure);
+ fakeLibrary.classes.add(fakeClass);
+ } else {
+ fakeLibrary.procedures.add(procedure);
+ procedure.parent = fakeLibrary;
+ }
+
+ Component program = new Component(libraries: [fakeLibrary]);
+ return serializeComponent(program);
+}
+
/// A [Sink] that directly writes data into a byte builder.
class ByteSink implements Sink<List<int>> {
final BytesBuilder builder = new BytesBuilder();
diff --git a/pkg/front_end/test/fasta/expression_test.dart b/pkg/front_end/test/fasta/expression_test.dart
index 4a21e78..ee97b9d 100644
--- a/pkg/front_end/test/fasta/expression_test.dart
+++ b/pkg/front_end/test/fasta/expression_test.dart
@@ -325,6 +325,7 @@
test.expression,
definitions,
typeParams,
+ "debugExpr",
test.library,
test.className,
test.isStaticMethod);
diff --git a/pkg/status_file/test/data/vm.status b/pkg/status_file/test/data/vm.status
index e446356..726d64e 100644
--- a/pkg/status_file/test/data/vm.status
+++ b/pkg/status_file/test/data/vm.status
@@ -217,6 +217,7 @@
cc/IsolateReload_KernelIncrementalCompile: Skip
cc/IsolateReload_KernelIncrementalCompileAppAndLib: Skip
cc/IsolateReload_KernelIncrementalCompileGenerics: Skip
+cc/IsolateReload_KernelIncrementalCompileExpression: Skip
cc/Mixin_PrivateSuperResolution: Skip
cc/Mixin_PrivateSuperResolutionCrossLibraryShouldFail: Skip
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 329b554..0590e39 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -33,7 +33,7 @@
show computePlatformBinariesLocation;
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/hybrid_file_system.dart';
-import 'package:kernel/kernel.dart' show Component;
+import 'package:kernel/kernel.dart' show Component, Procedure;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm.dart' show VmTarget;
import 'package:vm/incremental_compiler.dart';
@@ -49,10 +49,15 @@
// 1 - Update in-memory file system with in-memory sources (used by tests).
// 2 - Accept last compilation result.
// 3 - APP JIT snapshot training run for kernel_service.
+// 4 - Compile an individual expression in some context (for debugging
+// purposes).
const int kCompileTag = 0;
const int kUpdateSourcesTag = 1;
const int kAcceptTag = 2;
const int kTrainTag = 3;
+const int kCompileExpressionTag = 4;
+
+bool allowDartInternalImport = false;
abstract class Compiler {
final FileSystem fileSystem;
@@ -177,9 +182,10 @@
}
}
-final Map<int, Compiler> isolateCompilers = new Map<int, Compiler>();
+final Map<int, IncrementalCompilerWrapper> isolateCompilers =
+ new Map<int, IncrementalCompilerWrapper>();
-Compiler lookupIncrementalCompiler(int isolateId) {
+IncrementalCompilerWrapper lookupIncrementalCompiler(int isolateId) {
return isolateCompilers[isolateId];
}
@@ -242,10 +248,60 @@
// Process a request from the runtime. See KernelIsolate::CompileToKernel in
// kernel_isolate.cc and Loader::SendKernelRequest in loader.cc.
+Future _processExpressionCompilationRequest(request) async {
+ final SendPort port = request[1];
+ final int isolateId = request[2];
+ final String expression = request[3];
+ final List definitions = request[4];
+ final List typeDefinitions = request[5];
+ final String libraryUri = request[6];
+ final String klass = request[7]; // might be null
+ final bool isStatic = request[8];
+
+ IncrementalCompilerWrapper compiler = isolateCompilers[isolateId];
+
+ if (compiler == null) {
+ port.send(new CompilationResult.errors(
+ ["No incremental compiler available for this isolate."]).toResponse());
+ return;
+ }
+
+ compiler.errors.clear();
+
+ CompilationResult result;
+ try {
+ Procedure procedure = await compiler.generator.compileExpression(
+ expression, definitions, typeDefinitions, libraryUri, klass, isStatic);
+
+ if (procedure == null) {
+ port.send(new CompilationResult.errors(["Invalid scope."]).toResponse());
+ return;
+ }
+
+ if (compiler.errors.isNotEmpty) {
+ // TODO(sigmund): the compiler prints errors to the console, so we
+ // shouldn't print those messages again here.
+ result = new CompilationResult.errors(compiler.errors);
+ } else {
+ result = new CompilationResult.ok(serializeProcedure(procedure));
+ }
+ } catch (error, stack) {
+ result = new CompilationResult.crash(error, stack);
+ }
+
+ port.send(result.toResponse());
+}
+
Future _processLoadRequest(request) async {
if (verbose) print("DFE: request: $request");
int tag = request[0];
+
+ if (tag == kCompileExpressionTag) {
+ await _processExpressionCompilationRequest(request);
+ return;
+ }
+
final SendPort port = request[1];
final String inputFileUri = request[2];
final Uri script =
diff --git a/pkg/vm/lib/incremental_compiler.dart b/pkg/vm/lib/incremental_compiler.dart
index 91d9426..3541bc2 100644
--- a/pkg/vm/lib/incremental_compiler.dart
+++ b/pkg/vm/lib/incremental_compiler.dart
@@ -10,6 +10,8 @@
import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart';
import 'package:kernel/kernel.dart';
+const String kDebugProcedureName = ":Eval";
+
/// Wrapper around [IncrementalKernelGenerator] that keeps track of rejected
/// deltas and combines them together into resultant program until it is
/// accepted.
@@ -74,4 +76,30 @@
_pendingDeltas.clear();
fullComponent = true;
}
+
+ Future<Procedure> compileExpression(
+ String expression,
+ List<String> definitions,
+ List<String> typeDefinitions,
+ String libraryUri,
+ String klass,
+ bool isStatic) {
+ Map<String, DartType> completeDefinitions = {};
+ for (String name in definitions) {
+ if (!isLegalIdentifier(name)) continue;
+ completeDefinitions[name] = new DynamicType();
+ }
+
+ List<TypeParameter> typeParameters = [];
+ for (String name in typeDefinitions) {
+ if (!isLegalIdentifier(name)) continue;
+ typeParameters.add(new TypeParameter(name, new DynamicType()));
+ }
+
+ Uri library = Uri.parse(libraryUri);
+ if (library == null) return null;
+
+ return _generator.compileExpression(expression, completeDefinitions,
+ typeParameters, kDebugProcedureName, library, klass, isStatic);
+ }
}
diff --git a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
index 6781af7..79c6be7 100644
--- a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
+++ b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
@@ -69,7 +69,8 @@
var hits = [];
- isolate.rootLibrary.evaluate('testerReady = true;').then((result) {
+ isolate.rootLibrary.evaluate('testerReady = true').then((result) {
+ print(result);
expect((result as Instance).valueAsString, equals('true'));
});
diff --git a/runtime/observatory/tests/service/bad_reload_test.dart b/runtime/observatory/tests/service/bad_reload_test.dart
index 8e9aed7..23927e9 100644
--- a/runtime/observatory/tests/service/bad_reload_test.dart
+++ b/runtime/observatory/tests/service/bad_reload_test.dart
@@ -72,9 +72,11 @@
expect(reasonForCancelling['type'], equals('ReasonForCancelling'));
expect(reasonForCancelling['message'], contains('library_isnt_here_man'));
- // Invoke test in v2.
- String v2 = await invokeTest(spawnedIsolate);
- expect(v2, 'apple');
+ // TODO(32341): enable in Dart 2
+ if (!Platform.executableArguments.contains("--preview_dart_2")) {
+ String v2 = await invokeTest(spawnedIsolate);
+ expect(v2, 'apple');
+ }
}
];
diff --git a/runtime/observatory/tests/service/debugger_inspect_test.dart b/runtime/observatory/tests/service/debugger_inspect_test.dart
index c52c42f..4f8f680 100644
--- a/runtime/observatory/tests/service/debugger_inspect_test.dart
+++ b/runtime/observatory/tests/service/debugger_inspect_test.dart
@@ -32,7 +32,7 @@
});
// Start listening for events first.
- await isolate.rootLibrary.evaluate('testeeDo();');
+ await isolate.rootLibrary.evaluate('testeeDo()');
return completer.future;
},
];
diff --git a/runtime/observatory/tests/service/evaluate_activation_test.dart b/runtime/observatory/tests/service/evaluate_activation_test.dart
index fc87190..cb352cd 100644
--- a/runtime/observatory/tests/service/evaluate_activation_test.dart
+++ b/runtime/observatory/tests/service/evaluate_activation_test.dart
@@ -114,7 +114,7 @@
}
});
- var result = await rootLib.evaluate('new C().method(3);');
+ var result = await rootLib.evaluate('new C().method(3)');
print("Result $result");
expect(hitBreakpoint, isTrue);
}
@@ -163,7 +163,7 @@
}
});
- var result = await rootLib.evaluate('C.method2(3);');
+ var result = await rootLib.evaluate('C.method2(3)');
print("Result $result");
expect(hitBreakpoint, isTrue);
}
@@ -204,7 +204,7 @@
}
});
- var result = await rootLib.evaluate('new C().method3(3);');
+ var result = await rootLib.evaluate('new C().method3(3)');
print("Result $result");
expect(hitBreakpoint, isTrue);
}
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 c458396..6211574 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
@@ -40,7 +40,7 @@
// Expect a simple path through variable x instead of long path filled
// with VM objects
(Isolate isolate) async {
- var target1 = await eval(isolate, 'x;');
+ var target1 = await eval(isolate, 'x');
var params = {
'targetId': target1['id'],
'limit': 100,
@@ -56,7 +56,7 @@
// Expect a simple path through variable fn instead of long path filled
// with VM objects
(Isolate isolate) async {
- var target2 = await eval(isolate, 'fn;');
+ var target2 = await eval(isolate, 'fn');
var params = {
'targetId': target2['id'],
'limit': 100,
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index c9b5f1d..8a8fd82 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -11,7 +11,6 @@
async_star_step_out_test: RuntimeError # Issue 29158, Async debugging
async_step_out_test: RuntimeError # Issue 29158, Async debugging
awaiter_async_stack_contents_test: RuntimeError # Issue 29158, Async debugging
-eval_internal_class_test: RuntimeError
evaluate_activation_in_method_class_test: RuntimeError
evaluate_activation_test/instance: RuntimeError
evaluate_activation_test/scope: RuntimeError
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 1c25d3c..b097d1e 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -55,6 +55,7 @@
[ $compiler != dartk ]
cc/IsolateReload_KernelIncrementalCompile: SkipByDesign
cc/IsolateReload_KernelIncrementalCompileAppAndLib: SkipByDesign
+cc/IsolateReload_KernelIncrementalCompileExpression: SkipByDesign
cc/IsolateReload_KernelIncrementalCompileGenerics: SkipByDesign
cc/Mixin_PrivateSuperResolution: Skip
cc/Mixin_PrivateSuperResolutionCrossLibraryShouldFail: Skip
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 2bd04fa..66037a1 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -336,7 +336,7 @@
// The platform binary may contain other libraries (e.g., dart:_builtin or
// dart:io) that will not be bundled with application. Load them now.
- const Object& result = loader.LoadProgram();
+ const Object& result = Object::Handle(zone, loader.LoadProgram());
if (result.IsError()) {
return Error::Cast(result).raw();
}
diff --git a/runtime/vm/bootstrap_nocore.cc b/runtime/vm/bootstrap_nocore.cc
index 679c41f..b311558 100644
--- a/runtime/vm/bootstrap_nocore.cc
+++ b/runtime/vm/bootstrap_nocore.cc
@@ -96,7 +96,7 @@
// The platform binary may contain other libraries (e.g., dart:_builtin or
// dart:io) that will not be bundled with application. Load them now.
- const Object& result = loader.LoadProgram();
+ const Object& result = Object::Handle(loader.LoadProgram());
if (result.IsError()) {
return Error::Cast(result).raw();
}
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index 091dd5d..bbc4d16 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -179,6 +179,10 @@
}
ISOLATE_UNIT_TEST_CASE(EvalExpressionWithLazyCompile) {
+ { // Initialize an incremental compiler in DFE mode.
+ TransitionVMToNative transition(thread);
+ TestCase::LoadTestScript("", NULL);
+ }
Library& lib = Library::Handle(Library::CoreLibrary());
const String& expression = String::Handle(
@@ -193,6 +197,10 @@
}
ISOLATE_UNIT_TEST_CASE(EvalExpressionExhaustCIDs) {
+ { // Initialize an incremental compiler in DFE mode.
+ TransitionVMToNative transition(thread);
+ TestCase::LoadTestScript("", NULL);
+ }
Library& lib = Library::Handle(Library::CoreLibrary());
const String& expression = String::Handle(String::New("3 + 4"));
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 1362438..3c30629 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -8,6 +8,7 @@
#include "vm/debugger_api_impl_test.h"
#include "vm/globals.h"
#include "vm/isolate.h"
+#include "vm/kernel_loader.h"
#include "vm/lockers.h"
#include "vm/thread_barrier.h"
#include "vm/thread_pool.h"
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index cf12542..90325c2 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -52,6 +52,7 @@
const int KernelIsolate::kUpdateSourcesTag = 1;
const int KernelIsolate::kAcceptTag = 2;
const int KernelIsolate::kTrainTag = 3;
+const int KernelIsolate::kCompileExpressionTag = 4;
Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL;
Monitor* KernelIsolate::monitor_ = new Monitor();
@@ -341,6 +342,125 @@
}
Dart_KernelCompilationResult SendAndWaitForResponse(
+ Dart_Port kernel_port,
+ const char* expression,
+ const Array& definitions,
+ const Array& type_definitions,
+ char const* library_uri,
+ char const* klass,
+ bool is_static) {
+ Dart_CObject tag;
+ tag.type = Dart_CObject_kInt32;
+ tag.value.as_int32 = KernelIsolate::kCompileExpressionTag;
+
+ Dart_CObject send_port;
+ send_port.type = Dart_CObject_kSendPort;
+ send_port.value.as_send_port.id = port_;
+ send_port.value.as_send_port.origin_id = ILLEGAL_PORT;
+
+ Dart_CObject expression_object;
+ expression_object.type = Dart_CObject_kString;
+ expression_object.value.as_string = const_cast<char*>(expression);
+
+ Dart_CObject definitions_object;
+ intptr_t num_definitions = definitions.Length();
+ definitions_object.type = Dart_CObject_kArray;
+ definitions_object.value.as_array.length = num_definitions;
+
+ Dart_CObject** definitions_array = new Dart_CObject*[num_definitions];
+ for (intptr_t i = 0; i < num_definitions; ++i) {
+ definitions_array[i] = new Dart_CObject;
+ definitions_array[i]->type = Dart_CObject_kString;
+ definitions_array[i]->value.as_string = const_cast<char*>(
+ String::CheckedHandle(definitions.At(i)).ToCString());
+ }
+ definitions_object.value.as_array.values = definitions_array;
+
+ Dart_CObject type_definitions_object;
+ intptr_t num_type_definitions = type_definitions.Length();
+ type_definitions_object.type = Dart_CObject_kArray;
+ type_definitions_object.value.as_array.length = num_type_definitions;
+
+ Dart_CObject** type_definitions_array =
+ new Dart_CObject*[num_type_definitions];
+ for (intptr_t i = 0; i < num_type_definitions; ++i) {
+ type_definitions_array[i] = new Dart_CObject;
+ type_definitions_array[i]->type = Dart_CObject_kString;
+ type_definitions_array[i]->value.as_string = const_cast<char*>(
+ String::CheckedHandle(type_definitions.At(i)).ToCString());
+ }
+ type_definitions_object.value.as_array.values = type_definitions_array;
+
+ Dart_CObject library_uri_object;
+ library_uri_object.type = Dart_CObject_kString;
+ library_uri_object.value.as_string = const_cast<char*>(library_uri);
+
+ Dart_CObject class_object;
+ if (klass != NULL) {
+ class_object.type = Dart_CObject_kString;
+ class_object.value.as_string = const_cast<char*>(klass);
+ } else {
+ class_object.type = Dart_CObject_kNull;
+ }
+
+ Dart_CObject is_static_object;
+ is_static_object.type = Dart_CObject_kBool;
+ is_static_object.value.as_bool = is_static;
+
+ Isolate* isolate =
+ Thread::Current() != NULL ? Thread::Current()->isolate() : NULL;
+ ASSERT(isolate != NULL);
+ Dart_CObject isolate_id;
+ isolate_id.type = Dart_CObject_kInt64;
+ isolate_id.value.as_int64 =
+ isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
+
+ Dart_CObject message;
+ message.type = Dart_CObject_kArray;
+ Dart_CObject suppress_warnings;
+ suppress_warnings.type = Dart_CObject_kBool;
+ suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
+
+ Dart_CObject dart_sync_async;
+ dart_sync_async.type = Dart_CObject_kBool;
+ dart_sync_async.value.as_bool = FLAG_sync_async;
+
+ Dart_CObject* message_arr[] = {&tag,
+ &send_port,
+ &isolate_id,
+ &expression_object,
+ &definitions_object,
+ &type_definitions_object,
+ &library_uri_object,
+ &class_object,
+ &is_static_object,
+ &suppress_warnings,
+ &dart_sync_async};
+ message.value.as_array.values = message_arr;
+ message.value.as_array.length = ARRAY_SIZE(message_arr);
+ // Send the message.
+ Dart_PostCObject(kernel_port, &message);
+
+ // Wait for reply to arrive.
+ MonitorLocker ml(monitor_);
+ while (result_.status == Dart_KernelCompilationStatus_Unknown) {
+ ml.Wait();
+ }
+
+ for (intptr_t i = 0; i < num_definitions; ++i) {
+ delete definitions_array[i];
+ }
+ delete[] definitions_array;
+
+ for (intptr_t i = 0; i < num_type_definitions; ++i) {
+ delete type_definitions_array[i];
+ }
+ delete[] type_definitions_array;
+
+ return result_;
+ }
+
+ Dart_KernelCompilationResult SendAndWaitForResponse(
int request_tag,
Dart_Port kernel_port,
const char* script_uri,
@@ -602,6 +722,27 @@
0, NULL, true, NULL);
}
+Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
+ const char* expression,
+ const Array& definitions,
+ const Array& type_definitions,
+ const char* library_url,
+ const char* klass,
+ bool is_static) {
+ Dart_Port kernel_port = WaitForKernelPort();
+ if (kernel_port == ILLEGAL_PORT) {
+ Dart_KernelCompilationResult result;
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Error while initializing Kernel isolate");
+ return result;
+ }
+
+ KernelCompilationRequest request;
+ return request.SendAndWaitForResponse(kernel_port, expression, definitions,
+ type_definitions, library_url, klass,
+ is_static);
+}
+
Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources(
int source_files_count,
Dart_SourceFile source_files[]) {
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index f9084cf..2e45b52 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -8,6 +8,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "include/dart_api.h"
+#include "include/dart_native_api.h"
#include "vm/allocation.h"
#include "vm/dart.h"
@@ -22,6 +23,7 @@
static const int kUpdateSourcesTag;
static const int kAcceptTag;
static const int kTrainTag;
+ static const int kCompileExpressionTag;
static void Run();
@@ -46,6 +48,14 @@
int source_files_count,
Dart_SourceFile source_files[]);
+ static Dart_KernelCompilationResult CompileExpressionToKernel(
+ const char* expression,
+ const Array& definitions,
+ const Array& type_definitions,
+ const char* library_url,
+ const char* klass,
+ bool is_static);
+
protected:
static Monitor* monitor_;
static Dart_IsolateCreateCallback create_callback_;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 6a3358c..d151f4e 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -195,7 +195,7 @@
bool process_pending_classes) {
if (program->is_single_program()) {
KernelLoader loader(program);
- return loader.LoadProgram(process_pending_classes);
+ return Object::Handle(loader.LoadProgram(process_pending_classes));
}
kernel::Reader reader(program->kernel_data(), program->kernel_data_size());
@@ -216,7 +216,7 @@
Program* subprogram = Program::ReadFrom(&reader, false);
ASSERT(subprogram->is_single_program());
KernelLoader loader(subprogram);
- Object& load_result = loader.LoadProgram(false);
+ Object& load_result = Object::Handle(loader.LoadProgram(false));
if (load_result.IsError()) return load_result;
if (library.IsNull() && load_result.IsLibrary()) {
@@ -545,7 +545,7 @@
potential_extension_libraries_ = GrowableObjectArray::null();
}
-Object& KernelLoader::LoadProgram(bool process_pending_classes) {
+RawObject* KernelLoader::LoadProgram(bool process_pending_classes) {
ASSERT(kernel_program_info_.constants() == Array::null());
if (!program_->is_single_program()) {
@@ -557,15 +557,15 @@
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
const intptr_t length = program_->library_count();
+ Object& last_library = Library::Handle(Z);
for (intptr_t i = 0; i < length; i++) {
- LoadLibrary(i);
+ last_library = LoadLibrary(i);
}
if (process_pending_classes) {
if (!ClassFinalizer::ProcessPendingClasses()) {
// Class finalization failed -> sticky error would be set.
- Error& error = Error::Handle(Z);
- error = H.thread()->sticky_error();
+ RawError* error = H.thread()->sticky_error();
H.thread()->clear_sticky_error();
return error;
}
@@ -586,19 +586,18 @@
NameIndex main = program_->main_method();
if (main == -1) {
- return Library::Handle(Z);
+ return Library::null();
}
NameIndex main_library = H.EnclosingName(main);
Library& library = LookupLibrary(main_library);
- return library;
+ return library.raw();
}
// Either class finalization failed or we caught a compile error.
// In both cases sticky error would be set.
- Error& error = Error::Handle(Z);
- error = thread_->sticky_error();
+ RawError* error = thread_->sticky_error();
thread_->clear_sticky_error();
return error;
}
@@ -683,7 +682,7 @@
field.set_has_initializer(false);
}
-void KernelLoader::LoadLibrary(intptr_t index) {
+RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
if (!program_->is_single_program()) {
FATAL(
"Trying to load a concatenated dill file at a time where that is "
@@ -713,15 +712,16 @@
// snapshot so we skip loading 'dart:vmservice_io'.
skip_vmservice_library_ = library_helper.canonical_name_;
ASSERT(H.IsLibrary(skip_vmservice_library_));
- return;
+ return Library::null();
}
}
- Library& library = LookupLibrary(library_helper.canonical_name_);
+ Library& library =
+ Library::Handle(Z, LookupLibrary(library_helper.canonical_name_).raw());
// The Kernel library is external implies that it is already loaded.
ASSERT(!library_helper.IsExternal() || library.Loaded());
- if (library.Loaded()) return;
+ if (library.Loaded()) return library.raw();
library_kernel_data_ =
TypedData::New(kTypedDataUint8ArrayCid, library_size, Heap::kOld);
@@ -846,6 +846,8 @@
toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
classes.Add(toplevel_class, Heap::kOld);
if (!library.Loaded()) library.SetLoaded();
+
+ return library.raw();
}
void KernelLoader::LoadLibraryImportsAndExports(Library* library) {
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index ed47893..21f4bb2 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -128,7 +128,7 @@
// Returns the library containing the main procedure, null if there
// was no main procedure, or a failure object if there was an error.
- Object& LoadProgram(bool process_pending_classes = true);
+ RawObject* LoadProgram(bool process_pending_classes = true);
// Finds all libraries that have been modified in this incremental
// version of the kernel program file.
@@ -137,7 +137,7 @@
BitVector* modified_libs,
bool force_reload);
- void LoadLibrary(intptr_t index);
+ RawLibrary* LoadLibrary(intptr_t index);
static void FinishLoading(const Class& klass);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 1e84c31..4923104 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -34,6 +34,8 @@
#include "vm/heap.h"
#include "vm/isolate_reload.h"
#include "vm/kernel.h"
+#include "vm/kernel_isolate.h"
+#include "vm/kernel_loader.h"
#include "vm/native_symbol.h"
#include "vm/object_store.h"
#include "vm/parser.h"
@@ -3195,6 +3197,14 @@
return String::ConcatAll(Array::Handle(Array::MakeFixedLength(src_pieces)));
}
+static RawObject* EvaluateWithDFEHelper(const String& expression,
+ const Array& definitions,
+ const Array& type_definitions,
+ const String& library_url,
+ const String& klass,
+ bool is_static,
+ const Array& arguments);
+
RawFunction* Function::EvaluateHelper(const Class& cls,
const String& expr,
const Array& param_names,
@@ -3221,6 +3231,12 @@
return func.raw();
}
+#if !defined(DART_PRECOMPILED_RUNTIME)
+static void ReleaseFetchedBytes(uint8_t* buffer) {
+ free(buffer);
+}
+#endif
+
RawObject* Class::Evaluate(const String& expr,
const Array& param_names,
const Array& param_values) const {
@@ -3232,11 +3248,17 @@
return UnhandledException::New(exception, stacktrace);
}
- const Function& eval_func = Function::Handle(
- Function::EvaluateHelper(*this, expr, param_names, true));
- const Object& result =
- Object::Handle(DartEntry::InvokeFunction(eval_func, param_values));
- return result.raw();
+ if (Library::Handle(library()).kernel_data() == TypedData::null()) {
+ const Function& eval_func = Function::Handle(
+ Function::EvaluateHelper(*this, expr, param_names, true));
+ return DartEntry::InvokeFunction(eval_func, param_values);
+ }
+
+ return EvaluateWithDFEHelper(
+ expr, param_names, Array::Handle(Array::New(0)),
+ String::Handle(Library::Handle(library()).url()),
+ IsTopLevel() ? String::Handle() : String::Handle(UserVisibleName()),
+ !IsTopLevel(), param_values);
}
// Ensure that top level parsing of the class has been done.
@@ -6033,6 +6055,9 @@
// This field is heavily overloaded:
// eval function: Script expression source
+// kernel eval function: Array[0] = Script
+// Array[1] = Kernel data
+// Array[2] = Kernel offset of enclosing library
// signature function: SignatureData
// method extractor: Function extracted closure function
// noSuchMethod dispatcher: Array arguments descriptor
@@ -7505,9 +7530,26 @@
return PatchClass::Cast(obj).origin_class();
}
+void Function::SetKernelDataAndScript(const Script& script,
+ const TypedData& data,
+ intptr_t offset) {
+ Array& data_field = Array::Handle(Array::New(3));
+ data_field.SetAt(0, script);
+ data_field.SetAt(1, data);
+ data_field.SetAt(2, Smi::Handle(Smi::New(offset)));
+ set_data(data_field);
+}
+
RawScript* Function::script() const {
// NOTE(turnidge): If you update this function, you probably want to
// update Class::PatchFieldsAndFunctions() at the same time.
+ Object& data = Object::Handle(raw_ptr()->data_);
+ if (data.IsArray()) {
+ Object& script = Object::Handle(Array::Cast(data).At(0));
+ if (script.IsScript()) {
+ return Script::Cast(script).raw();
+ }
+ }
if (token_pos() == TokenPosition::kMinSource) {
// Testing for position 0 is an optimization that relies on temporary
// eval functions having token position 0.
@@ -7532,6 +7574,13 @@
}
RawTypedData* Function::KernelData() const {
+ Object& data = Object::Handle(raw_ptr()->data_);
+ if (data.IsArray()) {
+ Object& script = Object::Handle(Array::Cast(data).At(0));
+ if (script.IsScript()) {
+ return TypedData::RawCast(Array::Cast(data).At(1));
+ }
+ }
if (IsClosureFunction()) {
Function& parent = Function::Handle(parent_function());
ASSERT(!parent.IsNull());
@@ -7548,6 +7597,13 @@
}
intptr_t Function::KernelDataProgramOffset() const {
+ Object& data = Object::Handle(raw_ptr()->data_);
+ if (data.IsArray()) {
+ Object& script = Object::Handle(Array::Cast(data).At(0));
+ if (script.IsScript()) {
+ return Smi::Value(Smi::RawCast(Array::Cast(data).At(2)));
+ }
+ }
if (IsClosureFunction()) {
Function& parent = Function::Handle(parent_function());
ASSERT(!parent.IsNull());
@@ -11310,10 +11366,15 @@
RawObject* Library::Evaluate(const String& expr,
const Array& param_names,
const Array& param_values) const {
- // Evaluate the expression as a static function of the toplevel class.
- Class& top_level_class = Class::Handle(toplevel_class());
- ASSERT(top_level_class.is_finalized());
- return top_level_class.Evaluate(expr, param_names, param_values);
+ if (kernel_data() == TypedData::null()) {
+ // Evaluate the expression as a static function of the toplevel class.
+ Class& top_level_class = Class::Handle(toplevel_class());
+ ASSERT(top_level_class.is_finalized());
+ return top_level_class.Evaluate(expr, param_names, param_values);
+ }
+ return EvaluateWithDFEHelper(expr, param_names, Array::Handle(Array::New(0)),
+ String::Handle(url()), String::Handle(), false,
+ param_values);
}
void Library::InitNativeWrappersLibrary(Isolate* isolate, bool is_kernel) {
@@ -11370,6 +11431,118 @@
};
typedef UnorderedHashMap<LibraryLookupTraits> LibraryLookupMap;
+static RawObject* EvaluateWithDFEHelper(const String& expression,
+ const Array& definitions,
+ const Array& type_definitions,
+ const String& library_url,
+ const String& klass,
+ bool is_static,
+ const Array& arguments) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ const String& error_str = String::Handle(
+ String::New("Kernel service isolate not available in precompiled mode."));
+ return ApiError::New(error_str);
+#else
+ Isolate* I = Isolate::Current();
+ Thread* T = Thread::Current();
+
+ Dart_KernelCompilationResult compilation_result;
+ {
+ TransitionVMToNative transition(T);
+ compilation_result = KernelIsolate::CompileExpressionToKernel(
+ expression.ToCString(), definitions, type_definitions,
+ library_url.ToCString(), klass.IsNull() ? NULL : klass.ToCString(),
+ is_static);
+ }
+
+ Function& callee = Function::Handle();
+ intptr_t num_cids = I->class_table()->NumCids();
+ intptr_t num_libs =
+ GrowableObjectArray::Handle(I->object_store()->libraries()).Length();
+
+ void* kernel_pgm = NULL;
+ if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
+ const String& prefix =
+ String::Handle(String::New("Kernel isolate rejected this request:\n"));
+ const String& error_str = String::Handle(String::Concat(
+ prefix, String::Handle(String::New(compilation_result.error))));
+ free(compilation_result.error);
+ return ApiError::New(error_str);
+ }
+
+ const uint8_t* kernel_file = compilation_result.kernel;
+ intptr_t kernel_length = compilation_result.kernel_size;
+ ASSERT(kernel_file != NULL);
+ kernel_pgm =
+ Dart_ReadKernelBinary(kernel_file, kernel_length, ReleaseFetchedBytes);
+ if (kernel_pgm == NULL) {
+ return ApiError::New(String::Handle(
+ String::New("Kernel isolate returned ill-formed kernel.")));
+ }
+
+ // Load the program with the debug procedure as a regular, independent
+ // program.
+ kernel::KernelLoader loader(reinterpret_cast<kernel::Program*>(kernel_pgm));
+ loader.LoadProgram();
+ ASSERT(I->class_table()->NumCids() > num_cids &&
+ GrowableObjectArray::Handle(I->object_store()->libraries()).Length() ==
+ num_libs + 1);
+ const String& fake_library_url =
+ String::Handle(String::New("evaluate:source"));
+ const Library& loaded =
+ Library::Handle(Library::LookupLibrary(T, fake_library_url));
+ ASSERT(!loaded.IsNull());
+
+ String& debug_name = String::Handle(
+ String::New(Symbols::Symbol(Symbols::kDebugProcedureNameId)));
+ Class& fake_class = Class::Handle();
+ if (!klass.IsNull()) {
+ fake_class = loaded.LookupClass(String::Handle(String::New(klass)));
+ ASSERT(!fake_class.IsNull());
+ callee = fake_class.LookupFunctionAllowPrivate(debug_name);
+ } else {
+ callee = loaded.LookupFunctionAllowPrivate(debug_name);
+ }
+ ASSERT(!callee.IsNull());
+
+ // Save the loaded library's kernel data to the generic "data" field of the
+ // callee, so it doesn't require access it's parent library during
+ // compilation.
+ callee.SetKernelDataAndScript(Script::Handle(callee.script()),
+ TypedData::Handle(loaded.kernel_data()),
+ loaded.kernel_offset());
+
+ // Reparent the callee to the real enclosing class so we can remove the fake
+ // class and library from the object store.
+ const Library& real_library =
+ Library::Handle(Library::LookupLibrary(T, library_url));
+ ASSERT(!real_library.IsNull());
+ Class& real_class = Class::Handle();
+ if (!klass.IsNull()) {
+ real_class = real_library.LookupClass(String::Handle(String::New(klass)));
+ } else {
+ real_class = real_library.toplevel_class();
+ }
+ ASSERT(!real_class.IsNull());
+
+ callee.set_owner(real_class);
+
+ // Unlink the fake library and class from the object store.
+ GrowableObjectArray::Handle(I->object_store()->libraries())
+ .SetLength(num_libs);
+ I->class_table()->SetNumCids(num_cids);
+ if (!fake_class.IsNull()) {
+ fake_class.set_id(kIllegalCid);
+ }
+ LibraryLookupMap libraries_map(I->object_store()->libraries_map());
+ bool removed = libraries_map.Remove(fake_library_url);
+ ASSERT(removed);
+ I->object_store()->set_libraries_map(libraries_map.Release());
+
+ return DartEntry::InvokeFunction(callee, arguments);
+#endif
+}
+
// Returns library with given url in current isolate, or NULL.
RawLibrary* Library::LookupLibrary(Thread* thread, const String& url) {
Zone* zone = thread->zone();
@@ -15522,8 +15695,6 @@
const String& expr,
const Array& param_names,
const Array& param_values) const {
- const Function& eval_func = Function::Handle(
- Function::EvaluateHelper(method_cls, expr, param_names, false));
const Array& args = Array::Handle(Array::New(1 + param_values.Length()));
PassiveObject& param = PassiveObject::Handle();
args.SetAt(0, *this);
@@ -15531,7 +15702,18 @@
param = param_values.At(i);
args.SetAt(i + 1, param);
}
- return DartEntry::InvokeFunction(eval_func, args);
+
+ const Library& library = Library::Handle(method_cls.library());
+ if (library.kernel_data() == TypedData::null()) {
+ const Function& eval_func = Function::Handle(
+ Function::EvaluateHelper(method_cls, expr, param_names, false));
+ return DartEntry::InvokeFunction(eval_func, args);
+ } else {
+ return EvaluateWithDFEHelper(
+ expr, param_names, Array::Handle(Array::New(0)),
+ String::Handle(Library::Handle(method_cls.library()).url()),
+ String::Handle(method_cls.UserVisibleName()), false, args);
+ }
}
RawObject* Instance::HashCode() const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6a99622..7d373a9 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2130,6 +2130,7 @@
void ZeroEdgeCounters() const;
RawClass* Owner() const;
+ void set_owner(const Object& value) const;
RawClass* origin() const;
RawScript* script() const;
RawObject* RawOwner() const { return raw_ptr()->owner_; }
@@ -2488,6 +2489,10 @@
set_optimized_call_site_count(value);
}
+ void SetKernelDataAndScript(const Script& script,
+ const TypedData& data,
+ intptr_t offset);
+
intptr_t KernelDataProgramOffset() const;
RawTypedData* KernelData() const;
@@ -2888,7 +2893,6 @@
void set_name(const String& value) const;
void set_kind(RawFunction::Kind value) const;
void set_parent_function(const Function& value) const;
- void set_owner(const Object& value) const;
RawFunction* implicit_closure_function() const;
void set_implicit_closure_function(const Function& value) const;
RawInstance* implicit_static_closure() const;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 4890d04..0fc1385 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4495,6 +4495,7 @@
LinkedHashMap& cc_map = LinkedHashMap::Handle(LinkedHashMap::NewDefault());
// 3. Expect them to have identical structure.
+ TransitionNativeToVM transition(thread);
CheckIdenticalHashStructure(dart_map, cc_map);
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 4b3f6bc..5ca98a9 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -450,7 +450,8 @@
V(PrependTypeArguments, "_prependTypeArguments") \
V(DartDeveloperCausalAsyncStacks, "dart.developer.causal_async_stacks") \
V(_AsyncStarListenHelper, "_asyncStarListenHelper") \
- V(GrowRegExpStack, "_growRegExpStack")
+ V(GrowRegExpStack, "_growRegExpStack") \
+ V(DebugProcedureName, ":Eval")
// Contains a list of frequently used strings in a canonicalized form. This
// list is kept in the vm_isolate in order to share the copy across isolates
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 10795eb..7dd78a0 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -267,7 +267,13 @@
url, FLAG_strong ? platform_strong_dill : platform_dill,
FLAG_strong ? platform_strong_dill_size : platform_dill_size,
sourcefiles_count, sourcefiles, incrementally, NULL);
+ return ValidateCompilationResult(zone, compilation_result, kernel_pgm);
+}
+char* TestCase::ValidateCompilationResult(
+ Zone* zone,
+ Dart_KernelCompilationResult compilation_result,
+ void** kernel_pgm) {
if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
char* result =
OS::SCreate(zone, "Compilation failed %s", compilation_result.error);
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 5aa1d6a..7a500d4 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -379,6 +379,10 @@
const char* name,
void* data = NULL);
+ static char* ValidateCompilationResult(Zone* zone,
+ Dart_KernelCompilationResult result,
+ void** kernel_pgm);
+
RunEntry* const run_;
};